OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | |
5 /** | 4 /** |
6 * @interface | 5 * @interface |
7 */ | 6 */ |
8 function Service() { } | 7 function Service() { |
| 8 } |
9 | 9 |
10 Service.prototype = { | 10 Service.prototype = { |
11 /** | 11 /** |
12 * @return {!Promise} | 12 * @return {!Promise} |
13 */ | 13 */ |
14 dispose: function() { }, | 14 dispose: function() {}, |
15 | 15 |
16 /** | 16 /** |
17 * @return {function(string)} | 17 * @return {function(string)} |
18 */ | 18 */ |
19 setNotify: function(notify) { } | 19 setNotify: function(notify) {} |
20 }; | 20 }; |
21 | 21 |
22 /** | 22 /** |
23 * @constructor | 23 * @unrestricted |
24 * @param {!ServicePort} port | |
25 */ | 24 */ |
26 function ServiceDispatcher(port) | 25 var ServiceDispatcher = class { |
27 { | 26 /** |
| 27 * @param {!ServicePort} port |
| 28 */ |
| 29 constructor(port) { |
28 /** @type {!Map<string, !Object>} */ | 30 /** @type {!Map<string, !Object>} */ |
29 this._objects = new Map(); | 31 this._objects = new Map(); |
30 this._lastObjectId = 1; | 32 this._lastObjectId = 1; |
31 this._port = port; | 33 this._port = port; |
32 this._port.setHandlers(this._dispatchMessageWrapped.bind(this), this._connec
tionClosed.bind(this)); | 34 this._port.setHandlers(this._dispatchMessageWrapped.bind(this), this._connec
tionClosed.bind(this)); |
33 } | 35 } |
34 | 36 |
35 ServiceDispatcher.prototype = { | 37 /** |
36 /** | 38 * @param {string} data |
37 * @param {string} data | 39 */ |
38 */ | 40 _dispatchMessageWrapped(data) { |
39 _dispatchMessageWrapped: function(data) | 41 try { |
40 { | 42 var message = JSON.parse(data); |
41 try { | 43 if (!(message instanceof Object)) { |
42 var message = JSON.parse(data); | 44 this._sendErrorResponse(message['id'], 'Malformed message'); |
43 if (!(message instanceof Object)) { | 45 return; |
44 this._sendErrorResponse(message["id"], "Malformed message"); | 46 } |
45 return; | 47 this._dispatchMessage(message); |
46 } | 48 } catch (e) { |
47 this._dispatchMessage(message); | 49 this._sendErrorResponse(message['id'], e.toString()); |
48 } catch (e) { | |
49 this._sendErrorResponse(message["id"], e.toString()); | |
50 } | |
51 }, | |
52 | |
53 /** | |
54 * @param {!Object} message | |
55 */ | |
56 _dispatchMessage: function(message) | |
57 { | |
58 var domainAndMethod = message["method"].split("."); | |
59 var serviceName = domainAndMethod[0]; | |
60 var method = domainAndMethod[1]; | |
61 | |
62 if (method === "create") { | |
63 var extensions = self.runtime.extensions(Service).filter(extension =
> extension.descriptor()["name"] === serviceName); | |
64 if (!extensions.length) { | |
65 this._sendErrorResponse(message["id"], "Could not resolve servic
e '" + serviceName + "'"); | |
66 return; | |
67 } | |
68 extensions[0].instance().then(object => { | |
69 var id = String(this._lastObjectId++); | |
70 object.setNotify(this._notify.bind(this, id, serviceName)); | |
71 this._objects.set(id, object); | |
72 this._sendResponse(message["id"], { id: id }); | |
73 }); | |
74 } else if (method === "dispose") { | |
75 var object = this._objects.get(message["params"]["id"]); | |
76 if (!object) { | |
77 console.error("Could not look up object with id for " + JSON.str
ingify(message)); | |
78 return; | |
79 } | |
80 this._objects.delete(message["params"]["id"]); | |
81 object.dispose().then(() => this._sendResponse(message["id"], {})); | |
82 } else { | |
83 if (!message["params"]) { | |
84 console.error("No params in the message: " + JSON.stringify(mess
age)); | |
85 return; | |
86 } | |
87 var object = this._objects.get(message["params"]["id"]); | |
88 if (!object) { | |
89 console.error("Could not look up object with id for " + JSON.str
ingify(message)); | |
90 return; | |
91 } | |
92 var handler = object[method]; | |
93 if (!(handler instanceof Function)) { | |
94 console.error("Handler for '" + method + "' is missing."); | |
95 return; | |
96 } | |
97 object[method](message["params"]).then(result => this._sendResponse(
message["id"], result)); | |
98 } | |
99 }, | |
100 | |
101 _connectionClosed: function() | |
102 { | |
103 for (var object of this._objects.values()) | |
104 object.dispose(); | |
105 this._objects.clear(); | |
106 }, | |
107 | |
108 /** | |
109 * @param {string} objectId | |
110 * @param {string} serviceName | |
111 * @param {string} method | |
112 * @param {!Object} params | |
113 */ | |
114 _notify: function(objectId, serviceName, method, params) | |
115 { | |
116 params["id"] = objectId; | |
117 var message = { method: serviceName + "." + method, params: params }; | |
118 this._port.send(JSON.stringify(message)); | |
119 }, | |
120 | |
121 /** | |
122 * @param {string} messageId | |
123 * @param {!Object} result | |
124 */ | |
125 _sendResponse: function(messageId, result) | |
126 { | |
127 var message = { id: messageId, result: result }; | |
128 this._port.send(JSON.stringify(message)); | |
129 }, | |
130 | |
131 /** | |
132 * @param {string} messageId | |
133 * @param {string} error | |
134 */ | |
135 _sendErrorResponse: function(messageId, error) | |
136 { | |
137 var message = { id: messageId, error: error }; | |
138 this._port.send(JSON.stringify(message)); | |
139 } | 50 } |
| 51 } |
| 52 |
| 53 /** |
| 54 * @param {!Object} message |
| 55 */ |
| 56 _dispatchMessage(message) { |
| 57 var domainAndMethod = message['method'].split('.'); |
| 58 var serviceName = domainAndMethod[0]; |
| 59 var method = domainAndMethod[1]; |
| 60 |
| 61 if (method === 'create') { |
| 62 var extensions = |
| 63 self.runtime.extensions(Service).filter(extension => extension.descrip
tor()['name'] === serviceName); |
| 64 if (!extensions.length) { |
| 65 this._sendErrorResponse(message['id'], 'Could not resolve service \'' +
serviceName + '\''); |
| 66 return; |
| 67 } |
| 68 extensions[0].instance().then(object => { |
| 69 var id = String(this._lastObjectId++); |
| 70 object.setNotify(this._notify.bind(this, id, serviceName)); |
| 71 this._objects.set(id, object); |
| 72 this._sendResponse(message['id'], {id: id}); |
| 73 }); |
| 74 } else if (method === 'dispose') { |
| 75 var object = this._objects.get(message['params']['id']); |
| 76 if (!object) { |
| 77 console.error('Could not look up object with id for ' + JSON.stringify(m
essage)); |
| 78 return; |
| 79 } |
| 80 this._objects.delete(message['params']['id']); |
| 81 object.dispose().then(() => this._sendResponse(message['id'], {})); |
| 82 } else { |
| 83 if (!message['params']) { |
| 84 console.error('No params in the message: ' + JSON.stringify(message)); |
| 85 return; |
| 86 } |
| 87 var object = this._objects.get(message['params']['id']); |
| 88 if (!object) { |
| 89 console.error('Could not look up object with id for ' + JSON.stringify(m
essage)); |
| 90 return; |
| 91 } |
| 92 var handler = object[method]; |
| 93 if (!(handler instanceof Function)) { |
| 94 console.error('Handler for \'' + method + '\' is missing.'); |
| 95 return; |
| 96 } |
| 97 object[method](message['params']).then(result => this._sendResponse(messag
e['id'], result)); |
| 98 } |
| 99 } |
| 100 |
| 101 _connectionClosed() { |
| 102 for (var object of this._objects.values()) |
| 103 object.dispose(); |
| 104 this._objects.clear(); |
| 105 } |
| 106 |
| 107 /** |
| 108 * @param {string} objectId |
| 109 * @param {string} serviceName |
| 110 * @param {string} method |
| 111 * @param {!Object} params |
| 112 */ |
| 113 _notify(objectId, serviceName, method, params) { |
| 114 params['id'] = objectId; |
| 115 var message = {method: serviceName + '.' + method, params: params}; |
| 116 this._port.send(JSON.stringify(message)); |
| 117 } |
| 118 |
| 119 /** |
| 120 * @param {string} messageId |
| 121 * @param {!Object} result |
| 122 */ |
| 123 _sendResponse(messageId, result) { |
| 124 var message = {id: messageId, result: result}; |
| 125 this._port.send(JSON.stringify(message)); |
| 126 } |
| 127 |
| 128 /** |
| 129 * @param {string} messageId |
| 130 * @param {string} error |
| 131 */ |
| 132 _sendErrorResponse(messageId, error) { |
| 133 var message = {id: messageId, error: error}; |
| 134 this._port.send(JSON.stringify(message)); |
| 135 } |
140 }; | 136 }; |
141 | 137 |
142 /** | 138 /** |
143 * @constructor | |
144 * @param {!Port|!Worker} port | |
145 * @implements {ServicePort} | 139 * @implements {ServicePort} |
| 140 * @unrestricted |
146 */ | 141 */ |
147 function WorkerServicePort(port) | 142 var WorkerServicePort = class { |
148 { | 143 /** |
| 144 * @param {!Port|!Worker} port |
| 145 */ |
| 146 constructor(port) { |
149 this._port = port; | 147 this._port = port; |
150 this._port.onmessage = this._onMessage.bind(this); | 148 this._port.onmessage = this._onMessage.bind(this); |
151 this._port.onerror = console.error; | 149 this._port.onerror = console.error; |
| 150 } |
| 151 |
| 152 /** |
| 153 * @override |
| 154 * @param {function(string)} messageHandler |
| 155 * @param {function(string)} closeHandler |
| 156 */ |
| 157 setHandlers(messageHandler, closeHandler) { |
| 158 this._messageHandler = messageHandler; |
| 159 this._closeHandler = closeHandler; |
| 160 } |
| 161 |
| 162 /** |
| 163 * @override |
| 164 * @param {string} data |
| 165 * @return {!Promise} |
| 166 */ |
| 167 send(data) { |
| 168 this._port.postMessage(data); |
| 169 return Promise.resolve(); |
| 170 } |
| 171 |
| 172 /** |
| 173 * @override |
| 174 * @return {!Promise} |
| 175 */ |
| 176 close() { |
| 177 return Promise.resolve(); |
| 178 } |
| 179 |
| 180 /** |
| 181 * @param {!MessageEvent} event |
| 182 */ |
| 183 _onMessage(event) { |
| 184 this._messageHandler(event.data); |
| 185 } |
| 186 }; |
| 187 |
| 188 var dispatchers = []; |
| 189 |
| 190 if (self instanceof SharedWorkerGlobalScope) { |
| 191 function onNewPort(port) { |
| 192 var dispatcher = new ServiceDispatcher(new WorkerServicePort(port)); |
| 193 dispatchers.push(dispatcher); |
| 194 } |
| 195 Runtime.setSharedWorkerNewPortCallback(onNewPort); |
| 196 } else { |
| 197 var worker = /** @type {!Object} */ (self); |
| 198 var servicePort = new WorkerServicePort(/** @type {!Worker} */ (worker)); |
| 199 dispatchers.push(new ServiceDispatcher(servicePort)); |
152 } | 200 } |
153 | |
154 WorkerServicePort.prototype = { | |
155 /** | |
156 * @override | |
157 * @param {function(string)} messageHandler | |
158 * @param {function(string)} closeHandler | |
159 */ | |
160 setHandlers: function(messageHandler, closeHandler) | |
161 { | |
162 this._messageHandler = messageHandler; | |
163 this._closeHandler = closeHandler; | |
164 }, | |
165 | |
166 /** | |
167 * @override | |
168 * @param {string} data | |
169 * @return {!Promise} | |
170 */ | |
171 send: function(data) | |
172 { | |
173 this._port.postMessage(data); | |
174 return Promise.resolve(); | |
175 }, | |
176 | |
177 /** | |
178 * @override | |
179 * @return {!Promise} | |
180 */ | |
181 close: function() | |
182 { | |
183 return Promise.resolve(); | |
184 }, | |
185 | |
186 /** | |
187 * @param {!MessageEvent} event | |
188 */ | |
189 _onMessage: function(event) | |
190 { | |
191 this._messageHandler(event.data); | |
192 } | |
193 }; | |
194 | |
195 var dispatchers = []; | |
196 | |
197 if (self instanceof SharedWorkerGlobalScope) { | |
198 function onNewPort(port) | |
199 { | |
200 var dispatcher = new ServiceDispatcher(new WorkerServicePort(port)); | |
201 dispatchers.push(dispatcher); | |
202 } | |
203 Runtime.setSharedWorkerNewPortCallback(onNewPort); | |
204 } else { | |
205 var worker = /** @type {!Object} */(self); | |
206 var servicePort = new WorkerServicePort(/** @type {!Worker} */(worker)); | |
207 dispatchers.push(new ServiceDispatcher(servicePort)); | |
208 } | |
OLD | NEW |