123456789101112131415161718192021222324252627282930313233343536373839404142434445464748 |
- export default class ServiceManager{createRemoteService(serviceName){if(!this._remoteConnection){const url=Root.Runtime.queryParam('service-backend');if(!url){console.error('No endpoint address specified');return(Promise.resolve(null));}
- this._remoteConnection=new Connection(new RemoteServicePort(url));}
- return this._remoteConnection._createService(serviceName);}
- createAppService(appName,serviceName){let url=appName+'.js';const remoteBase=Root.Runtime.queryParam('remoteBase');const debugFrontend=Root.Runtime.queryParam('debugFrontend');const isUnderTest=Host.isUnderTest();const queryParams=[];if(remoteBase){queryParams.push('remoteBase='+remoteBase);}
- if(debugFrontend){queryParams.push('debugFrontend='+debugFrontend);}
- if(isUnderTest){queryParams.push('isUnderTest=true');}
- if(queryParams.length){url+=`?${queryParams.join('&')}`;}
- const worker=new Worker(url);const connection=new Connection(new WorkerServicePort(worker));return connection._createService(serviceName);}}
- class Connection{constructor(port){this._port=port;this._port.setHandlers(this._onMessage.bind(this),this._connectionClosed.bind(this));this._lastId=1;this._callbacks=new Map();this._services=new Map();}
- _createService(serviceName){return this._sendCommand(serviceName+'.create').then(result=>{if(!result){console.error('Could not initialize service: '+serviceName);return null;}
- const service=new Service(this,serviceName,result.id);this._services.set(serviceName+':'+result.id,service);return service;});}
- _serviceDisposed(service){this._services.delete(service._serviceName+':'+service._objectId);if(!this._services.size){this._port.close();}}
- _sendCommand(method,params){const id=this._lastId++;const message=JSON.stringify({id:id,method:method,params:params||{}});return this._port.send(message).then(success=>{if(!success){return Promise.resolve(null);}
- return new Promise(fulfill=>this._callbacks.set(id,fulfill));});}
- _onMessage(data){let object;try{object=JSON.parse(data);}catch(e){console.error(e);return;}
- if(object.id){if(object.error){console.error('Service error: '+object.error);}
- this._callbacks.get(object.id)(object.error?null:object.result);this._callbacks.delete(object.id);return;}
- const tokens=object.method.split('.');const serviceName=tokens[0];const methodName=tokens[1];const service=this._services.get(serviceName+':'+object.params.id);if(!service){console.error('Unable to lookup stub for '+serviceName+':'+object.params.id);return;}
- service._dispatchNotification(methodName,object.params);}
- _connectionClosed(){for(const callback of this._callbacks.values()){callback(null);}
- this._callbacks.clear();for(const service of this._services.values()){service._dispatchNotification('disposed');}
- this._services.clear();}}
- export class Service{constructor(connection,serviceName,objectId){this._connection=connection;this._serviceName=serviceName;this._objectId=objectId;this._notificationHandlers=new Map();}
- dispose(){const params={id:this._objectId};return this._connection._sendCommand(this._serviceName+'.dispose',params).then(()=>{this._connection._serviceDisposed(this);});}
- on(methodName,handler){this._notificationHandlers.set(methodName,handler);}
- send(methodName,params){params=params||{};params.id=this._objectId;return this._connection._sendCommand(this._serviceName+'.'+methodName,params);}
- _dispatchNotification(methodName,params){const handler=this._notificationHandlers.get(methodName);if(!handler){console.error('Could not report notification \''+methodName+'\' on \''+this._objectId+'\'');return;}
- handler(params);}}
- class RemoteServicePort{constructor(url){this._url=url;}
- setHandlers(messageHandler,closeHandler){this._messageHandler=messageHandler;this._closeHandler=closeHandler;}
- _open(){if(!this._connectionPromise){this._connectionPromise=new Promise(promiseBody.bind(this));}
- return this._connectionPromise;function promiseBody(fulfill){let socket;try{socket=new WebSocket((this._url));socket.onmessage=onMessage.bind(this);socket.onclose=onClose.bind(this);socket.onopen=onConnect.bind(this);}catch(e){fulfill(false);}
- function onConnect(){this._socket=socket;fulfill(true);}
- function onMessage(event){this._messageHandler(event.data);}
- function onClose(){if(!this._socket){fulfill(false);}
- this._socketClosed(!!this._socket);}}}
- send(message){return this._open().then(()=>{if(this._socket){this._socket.send(message);return true;}
- return false;});}
- close(){return this._open().then(()=>{if(this._socket){this._socket.close();this._socketClosed(true);}
- return true;});}
- _socketClosed(notifyClient){this._socket=null;delete this._connectionPromise;if(notifyClient){this._closeHandler();}}}
- class WorkerServicePort{constructor(worker){this._worker=worker;let fulfill;this._workerPromise=new Promise(resolve=>fulfill=resolve);this._worker.onmessage=onMessage.bind(this);this._worker.onclose=this._closeHandler;function onMessage(event){if(event.data==='workerReady'){fulfill(true);return;}
- this._messageHandler(event.data);}}
- setHandlers(messageHandler,closeHandler){this._messageHandler=messageHandler;this._closeHandler=closeHandler;}
- send(message){return this._workerPromise.then(()=>{try{this._worker.postMessage(message);return true;}catch(e){return false;}});}
- close(){return this._workerPromise.then(()=>{if(this._worker){this._worker.terminate();}
- return false;});}}
- self.Services=self.Services||{};Services=Services||{};Services.ServiceManager=ServiceManager;Services.ServiceManager.Service=Service;Services.serviceManager=new ServiceManager();
|