diff --git a/js/scripts/JSRootCore.js b/js/scripts/JSRootCore.js index c9b070d996b0f3a230d749614943a054cf0d26d2..9d1182ebf322068b12305a0aa458c2637471aff5 100644 --- a/js/scripts/JSRootCore.js +++ b/js/scripts/JSRootCore.js @@ -95,7 +95,7 @@ "use strict"; - JSROOT.version = "dev 20/11/2019"; + JSROOT.version = "dev 28/11/2019"; JSROOT.source_dir = ""; JSROOT.source_min = false; diff --git a/js/scripts/JSRootPainter.js b/js/scripts/JSRootPainter.js index 9d23b59092ac8fa2c4759ce893c57c9dc0a59383..6b1fa3e1ecd89136895cb8e9f0e4aa10d56f05cf 100644 --- a/js/scripts/JSRootPainter.js +++ b/js/scripts/JSRootPainter.js @@ -1806,7 +1806,7 @@ this.wait_for_file = false; if (!res) return; if (this.receiver.ProvideData) - this.receiver.ProvideData(res, 0); + this.receiver.ProvideData(1, res, 0); setTimeout(this.next_operation.bind(this),10); } @@ -1856,16 +1856,35 @@ /** Invoke method in the receiver. * @private */ - WebWindowHandle.prototype.InvokeReceiver = function(method, arg, arg2) { + WebWindowHandle.prototype.InvokeReceiver = function(brdcst, method, arg, arg2) { if (this.receiver && (typeof this.receiver[method] == 'function')) this.receiver[method](this, arg, arg2); + + if (brdcst & this.channels) { + var ks = Object.keys(this.channels); + for (var n=0;n<ks.length;++n) + this.channels[ks[n]].InvokeReceiver(false, method, arg, arg2); + } } /** Provide data for receiver. When no queue - do it directly. * @private */ - WebWindowHandle.prototype.ProvideData = function(_msg, _len) { + WebWindowHandle.prototype.ProvideData = function(chid, _msg, _len) { + if (this.wait_first_recv) { + console.log("FIRST MESSAGE", chid, _msg); + delete this.wait_first_recv; + return this.InvokeReceiver(false, "OnWebsocketOpened"); + } + + if ((chid > 1) && this.channels) { + var channel = this.channels[chid]; + if (channel) + return channel.ProvideData(1, _msg, _len); + } + if (!this.msgqueue || !this.msgqueue.length) - return this.InvokeReceiver("OnWebsocketMsg", _msg, _len); + return this.InvokeReceiver(false, "OnWebsocketMsg", _msg, _len); + this.msgqueue.push({ ready: true, msg: _msg, len: _len}); } @@ -1888,7 +1907,7 @@ this._loop_msgqueue = true; while ((this.msgqueue.length > 0) && this.msgqueue[0].ready) { var front = this.msgqueue.shift(); - this.InvokeReceiver("OnWebsocketMsg", front.msg, front.len); + this.InvokeReceiver(false, "OnWebsocketMsg", front.msg, front.len); } if (this.msgqueue.length == 0) delete this.msgqueue; @@ -1897,6 +1916,12 @@ /** Close connection. */ WebWindowHandle.prototype.Close = function(force) { + if (this.master) { + delete this.master.channels[this.channelid]; + delete this.master; + return; + } + if (this.timerid) { clearTimeout(this.timerid); delete this.timerid; @@ -1917,6 +1942,9 @@ /** Send text message via the connection. */ WebWindowHandle.prototype.Send = function(msg, chid) { + if (this.master) + return this.master.Send(msg, this.channelid); + if (!this._websocket || (this.state<=0)) return false; if (isNaN(chid) || (chid===undefined)) chid = 1; // when not configured, channel 1 is used - main widget @@ -1943,6 +1971,36 @@ this.Send("KEEPALIVE", 0); } + /** Method open channel, which will share same connection, but can be used independently from main + * @private */ + WebWindowHandle.prototype.CreateChannel = function() { + if (this.master) + return master.CreateChannel(); + + var channel = new WebWindowHandle("channel"); + channel.wait_first_recv = true; // first received message via the channel is confirmation of established connection + + if (!this.channels) { + this.channels = {}; + this.freechannelid = 2; + } + + channel.master = this; + channel.channelid = this.freechannelid++; + + // register + this.channels[channel.channelid] = channel; + + // now server-side entity should be initialized and init message send from server side! + return channel; + } + + /** Returns used channel ID, 1 by default */ + WebWindowHandle.prototype.getChannelId = function() { + return this.channelid && this.master ? this.channelid : 1; + } + + /** Method opens relative path with the same kind of socket. * @private */ @@ -2012,13 +2070,15 @@ var key = pthis.key || ""; pthis.Send("READY=" + key, 0); // need to confirm connection - pthis.InvokeReceiver('OnWebsocketOpened'); + pthis.InvokeReceiver(false, "OnWebsocketOpened"); } conn.onmessage = function(e) { var msg = e.data; if (pthis.next_binary) { + + var binchid = pthis.next_binary; delete pthis.next_binary; if (msg instanceof Blob) { @@ -2033,7 +2093,7 @@ } else { // console.log('got array ' + (typeof msg) + ' len = ' + msg.byteLength); // this is from CEF or LongPoll handler - pthis.ProvideData(msg, e.offset || 0); + pthis.ProvideData(binchid, msg, e.offset || 0); } return; @@ -2059,14 +2119,14 @@ console.log('GET chid=0 message', msg); if (msg == "CLOSE") { pthis.Close(true); // force closing of socket - pthis.InvokeReceiver('OnWebsocketClosed'); + pthis.InvokeReceiver(true, "OnWebsocketClosed"); } } else if (msg == "$$binary$$") { - pthis.next_binary = true; + pthis.next_binary = chid; } else if (msg == "$$nullbinary$$") { - pthis.ProvideData(new ArrayBuffer(0), 0); + pthis.ProvideData(chid, new ArrayBuffer(0), 0); } else { - pthis.ProvideData(msg); + pthis.ProvideData(chid, msg); } if (pthis.ackn > 7) @@ -2078,14 +2138,14 @@ if (pthis.state > 0) { console.log('websocket closed'); pthis.state = 0; - pthis.InvokeReceiver('OnWebsocketClosed'); + pthis.InvokeReceiver(true, "OnWebsocketClosed"); } } conn.onerror = function (err) { console.log("websocket error " + err); if (pthis.state > 0) { - pthis.InvokeReceiver('OnWebsocketError', err); + pthis.InvokeReceiver(true, "OnWebsocketError", err); pthis.state = 0; } }