|  | 
| 1 | 1 | package jsenv.playwright | 
| 2 | 2 | 
 | 
|  | 3 | +import cats.effect.IO | 
| 3 | 4 | import cats.effect.unsafe.implicits.global | 
| 4 |  | -import cats.effect.{IO, Resource} | 
| 5 |  | -import com.microsoft.playwright.BrowserType.LaunchOptions | 
| 6 | 5 | import jsenv.playwright.PWEnv.Config | 
| 7 |  | -import jsenv.playwright.PageFactory._ | 
| 8 |  | -import jsenv.playwright.ResourcesFactory._ | 
| 9 |  | -import org.scalajs.jsenv.{Input, JSComRun, JSRun, RunConfig} | 
|  | 6 | +import org.scalajs.jsenv.Input | 
|  | 7 | +import org.scalajs.jsenv.JSRun | 
|  | 8 | +import org.scalajs.jsenv.RunConfig | 
| 10 | 9 | 
 | 
| 11 |  | -import java.util.concurrent.ConcurrentLinkedQueue | 
| 12 |  | -import java.util.concurrent.atomic.AtomicBoolean | 
| 13 | 10 | import scala.concurrent._ | 
| 14 |  | -import scala.concurrent.duration.DurationInt | 
| 15 | 11 | 
 | 
| 16 | 12 | class CERun( | 
| 17 |  | -    browserName: String, | 
| 18 |  | -    headless: Boolean, | 
| 19 |  | -    pwConfig: Config, | 
| 20 |  | -    runConfig: RunConfig, | 
| 21 |  | -    input: Seq[Input] | 
| 22 |  | -) extends JSRun { | 
| 23 |  | - | 
| 24 |  | -  implicit val ec: scala.concurrent.ExecutionContext = | 
| 25 |  | -    scala.concurrent.ExecutionContext.global | 
| 26 |  | - | 
| 27 |  | -  // enableCom is false for CERun and true for CEComRun | 
| 28 |  | -  protected val enableCom = false | 
| 29 |  | -  protected val intf = "this.scalajsPlayWrightInternalInterface" | 
| 30 |  | -  protected val sendQueue = new ConcurrentLinkedQueue[String] | 
| 31 |  | -  // receivedMessage is called only from JSComRun. Hence its implementation is empty in CERun | 
| 32 |  | -  protected def receivedMessage(msg: String): Unit = () | 
| 33 |  | - | 
| 34 |  | -  /** A Future that completes if the run completes. | 
| 35 |  | -    * | 
| 36 |  | -    * The future is failed if the run fails. | 
| 37 |  | -    * | 
| 38 |  | -    * Note that a JSRun is not required to ever terminate on it's own. That | 
| 39 |  | -    * means even if all code is executed and the event loop is empty, the run | 
| 40 |  | -    * may continue to run. As a consequence, it is *not* correct to rely on | 
| 41 |  | -    * termination of a JSRun without any external means of stopping it (i.e. | 
| 42 |  | -    * calling [[close]]). | 
| 43 |  | -    */ | 
| 44 |  | -  var wantToClose = new AtomicBoolean(false) | 
| 45 |  | -  // List of programs | 
| 46 |  | -  // 1. isInterfaceUp() | 
| 47 |  | -  // Create PW resource if not created. Create browser,context and page | 
| 48 |  | -  // 2. Sleep | 
| 49 |  | -  // 3. wantClose | 
| 50 |  | -  // 4. sendAll() | 
| 51 |  | -  // 5. fetchAndProcess() | 
| 52 |  | -  // 6. Close diver | 
| 53 |  | -  // 7. Close streams | 
| 54 |  | -  // 8. Close materializer | 
| 55 |  | -  // Flow | 
| 56 |  | -  // if interface is down and dont want to close wait for 100 milliseconds | 
| 57 |  | -  // interface is up and dont want to close sendAll(), fetchAndProcess() Sleep for 100 milliseconds | 
| 58 |  | -  // If want to close then close driver, streams, materializer | 
| 59 |  | -  // After future is completed close driver, streams, materializer | 
| 60 |  | - | 
| 61 |  | -  def jsRunPrg( | 
| 62 |  | -      browserName: String, | 
| 63 |  | -      headless: Boolean, | 
| 64 |  | -      isComEnabled: Boolean, | 
| 65 |  | -      launchOptions: Option[LaunchOptions] | 
| 66 |  | -  ): Resource[IO, Unit] = for { | 
| 67 |  | -    _ <- Resource.pure( | 
| 68 |  | -      scribe.info( | 
| 69 |  | -        s"Begin Main with isComEnabled $isComEnabled " + | 
| 70 |  | -          s"and  browserName $browserName " + | 
| 71 |  | -          s"and headless is $headless " | 
| 72 |  | -      ) | 
| 73 |  | -    ) | 
| 74 |  | -    pageInstance <- createPage( | 
| 75 |  | -      browserName, | 
| 76 |  | -      headless, | 
| 77 |  | -      launchOptions | 
| 78 |  | -    ) | 
| 79 |  | -    _ <- preparePageForJsRun( | 
| 80 |  | -      pageInstance, | 
| 81 |  | -      materializer(pwConfig), | 
| 82 |  | -      input, | 
| 83 |  | -      isComEnabled | 
| 84 |  | -    ) | 
| 85 |  | -    connectionReady <- isConnectionUp(pageInstance, intf) | 
| 86 |  | -    _ <- | 
| 87 |  | -      if (!connectionReady) Resource.pure[IO, Unit](IO.sleep(100.milliseconds)) | 
| 88 |  | -      else Resource.pure[IO, Unit](IO.unit) | 
| 89 |  | -    _ <- isConnectionUp(pageInstance, intf) | 
| 90 |  | -    out <- outputStream(runConfig) | 
| 91 |  | -    _ <- processUntilStop( | 
| 92 |  | -      wantToClose, | 
| 93 |  | -      pageInstance, | 
| 94 |  | -      intf, | 
| 95 |  | -      sendQueue, | 
| 96 |  | -      out, | 
| 97 |  | -      receivedMessage, | 
| 98 |  | -      isComEnabled | 
| 99 |  | -    ) | 
| 100 |  | -  } yield () | 
| 101 |  | - | 
|  | 13 | +    override val browserName: String, | 
|  | 14 | +    override val headless: Boolean, | 
|  | 15 | +    override val pwConfig: Config, | 
|  | 16 | +    override val runConfig: RunConfig, | 
|  | 17 | +    override val input: Seq[Input] | 
|  | 18 | +) extends JSRun | 
|  | 19 | +    with Runner { | 
|  | 20 | +  scribe.debug(s"Creating CERun for $browserName") | 
| 102 | 21 |   lazy val future: Future[Unit] = | 
| 103 |  | -    jsRunPrg(browserName, headless, enableCom, None) | 
|  | 22 | +    jsRunPrg(browserName, headless, isComEnabled = false, None) | 
| 104 | 23 |       .use(_ => IO.unit) | 
| 105 | 24 |       .unsafeToFuture() | 
| 106 | 25 | 
 | 
| 107 |  | -  /** Stops the run and releases all the resources. | 
| 108 |  | -    * | 
| 109 |  | -    * This <strong>must</strong> be called to ensure the run's resources are | 
| 110 |  | -    * released. | 
| 111 |  | -    * | 
| 112 |  | -    * Whether or not this makes the run fail or not is up to the implementation. | 
| 113 |  | -    * However, in the following cases, calling [[close]] may not fail the run: | 
| 114 |  | -    * <ul> <li>[[future]] is already completed when [[close]] is called. | 
| 115 |  | -    * <li>This is a [[CERun]] and the event loop inside the VM is empty. | 
| 116 |  | -    * </ul> | 
| 117 |  | -    * | 
| 118 |  | -    * Idempotent, async, nothrow. | 
| 119 |  | -    */ | 
| 120 |  | - | 
| 121 |  | -  override def close(): Unit = { | 
| 122 |  | -    wantToClose.set(true) | 
| 123 |  | -    scribe.info(s"StopSignal is ${wantToClose.get()}") | 
| 124 |  | -  } | 
| 125 |  | - | 
|  | 26 | +  override protected def receivedMessage(msg: String): Unit = () | 
| 126 | 27 | } | 
| 127 |  | -// browserName, headless, pwConfig, runConfig, input, onMessage | 
| 128 |  | -class CEComRun( | 
| 129 |  | -    browserName: String, | 
| 130 |  | -    headless: Boolean, | 
| 131 |  | -    pwConfig: Config, | 
| 132 |  | -    runConfig: RunConfig, | 
| 133 |  | -    input: Seq[Input], | 
| 134 |  | -    onMessage: String => Unit | 
| 135 |  | -) extends CERun( | 
| 136 |  | -      browserName, | 
| 137 |  | -      headless, | 
| 138 |  | -      pwConfig, | 
| 139 |  | -      runConfig, | 
| 140 |  | -      input | 
| 141 |  | -    ) | 
| 142 |  | -    with JSComRun { | 
| 143 |  | -  // enableCom is false for CERun and true for CEComRun | 
| 144 |  | -  override protected val enableCom = true | 
| 145 |  | -  // send is called only from JSComRun | 
| 146 |  | -  override def send(msg: String): Unit = sendQueue.offer(msg) | 
| 147 |  | -  // receivedMessage is called only from JSComRun. Hence its implementation is empty in CERun | 
| 148 |  | -  override protected def receivedMessage(msg: String): Unit = onMessage(msg) | 
| 149 |  | -} | 
| 150 |  | - | 
| 151 |  | -private class WindowOnErrorException(errs: List[String]) | 
| 152 |  | -    extends Exception(s"JS error: $errs") | 
0 commit comments