document.addEventListener("DOMContentLoaded", function(event) { if(!document.title) document.title="Super8"; },true) function setupWS( cbCnx ) { var url=window.location.origin.replace("http","ws")+"/Super8_7f9f450775b0-ws" var ws=new WebSocket( url ); ws.onmessage = function(evt) { var r = guy._jsonParse(evt.data); guy.log("** WS RECEPT:",r) if(r.uuid) // that's a response from call py ! document.dispatchEvent( new CustomEvent('guy-'+r.uuid,{ detail: r} ) ); else if(r.jsmethod) { // call from py : self.js.() function sendBackReturn( response ) { var cmd={ command: "return", args: response, uuid: r.key, }; ws.send( JSON.stringify(cmd) ); guy.log("call jsmethod from py:",r.jsmethod,r.args,"-->",cmd.args) } let jsmethod=window[r.jsmethod]; if(!jsmethod) sendBackReturn( {error:"Unknown JS method "+r.jsmethod} ) else { if(jsmethod.constructor.name == 'AsyncFunction') { jsmethod.apply(window,r.args).then( function(x) { sendBackReturn( { value: x } ); }).catch(function(e) { sendBackReturn( { error: `JS Exception calling '${r.jsmethod}(...)' : ${e}` } ); }) } else { try { sendBackReturn( { value: jsmethod.apply(window,r.args) } ); } catch(e) { sendBackReturn( { error: `JS Exception calling '${r.jsmethod}(...)' : ${e}` } ); } } } } else if(r.event){ // that's an event from anywhere ! document.dispatchEvent( new CustomEvent(r.event,{ detail: r.args } ) ); } }; ws.onclose = function(evt) { guy.log("** WS Disconnected"); setTimeout( function() {setupWS(cbCnx)}, 500); }; ws.onerror = function(evt) { guy.log("** WS Disconnected"); setTimeout( function() {setupWS(cbCnx)}, 500); }; ws.onopen=function(evt) { guy.log("** WS Connected") cbCnx(ws); } return ws; } var guy={ _jsonParse: function(x) { function reviver(key, value) { const dateFormat = /^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?Z$/; if (typeof value === "string" && dateFormat.test(value)) return new Date(value); else return value; } return JSON.parse(x, reviver ) }, _log: false, log:function(_) { if(guy._log) { var args=Array.prototype.slice.call(arguments) args.unshift("--") console.log.apply(console.log,args.map( function(x) {return x==null?"NULL":x})); } }, _ws: setupWS( function(ws){guy._ws = ws; document.dispatchEvent( new CustomEvent("init") )} ), on: function( evt, callback ) { // to register an event on a callback guy.log("guy.on:","DECLARE",evt,callback.name) var listener=function(e) { callback.apply(callback,e.detail) }; document.addEventListener(evt,listener) return function() { document.removeEventListener(evt, listener) } }, emitMe: function( _) { // to emit to itself let ll=Array.prototype.slice.call(arguments) let evt=ll.shift() guy.log("guy.emitMe:", evt,ll) document.dispatchEvent( new CustomEvent(evt,{ detail: ll }) ); }, emit: function( _ ) { // to emit a event to all clients var args=Array.prototype.slice.call(arguments) guy.log("guy.emit:", args) return guy._call("emit", args) }, init: function( callback ) { function start() { guy.log("guy.init:",callback.name) document.removeEventListener("init", start) callback() } if(guy._ws.readyState == guy._ws.OPEN) start() else document.addEventListener("init", start) }, _cptFetch: 0, _applyClass: function(i) { guy._cptFetch+=i; if(guy._cptFetch>0) document.body.classList.add("wsguy") else document.body.classList.remove("wsguy") }, _call: function( method, args ) { guy._applyClass(1); guy.log("guy.call:","CALL",method,args) var cmd={ command: method, args: args, uuid: method+"-"+Math.random().toString(36).substring(2), // stamp the exchange, so the callback can be called back (thru customevent), }; if(guy._ws) { guy._ws.send( JSON.stringify(cmd) ); return new Promise( function (resolve, reject) { document.addEventListener('guy-'+cmd.uuid, function handler(x) { guy._applyClass(-1); guy.log("guy.call:","RESPONSE",method,"-->",x.detail) this.removeEventListener('guy-'+cmd.uuid, handler); var x=x.detail; if(x && x.result!==undefined) { if(x.script) resolve( eval(x.script) ) else resolve(x.result) } else if(x && x.error!==undefined) reject(x.error) }); }) } else return new Promise( function (resolve, reject) { reject("not connected"); }) }, fetch: function(url,obj) { guy.log("guy.fetch:", url, "body:",obj) var h={"cache-control": "no-cache"}; // !!! if(obj && obj.headers) Object.keys(obj.headers).forEach( function(k) { h["set-"+k]=obj.headers[k]; }) var newObj = Object.assign({}, obj) newObj.headers=h; newObj.credentials= 'same-origin'; return fetch( "/_/"+url,newObj ) }, cfg: new Proxy({}, { get: function (obj, prop) { return guy._call("cfg_get",[prop]) }, set: function (obj, prop, value) { return guy._call("cfg_set",[prop,value]); }, }), exit: function(x) {guy._call("exit",[x])}, }; var self= { exit:function(x) {guy.exit(x)}, get_list:function(_) {return guy._call("get_list", Array.prototype.slice.call(arguments) )}, get_mtime:function(_) {return guy._call("get_mtime", Array.prototype.slice.call(arguments) )}, get_wiki:function(_) {return guy._call("get_wiki", Array.prototype.slice.call(arguments) )}, read_file:function(_) {return guy._call("read_file", Array.prototype.slice.call(arguments) )}, remove_game:function(_) {return guy._call("remove_game", Array.prototype.slice.call(arguments) )}, write_file:function(_) {return guy._call("write_file", Array.prototype.slice.call(arguments) )}, write_img:function(_) {return guy._call("write_img", Array.prototype.slice.call(arguments) )}, };