Websocket on PhantomJS 2.0 closes prematurely

466 views
Skip to first unread message

Jakub Liska

unread,
Aug 19, 2014, 8:22:06 AM8/19/14
to scal...@googlegroups.com
Hey,

I'm using PhantomJS 2.0 (qt5) branch because it supports current version of websockets (1.9 supports only hixie-76). 

If I create a basic javascript websocket sample it works fine on PhantomJS, although the same sample in Scala.js does not. It establishes the connection but before netty has a chance to answer the connection closes. At first I thought that phantomJS exits and the connection closes, but it behaves the same if I sleep it for a while...  (btw for those who would want to build the PhantomJS fork 2.0 branch it is necessary to chmod -R 775 ./* for it to build successfully...)

JAVASCRIPT: 

var ws = new WebSocket("ws://localhost:8182/gremlin");

ws.onopen = function() {
    console.log("On connection open");
    ws.send("Message to send");
};

ws.onmessage = function (evt) {
    console.log("On message");
    var received_msg = evt.data;
    phantom.exit()
};

ws.onclose = function() {
    console.log("Closing socket");
};
ws.onerror = function(err) {
    console.log("Some error has occurred : " + err);
};


SCALA.JS: 

import org.scalajs.dom
import scala.scalajs.js.{Date, JSApp}
import org.scalajs.dom.{CloseEvent, ErrorEvent, Event, MessageEvent}


object ExampleJS extends JSApp {

  def main(): Unit = {
    val ws = new dom.WebSocket("ws://localhost:8182/gremlin")

    ws.onopen = (x: Event) => {
      println("On connection open")
      ws.send("Message to send")
    }
    ws.onmessage = (x: MessageEvent) => {
      println("On message")
      println(x.data.toString)
    }
    ws.onclose = (x: CloseEvent) =>
      println("Closing socket")
    ws.onerror = (x: ErrorEvent) =>
      println("Some error has occurred : " + x)

    sleep(2000)
  }

  def sleep(ms: Long) {
    val start = new Date().getTime()
    for (i <- 1 until 10000000) {
      if ((new Date().getTime() - start) > ms){
        return
      }
    }
  }
}

Does anybody have an idea how to deal with it ?

Jakub Liska

unread,
Aug 19, 2014, 8:41:17 AM8/19/14
to scal...@googlegroups.com
I just found out that https://github.com/ariya/phantomjs already contains the qt5 merge commit with current websocket version...I'm gonna try it.

Jakub Liska

unread,
Aug 19, 2014, 8:48:22 AM8/19/14
to scal...@googlegroups.com
It's the same with master of https://github.com/ariya/phantomjs...

Tobias Schlatter

unread,
Aug 19, 2014, 8:53:18 AM8/19/14
to scal...@googlegroups.com
The PhantomJS runner of the sbt plugin inserts a phantom.exit() at the end of the invocation of the main, since otherwise a "normal" program would never terminate (you might also note that your code is actually run inside a loaded webpage; otherwise you won't get a DOM).

I doubt that I can just add a flag to not emit this statement, since the  phantom.exit() you'll write in your code will probably raise a security error.

I'm sure we can add some escape hatch, but it'd be specific to Scala.js phantomJS runner.

The other, cleaner option would be to give you a pure phantomJS runner, that doesn't do all the webpage magic, but in that one, there would be no DOM.

Any ideas?

Jakub Liska

unread,
Aug 19, 2014, 10:12:21 AM8/19/14
to scal...@googlegroups.com
Well, theoretically you might exit phantom after a small delay like 2 seconds :

window.setTimeout(
    function () {
        console.log( "Exiting phantomJS" );
        phantom.exit(1);
    }, 2000
);

This way developers would have at least some time to have their callbacks finish. The same would be handy for utest testing if I'm not mistaken.

Jason Jackson

unread,
Aug 19, 2014, 10:32:36 AM8/19/14
to scal...@googlegroups.com
I had to work around a similar issue on one of my projects. This was with 1.9, and not with scalajs, so I am not certain it works with your situation, but it involves assigning a function to the page.onCallback function within the phantomjs script. You can then trigger the callback at the appropriate time by using the following code within the javascript of your page after everything is ready:

  if (typeof window.callPhantom === 'function') {
    window.callPhantom({ done: true});
  }

Then you put the call to phantom.exit() within the page.onCallback function handler, allowing phantom to wait until the time is right.

Jason

Jakub Liska

unread,
Aug 19, 2014, 1:59:22 PM8/19/14
to scal...@googlegroups.com
I can hardly think of a way of doing it, anyway without explicitly exiting there is practically impossible to test asynchronously in single threaded environment...

Jakub Liska

unread,
Aug 19, 2014, 2:25:32 PM8/19/14
to scal...@googlegroups.com
I created an issue #958 
Reply all
Reply to author
Forward
0 new messages