@interopio/bridge 0.0.6-beta.0 → 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +18 -0
- package/dist/main.js +633 -252
- package/dist/main.js.map +4 -4
- package/package.json +10 -4
package/dist/main.js
CHANGED
|
@@ -1,3 +1,125 @@
|
|
|
1
|
+
// ../bridge-mesh/src/mesh/relays.ts
|
|
2
|
+
import { IOGateway } from "@interopio/gateway";
|
|
3
|
+
import { EventEmitter } from "node:events";
|
|
4
|
+
var codec = IOGateway.Encoding.transit({
|
|
5
|
+
keywordize: /* @__PURE__ */ new Map([
|
|
6
|
+
["/type", "*"],
|
|
7
|
+
["/message/body/type", "*"],
|
|
8
|
+
["/message/origin", "*"],
|
|
9
|
+
["/message/receiver/type", "*"],
|
|
10
|
+
["/message/source/type", "*"],
|
|
11
|
+
["/message/body/type", "*"]
|
|
12
|
+
])
|
|
13
|
+
});
|
|
14
|
+
function isEncoded(msg) {
|
|
15
|
+
return typeof msg === "string" || Buffer.isBuffer(msg);
|
|
16
|
+
}
|
|
17
|
+
var InternalRelays = class {
|
|
18
|
+
#logger;
|
|
19
|
+
// key -> handler
|
|
20
|
+
#handlersByKey = /* @__PURE__ */ new Map();
|
|
21
|
+
// node -> keyed link
|
|
22
|
+
#links = /* @__PURE__ */ new Map();
|
|
23
|
+
#eventEmitter = new EventEmitter();
|
|
24
|
+
constructor(logger) {
|
|
25
|
+
this.#logger = logger;
|
|
26
|
+
}
|
|
27
|
+
add(key, handler) {
|
|
28
|
+
this.#handlersByKey.set(key, handler);
|
|
29
|
+
}
|
|
30
|
+
remove(key) {
|
|
31
|
+
this.#handlersByKey.delete(key);
|
|
32
|
+
this.#disconnect(key);
|
|
33
|
+
}
|
|
34
|
+
#disconnect(key, from) {
|
|
35
|
+
for (const [node, k] of this.#links) {
|
|
36
|
+
if (k.key === key && (from === void 0 || k.node === from)) {
|
|
37
|
+
const links = k.linksByNode;
|
|
38
|
+
if (this.#logger.enabledFor("debug")) {
|
|
39
|
+
this.#logger.debug(`${key} unregisters node ${node}, linked to ${Array.from(links.keys()).join(", ")}`);
|
|
40
|
+
}
|
|
41
|
+
this.#links.delete(node);
|
|
42
|
+
this.#eventEmitter.emit("disconnect", key, node, links);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
#connect(key, node) {
|
|
47
|
+
if (this.#logger.enabledFor("debug")) {
|
|
48
|
+
this.#logger.debug(`${key} registers node ${node}`);
|
|
49
|
+
}
|
|
50
|
+
this.#links.set(node, { key, node, linksByNode: /* @__PURE__ */ new Map() });
|
|
51
|
+
this.#eventEmitter.emit("connect", key, node);
|
|
52
|
+
}
|
|
53
|
+
receive(key, msg) {
|
|
54
|
+
const { node, decoded, encoded } = this.link(key, msg);
|
|
55
|
+
if (node) {
|
|
56
|
+
this.#eventEmitter.emit("message", key, node, encoded, decoded);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
link(key, msg) {
|
|
60
|
+
try {
|
|
61
|
+
const decoded = isEncoded(msg) ? codec.decode(msg) : msg;
|
|
62
|
+
const { type, from, to } = decoded;
|
|
63
|
+
if (to === "all") {
|
|
64
|
+
switch (type) {
|
|
65
|
+
case "hello": {
|
|
66
|
+
this.#connect(key, from);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
case "bye": {
|
|
70
|
+
this.#disconnect(key, from);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { decoded };
|
|
75
|
+
}
|
|
76
|
+
const encoded = isEncoded(msg) ? msg : codec.encode(msg);
|
|
77
|
+
return { node: from, decoded, encoded };
|
|
78
|
+
} catch (e) {
|
|
79
|
+
if (!this.#eventEmitter.emit("error", key, e instanceof Error ? e : new Error(`link failed :${e}`))) {
|
|
80
|
+
this.#logger.warn(`${key} unable to process ${msg}`, e);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
on(event, listener) {
|
|
85
|
+
this.#eventEmitter.on(event, listener);
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
88
|
+
send(key, node, msg, cb) {
|
|
89
|
+
if (this.#logger.enabledFor("debug")) {
|
|
90
|
+
this.#logger.debug(`${key} sending msg to ${node}`);
|
|
91
|
+
}
|
|
92
|
+
const encoded = isEncoded(msg) ? msg : codec.encode(msg);
|
|
93
|
+
const decoded = isEncoded(msg) ? codec.decode(msg) : msg;
|
|
94
|
+
{
|
|
95
|
+
const senderLinkData = this.#links.get(decoded.from);
|
|
96
|
+
switch (decoded.type) {
|
|
97
|
+
case "hello":
|
|
98
|
+
if (node === decoded.to) {
|
|
99
|
+
senderLinkData?.linksByNode.set(decoded.to, key);
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
case "bye":
|
|
103
|
+
if (node === decoded.to) {
|
|
104
|
+
senderLinkData?.linksByNode.delete(decoded.to);
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
{
|
|
110
|
+
const receiverLinkData = this.#links.get(node);
|
|
111
|
+
if (receiverLinkData?.key) {
|
|
112
|
+
const handler = this.#handlersByKey.get(receiverLinkData?.key);
|
|
113
|
+
if (handler) {
|
|
114
|
+
handler(encoded, decoded, cb);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
throw new Error(`${key} no active link for ${node}`);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
1
123
|
// src/utils/uuid.ts
|
|
2
124
|
import { nanoid } from "nanoid";
|
|
3
125
|
function newUUID() {
|
|
@@ -201,9 +323,9 @@ var DefaultDiscoveryConfig = class {
|
|
|
201
323
|
};
|
|
202
324
|
|
|
203
325
|
// src/logging.ts
|
|
204
|
-
import {
|
|
326
|
+
import { getLogger as getGatewayLogger } from "@interopio/gateway/logging/core";
|
|
205
327
|
function getLogger(name) {
|
|
206
|
-
return
|
|
328
|
+
return getGatewayLogger(`gateway.bridge.${name}`);
|
|
207
329
|
}
|
|
208
330
|
|
|
209
331
|
// src/kubernetes/KubernetesDiscoveryStrategyFactory.ts
|
|
@@ -697,6 +819,9 @@ var ServerConfig = class {
|
|
|
697
819
|
type: "none",
|
|
698
820
|
basic: {
|
|
699
821
|
realm: "io.Bridge"
|
|
822
|
+
},
|
|
823
|
+
oauth2: {
|
|
824
|
+
jwt: { issuerUri: "" }
|
|
700
825
|
}
|
|
701
826
|
};
|
|
702
827
|
wsPingInterval = 3e4;
|
|
@@ -1209,7 +1334,7 @@ function parseVersion(version) {
|
|
|
1209
1334
|
// package.json
|
|
1210
1335
|
var package_default = {
|
|
1211
1336
|
name: "@interopio/bridge",
|
|
1212
|
-
version: "0.0
|
|
1337
|
+
version: "0.1.0-beta.0",
|
|
1213
1338
|
license: "see license in license.md",
|
|
1214
1339
|
author: "interop.io",
|
|
1215
1340
|
homepage: "https://docs.interop.io/bridge",
|
|
@@ -1220,6 +1345,11 @@ var package_default = {
|
|
|
1220
1345
|
"glue42",
|
|
1221
1346
|
"interop.io"
|
|
1222
1347
|
],
|
|
1348
|
+
repository: {
|
|
1349
|
+
type: "git",
|
|
1350
|
+
url: "https://github.com/InteropIO/bridge.git",
|
|
1351
|
+
directory: "packages/bridge"
|
|
1352
|
+
},
|
|
1223
1353
|
type: "module",
|
|
1224
1354
|
exports: {
|
|
1225
1355
|
"./package.json": "./package.json",
|
|
@@ -1244,12 +1374,13 @@ var package_default = {
|
|
|
1244
1374
|
build: "npm run build:main && npm run build:index"
|
|
1245
1375
|
},
|
|
1246
1376
|
dependencies: {
|
|
1247
|
-
"@interopio/gateway-server": "^0.
|
|
1248
|
-
dotenv: "^17.2.
|
|
1377
|
+
"@interopio/gateway-server": "^0.13.0-beta.1",
|
|
1378
|
+
dotenv: "^17.2.3",
|
|
1249
1379
|
jsrsasign: "^11.1.0",
|
|
1250
|
-
nanoid: "^5.
|
|
1380
|
+
nanoid: "^5.1.6"
|
|
1251
1381
|
},
|
|
1252
1382
|
devDependencies: {
|
|
1383
|
+
"@interopio/gateway": "^0.16.1-beta.0",
|
|
1253
1384
|
"@types/jsrsasign": "^10.5.15",
|
|
1254
1385
|
"@types/ws": "^8.18.1",
|
|
1255
1386
|
"rand-seed": "^3.0.0"
|
|
@@ -1579,195 +1710,6 @@ var BridgeLicenseValidator = (logger) => new LicenseValidator({ validationKey, l
|
|
|
1579
1710
|
// src/instance/BridgeNode.ts
|
|
1580
1711
|
import { userInfo } from "node:os";
|
|
1581
1712
|
|
|
1582
|
-
// ../bridge-mesh/src/mesh/connections.ts
|
|
1583
|
-
import "@interopio/gateway";
|
|
1584
|
-
var InMemoryNodeConnections = class {
|
|
1585
|
-
#logger;
|
|
1586
|
-
#nodes = /* @__PURE__ */ new Map();
|
|
1587
|
-
#nodesByEndpoint = /* @__PURE__ */ new Map();
|
|
1588
|
-
#memberIds = 0;
|
|
1589
|
-
#timeout;
|
|
1590
|
-
constructor(logger, timeout = 6e4) {
|
|
1591
|
-
this.#logger = logger;
|
|
1592
|
-
this.#timeout = timeout;
|
|
1593
|
-
}
|
|
1594
|
-
announce(nodes) {
|
|
1595
|
-
for (const node of nodes) {
|
|
1596
|
-
const { node: nodeId, users, endpoint } = node;
|
|
1597
|
-
const foundId = this.#nodesByEndpoint.get(endpoint);
|
|
1598
|
-
if (foundId) {
|
|
1599
|
-
if (foundId !== nodeId) {
|
|
1600
|
-
this.#logger.warn(`endpoint ${endpoint} clash. replacing node ${foundId} with ${nodeId}`);
|
|
1601
|
-
this.#nodesByEndpoint.set(endpoint, nodeId);
|
|
1602
|
-
this.#nodes.delete(foundId);
|
|
1603
|
-
}
|
|
1604
|
-
} else {
|
|
1605
|
-
this.#logger.info(`endpoint ${endpoint} announced for ${nodeId}`);
|
|
1606
|
-
this.#nodesByEndpoint.set(endpoint, nodeId);
|
|
1607
|
-
}
|
|
1608
|
-
this.#nodes.set(nodeId, this.updateNode(node, new Set(users ?? []), nodeId, this.#nodes.get(nodeId)));
|
|
1609
|
-
}
|
|
1610
|
-
this.cleanupOldNodes();
|
|
1611
|
-
const sortedNodes = this.sortedNodeValues();
|
|
1612
|
-
return nodes.map((e) => {
|
|
1613
|
-
const { node } = e;
|
|
1614
|
-
const connect = this.findConnections(sortedNodes, this.#nodes.get(node));
|
|
1615
|
-
return { node, connect };
|
|
1616
|
-
});
|
|
1617
|
-
}
|
|
1618
|
-
find(nodeId) {
|
|
1619
|
-
const e = this.#nodes.get(nodeId);
|
|
1620
|
-
if (e !== void 0) {
|
|
1621
|
-
const sortedNodes = this.sortedNodeValues();
|
|
1622
|
-
const { node } = e;
|
|
1623
|
-
return this.findConnections(sortedNodes, this.#nodes.get(node));
|
|
1624
|
-
}
|
|
1625
|
-
return void 0;
|
|
1626
|
-
}
|
|
1627
|
-
remove(nodeId) {
|
|
1628
|
-
const removed = this.#nodes.get(nodeId);
|
|
1629
|
-
if (removed !== void 0) {
|
|
1630
|
-
this.#nodes.delete(nodeId);
|
|
1631
|
-
const endpoint = removed.endpoint;
|
|
1632
|
-
this.#nodesByEndpoint.delete(endpoint);
|
|
1633
|
-
this.#logger.info(`endpoint ${endpoint} removed for ${nodeId}`);
|
|
1634
|
-
return true;
|
|
1635
|
-
}
|
|
1636
|
-
return false;
|
|
1637
|
-
}
|
|
1638
|
-
updateNode(newNode, users, _key, oldNode) {
|
|
1639
|
-
const node = oldNode ?? { ...newNode, memberId: this.#memberIds++ };
|
|
1640
|
-
return { ...node, users, lastAccess: Date.now() };
|
|
1641
|
-
}
|
|
1642
|
-
sortedNodeValues() {
|
|
1643
|
-
return Array.from(this.#nodes.values()).sort((a, b) => a.memberId - b.memberId);
|
|
1644
|
-
}
|
|
1645
|
-
cleanupOldNodes() {
|
|
1646
|
-
const threshold = Date.now() - this.#timeout;
|
|
1647
|
-
for (const [nodeId, v] of this.#nodes) {
|
|
1648
|
-
if (v.lastAccess < threshold) {
|
|
1649
|
-
if (this.#logger.enabledFor("debug")) {
|
|
1650
|
-
this.#logger.debug(`${nodeId} expired - no announcement since ${new Date(v.lastAccess).toISOString()}, timeout is ${this.#timeout} ms.`);
|
|
1651
|
-
}
|
|
1652
|
-
this.#nodes.delete(nodeId);
|
|
1653
|
-
}
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1656
|
-
findConnections(sortedNodes, node) {
|
|
1657
|
-
return sortedNodes.reduce((l, c) => {
|
|
1658
|
-
if (node !== void 0 && c.memberId < node.memberId) {
|
|
1659
|
-
const intersection = new Set(c.users);
|
|
1660
|
-
node.users.forEach((user) => {
|
|
1661
|
-
if (!c.users.has(user)) {
|
|
1662
|
-
intersection.delete(user);
|
|
1663
|
-
}
|
|
1664
|
-
});
|
|
1665
|
-
c.users.forEach((user) => {
|
|
1666
|
-
if (!node.users.has(user)) {
|
|
1667
|
-
intersection.delete(user);
|
|
1668
|
-
}
|
|
1669
|
-
});
|
|
1670
|
-
if (intersection.size > 0) {
|
|
1671
|
-
const e = { node: c.node, endpoint: c.endpoint };
|
|
1672
|
-
return l.concat(e);
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1675
|
-
return l;
|
|
1676
|
-
}, new Array());
|
|
1677
|
-
}
|
|
1678
|
-
};
|
|
1679
|
-
|
|
1680
|
-
// ../bridge-mesh/src/mesh/relays.ts
|
|
1681
|
-
import { IOGateway as IOGateway3 } from "@interopio/gateway";
|
|
1682
|
-
var codec = IOGateway3.Encoding.transit({
|
|
1683
|
-
keywordize: /* @__PURE__ */ new Map([
|
|
1684
|
-
["/type", "*"],
|
|
1685
|
-
["/message/body/type", "*"],
|
|
1686
|
-
["/message/origin", "*"],
|
|
1687
|
-
["/message/receiver/type", "*"],
|
|
1688
|
-
["/message/source/type", "*"],
|
|
1689
|
-
["/message/body/type", "*"]
|
|
1690
|
-
])
|
|
1691
|
-
});
|
|
1692
|
-
var InternalRelays = class {
|
|
1693
|
-
#logger;
|
|
1694
|
-
// key -> socket
|
|
1695
|
-
#clients = /* @__PURE__ */ new Map();
|
|
1696
|
-
// node -> key
|
|
1697
|
-
#links = /* @__PURE__ */ new Map();
|
|
1698
|
-
onMsg;
|
|
1699
|
-
onErr;
|
|
1700
|
-
constructor(logger) {
|
|
1701
|
-
this.#logger = logger;
|
|
1702
|
-
}
|
|
1703
|
-
add(key, soc) {
|
|
1704
|
-
this.#clients.set(key, soc);
|
|
1705
|
-
}
|
|
1706
|
-
remove(key) {
|
|
1707
|
-
this.#clients.delete(key);
|
|
1708
|
-
for (const [node, k] of this.#links) {
|
|
1709
|
-
if (k === key) {
|
|
1710
|
-
this.#links.delete(node);
|
|
1711
|
-
}
|
|
1712
|
-
}
|
|
1713
|
-
}
|
|
1714
|
-
receive(key, msg) {
|
|
1715
|
-
const node = this.link(key, msg);
|
|
1716
|
-
if (node && this.onMsg) {
|
|
1717
|
-
this.onMsg(key, node, msg);
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1720
|
-
link(key, msg) {
|
|
1721
|
-
try {
|
|
1722
|
-
const decoded = codec.decode(msg);
|
|
1723
|
-
const { type, from, to } = decoded;
|
|
1724
|
-
if (to === "all") {
|
|
1725
|
-
switch (type) {
|
|
1726
|
-
case "hello": {
|
|
1727
|
-
if (this.#logger.enabledFor("debug")) {
|
|
1728
|
-
this.#logger.debug(`${key} registers node ${from}`);
|
|
1729
|
-
}
|
|
1730
|
-
this.#links.set(from, key);
|
|
1731
|
-
break;
|
|
1732
|
-
}
|
|
1733
|
-
case "bye": {
|
|
1734
|
-
if (this.#logger.enabledFor("debug")) {
|
|
1735
|
-
this.#logger.debug(`${key} unregisters node ${from}`);
|
|
1736
|
-
}
|
|
1737
|
-
this.#links.delete(from);
|
|
1738
|
-
break;
|
|
1739
|
-
}
|
|
1740
|
-
}
|
|
1741
|
-
return;
|
|
1742
|
-
}
|
|
1743
|
-
return from;
|
|
1744
|
-
} catch (e) {
|
|
1745
|
-
if (this.onErr) {
|
|
1746
|
-
this.onErr(key, e instanceof Error ? e : new Error(`link failed :${e}`));
|
|
1747
|
-
} else {
|
|
1748
|
-
this.#logger.warn(`${key} unable to process ${msg}`, e);
|
|
1749
|
-
}
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
send(key, node, msg, cb) {
|
|
1753
|
-
const decoded = codec.decode(msg);
|
|
1754
|
-
if (this.#logger.enabledFor("debug")) {
|
|
1755
|
-
this.#logger.debug(`${key} sending msg to ${node} ${JSON.stringify(decoded)}`);
|
|
1756
|
-
}
|
|
1757
|
-
const clientKey = this.#links.get(node);
|
|
1758
|
-
if (clientKey) {
|
|
1759
|
-
const client = this.#clients.get(clientKey);
|
|
1760
|
-
if (client) {
|
|
1761
|
-
client.send(msg, { binary: false }, (err) => {
|
|
1762
|
-
cb(clientKey, err);
|
|
1763
|
-
});
|
|
1764
|
-
return;
|
|
1765
|
-
}
|
|
1766
|
-
}
|
|
1767
|
-
throw new Error(`${key} no active link for ${decoded.to}`);
|
|
1768
|
-
}
|
|
1769
|
-
};
|
|
1770
|
-
|
|
1771
1713
|
// ../bridge-mesh/src/mesh/rest-directory/routes.ts
|
|
1772
1714
|
function buildCanonicalBaseURL(request) {
|
|
1773
1715
|
const requestURL = request.URL;
|
|
@@ -1888,7 +1830,11 @@ async function create(log, internal, env) {
|
|
|
1888
1830
|
const logPrefix = handshake.logPrefix;
|
|
1889
1831
|
const key = `r.${id}.${++keyId}`;
|
|
1890
1832
|
log.info(`${logPrefix}connected on /relays with assigned key ${key}`);
|
|
1891
|
-
internal.add(key,
|
|
1833
|
+
internal.add(key, (msg, c, cb) => {
|
|
1834
|
+
socket.send(msg, { binary: false }, (err) => {
|
|
1835
|
+
cb(key, err);
|
|
1836
|
+
});
|
|
1837
|
+
});
|
|
1892
1838
|
socket.on("error", (err) => {
|
|
1893
1839
|
log.error(`${logPrefix}websocket error: ${err.message}`, err);
|
|
1894
1840
|
});
|
|
@@ -1908,9 +1854,9 @@ async function create(log, internal, env) {
|
|
|
1908
1854
|
});
|
|
1909
1855
|
};
|
|
1910
1856
|
}
|
|
1911
|
-
var meshRelays = ({ logger,
|
|
1857
|
+
var meshRelays = ({ logger, relays }) => {
|
|
1912
1858
|
return async (env) => {
|
|
1913
|
-
return await create(logger,
|
|
1859
|
+
return await create(logger, relays, env);
|
|
1914
1860
|
};
|
|
1915
1861
|
};
|
|
1916
1862
|
|
|
@@ -1938,10 +1884,13 @@ function onMessage(relays, log, key, node, socketsByNodeId, msg) {
|
|
|
1938
1884
|
var handlerId2 = 0;
|
|
1939
1885
|
async function create2(log, relays, env) {
|
|
1940
1886
|
const socketsByNodeId = /* @__PURE__ */ new Map();
|
|
1941
|
-
relays.
|
|
1887
|
+
relays.on("message", (k, nodeId, msg) => {
|
|
1942
1888
|
try {
|
|
1943
1889
|
const sockets = socketsByNodeId.get(nodeId);
|
|
1944
1890
|
if (sockets && sockets.size > 0) {
|
|
1891
|
+
if (log.enabledFor("trace")) {
|
|
1892
|
+
log.debug(`${k} sending message to ${[...sockets.keys()]}`);
|
|
1893
|
+
}
|
|
1945
1894
|
for (const [key, socket] of sockets) {
|
|
1946
1895
|
socket.send(msg, { binary: false }, (err) => {
|
|
1947
1896
|
if (err) {
|
|
@@ -1959,7 +1908,16 @@ async function create2(log, relays, env) {
|
|
|
1959
1908
|
} catch (ex) {
|
|
1960
1909
|
log.error(`${k} unable to process message`, ex);
|
|
1961
1910
|
}
|
|
1962
|
-
};
|
|
1911
|
+
});
|
|
1912
|
+
relays.on("disconnect", (k, nodeId) => {
|
|
1913
|
+
const sockets = socketsByNodeId.get(nodeId);
|
|
1914
|
+
if (sockets) {
|
|
1915
|
+
for (const [key, socket] of sockets) {
|
|
1916
|
+
socket.terminate();
|
|
1917
|
+
log.info(`${key} terminated because ${k} disconnected ${nodeId}`);
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
});
|
|
1963
1921
|
const id = ++handlerId2;
|
|
1964
1922
|
let keyId = 0;
|
|
1965
1923
|
return async ({ socket, handshake }) => {
|
|
@@ -2008,19 +1966,222 @@ var meshCluster = ({ logger, relays }) => {
|
|
|
2008
1966
|
|
|
2009
1967
|
// ../bridge-mesh/src/index.ts
|
|
2010
1968
|
import "@interopio/gateway-server";
|
|
2011
|
-
|
|
1969
|
+
|
|
1970
|
+
// ../bridge-mesh/src/mesh/gateway/mesh.ts
|
|
1971
|
+
import { nanoid as nanoid2 } from "nanoid";
|
|
1972
|
+
var instanceId = 0;
|
|
1973
|
+
var BridgeMeshChannel = class {
|
|
1974
|
+
#logger;
|
|
1975
|
+
#relays;
|
|
1976
|
+
#connections;
|
|
1977
|
+
#state;
|
|
1978
|
+
#keyPrefix;
|
|
1979
|
+
constructor(relays, nodes, logger) {
|
|
1980
|
+
this.#relays = relays;
|
|
1981
|
+
this.#connections = nodes;
|
|
1982
|
+
this.#logger = logger;
|
|
1983
|
+
this.#state = /* @__PURE__ */ new Map();
|
|
1984
|
+
this.#keyPrefix = `g.${++instanceId}`;
|
|
1985
|
+
}
|
|
1986
|
+
get relays() {
|
|
1987
|
+
return this.#relays;
|
|
1988
|
+
}
|
|
1989
|
+
get connections() {
|
|
1990
|
+
return this.#connections;
|
|
1991
|
+
}
|
|
1992
|
+
#intervalId;
|
|
1993
|
+
subscribe(node, subscriber) {
|
|
1994
|
+
node ??= nanoid2();
|
|
1995
|
+
const key = `${this.#keyPrefix}-${node}`;
|
|
1996
|
+
if (this.#state.has(key)) {
|
|
1997
|
+
throw new Error(`already subscribed to node ${node}`);
|
|
1998
|
+
}
|
|
1999
|
+
this.#state.set(node, { subscriber, users: /* @__PURE__ */ new Set(), members: /* @__PURE__ */ new Set() });
|
|
2000
|
+
this.#relays.receive(key, { type: "hello", from: node, to: "all" });
|
|
2001
|
+
this.#relays.add(key, this.createRelayClient(key, node));
|
|
2002
|
+
this.#intervalId ??= setInterval(() => this.#announce(), 3e4);
|
|
2003
|
+
return node;
|
|
2004
|
+
}
|
|
2005
|
+
createRelayClient(key, node) {
|
|
2006
|
+
return (_msg, command, cb) => {
|
|
2007
|
+
switch (command.type) {
|
|
2008
|
+
case "hello":
|
|
2009
|
+
case "bye":
|
|
2010
|
+
break;
|
|
2011
|
+
case "data": {
|
|
2012
|
+
try {
|
|
2013
|
+
const event = {
|
|
2014
|
+
type: "message-received",
|
|
2015
|
+
message: command.data
|
|
2016
|
+
};
|
|
2017
|
+
this.#state.get(node)?.subscriber(event, node, this);
|
|
2018
|
+
} catch (err) {
|
|
2019
|
+
cb(key, err);
|
|
2020
|
+
}
|
|
2021
|
+
break;
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
};
|
|
2025
|
+
}
|
|
2026
|
+
unsubscribe(node) {
|
|
2027
|
+
this.#delete(node);
|
|
2028
|
+
this.#relays.remove(`${this.#keyPrefix}-${node}`);
|
|
2029
|
+
}
|
|
2030
|
+
execute(node, action) {
|
|
2031
|
+
switch (action.type) {
|
|
2032
|
+
case "publish-message": {
|
|
2033
|
+
this.#onMessage(node, action.message);
|
|
2034
|
+
break;
|
|
2035
|
+
}
|
|
2036
|
+
case "add-users": {
|
|
2037
|
+
this.#onAddUsers(node, action.added);
|
|
2038
|
+
break;
|
|
2039
|
+
}
|
|
2040
|
+
case "remove-users": {
|
|
2041
|
+
this.#onRemoveUsers(node, action.removed);
|
|
2042
|
+
break;
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
#onMessage(node, data) {
|
|
2047
|
+
const nodes = this.#connections.find(node);
|
|
2048
|
+
if (nodes !== void 0) {
|
|
2049
|
+
const key = `${this.#keyPrefix}-${node}`;
|
|
2050
|
+
const command = { type: "data", from: node, data };
|
|
2051
|
+
nodes.forEach((connection) => {
|
|
2052
|
+
const to = connection.node;
|
|
2053
|
+
if (to === node) {
|
|
2054
|
+
return;
|
|
2055
|
+
}
|
|
2056
|
+
try {
|
|
2057
|
+
this.#relays.send(key, to, { ...command, to }, (k, err) => {
|
|
2058
|
+
if (err) {
|
|
2059
|
+
this.#logger.warn(`failed to send message from ${node} to ${to} via ${k}: ${err.message}`);
|
|
2060
|
+
}
|
|
2061
|
+
});
|
|
2062
|
+
} catch (err) {
|
|
2063
|
+
this.#logger.warn(`failed to send message from ${node} to ${to} via ${key}: ${err.message}`);
|
|
2064
|
+
}
|
|
2065
|
+
});
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
#onAddUsers(node, usersToAdd) {
|
|
2069
|
+
let shouldAnnounce = false;
|
|
2070
|
+
const nodeState = this.#state.get(node);
|
|
2071
|
+
const nodeUsers = nodeState?.users;
|
|
2072
|
+
if (nodeUsers === void 0) {
|
|
2073
|
+
nodeState.users = new Set(usersToAdd);
|
|
2074
|
+
shouldAnnounce = true;
|
|
2075
|
+
} else {
|
|
2076
|
+
for (const u of usersToAdd) {
|
|
2077
|
+
if (nodeUsers.has(u)) {
|
|
2078
|
+
continue;
|
|
2079
|
+
}
|
|
2080
|
+
nodeUsers.add(u);
|
|
2081
|
+
shouldAnnounce = true;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
if (shouldAnnounce) {
|
|
2085
|
+
this.#announce(node);
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
#onRemoveUsers(node, usersToRemove) {
|
|
2089
|
+
const nodeState = this.#state.get(node);
|
|
2090
|
+
const nodeUsers = nodeState?.users;
|
|
2091
|
+
if (nodeUsers === void 0) {
|
|
2092
|
+
return;
|
|
2093
|
+
}
|
|
2094
|
+
let shouldAnnounce = false;
|
|
2095
|
+
for (const u of usersToRemove) {
|
|
2096
|
+
if (!nodeUsers.has(u)) {
|
|
2097
|
+
continue;
|
|
2098
|
+
}
|
|
2099
|
+
nodeUsers.delete(u);
|
|
2100
|
+
shouldAnnounce = true;
|
|
2101
|
+
}
|
|
2102
|
+
if (nodeUsers.size === 0) {
|
|
2103
|
+
this.#delete(node);
|
|
2104
|
+
} else if (shouldAnnounce) {
|
|
2105
|
+
this.#announce(node);
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
#announce(node) {
|
|
2109
|
+
const entries = node === void 0 ? this.#state.entries() : [[node, this.#state.get(node)]];
|
|
2110
|
+
const nodes = Array.from(entries, entryToNode);
|
|
2111
|
+
const nodeConnections = this.#connections.announce(nodes);
|
|
2112
|
+
for (const { node: n, connect } of nodeConnections) {
|
|
2113
|
+
const state = this.#state.get(n);
|
|
2114
|
+
if (state === void 0) {
|
|
2115
|
+
continue;
|
|
2116
|
+
}
|
|
2117
|
+
const toRemove = new Set(state.members);
|
|
2118
|
+
for (const c of connect) {
|
|
2119
|
+
if (c.node === n) {
|
|
2120
|
+
continue;
|
|
2121
|
+
}
|
|
2122
|
+
toRemove.delete(c.node);
|
|
2123
|
+
if (state.members.has(c.node)) {
|
|
2124
|
+
continue;
|
|
2125
|
+
}
|
|
2126
|
+
state.members.add(c.node);
|
|
2127
|
+
state.subscriber({ type: "member-added", node: c.node }, n, this);
|
|
2128
|
+
}
|
|
2129
|
+
for (const r of toRemove) {
|
|
2130
|
+
state.members.delete(r);
|
|
2131
|
+
state.subscriber({ type: "member-removed", node: r }, n, this);
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
#delete(node) {
|
|
2136
|
+
this.#state.delete(node);
|
|
2137
|
+
this.#connections.remove(node);
|
|
2138
|
+
}
|
|
2139
|
+
close() {
|
|
2140
|
+
for (const node of this.#state.keys()) {
|
|
2141
|
+
this.#delete(node);
|
|
2142
|
+
this.#relays.remove(`${this.#keyPrefix}-${node}`);
|
|
2143
|
+
}
|
|
2144
|
+
clearInterval(this.#intervalId);
|
|
2145
|
+
}
|
|
2146
|
+
};
|
|
2147
|
+
var entryToNode = ([node, state]) => {
|
|
2148
|
+
const users = Array.from(state?.users);
|
|
2149
|
+
const endpoint = `/cluster?node=${node}`;
|
|
2150
|
+
return { node, endpoint, users };
|
|
2151
|
+
};
|
|
2152
|
+
|
|
2153
|
+
// ../bridge-mesh/src/index.ts
|
|
2154
|
+
function connectNodeRelays(logger, relays, connections) {
|
|
2155
|
+
relays.on("disconnect", (key, node, links) => {
|
|
2156
|
+
for (const [linkNode, linkKey] of links) {
|
|
2157
|
+
try {
|
|
2158
|
+
relays.send(linkKey, linkNode, { type: "bye", from: node, to: linkNode }, (k, err) => {
|
|
2159
|
+
if (err) {
|
|
2160
|
+
logger.warn(`${k} error writing 'bye' msg to ${linkNode}: ${err}`);
|
|
2161
|
+
return;
|
|
2162
|
+
}
|
|
2163
|
+
if (logger.enabledFor("debug")) {
|
|
2164
|
+
logger.debug(`${k} sent 'bye' msg to ${linkNode}`);
|
|
2165
|
+
}
|
|
2166
|
+
});
|
|
2167
|
+
} catch (err) {
|
|
2168
|
+
logger.warn(`${linkKey} exception writing 'bye' msg to ${linkNode}: ${err}`);
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
});
|
|
2172
|
+
}
|
|
2012
2173
|
var mesh = async (options, configurer, config) => {
|
|
2013
|
-
const { enabled, logger } = options;
|
|
2174
|
+
const { enabled, logger, relays, connections } = options;
|
|
2014
2175
|
if (enabled !== true) {
|
|
2015
|
-
logger.debug
|
|
2176
|
+
if (logger.enabledFor("debug")) {
|
|
2177
|
+
logger.debug(`no mesh`);
|
|
2178
|
+
}
|
|
2016
2179
|
return;
|
|
2017
2180
|
}
|
|
2018
|
-
let { socket
|
|
2181
|
+
let { socket } = options;
|
|
2019
2182
|
const authorize = socket.authorize ?? { access: config.auth.type === "none" ? "permitted" : "authenticated" };
|
|
2020
2183
|
socket = { ping: 3e4, authorize, ...socket };
|
|
2021
|
-
|
|
2022
|
-
const connections = new InMemoryNodeConnections(logger, timeout);
|
|
2023
|
-
const relays = new InternalRelays(logger);
|
|
2184
|
+
connectNodeRelays(logger, relays, connections);
|
|
2024
2185
|
routes_default({ connections, authorize }, configurer);
|
|
2025
2186
|
configurer.socket(
|
|
2026
2187
|
{
|
|
@@ -2031,11 +2192,258 @@ var mesh = async (options, configurer, config) => {
|
|
|
2031
2192
|
{
|
|
2032
2193
|
path: "/relays",
|
|
2033
2194
|
options: socket,
|
|
2034
|
-
factory: meshRelays({ logger,
|
|
2195
|
+
factory: meshRelays({ logger, relays })
|
|
2035
2196
|
}
|
|
2036
2197
|
);
|
|
2037
2198
|
};
|
|
2038
2199
|
|
|
2200
|
+
// ../bridge-mesh/src/mesh/connections.ts
|
|
2201
|
+
import "@interopio/gateway";
|
|
2202
|
+
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
2203
|
+
var OrderedMap = class {
|
|
2204
|
+
#elements = [];
|
|
2205
|
+
#binarySearch(key) {
|
|
2206
|
+
let low = 0;
|
|
2207
|
+
let high = this.#elements.length - 1;
|
|
2208
|
+
while (low <= high) {
|
|
2209
|
+
const mid = low + high >> 1;
|
|
2210
|
+
const cmp = this.#elements[mid][0].localeCompare(key);
|
|
2211
|
+
if (cmp === 0) return mid;
|
|
2212
|
+
if (cmp < 0) low = mid + 1;
|
|
2213
|
+
else high = mid - 1;
|
|
2214
|
+
}
|
|
2215
|
+
return -low - 1;
|
|
2216
|
+
}
|
|
2217
|
+
set(key, value) {
|
|
2218
|
+
const idx = this.#binarySearch(key);
|
|
2219
|
+
if (idx >= 0) {
|
|
2220
|
+
this.#elements[idx][1] = value;
|
|
2221
|
+
} else {
|
|
2222
|
+
this.#elements.splice(~idx, 0, [key, value]);
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
get(key) {
|
|
2226
|
+
const idx = this.#binarySearch(key);
|
|
2227
|
+
return idx >= 0 ? this.#elements[idx][1] : void 0;
|
|
2228
|
+
}
|
|
2229
|
+
has(key) {
|
|
2230
|
+
return this.#binarySearch(key) >= 0;
|
|
2231
|
+
}
|
|
2232
|
+
delete(key) {
|
|
2233
|
+
const idx = this.#binarySearch(key);
|
|
2234
|
+
if (idx >= 0) {
|
|
2235
|
+
this.#elements.splice(idx, 1);
|
|
2236
|
+
return true;
|
|
2237
|
+
}
|
|
2238
|
+
return false;
|
|
2239
|
+
}
|
|
2240
|
+
entries() {
|
|
2241
|
+
return this.#elements[Symbol.iterator]();
|
|
2242
|
+
}
|
|
2243
|
+
values() {
|
|
2244
|
+
return this.#elements.map((e) => e[1]);
|
|
2245
|
+
}
|
|
2246
|
+
};
|
|
2247
|
+
var InMemoryNodeConnections = class {
|
|
2248
|
+
#logger;
|
|
2249
|
+
#eventEmitter = new EventEmitter2();
|
|
2250
|
+
#nodes = new OrderedMap();
|
|
2251
|
+
#nodesByEndpoint = /* @__PURE__ */ new Map();
|
|
2252
|
+
#timeout;
|
|
2253
|
+
constructor(logger, timeout = 6e4) {
|
|
2254
|
+
this.#logger = logger;
|
|
2255
|
+
this.#timeout = timeout;
|
|
2256
|
+
}
|
|
2257
|
+
announce(nodes) {
|
|
2258
|
+
const now = Date.now();
|
|
2259
|
+
for (const node of nodes) {
|
|
2260
|
+
const { node: nodeId, users, endpoint } = node;
|
|
2261
|
+
const foundId = this.#nodesByEndpoint.get(endpoint);
|
|
2262
|
+
if (foundId) {
|
|
2263
|
+
if (foundId !== nodeId) {
|
|
2264
|
+
this.#logger.warn(`endpoint ${endpoint} clash. replacing node ${foundId} with ${nodeId}`);
|
|
2265
|
+
this.#nodesByEndpoint.set(endpoint, nodeId);
|
|
2266
|
+
this.#nodes.delete(foundId);
|
|
2267
|
+
this.#eventEmitter.emit("endpoint-deleted", foundId, endpoint, "clashed");
|
|
2268
|
+
}
|
|
2269
|
+
} else {
|
|
2270
|
+
this.#logger.info(`endpoint ${endpoint} announced for ${nodeId}`);
|
|
2271
|
+
this.#nodesByEndpoint.set(endpoint, nodeId);
|
|
2272
|
+
}
|
|
2273
|
+
const set = new Set(users ?? []);
|
|
2274
|
+
this.#nodes.set(nodeId, this.updateNode(node, set, nodeId, now, this.#nodes.get(nodeId)));
|
|
2275
|
+
this.#eventEmitter.emit("endpoint-announced", nodeId, endpoint, set);
|
|
2276
|
+
}
|
|
2277
|
+
this.cleanupOldNodes();
|
|
2278
|
+
return nodes.map((e) => {
|
|
2279
|
+
const { node } = e;
|
|
2280
|
+
const connect = this.findConnections(this.#nodes.get(node));
|
|
2281
|
+
return { node, connect };
|
|
2282
|
+
});
|
|
2283
|
+
}
|
|
2284
|
+
find(nodeId) {
|
|
2285
|
+
const e = this.#nodes.get(nodeId);
|
|
2286
|
+
if (e !== void 0) {
|
|
2287
|
+
return this.findConnections(e);
|
|
2288
|
+
}
|
|
2289
|
+
return void 0;
|
|
2290
|
+
}
|
|
2291
|
+
remove(nodeId) {
|
|
2292
|
+
const removed = this.#nodes.get(nodeId);
|
|
2293
|
+
if (removed !== void 0) {
|
|
2294
|
+
this.#nodes.delete(nodeId);
|
|
2295
|
+
const endpoint = removed.endpoint;
|
|
2296
|
+
this.#nodesByEndpoint.delete(endpoint);
|
|
2297
|
+
this.#logger.info(`endpoint ${endpoint} removed for ${nodeId}`);
|
|
2298
|
+
this.#eventEmitter.emit("endpoint-deleted", nodeId, endpoint, "removed");
|
|
2299
|
+
return true;
|
|
2300
|
+
}
|
|
2301
|
+
return false;
|
|
2302
|
+
}
|
|
2303
|
+
updateNode(newNode, users, _key, lastAccess, oldNode) {
|
|
2304
|
+
const node = oldNode ?? { ...newNode };
|
|
2305
|
+
return { ...node, users, lastAccess };
|
|
2306
|
+
}
|
|
2307
|
+
cleanupOldNodes() {
|
|
2308
|
+
const threshold = Date.now() - this.#timeout;
|
|
2309
|
+
for (const [nodeId, v] of this.#nodes.entries()) {
|
|
2310
|
+
if (v.lastAccess < threshold) {
|
|
2311
|
+
if (this.#logger.enabledFor("debug")) {
|
|
2312
|
+
this.#logger.debug(`${nodeId} expired - no announcement since ${new Date(v.lastAccess).toISOString()}, timeout is ${this.#timeout} ms.`);
|
|
2313
|
+
}
|
|
2314
|
+
this.#nodes.delete(nodeId);
|
|
2315
|
+
const endpoint = v.endpoint;
|
|
2316
|
+
this.#nodesByEndpoint.delete(endpoint);
|
|
2317
|
+
this.#eventEmitter.emit("endpoint-deleted", nodeId, endpoint, "expired");
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
on(event, listener) {
|
|
2322
|
+
this.#eventEmitter.on(event, listener);
|
|
2323
|
+
return this;
|
|
2324
|
+
}
|
|
2325
|
+
off(event, listener) {
|
|
2326
|
+
this.#eventEmitter.off(event, listener);
|
|
2327
|
+
return this;
|
|
2328
|
+
}
|
|
2329
|
+
findConnections(node) {
|
|
2330
|
+
const connections = new Array();
|
|
2331
|
+
for (const [key, value] of this.#nodes.entries()) {
|
|
2332
|
+
if (node !== void 0 && key < node.node) {
|
|
2333
|
+
const intersection = new Set(value.users);
|
|
2334
|
+
node.users.forEach((user) => {
|
|
2335
|
+
if (!value.users.has(user)) {
|
|
2336
|
+
intersection.delete(user);
|
|
2337
|
+
}
|
|
2338
|
+
});
|
|
2339
|
+
value.users.forEach((user) => {
|
|
2340
|
+
if (!node.users.has(user)) {
|
|
2341
|
+
intersection.delete(user);
|
|
2342
|
+
}
|
|
2343
|
+
});
|
|
2344
|
+
if (intersection.size > 0) {
|
|
2345
|
+
const e = { node: value.node, endpoint: value.endpoint };
|
|
2346
|
+
connections.push(e);
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
return connections;
|
|
2351
|
+
}
|
|
2352
|
+
};
|
|
2353
|
+
|
|
2354
|
+
// ../bridge-gateway/src/desktop.ts
|
|
2355
|
+
function isRunningInConnectDesktop(env = process.env) {
|
|
2356
|
+
return env._GD_STARTING_CONTEXT_ !== void 0;
|
|
2357
|
+
}
|
|
2358
|
+
function parseStartingContext(env = process.env) {
|
|
2359
|
+
if (!isRunningInConnectDesktop(env)) {
|
|
2360
|
+
throw new Error("Not running in io.Connect Desktop");
|
|
2361
|
+
}
|
|
2362
|
+
return JSON.parse(env._GD_STARTING_CONTEXT_).applicationConfig?.customProperties;
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2365
|
+
// ../bridge-gateway/src/index.ts
|
|
2366
|
+
import { tmpdir } from "node:os";
|
|
2367
|
+
import { createServer as createServer2 } from "node:net";
|
|
2368
|
+
import { join } from "node:path";
|
|
2369
|
+
import "@interopio/gateway";
|
|
2370
|
+
import "@interopio/gateway-server";
|
|
2371
|
+
function onGatewayStarted(log) {
|
|
2372
|
+
return (gateway) => {
|
|
2373
|
+
const info = JSON.stringify(gateway.info());
|
|
2374
|
+
if (isRunningInConnectDesktop()) {
|
|
2375
|
+
const env = process.env["GLUE-ENV"] || "DEMO";
|
|
2376
|
+
const region = process.env["GLUE-REGION"] || "INTEROP.IO";
|
|
2377
|
+
const user = process.env.USERNAME ?? process.env.USER;
|
|
2378
|
+
const pipe = `glue42-${env}-${region}-${user}`;
|
|
2379
|
+
const pipeName = process.platform === "win32" ? `\\\\.\\pipe\\${pipe}` : `${join(tmpdir(), pipe + ".sock")}`;
|
|
2380
|
+
log.info(`gateway started: ${info}, opening ${pipeName}`);
|
|
2381
|
+
const server = createServer2((stream) => {
|
|
2382
|
+
log.info(`stream connected, sending info...`);
|
|
2383
|
+
stream.write(info);
|
|
2384
|
+
stream.end(() => {
|
|
2385
|
+
server.close();
|
|
2386
|
+
});
|
|
2387
|
+
});
|
|
2388
|
+
server.listen(pipeName);
|
|
2389
|
+
} else {
|
|
2390
|
+
log.info(`gateway started: ${info}`);
|
|
2391
|
+
}
|
|
2392
|
+
};
|
|
2393
|
+
}
|
|
2394
|
+
async function serverGatewayConfig(gateway, bridge, env = process.env) {
|
|
2395
|
+
let enabled = gateway.enabled;
|
|
2396
|
+
if (enabled === void 0) {
|
|
2397
|
+
if (isRunningInConnectDesktop(env)) {
|
|
2398
|
+
enabled = parseStartingContext(env)?.gatewayApp === true;
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
let contextsLifetime = gateway.contexts.lifetime;
|
|
2402
|
+
if (contextsLifetime === void 0) {
|
|
2403
|
+
if (isRunningInConnectDesktop(env)) {
|
|
2404
|
+
contextsLifetime = "retained";
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
if (enabled) {
|
|
2408
|
+
return {
|
|
2409
|
+
// globals: { websocket },
|
|
2410
|
+
clients: {
|
|
2411
|
+
inactive_seconds: 0
|
|
2412
|
+
},
|
|
2413
|
+
ping: bridge.wsPingInterval ?? void 0,
|
|
2414
|
+
mesh: {
|
|
2415
|
+
channel: bridge.meshChannel
|
|
2416
|
+
},
|
|
2417
|
+
contexts: {
|
|
2418
|
+
lifetime: contextsLifetime,
|
|
2419
|
+
visibility: [
|
|
2420
|
+
{ context: /___channel___.+/, restrictions: "cluster" },
|
|
2421
|
+
{ context: /T42\..*/, restrictions: "local" },
|
|
2422
|
+
{ context: "___platform_prefs___", restrictions: "local" },
|
|
2423
|
+
{ context: /___workspace___.+/, restrictions: "local" },
|
|
2424
|
+
{ context: /___window-hibernation___.+/, restrictions: "local" },
|
|
2425
|
+
{ context: /___instance___.+/, restrictions: "local" },
|
|
2426
|
+
{ context: /___window___.+/, restrictions: "local" },
|
|
2427
|
+
{ restrictions: "cluster" }
|
|
2428
|
+
]
|
|
2429
|
+
},
|
|
2430
|
+
methods: {
|
|
2431
|
+
visibility: [
|
|
2432
|
+
{ method: /T42\..*/, restrictions: "local" },
|
|
2433
|
+
{ restrictions: "cluster" }
|
|
2434
|
+
]
|
|
2435
|
+
},
|
|
2436
|
+
peers: {
|
|
2437
|
+
visibility: [
|
|
2438
|
+
{ domain: "context", restrictions: "cluster" },
|
|
2439
|
+
{ domain: "interop", restrictions: "cluster" },
|
|
2440
|
+
{ domain: "bus", restrictions: "local" }
|
|
2441
|
+
]
|
|
2442
|
+
}
|
|
2443
|
+
};
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
|
|
2039
2447
|
// src/instance/BridgeNode.ts
|
|
2040
2448
|
function logStartingInfo(logger) {
|
|
2041
2449
|
logger.info(`Starting io.Bridge v${package_default.version} using Node.js ${process.version} with PID ${process.pid} (started by ${userInfo().username} in ${process.cwd()})`);
|
|
@@ -2061,12 +2469,13 @@ var BridgeNode = class {
|
|
|
2061
2469
|
config;
|
|
2062
2470
|
uuid;
|
|
2063
2471
|
discoveryService;
|
|
2472
|
+
meshChannel;
|
|
2064
2473
|
version;
|
|
2065
2474
|
server;
|
|
2066
2475
|
licenseValidator;
|
|
2067
2476
|
constructor(config) {
|
|
2068
2477
|
this.config = config;
|
|
2069
|
-
this.licenseValidator = BridgeLicenseValidator(this.getLogger("license
|
|
2478
|
+
this.licenseValidator = BridgeLicenseValidator(this.getLogger("license"));
|
|
2070
2479
|
this.licenseValidator.validate(config.license);
|
|
2071
2480
|
this.uuid = newUUID();
|
|
2072
2481
|
this.version = parseVersion(package_default.version);
|
|
@@ -2082,7 +2491,10 @@ var BridgeNode = class {
|
|
|
2082
2491
|
const joinConfig = config.network.join;
|
|
2083
2492
|
const isAutoDetectionEnabled = joinConfig.autoDetectionEnabled;
|
|
2084
2493
|
const discoveryConfig = joinConfig.discovery;
|
|
2085
|
-
this.discoveryService = createDiscoveryService(getLogger("discovery
|
|
2494
|
+
this.discoveryService = createDiscoveryService(getLogger("discovery"), discoveryConfig, isAutoDetectionEnabled, localMemberPromise);
|
|
2495
|
+
const relays = new InternalRelays(this.getLogger("relays"));
|
|
2496
|
+
const connections = new InMemoryNodeConnections(this.getLogger("nodes"), this.config.mesh.timeout ?? 6e4);
|
|
2497
|
+
this.meshChannel = new BridgeMeshChannel(relays, connections, this.getLogger("channel"));
|
|
2086
2498
|
}
|
|
2087
2499
|
getLogger(name) {
|
|
2088
2500
|
return getLogger(name);
|
|
@@ -2108,8 +2520,8 @@ var BridgeNode = class {
|
|
|
2108
2520
|
await mesh({
|
|
2109
2521
|
logger: this.getLogger("mesh"),
|
|
2110
2522
|
enabled: true,
|
|
2111
|
-
|
|
2112
|
-
|
|
2523
|
+
relays: this.meshChannel.relays,
|
|
2524
|
+
connections: this.meshChannel.connections,
|
|
2113
2525
|
socket: {
|
|
2114
2526
|
ping: this.config.server.wsPingInterval ?? 3e4
|
|
2115
2527
|
// 30 seconds
|
|
@@ -2119,50 +2531,15 @@ var BridgeNode = class {
|
|
|
2119
2531
|
auth: { type: "none", ...this.config.server.auth },
|
|
2120
2532
|
cors: this.config.server.cors.disabled ? false : this.config.server.cors
|
|
2121
2533
|
};
|
|
2122
|
-
|
|
2123
|
-
const { WebSocket: websocket } = await import("ws");
|
|
2124
|
-
config.gateway = {
|
|
2125
|
-
globals: { websocket },
|
|
2126
|
-
clients: {
|
|
2127
|
-
inactive_seconds: 0
|
|
2128
|
-
},
|
|
2129
|
-
ping: this.config.server.wsPingInterval ?? void 0,
|
|
2130
|
-
mesh: {
|
|
2131
|
-
cluster: {
|
|
2132
|
-
endpoint: `http://localhost:${this.config.server.port}`,
|
|
2133
|
-
directory: { interval: 1e3 * 30 }
|
|
2134
|
-
// 30 seconds
|
|
2135
|
-
}
|
|
2136
|
-
},
|
|
2137
|
-
contexts: {
|
|
2138
|
-
lifetime: this.config.gateway.contexts.lifetime,
|
|
2139
|
-
visibility: [
|
|
2140
|
-
{ context: /___channel___.+/, restrictions: "cluster" },
|
|
2141
|
-
{ context: /T42\..*/, restrictions: "local" },
|
|
2142
|
-
{ context: "___platform_prefs___", restrictions: "local" },
|
|
2143
|
-
{ restrictions: "cluster" }
|
|
2144
|
-
]
|
|
2145
|
-
},
|
|
2146
|
-
methods: {
|
|
2147
|
-
visibility: [
|
|
2148
|
-
{ method: /T42\..*/, restrictions: "local" },
|
|
2149
|
-
{ restrictions: "cluster" }
|
|
2150
|
-
]
|
|
2151
|
-
},
|
|
2152
|
-
peers: {
|
|
2153
|
-
visibility: [
|
|
2154
|
-
{ domain: "context", restrictions: "cluster" },
|
|
2155
|
-
{ domain: "interop", restrictions: "cluster" },
|
|
2156
|
-
{ domain: "bus", restrictions: "local" }
|
|
2157
|
-
]
|
|
2158
|
-
}
|
|
2159
|
-
};
|
|
2160
|
-
}
|
|
2534
|
+
config.gateway = await serverGatewayConfig(this.config.gateway, { meshChannel: this.meshChannel, wsPingInterval: this.config.server.wsPingInterval });
|
|
2161
2535
|
logStartingInfo(this.getLogger("node"));
|
|
2162
2536
|
this.server = await gatewayServer(config);
|
|
2163
2537
|
if (false) {
|
|
2164
2538
|
await this.discoveryService.start();
|
|
2165
2539
|
}
|
|
2540
|
+
if (config.gateway !== void 0) {
|
|
2541
|
+
onGatewayStarted(this.getLogger("gw"))(this.server.gateway);
|
|
2542
|
+
}
|
|
2166
2543
|
await this.scheduleLicenseCheck();
|
|
2167
2544
|
}
|
|
2168
2545
|
async stop() {
|
|
@@ -2173,6 +2550,7 @@ var BridgeNode = class {
|
|
|
2173
2550
|
await this.discoveryService.close();
|
|
2174
2551
|
} catch (e) {
|
|
2175
2552
|
}
|
|
2553
|
+
this.meshChannel.close();
|
|
2176
2554
|
}
|
|
2177
2555
|
};
|
|
2178
2556
|
|
|
@@ -2234,12 +2612,15 @@ try {
|
|
|
2234
2612
|
await import("dotenv/config");
|
|
2235
2613
|
const config = new Config();
|
|
2236
2614
|
config.license ??= loadLicense();
|
|
2237
|
-
config.server.port ??= loadConfig("server.port", NUMBER) ??
|
|
2615
|
+
config.server.port ??= loadConfig("server.port", NUMBER) ?? 8084;
|
|
2238
2616
|
config.server.host ??= loadConfig("server.host", STRING);
|
|
2239
2617
|
config.server.wsPingInterval ??= loadConfig("server.ws-ping-interval", NUMBER);
|
|
2240
2618
|
config.gateway.enabled ??= loadConfig("gateway.enabled", BOOLEAN);
|
|
2241
2619
|
config.gateway.contexts.lifetime ??= loadConfig("gateway.contexts.lifetime", STRING);
|
|
2242
2620
|
config.server.auth.type = loadConfig("server.auth.type", STRING) ?? "none";
|
|
2621
|
+
config.server.auth.oauth2.jwt.issuerUri = loadConfig("server.auth.oauth2.jwt.issuer-uri", STRING) ?? void 0;
|
|
2622
|
+
config.server.auth.oauth2.jwt.issuer = loadConfig("server.auth.oauth2.jwt.issuer", STRING) ?? void 0;
|
|
2623
|
+
config.server.auth.oauth2.jwt.audience = loadConfig("server.auth.oauth2.jwt.audience", STRING) ?? void 0;
|
|
2243
2624
|
config.server.cors.allowOrigin = loadConfig("server.cors.allow-origin", STRING) ?? "*";
|
|
2244
2625
|
config.server.cors.allowCredentials = loadConfig("server.cors.allow-credentials", BOOLEAN) ?? true;
|
|
2245
2626
|
config.server.cors.disabled = loadConfig("server.cors.disabled", BOOLEAN) ?? false ? true : void 0;
|