WebSocketTransport.sys.mjs (2936B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 // This is an XPCOM service-ified copy of ../devtools/shared/transport/websocket-transport.js. 6 7 const lazy = {}; 8 9 ChromeUtils.defineESModuleGetters(lazy, { 10 EventEmitter: "resource://gre/modules/EventEmitter.sys.mjs", 11 }); 12 13 export function WebSocketTransport(socket) { 14 lazy.EventEmitter.decorate(this); 15 16 this.active = false; 17 this.hooks = null; 18 this.socket = socket; 19 } 20 21 WebSocketTransport.prototype = { 22 ready() { 23 if (this.active) { 24 return; 25 } 26 27 this.socket.addEventListener("message", this); 28 this.socket.addEventListener("close", this); 29 30 this.active = true; 31 }, 32 33 send(object) { 34 this.emit("send", object); 35 if (this.socket) { 36 this.socket.send(JSON.stringify(object)); 37 } 38 }, 39 40 startBulkSend() { 41 throw new Error("Bulk send is not supported by WebSocket transport"); 42 }, 43 44 /** 45 * Force closing the active connection and WebSocket. 46 */ 47 close() { 48 if (!this.socket) { 49 return; 50 } 51 this.emit("close"); 52 53 if (this.hooks) { 54 this.hooks.onConnectionClose(); 55 } 56 57 this.active = false; 58 59 this.socket.removeEventListener("message", this); 60 61 // Remove the listener that is used when the connection 62 // is closed because we already emitted the 'close' event. 63 // Instead listen for the closing of the WebSocket. 64 this.socket.removeEventListener("close", this); 65 this.socket.addEventListener("close", this.onSocketClose.bind(this)); 66 67 // Close socket with code `1000` for a normal closure. 68 this.socket.close(1000); 69 }, 70 71 /** 72 * Callback for socket on close event, 73 * it is used in case websocket was closed by the client. 74 */ 75 onClose() { 76 if (!this.socket) { 77 return; 78 } 79 this.emit("close"); 80 81 if (this.hooks) { 82 this.hooks.onConnectionClose(); 83 this.hooks.onSocketClose(); 84 this.hooks = null; 85 } 86 87 this.active = false; 88 89 this.socket.removeEventListener("message", this); 90 this.socket.removeEventListener("close", this); 91 this.socket = null; 92 }, 93 94 /** 95 * Callback which is called when we can be sure that websocket is closed. 96 */ 97 onSocketClose() { 98 this.socket = null; 99 100 if (this.hooks) { 101 this.hooks.onSocketClose(); 102 this.hooks = null; 103 } 104 }, 105 106 handleEvent(event) { 107 switch (event.type) { 108 case "message": 109 this.onMessage(event); 110 break; 111 case "close": 112 this.onClose(); 113 break; 114 } 115 }, 116 117 onMessage({ data }) { 118 if (typeof data !== "string") { 119 throw new Error( 120 "Binary messages are not supported by WebSocket transport" 121 ); 122 } 123 124 const object = JSON.parse(data); 125 this.emit("packet", object); 126 if (this.hooks) { 127 this.hooks.onPacket(object); 128 } 129 }, 130 };