/* classe client WebSocket */ class WSClient{ /* (1) Constructor * * @server_url The url of the desired server * @channel_uri The url of the desired channel * ---------------------------------------------------------*/ constructor(server_url, channel_uri){ /* (1) Store & create data ---------------------------------------------------------*/ /* (1) Store the arguments */ this.server_url = server_url; this.channel_uri = channel_uri; /* (2) Initialise event data */ this.is_opened = false; // Set to TRUE when connection opened this.pending = null; // Next message to send through connection this.handler = []; // On reveice handlers /* (3) Create the websocket connection */ this.ws = new WebSocket(this.server_url+'/'+channel_uri); /* (2) Bind events ---------------------------------------------------------*/ /* (1) OPEN: when connection is established */ this.ws.onopen = this._onopen.bind(this); /* (2) MESSAGE: when message received */ this.ws.onmessage = this._onmessage.bind(this); /* (3) ERROR: when websocket error */ this.ws.onerror = this._onerror.bind(this); /* (4) CLOSE: when websocket closes */ this.ws.onclose = this._onclose.bind(this); } /* (2) Binds a handle to the onReceive event (global only) * * @callback Callback function(message, error) * ---------------------------------------------------------*/ listen(callback){ /* (1) Check @callback type (default value) */ if( !(callback instanceof Function) ) throw new Error('WSClient.bind(callback) expected argument *callback* to be a function'); /* (2) Store callback */ this.on_receive = callback; return this; } /* (3) Sends a message through the socket * * @message The data to send * The data to send (will be serialized) * ---------------------------------------------------------*/ send(message){ /* (1) Manage arguments ---------------------------------------------------------*/ /* (2) Check @message type */ if( typeof message != 'string' && typeof message != 'object' ){ this.on_receive(null, 'wrong message type'); return this; } /* (2) Stringify JSON if object */ if( typeof message == 'object' ) message = JSON.stringify(message); /* (2) Send process ---------------------------------------------------------*/ /* (1) If not opened -> store message (will send when onopen()) */ if( !this.is_opened ) this.pending = message; /* (2) If already opened -> send now */ else this.ws.send(message); return this; } /* (4) PRIVATE: Open handler * ---------------------------------------------------------*/ _onopen(){ /* (1) Set @is_opened status variable */ this.is_opened = true; /* (2) If message pending */ if( this.pending != null ){ this.ws.send(this.pending); // send message this.pending = null; // reset message (optional) } } /* (5) PRIVATE: Receive handler * ---------------------------------------------------------*/ _onmessage(msg_event){ /* (1) If not trusted -> error */ if( !msg_event.isTrusted ){ this.on_receive(null, 'not trusted'); return; } /* (2) If wrong origin -> error */ if( msg_event.origin != this.server_url ){ this.on_receive(null, 'unknown origin'); return; } /* (3) If not for this channel -> exit */ if( msg_event.target.url != this.server_url+'/'+this.channel_uri ) return; /* (3) Try to JSON parse */ var parsedMsg = null; try{ parsedMsg = JSON.parse(msg_event.data); }catch(e){ this.on_receive(null, 'JSON error'); return; } /* (4) If all right -> success */ this.on_receive(parsedMsg, null); } /* (6) PRIVATE: Error handler * ---------------------------------------------------------*/ _onerror(){ /* (1) Remove other handlers (only 1 error) */ this.ws.onmessage = null; this.ws.onclose = null; /* (2) Send error */ this.on_receive(null, 'websocket error'); } /* (7) PRIVATE: Close handler * ---------------------------------------------------------*/ _onclose(){ /* (1) Remove onmessage (not to catch messages) */ this.ws.onmessage = null; /* (2) Send end */ this.on_receive(null, 'websocket closed'); } } class WSClientBuilder{ /* (1) Constructor * * @server_url The url of the desired server * ---------------------------------------------------------*/ constructor(server_url){ /* (1) Store the server url */ this.server_url = server_url; } /* (2) Builds a WSClient with desired channel * * @channel_uri The uri of the desired channel * ---------------------------------------------------------*/ channel(channel_uri=''){ return new WSClient(this.server_url, channel_uri); } } export{ WSClient, WSClientBuilder }