import WebSocket = require('ws'); import MetaGrammarManifest from '../../src/org/subalternproductions/seepResource/dsl/serialize/MetaGrammarManifest'; import GrammarTestSuite from '../../src/org/subalternproductions/seepResource/dsl/testsuite/GrammarTestSuite'; import GrammarTest from '../../src/org/subalternproductions/seepResource/dsl/testsuite/GrammarTest'; import GrammarTestSrc from '../../src/org/subalternproductions/seepResource/dsl/testsuite/GrammarTestSrc'; import GrammarTestSuiteMgr from '../../src/org/subalternproductions/seepResource/dsl/testrunner/GrammarTestsuiteMgr'; import TESTS from '../../test/minimal-testsuites' import { ITypeManifest, ArchiveDeserializer, Assert } from '@cafetextual/util'; import SimpleTypeManifest from '@cafetextual/util/dist/src/manifest/SimpleTypeManifest'; import GrammarTestsuiteRunner from '../../test/testrunner/GrammarTestsuiteRunner'; import {saveFile , loadFile, serialize } from './parse-ws-util' var WebSocketServer = require('ws').Server export default class ParserWsServer { constructor(port:number = 8007) { this.port = port; var archivePath:string = "/Users/ismcdonald/dev/seep2/seep/ex/SeasTestRunner/src/test/editable" var appPath:string = "/Users/ismcdonald/dev/seep2/seep/ex/SeasTestRunner/src/test" // hardcoding archive location for the moment this.savePath = archivePath + "/_saved/" } port:number private savePath:string private wss:any private index:number = 0 start() { var wss = new WebSocketServer({port:this.port}); this.wss = wss wss.on('connection', function(ws:any) { var connectionName = "Cn#" + this.index.toString() this.index++ var protocol:string = "unknown" if (typeof ws.protocol === "string") { protocol = ws.protocol as string } this.setConnected(connectionName, ws, protocol) console.log(" new connection: " + connectionName + " protocol: " + protocol); ws.send(serialize("handshake", "Connected" ,"")); ws.on('message', (message:string) => { // var type:string = message.type console.log("--- got message ") // message); // console.log(message) try { var o:any = JSON.parse(message) console.log(' parsed') } catch (e) { console.log(" failed to parse json") return } if (o && o.type) { console.log(" message of type: " + o.type) var msgType:string = o.type var target:string = o.target ? o.target : "*" if (msgType == "pub") { var channel:string = o.channel this.log(" got pub " + channel + " on protocol = " + protocol) // for the moment, be publish to all channels this.broadcast(connectionName, message, "*") return } else if (msgType == "anyonic-actor") { this.handleActorMsg(o) return } else if (msgType == "doc-request") { this.traceAppData() var data = this.getAppDataByTarget(protocol) if (data) { ws.send(data) } else { ws.send(serialize("error", "no data available for appID" + protocol, null)) this.log(" not sending app data to protocol: " + protocol) // if we had data for #protocol , could send it } } else if (msgType == "doc-script") { this.log(" serialize script from " + protocol) this.broadcast(connectionName, message, "*") // <--- scripts go everywhere, clients work out what to run } else if (msgType == "script-status") { console.log(" got script status") this.broadcast(connectionName, message, "#debug") } else if (msgType == "doc-serialization") { var uri:string = o.data.topURI var appID:string = o.data.appID if (appID) { this.persistDataByTarget(o.data, appID, uri) this.traceAppData() this.broadcastToTestSubs(uri) this.broadcast(connectionName, message, appID) // <-- TODO - target serializations if (uri) { console.log(" about to save: " + uri) saveFile(uri, this.savePath, message) } } } else if (msgType == "doc-increment") { var appID:string = o.data.appID if (appID) { console.log(" got incremental update for appID: " + appID) this.persistDataByTarget(null, protocol, uri) // <--- delete any persisted data for this target as it's no longer value this.broadcast(connectionName, message, appID) } else { this.log(" no appID from + " + protocol) } } else if (msgType == "dom") { console.log(" got dom serialization") this.broadcast(connectionName, message, "#debug") // <-- only send dom into to the debug client } else if (msgType == "dom-request") { console.log(" got dom request") this.broadcast(connectionName, message, "*") // <--- request dom from everything } else if (msgType == "figure-channel") { console.log(" got figure") } else if (msgType == "error") { console.log(" got error ") this.broadcast(connectionName, message, "#debug") // <--- request dom from everything } else if (msgType == "test-sub") { var testURI:string = o.data.testURI; this.addSubscription(connectionName, testURI) console.log(" recieved test subscription " + testURI ) this.broadcastToTestSubs( testURI) } else { ws.send(serialize("error", " unknown msgType : " + msgType, null)) } } // ws.send(serialize("echo", "connected", "")) this.traceConnections(connectionName); }) ws.on('close', function close() { console.log('disconnected'); this.removeConnection(connectionName) }); ws.on('open', function open() { console.log('opening'); ws.send(Date.now().toString(), {mask: true}); }); }) } // start private allConnections:{[name:string]:{ ws:any, protocol:string, subs?:Array }} = {} private appDataByTarget:{[targetID:string]:any} = {} private appDataByURI:{[uri:string]:any} = {} setConnected(name:string, ws:any, protocol:string) { this.allConnections[name] = {ws:ws, protocol:protocol} } removeConnection(name:string) { console.log("removeing connection " + name) delete this.allConnections[name] this.traceConnections(name) } traceConnections(current:string) { this.log(" ------- all current connections -----") for (var key in this.allConnections) { var isCurrent = (key == current) ? " <--- current " : "" var {ws, protocol} = this.allConnections[key] this.log("c: " + key + " (connected) " + isCurrent + "protocol: " + protocol) } } log = (v:string) => { console.log(v) } traceAppData() { this.log(" ---- all currently registered app data ----") for (var key in this.appDataByTarget) { var data = this.appDataByTarget[key] this.log(" " + key + " size: " + data.length) } this.log(" -------------------------------------------") } getAppDataByTarget(appID:string) { return this.appDataByTarget[appID] } persistDataByTarget(data:any, appID:string, uri:string):void { this.appDataByTarget[appID] = data if (uri) { this.appDataByURI[uri] = data; } } /** * @param source name (uid) of source,to ensure message isn't broadcast back to self * @param msg data to broadcase * @param target name of target protocol */ broadcast(source:string, msg:string, target:string) { var noTarget:Boolean = !target || target == '*' for (var name in this.allConnections) { if (name != source) { var {ws, protocol} = this.allConnections[name] if (noTarget || target == protocol) { ws.send(msg) } } } } broadcastToTestSubs( testURI:string) { var data = this.appDataByURI[testURI] if (!data) { // could attempt to load from disk here data = loadFile(testURI, this.savePath) if (!data) { console.log('ATTN: no data for testURI ' + testURI) // {data:[ ]. } // when loaded, doesn't have return; } data = data.data } else { //data = data.data; console.log('x') } var connectionName:string for (connectionName in this.allConnections) { let { ws, subs } = this.allConnections[connectionName]; if (subs) { if (testURI in subs) { ws.send(serialize("test-sub", "test data for uri=" + testURI, data)) } } } } }