UNPKG

dreemgl

Version:

DreemGL is an open-source multi-screen prototyping framework for mediated environments, with a visual editor and shader styling for webGL and DALi runtimes written in JavaScript. As a toolkit for gpu-accelerated multiscreen development, DreemGL includes

479 lines (430 loc) 12.3 kB
/* DreemGL is a collaboration between Teeming Society & Samsung Electronics, sponsored by Samsung and others. Copyright 2015-2016 Teeming Society. Licensed under the Apache License, Version 2.0 (the "License"); You may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.*/ define.class(function(require){ // internal, node websocket var crypto = require('crypto') var url = require('url') var http = require('http') this.atConstructor = function(req, socket, head){ if(arguments.length === 1){ if(typeof req === 'string'){ this.initClient(req) } else{ this.initBare(req) } } if(arguments.length === 3) this.initServer(req, socket, head) } // events (looks just like browser websocket) this.onmessage = function(event){ } this.onclose = function(){ } this.onerror = function(error){ } // turn the socket into a socket that can send json with binary data this.makeJSONSocket = function(){ var binary_buf = [] this.onmessage = function(event){ var message = event.data if(message instanceof ArrayBuffer){ binary_buf.push(message) return } var jsonmsg = JSON.parse(message) jsonmsg = define.structFromJSON(jsonmsg, binary_buf) binary_buf.length = 0 this.atJSONMessage(jsonmsg) } this.sendJSON = function(msg){ var binary = [] var newmsg = define.makeJSONSafe(msg, binary) for(var i = 0; i < binary.length; i++){ var bin = binary[i] this.send(bin.data.buffer)//data.buffer) } var jsonmsg = JSON.stringify(newmsg) this.send(jsonmsg) } } // us it as a communication pipe over any socket this.initBare = function(socket){ this.socket = socket this.initState() } this.initClient = function(server_url){ this.url = url.parse(server_url) // ok lets connect to a server var host = this.url.hostname + ':' + this.url.port // begin handshake var key = new Buffer(13 + '-' + Date.now()).toString('base64'); var shasum = crypto.createHash('sha1'); shasum.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'); this.expectedServerKey = shasum.digest('base64'); //var origin = host + this.url.path var opt = { port: this.url.port, host: this.url.hostname, path: this.url.path, headers: { 'connection': 'Upgrade', 'upgrade': 'websocket', 'pragma':'no-cache', 'host': host, 'origin': 'http://' + host, 'sec-websocket-version': 13, 'sec-websocket-key': key, } } var req = http.request(opt) req.on('error', function(err){ console.log("WebSocket client " + err) if(this.onError) this.onError(err) }.bind(this)) req.once('response', function(){ console.log('WebSocket unexpected response') }.bind(this)) req.once('upgrade', function(res, socket, upgradehead){ if(res.headers['sec-websocket-accept'] != this.expectedServerKey){ console.log('WebSocket unexpected server key') } this.socket = socket this.initState() if(this.onopen) this.onopen() }.bind(this)) req.end() } this.initServer = function(req, socket){ var version = req.headers['sec-websocket-version'] if(version != 13){ console.log("Incompatible websocket version requested (need 13) " + version) return socket.destroy() } this.socket = socket // calc key var key = req.headers['sec-websocket-key'] var sha1 = crypto.createHash('sha1'); sha1.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); var ack = 'HTTP/1.1 101 Switching Protocols\r\n'+ 'Upgrade: websocket\r\n'+ 'Connection: Upgrade\r\n'+ 'Sec-WebSocket-Accept: ' + sha1.digest('base64') +'\r\n\r\n' this.socket.write(ack) this.is_server = true this.initState() this.first_queue = [] } this.initState = function(){ this.max = 500000000 // maximum receive buffer size (10 megs) this.header = new Buffer(14) // header this.output = new Buffer(50000000) // output this.state = this.opcode // start in the opcode state this.expected = 1 // the bytes expected for the next state this.written = 0 // how much we have written in the output buffers this.read = 0 // the bytes we've read this.input = 0 // the input buffer received from the socket this.maskoff = 0 // the offset in the mask this.maskcount = 0 // mask counter this.paylen = 0 // payload length this.readyState = 1 this.partial_msg = '' this.partial_binary = [] this.partial_binary_bytes = 0 // 10 second ping frames this.pingframe = new Buffer(2) this.pingframe[0] = 9 | 128 this.pingframe[1] = 0 this.pongframe = new Buffer(2) this.pongframe[0] = 10 | 128 this.pongframe[1] = 0 if(this.is_server){ this.ping_interval = setInterval(function(){ if(!this.socket) clearInterval(this.ping_interval) else this.socket.write(this.pingframe) }.bind(this), 10000) } // Main socket data loop, uses state function to parse this.socket.on('data', function(data){ this.input = data this.read = 0 while(this.state()); }.bind(this)) this.socket.on('close', function(){ this.close() }.bind(this)) } this.error = function(t){ console.log("Error on websocket " + t) this.onerror(t) this.close() } this.send = function(data, ispartial, iscontinuation, domask){ if(this.first_queue){ // put a tiny gap between a server connect and first data send if(!this.first_queue.length){ setTimeout(function(){ var q = this.first_queue this.first_queue = undefined for(var i = 0;i < q.length;i++){ this.send(q[i]) } }.bind(this),10) } this.first_queue.push(data) return } //if(typeof data !== 'string' && !(data instanceof Buffer)){ // var msg = define. // data = JSON.stringify(data) //} if(!this.socket) return var head var buf = new Buffer(data) if(buf.length < 126){ head = new Buffer(2) head[1] = buf.length } else if (buf.length<=65535){ head = new Buffer(4) head[1] = 126 head.writeUInt16BE(buf.length, 2) } else { head = new Buffer(10) head[1] = 127 head[2] = head[3] = head[4] = head[5] = 0 head.writeUInt32BE(buf.length, 6) } var type = 1 if(data instanceof Buffer || data instanceof ArrayBuffer) type = 2 if(iscontinuation) type = 0 head[0] = (ispartial?0:128) | type this.socket.write(head) // lets mask the data if(domask){ head[1] |= 128 var mask = new Buffer(4) mask[0] = 0x7f mask[1] = 0x7f mask[2] = 0x7f mask[3] = 0x7f this.socket.write(mask) for(var i = 0; i < buf.length; i++){ buf[i] ^= mask[i&3] } } this.socket.write(buf) } this.close = function(){ if(this.socket){ this.onclose() this.socket.destroy() clearInterval(this.ping_interval) this.readyState = 3 } this.socket = undefined } this.head = function(){ var se = this.expected while(this.expected > 0 && this.read < this.input.length && this.written < this.header.length){ this.header[this.written++] = this.input[this.read++], this.expected-- } if(this.written > this.header.length) return this.err("unexpected data in header"+ se + s.toString()) return this.expected != 0 } var total = 0 this.data = function(){ if(this.masked){ while(this.expected > 0 && this.read < this.input.length){ this.output[this.written++] = this.input[this.read++] ^ this.header[this.maskoff + (this.maskcount++&3)] this.expected-- } } else{ if(this.written > this.output.length) console.log("NodeWebSocket output buffer overflow "+this.written) //console.log(this.expected)////console.log("i iz here",this.input.length - this.read, this.expected, this.written) while(this.expected > 0 && this.read < this.input.length){ this.output[this.written++] = this.input[this.read++] this.expected-- } } if(this.expected) return false if(this.binary){ // single message binary if(!this.partial && !this.partial_binary_bytes){ var msg = new Uint8Array(this.written) for(var i = 0; i < this.written; i++) msg[i] = this.output[i] this.onmessage({data:msg.buffer}) } else{ // multi message binary var store = new Uint8Array(this.written) this.partial_binary.push(store) for(var i = 0; i < this.written; i++){ store[i] = this.output[i] } this.partial_binary_bytes += i if(!this.partial){ var msg = new Uint8Array(this.partial_binary_bytes) var off = 0 for(var i = 0; i < this.partial_binary.length; i++){ var item = this.partial_binary[i] for(var j = 0; j < item.length; j++, off++){ msg[off] = item[j] } } this.partial_binary.length = 0 this.partial_binary_bytes = 0 this.onmessage({data:msg.buffer}) } } } else if(!this.partial){ this.onmessage({data:this.partial_msg + this.output.toString('utf8', 0, this.written)}) this.partial_msg = '' } else{ this.partial_msg += this.output.toString('utf8', 0, this.written) } this.written = 0 this.expected = 1 this.state = this.opcode return true } this.mask = function(){ if(this.head()) return false if(!this.paylen){ this.expected = 1 this.written = 0 this.state = this.opcode return true } this.maskoff = this.written - 4 this.written = this.maskcount = 0 this.expected = this.paylen if(this.paylen > this.max) return this.error("buffer size request too large " + l + " > " + max) if(this.paylen > this.output.length) this.output = new Buffer(this.paylen) this.state = this.data return true } this.len8 = function(){ if(this.head()) return false this.paylen = this.header.readUInt32BE(this.written - 4) if(this.masked){ this.expected = 4 this.state = this.mask } else{ this.expected = this.paylen this.state = this.data this.written = 0 } return true } this.len2 = function(){ if(this.head()) return this.paylen = this.header.readUInt16BE(this.written - 2) if(this.masked){ this.expected = 4 this.state = this.mask } else{ this.expected = this.paylen this.state = this.data this.written = 0 } return true } this.len1 = function(){ if(this.head()) return false // set masked flag if(!(this.header[this.written - 1] & 128)){ this.masked = false } else{ this.masked = true } var type = this.header[this.written - 1] & 127 if(type < 126){ this.paylen = type if(!this.masked){ this.expected = this.paylen this.state = this.data this.written = 0 } else{ this.expected = 4 this.state = this.mask } } else if(type == 126){ this.expected = 2 this.state = this.len2 } else if(type == 127){ this.expected = 8 this.state = this.len8 } return true } this.ping = function(){ if(this.head()) return false if(this.header[this.written - 1] & 128){ this.expected = 4 this.paylen = 0 this.state = this.mask return true } this.expected = 1 this.written = 0 this.state = this.opcode this.socket.write(this.pongframe) return true } this.pong = function(){ if(this.head()) return false if(this.header[this.written - 1] & 128){ this.expected = 4 this.paylen = 0 this.state = this.mask return true } this.expected = 1 this.written = 0 this.state = this.opcode return true } this.opcode = function(){ if(this.head()) return var frame = this.header[0] & 128 var type = this.header[0] & 15 if(type === 0 || type == 1 || type == 2){ if(!frame){ this.partial = true } else{ this.partial = false } this.binary = type === 2 || type === 0 && this.last_type === 2 this.expected = 1 this.state = this.len1 if(type) this.last_type = type return true } if(type == 8) return this.close() if(type == 9){// ping frame this.expected = 1 this.state = this.ping return true } if(type == 10){ this.expected = 1 this.state = this.pong return true } return this.error("opcode not supported " + type) } })