Version1 /
WebSocketImplementationNotesSummaryThis module is implemented in the Cape Code Host that uses Nashorn. It should be relatively easy to implement for the Node Host using Node.js because it is fashioned after the ws module in Node.js, with additional influence from the web socket submodule of the socket.io. Node HostNode Test CaseOur test case is invoked using Cape Code Host Cape Code: $PTII/bin/vergil -capecode $PTII/org/terraswarm/accessor/test/auto/WebSocketClientJS.xml Running the code generator creates accessors/web/net/test/auto/WebSocketClient.js, which can be invoked with: cd $PTII/org/terraswarm/accessor/accessors/web/net/test/auto; node ../../../hosts/node/nodeHostInvoke.js -timeout 2000 net/test/auto/WebSocketClientJS The WebSocketClient accessor is never firedWhen the Cape Code model above is run, we get the following output: WebSocketClient: WebSocketClient.js: initialize() (Thread[WebSocketClientJS,1,main]) WebSocketClient: WebSocketClient.js: connect() (Thread[WebSocketClientJS,1,main]) WebSocketClient: Connection failed. Will try again: Connection refused: localhost/127.0.0.1:8087 (Thread[vert.x-eventloop-thread-1,6,main]) WebSocketServer: Server: Listening for socket connection requests. (Thread[vert.x-eventloop-thread-3,6,main]) WebSocketServer: Server: new socket established with ID: 0 (Thread[vert.x-eventloop-thread-3,6,main]) WebSocketClient: WebSocketClient.js: onOpen(): Status: Connection established (Thread[vert.x-eventloop-thread-1,6,main]) WebSocketClient: Connection closed because model is no longer running. (Thread[AWT-EventQueue-0,6,main]) WebSocketClient: Status: Connection closed in wrapup. (Thread[AWT-EventQueue-0,6,main]) WebSocketClient: WebSocketClient.js onClose(): Status: Connection closed. (Thread[vert.x-eventloop-thread-1,6,main]) WARNING: Invoking send() too late (probably in a callback), so WebSocketServer is not able to send the token {socketID = 0, status = "closed"} to the output connection. Token is discarded. WebSocketClient: WebSocketClient.js onClose(): Status: Connection closed. (Thread[vert.x-eventloop-thread-1,6,main]) WARNING: Invoking send() too late (probably in a callback), so WebSocketServer is not able to send the token {socketID = 0, status = "closed"} to the output connection. Token is discarded. WebSocketClient: Connection closed because model is no longer running. (Thread[WebSocketClientJS,1,main]) WebSocketClient: Status: Connection closed in wrapup. (Thread[WebSocketClientJS,1,main]) 28984 ms. Memory: 448512K Free: 134833K (30%) When the node version is run, we get: Instantiated accessor WebSocketClientJS with class net/test/auto/WebSocketClientJS WebSocketClient.js: initialize() WebSocketClient.js: connect() webSocketServer.Server() webSocketServer.start(): localhost 8087 webSocketServer.start(): listening event webSocketServer.stop() undefined:121 throw new Error('The fire() function of this accessor was never called. ' + ^ Error: The fire() function of this accessor was never called. Usually, this is an error indicating that starvation is occurring. at Accessor.exports.wrapup (eval at Accessor (/Users/cxh/ptII/org/terraswarm/accessor/accessors/web/{$HOSTS_COMMON}/commonHost.js:425:19), <anonymous>:121:23) at Accessor.wrapup (/Users/cxh/ptII/org/terraswarm/accessor/accessors/web/{$HOSTS_COMMON}/commonHost.js:552:37) at Accessor.wrapup (/Users/cxh/ptII/org/terraswarm/accessor/accessors/web/{$HOSTS_COMMON}/commonHost.js:545:52) at null._onTimeout (/Users/cxh/ptII/org/terraswarm/accessor/accessors/web/{$HOSTS_NODE}/nodeHostInvoke.js:77:39) at Timer.listOnTimeout (timers.js:92:15) Comparing the two outputs:
AnalysisFrom the above:
Solutions
Continuing with NodeOne possible solution is to wait a bit and then try to connect again. However, that is not working.
/** Open the socket connection. Call this after setting up event handlers. */ exports.Client.prototype.open = function () { console.log("webSocketClient.open(): this.host: " + this.host); // The code below is from the Cape Code module. // this.helper.open(); // There is no ws open(). We wait to instantiate the WebSocket // until we are here because we want to be able to register // handlers before we open the WebSocket connection. // Strictly speaking, it is not necessary in Node to this, but it is in Vert.x. // Before this method is called, the client code will register an // open handler (for example) or a message handler. this.connectWebsocket(); }; // FIXME: this should probably not be exported. exports.Client.prototype.connectWebsocket = function () { console.log("webSocketClient.connectWebsocket()"); var protocol = 'http'; if (this.sslTls) { protocol = 'https'; } var url = protocol + "://" + this.host + ":" + this.port; try { this.helper = new WebSocket(url); } catch (err) { throw new Error("Failed to instantiate a Websocket host, url was '" + url + "': " + err); } this.helper.on('close', function() { console.log("webSocketClient.open(): close event"); this.emit('close'); }); var self = this; this.helper.on('error', function(message) { console.log("webSocketClient.open(): error event: " + message + " timeBetweenRetries: " + self.tim\ eBetweenRetries); // It could be that the WebSocketServer is not yet present. // See ptolemy/actor/lib/jjs/modules/webSocket/WebSocketHelper.java // FIXME: the body of this setTimeout() does not get invoked? setTimeout(function() { //console.log("webSocketClient.open(): error event: about to call connectWebsocket()"); self.connectWebsocket(); }, self.timeBetweenRetries); // However, if I uncomment the definition of retryConnection() // above and the line below, then that method gets invoked. // self.retryConnection(); this.emit('error', message); }); this.helper.on('message', function(body) { console.log("webSocketClient.open(): message event:" + body); this.emit('message', body); }); this.helper.on('open', function() { console.log("webSocketClient.open(): open event"); this.emit('open'); }); }; When I run under node 6.2.0: bash-3.2$ node --version v6.2.0 bash-3.2$ (cd $PTII/org/terraswarm/accessor/accessors/web/net/test/auto; node ../../../{$HOSTS_NODE}/nodeHost\ Invoke.js -timeout 3000 net/test/auto/WebSocketClientJS) Reading accessor at: /Users/cxh/ptII/org/terraswarm/accessor/accessors/web/net/test/auto/WebSocketClientJS\ .js Reading accessor at: /Users/cxh/ptII/org/terraswarm/accessor/accessors/web/net/WebSocketClient.js Reading accessor at: /Users/cxh/ptII/org/terraswarm/accessor/accessors/web/net/WebSocketServer.js Reading accessor at: /Users/cxh/ptII/org/terraswarm/accessor/accessors/web/test/TrainableTest.js Instantiated accessor WebSocketClientJS with class net/test/auto/WebSocketClientJS WebSocketClient.js: initialize() WebSocketClient.js: connect() WebSocketClient.js: connect() calling new WebSocket.Client() webSocketClient.Client() webSocketClient.open(): this.host: localhost webSocketClient.connectWebsocket() WebSocketClient.js: connect() done webSocketServer.Server() webSocketServer.start(): localhost 8087 webSocketServer.start(): listening event webSocketClient.open(): error event: Error: connect ECONNREFUSED 127.0.0.1:8087 timeBetweenRetries: 1000 webSocketClient.open(): error event: Error: connect ECONNREFUSED 127.0.0.1:8087 timeBetweenRetries: 1000 webSocketClient.open(): error event: Error: connect ECONNREFUSED 127.0.0.1:8087 timeBetweenRetries: 1000 webSocketClient.open(): error event: Error: connect ECONNREFUSED 127.0.0.1:8087 timeBetweenRetries: 1000 webSocketClient.open(): error event: Error: connect ECONNREFUSED 127.0.0.1:8087 timeBetweenRetries: 1000 webSocketClient.open(): error event: Error: connect ECONNREFUSED 127.0.0.1:8087 timeBetweenRetries: 1000 webSocketClient.open(): error event: Error: connect ECONNREFUSED 127.0.0.1:8087 timeBetweenRetries: 1000 webSocketClient.open(): error event: Error: connect ECONNREFUSED 127.0.0.1:8087 timeBetweenRetries: 1000 webSocketClient.open(): error event: Error:bash-3.2$ Using the debugger indicates that the issue is the stack size: WebSocketClient.js: connect() done webSocketServer.Server() webSocketServer.start(): localhost 8087 webSocketServer.start(): listening event webSocketClient.open(): error event: Error: connect ECONNREFUSED 127.0.0.1:8087 timeBetweenRetries: 1000 webSocketClient.open(): error event: Error: connect ECONNREFUSED 127.0.0.1:8087 timeBetweenRetries: 1000 webSocketClient.open(): error event: Error: connect ECONNREFUSED 127node.js:257 get: function() { ^ RangeError: Maximum call stack size exceeded at Object.defineProperty.get (node.js:257:20) at WebSocket.<anonymous> (/Users/cxh/ptII/org/terraswarm/accessor/accessors/web/{$HOSTS_NODE}/node_module\ s/webSocketClient/webSocketClient.js:232:9) at emitOne (events.js:96:13) at WebSocket.emit (events.js:188:7) at WebSocket.<anonymous> (/Users/cxh/ptII/org/terraswarm/accessor/accessors/web/{$HOSTS_NODE}/node_module\ s/webSocketClient/webSocketClient.js:248:14) at emitOne (events.js:96:13) at WebSocket.emit (events.js:188:7) at WebSocket.<anonymous> (/Users/cxh/ptII/org/terraswarm/accessor/accessors/web/{$HOSTS_NODE}/node_module\ s/webSocketClient/webSocketClient.js:248:14) at emitOne (events.js:96:13) at WebSocket.emit (events.js:188:7) [Inferior 1 (process 11441) exited with code 01] Adding the following method: exports.Client.prototype.retryConnection = function () { console.log("webSocketClient.retryConnection()"); // It could be that the WebSocketServer is not yet present. // See ptolemy/actor/lib/jjs/modules/webSocket/WebSocketHelper.java setTimeout(this.connectWebsocket, 1000); }; (:source:) and changing the contents of @@connectWebsocket()@@: (:source lang=javascript:) this.helper.on('error', function(message) { console.log("webSocketClient.open(): error event: " + message + " timeBetweenRetries: " + self.tim\ eBetweenRetries); // It could be that the WebSocketServer is not yet present. // See ptolemy/actor/lib/jjs/modules/webSocket/WebSocketHelper.java // FIXME: the body of this setTimeout() does not get invoked? // setTimeout(function() { // //console.log("webSocketClient.open(): error event: about to call connectWebsocket()"); // self.connectWebsocket(); // }, self.timeBetweenRetries); // However, if I uncomment the definition of retryConnection() // above and the line below, then that method gets invoked. self.retryConnection(); this.emit('error', message); }); results in this from within (gdb) break exit Breakpoint 1 at 0x7fff85f3973c (gdb) r ../../../{$HOSTS_NODE}/nodeHostInvoke.js -timeout 5000 net/test/auto/WebSocketClientJS The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /usr/local/bin/node ../../../{$HOSTS_NODE}/nodeHostInvoke.js -timeout 5000 net/test/auto/We\ bSocketClientJS Reading accessor at: /Users/cxh/ptII/org/terraswarm/accessor/accessors/web/net/test/auto/WebSocketClientJS\ .js Reading accessor at: /Users/cxh/ptII/org/terraswarm/accessor/accessors/web/net/WebSocketClient.js Reading accessor at: /Users/cxh/ptII/org/terraswarm/accessor/accessors/web/net/WebSocketServer.js Reading accessor at: /Users/cxh/ptII/org/terraswarm/accessor/accessors/web/test/TrainableTest.js Instantiated accessor WebSocketClientJS with class net/test/auto/WebSocketClientJS WebSocketClient.js: initialize() WebSocketClient.js: connect() WebSocketClient.js: connect() calling new WebSocket.Client() webSocketClient.Client() webSocketClient.open(): this.host: localhost webSocketClient.connectWebsocket() WebSocketClient.js: connect() done webSocketServer.Server() webSocketServer.start(): localhost 8087 webSocketServer.start(): listening event webSocketClient.open(): error event: Error: connect ECONNREFUSED 127.0.0.1:8087 timeBetweenRetries: 1000 webSocketClient.retryConnection() webSocketClient.open(): error event: Error: connect ECONNREFUSED 127.0.0.1:8087 timeBetweenRetries: 1000 webSocketClient.retryConnection() node.js:257 get: function() { ^ RangeError: Maximum call stack size exceeded at Object.defineProperty.get (node.js:257:20) at WebSocket.<anonymous> (/Users/cxh/ptII/org/terraswarm/accessor/accessors/web/{$HOSTS_NODE}/node_module\ s/webSocketClient/webSocketClient.js:232:9) at emitOne (events.js:96:13) at WebSocket.emit (events.js:188:7) at WebSocket.<anonymous> (/Users/cxh/ptII/org/terraswarm/accessor/accessors/web/{$HOSTS_NODE}/node_module\ s/webSocketClient/webSocketClient.js:248:14) at emitOne (events.js:96:13) at WebSocket.emit (events.js:188:7) at WebSocket.<anonymous> (/Users/cxh/ptII/org/terraswarm/accessor/accessors/web/{$HOSTS_NODE}/node_module\ s/webSocketClient/webSocketClient.js:248:14) at emitOne (events.js:96:13) at WebSocket.emit (events.js:188:7) [New Thread 0x1527 of process 11452] [New Thread 0x1627 of process 11452] [New Thread 0x1717 of process 11452] [New Thread 0x1807 of process 11452] [New Thread 0x1907 of process 11452] [New Thread 0x1a07 of process 11452] [New Thread 0x1b07 of process 11452] [New Thread 0x1c17 of process 11452] [New Thread 0x2007 of process 11452] Breakpoint 1, 0x00007fff85f3973c in exit () from /usr/lib/system/libsystem_c.dylib (gdb) where #0 0x00007fff85f3973c in exit () from /usr/lib/system/libsystem_c.dylib #1 0x00000001007e1ae5 in node::FatalException(v8::Isolate*, v8::Local<v8::Value>, v8::Local<v8::Message>)\ () #2 0x0000000100546bed in v8::internal::MessageHandler::ReportMessage(v8::internal::Isolate*, v8::internal\ ::MessageLocation*, v8::internal::Handle<v8::internal::JSMessageObject>) () #3 0x0000000100532c09 in v8::internal::Isolate::ReportPendingMessages() () #4 0x00000001004440e4 in v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, bool, v8::in\ ternal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handl\ e<v8::internal::Object>*, v8::internal::Handle<v8::internal::Object>) () #5 0x0000000100443e33 in v8::internal::Execution::Call(v8::internal::Isolate*, v8::internal::Handle<v8::i\ nternal::Object>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Obje\ ct>*) () #6 0x0000000100167a86 in v8::Function::Call(v8::Local<v8::Context>, v8::Local<v8::Value>, int, v8::Local<\ v8::Value>*) () #7 0x00000001007d3f51 in node::AsyncWrap::MakeCallback(v8::Local<v8::Function>, int, v8::Local<v8::Value>\ *) () #8 0x000000010081cea0 in node::TCPWrap::AfterConnect(uv_connect_s*, int) () #9 0x000000010091aa56 in uv.stream_io () #10 0x0000000100922510 in uv.io_poll () #11 0x00000001009135ef in uv_run () #12 0x00000001007e884d in node::Start(int, char**) () #13 0x0000000100000e34 in start () (gdb) Questions:
RetryMaybe instead, we should use a Node retry module
See Also
|