UNPKG

2.77 kBJavaScriptView Raw
1/**
2 * Copyright 2017 Google Inc. All Rights Reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 * http://www.apache.org/licenses/LICENSE-2.0
7 * Unless required by applicable law or agreed to in writing, software
8 * distributed under the License is distributed on an "AS IS" BASIS,
9 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 * See the License for the specific language governing permissions and
11 * limitations under the License.
12 */
13export function wrap(smc, id = null) {
14 const { port1, port2 } = new MessageChannel();
15 hookup(port2, smc, id);
16 return port1;
17}
18function hookup(internalPort, smc, id = null) {
19 internalPort.onmessage = (event) => {
20 if (!id)
21 id = generateUID();
22 const msg = event.data;
23 const messageChannels = Array.from(findMessageChannels(event.data));
24 for (const messageChannel of messageChannels) {
25 const id = generateUID();
26 const channel = replaceProperty(msg, messageChannel, id);
27 hookup(channel, smc, id);
28 }
29 const payload = JSON.stringify({ id, msg, messageChannels });
30 smc.send(payload);
31 };
32 smc.addEventListener("message", (event) => {
33 let data = {};
34 try {
35 data = JSON.parse(event.data);
36 }
37 catch (e) {
38 return;
39 }
40 if (!id)
41 id = data.id;
42 if (id !== data.id)
43 return;
44 const mcs = data.messageChannels.map(messageChannel => {
45 const id = messageChannel.reduce((obj, key) => obj[key], data.msg);
46 const port = wrap(smc, id);
47 replaceProperty(data.msg, messageChannel, port);
48 return port;
49 });
50 internalPort.postMessage(data.msg, mcs);
51 });
52}
53function replaceProperty(obj, path, newVal) {
54 for (const key of path.slice(0, -1))
55 obj = obj[key];
56 const key = path[path.length - 1];
57 const orig = obj[key];
58 obj[key] = newVal;
59 return orig;
60}
61function* findMessageChannels(obj, path = []) {
62 if (!obj)
63 return;
64 if (typeof obj === "string")
65 return;
66 if (obj instanceof MessagePort) {
67 yield path.slice();
68 return;
69 }
70 for (const key of Object.keys(obj)) {
71 path.push(key);
72 yield* findMessageChannels(obj[key], path);
73 path.pop();
74 }
75}
76function hex4() {
77 return Math.floor((1 + Math.random()) * 0x10000)
78 .toString(16)
79 .substring(1);
80}
81const bits = 128;
82function generateUID() {
83 return new Array(bits / 16)
84 .fill(0)
85 .map(_ => hex4())
86 .join("");
87}