@interopio/bridge 0.0.5-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 +29 -0
- package/dist/main.js +650 -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
|
|
@@ -686,6 +808,7 @@ var CorsConfig = class {
|
|
|
686
808
|
get allowOrigin() {
|
|
687
809
|
return this.#allowOrigin;
|
|
688
810
|
}
|
|
811
|
+
disabled;
|
|
689
812
|
allowCredentials = false;
|
|
690
813
|
};
|
|
691
814
|
var ServerConfig = class {
|
|
@@ -696,6 +819,9 @@ var ServerConfig = class {
|
|
|
696
819
|
type: "none",
|
|
697
820
|
basic: {
|
|
698
821
|
realm: "io.Bridge"
|
|
822
|
+
},
|
|
823
|
+
oauth2: {
|
|
824
|
+
jwt: { issuerUri: "" }
|
|
699
825
|
}
|
|
700
826
|
};
|
|
701
827
|
wsPingInterval = 3e4;
|
|
@@ -1208,7 +1334,7 @@ function parseVersion(version) {
|
|
|
1208
1334
|
// package.json
|
|
1209
1335
|
var package_default = {
|
|
1210
1336
|
name: "@interopio/bridge",
|
|
1211
|
-
version: "0.0
|
|
1337
|
+
version: "0.1.0-beta.0",
|
|
1212
1338
|
license: "see license in license.md",
|
|
1213
1339
|
author: "interop.io",
|
|
1214
1340
|
homepage: "https://docs.interop.io/bridge",
|
|
@@ -1219,6 +1345,11 @@ var package_default = {
|
|
|
1219
1345
|
"glue42",
|
|
1220
1346
|
"interop.io"
|
|
1221
1347
|
],
|
|
1348
|
+
repository: {
|
|
1349
|
+
type: "git",
|
|
1350
|
+
url: "https://github.com/InteropIO/bridge.git",
|
|
1351
|
+
directory: "packages/bridge"
|
|
1352
|
+
},
|
|
1222
1353
|
type: "module",
|
|
1223
1354
|
exports: {
|
|
1224
1355
|
"./package.json": "./package.json",
|
|
@@ -1243,12 +1374,13 @@ var package_default = {
|
|
|
1243
1374
|
build: "npm run build:main && npm run build:index"
|
|
1244
1375
|
},
|
|
1245
1376
|
dependencies: {
|
|
1246
|
-
"@interopio/gateway-server": "^0.
|
|
1247
|
-
dotenv: "^17.2.
|
|
1377
|
+
"@interopio/gateway-server": "^0.13.0-beta.1",
|
|
1378
|
+
dotenv: "^17.2.3",
|
|
1248
1379
|
jsrsasign: "^11.1.0",
|
|
1249
|
-
nanoid: "^5.
|
|
1380
|
+
nanoid: "^5.1.6"
|
|
1250
1381
|
},
|
|
1251
1382
|
devDependencies: {
|
|
1383
|
+
"@interopio/gateway": "^0.16.1-beta.0",
|
|
1252
1384
|
"@types/jsrsasign": "^10.5.15",
|
|
1253
1385
|
"@types/ws": "^8.18.1",
|
|
1254
1386
|
"rand-seed": "^3.0.0"
|
|
@@ -1578,195 +1710,6 @@ var BridgeLicenseValidator = (logger) => new LicenseValidator({ validationKey, l
|
|
|
1578
1710
|
// src/instance/BridgeNode.ts
|
|
1579
1711
|
import { userInfo } from "node:os";
|
|
1580
1712
|
|
|
1581
|
-
// ../bridge-mesh/src/mesh/connections.ts
|
|
1582
|
-
import "@interopio/gateway";
|
|
1583
|
-
var InMemoryNodeConnections = class {
|
|
1584
|
-
#logger;
|
|
1585
|
-
#nodes = /* @__PURE__ */ new Map();
|
|
1586
|
-
#nodesByEndpoint = /* @__PURE__ */ new Map();
|
|
1587
|
-
#memberIds = 0;
|
|
1588
|
-
#timeout;
|
|
1589
|
-
constructor(logger, timeout = 6e4) {
|
|
1590
|
-
this.#logger = logger;
|
|
1591
|
-
this.#timeout = timeout;
|
|
1592
|
-
}
|
|
1593
|
-
announce(nodes) {
|
|
1594
|
-
for (const node of nodes) {
|
|
1595
|
-
const { node: nodeId, users, endpoint } = node;
|
|
1596
|
-
const foundId = this.#nodesByEndpoint.get(endpoint);
|
|
1597
|
-
if (foundId) {
|
|
1598
|
-
if (foundId !== nodeId) {
|
|
1599
|
-
this.#logger.warn(`endpoint ${endpoint} clash. replacing node ${foundId} with ${nodeId}`);
|
|
1600
|
-
this.#nodesByEndpoint.set(endpoint, nodeId);
|
|
1601
|
-
this.#nodes.delete(foundId);
|
|
1602
|
-
}
|
|
1603
|
-
} else {
|
|
1604
|
-
this.#logger.info(`endpoint ${endpoint} announced for ${nodeId}`);
|
|
1605
|
-
this.#nodesByEndpoint.set(endpoint, nodeId);
|
|
1606
|
-
}
|
|
1607
|
-
this.#nodes.set(nodeId, this.updateNode(node, new Set(users ?? []), nodeId, this.#nodes.get(nodeId)));
|
|
1608
|
-
}
|
|
1609
|
-
this.cleanupOldNodes();
|
|
1610
|
-
const sortedNodes = this.sortedNodeValues();
|
|
1611
|
-
return nodes.map((e) => {
|
|
1612
|
-
const { node } = e;
|
|
1613
|
-
const connect = this.findConnections(sortedNodes, this.#nodes.get(node));
|
|
1614
|
-
return { node, connect };
|
|
1615
|
-
});
|
|
1616
|
-
}
|
|
1617
|
-
find(nodeId) {
|
|
1618
|
-
const e = this.#nodes.get(nodeId);
|
|
1619
|
-
if (e !== void 0) {
|
|
1620
|
-
const sortedNodes = this.sortedNodeValues();
|
|
1621
|
-
const { node } = e;
|
|
1622
|
-
return this.findConnections(sortedNodes, this.#nodes.get(node));
|
|
1623
|
-
}
|
|
1624
|
-
return void 0;
|
|
1625
|
-
}
|
|
1626
|
-
remove(nodeId) {
|
|
1627
|
-
const removed = this.#nodes.get(nodeId);
|
|
1628
|
-
if (removed !== void 0) {
|
|
1629
|
-
this.#nodes.delete(nodeId);
|
|
1630
|
-
const endpoint = removed.endpoint;
|
|
1631
|
-
this.#nodesByEndpoint.delete(endpoint);
|
|
1632
|
-
this.#logger.info(`endpoint ${endpoint} removed for ${nodeId}`);
|
|
1633
|
-
return true;
|
|
1634
|
-
}
|
|
1635
|
-
return false;
|
|
1636
|
-
}
|
|
1637
|
-
updateNode(newNode, users, _key, oldNode) {
|
|
1638
|
-
const node = oldNode ?? { ...newNode, memberId: this.#memberIds++ };
|
|
1639
|
-
return { ...node, users, lastAccess: Date.now() };
|
|
1640
|
-
}
|
|
1641
|
-
sortedNodeValues() {
|
|
1642
|
-
return Array.from(this.#nodes.values()).sort((a, b) => a.memberId - b.memberId);
|
|
1643
|
-
}
|
|
1644
|
-
cleanupOldNodes() {
|
|
1645
|
-
const threshold = Date.now() - this.#timeout;
|
|
1646
|
-
for (const [nodeId, v] of this.#nodes) {
|
|
1647
|
-
if (v.lastAccess < threshold) {
|
|
1648
|
-
if (this.#logger.enabledFor("debug")) {
|
|
1649
|
-
this.#logger.debug(`${nodeId} expired - no announcement since ${new Date(v.lastAccess).toISOString()}, timeout is ${this.#timeout} ms.`);
|
|
1650
|
-
}
|
|
1651
|
-
this.#nodes.delete(nodeId);
|
|
1652
|
-
}
|
|
1653
|
-
}
|
|
1654
|
-
}
|
|
1655
|
-
findConnections(sortedNodes, node) {
|
|
1656
|
-
return sortedNodes.reduce((l, c) => {
|
|
1657
|
-
if (node !== void 0 && c.memberId < node.memberId) {
|
|
1658
|
-
const intersection = new Set(c.users);
|
|
1659
|
-
node.users.forEach((user) => {
|
|
1660
|
-
if (!c.users.has(user)) {
|
|
1661
|
-
intersection.delete(user);
|
|
1662
|
-
}
|
|
1663
|
-
});
|
|
1664
|
-
c.users.forEach((user) => {
|
|
1665
|
-
if (!node.users.has(user)) {
|
|
1666
|
-
intersection.delete(user);
|
|
1667
|
-
}
|
|
1668
|
-
});
|
|
1669
|
-
if (intersection.size > 0) {
|
|
1670
|
-
const e = { node: c.node, endpoint: c.endpoint };
|
|
1671
|
-
return l.concat(e);
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
return l;
|
|
1675
|
-
}, new Array());
|
|
1676
|
-
}
|
|
1677
|
-
};
|
|
1678
|
-
|
|
1679
|
-
// ../bridge-mesh/src/mesh/relays.ts
|
|
1680
|
-
import { IOGateway as IOGateway3 } from "@interopio/gateway";
|
|
1681
|
-
var codec = IOGateway3.Encoding.transit({
|
|
1682
|
-
keywordize: /* @__PURE__ */ new Map([
|
|
1683
|
-
["/type", "*"],
|
|
1684
|
-
["/message/body/type", "*"],
|
|
1685
|
-
["/message/origin", "*"],
|
|
1686
|
-
["/message/receiver/type", "*"],
|
|
1687
|
-
["/message/source/type", "*"],
|
|
1688
|
-
["/message/body/type", "*"]
|
|
1689
|
-
])
|
|
1690
|
-
});
|
|
1691
|
-
var InternalRelays = class {
|
|
1692
|
-
#logger;
|
|
1693
|
-
// key -> socket
|
|
1694
|
-
#clients = /* @__PURE__ */ new Map();
|
|
1695
|
-
// node -> key
|
|
1696
|
-
#links = /* @__PURE__ */ new Map();
|
|
1697
|
-
onMsg;
|
|
1698
|
-
onErr;
|
|
1699
|
-
constructor(logger) {
|
|
1700
|
-
this.#logger = logger;
|
|
1701
|
-
}
|
|
1702
|
-
add(key, soc) {
|
|
1703
|
-
this.#clients.set(key, soc);
|
|
1704
|
-
}
|
|
1705
|
-
remove(key) {
|
|
1706
|
-
this.#clients.delete(key);
|
|
1707
|
-
for (const [node, k] of this.#links) {
|
|
1708
|
-
if (k === key) {
|
|
1709
|
-
this.#links.delete(node);
|
|
1710
|
-
}
|
|
1711
|
-
}
|
|
1712
|
-
}
|
|
1713
|
-
receive(key, msg) {
|
|
1714
|
-
const node = this.link(key, msg);
|
|
1715
|
-
if (node && this.onMsg) {
|
|
1716
|
-
this.onMsg(key, node, msg);
|
|
1717
|
-
}
|
|
1718
|
-
}
|
|
1719
|
-
link(key, msg) {
|
|
1720
|
-
try {
|
|
1721
|
-
const decoded = codec.decode(msg);
|
|
1722
|
-
const { type, from, to } = decoded;
|
|
1723
|
-
if (to === "all") {
|
|
1724
|
-
switch (type) {
|
|
1725
|
-
case "hello": {
|
|
1726
|
-
if (this.#logger.enabledFor("debug")) {
|
|
1727
|
-
this.#logger.debug(`${key} registers node ${from}`);
|
|
1728
|
-
}
|
|
1729
|
-
this.#links.set(from, key);
|
|
1730
|
-
break;
|
|
1731
|
-
}
|
|
1732
|
-
case "bye": {
|
|
1733
|
-
if (this.#logger.enabledFor("debug")) {
|
|
1734
|
-
this.#logger.debug(`${key} unregisters node ${from}`);
|
|
1735
|
-
}
|
|
1736
|
-
this.#links.delete(from);
|
|
1737
|
-
break;
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1740
|
-
return;
|
|
1741
|
-
}
|
|
1742
|
-
return from;
|
|
1743
|
-
} catch (e) {
|
|
1744
|
-
if (this.onErr) {
|
|
1745
|
-
this.onErr(key, e instanceof Error ? e : new Error(`link failed :${e}`));
|
|
1746
|
-
} else {
|
|
1747
|
-
this.#logger.warn(`${key} unable to process ${msg}`, e);
|
|
1748
|
-
}
|
|
1749
|
-
}
|
|
1750
|
-
}
|
|
1751
|
-
send(key, node, msg, cb) {
|
|
1752
|
-
const decoded = codec.decode(msg);
|
|
1753
|
-
if (this.#logger.enabledFor("debug")) {
|
|
1754
|
-
this.#logger.debug(`${key} sending msg to ${node} ${JSON.stringify(decoded)}`);
|
|
1755
|
-
}
|
|
1756
|
-
const clientKey = this.#links.get(node);
|
|
1757
|
-
if (clientKey) {
|
|
1758
|
-
const client = this.#clients.get(clientKey);
|
|
1759
|
-
if (client) {
|
|
1760
|
-
client.send(msg, { binary: false }, (err) => {
|
|
1761
|
-
cb(clientKey, err);
|
|
1762
|
-
});
|
|
1763
|
-
return;
|
|
1764
|
-
}
|
|
1765
|
-
}
|
|
1766
|
-
throw new Error(`${key} no active link for ${decoded.to}`);
|
|
1767
|
-
}
|
|
1768
|
-
};
|
|
1769
|
-
|
|
1770
1713
|
// ../bridge-mesh/src/mesh/rest-directory/routes.ts
|
|
1771
1714
|
function buildCanonicalBaseURL(request) {
|
|
1772
1715
|
const requestURL = request.URL;
|
|
@@ -1887,7 +1830,11 @@ async function create(log, internal, env) {
|
|
|
1887
1830
|
const logPrefix = handshake.logPrefix;
|
|
1888
1831
|
const key = `r.${id}.${++keyId}`;
|
|
1889
1832
|
log.info(`${logPrefix}connected on /relays with assigned key ${key}`);
|
|
1890
|
-
internal.add(key,
|
|
1833
|
+
internal.add(key, (msg, c, cb) => {
|
|
1834
|
+
socket.send(msg, { binary: false }, (err) => {
|
|
1835
|
+
cb(key, err);
|
|
1836
|
+
});
|
|
1837
|
+
});
|
|
1891
1838
|
socket.on("error", (err) => {
|
|
1892
1839
|
log.error(`${logPrefix}websocket error: ${err.message}`, err);
|
|
1893
1840
|
});
|
|
@@ -1907,9 +1854,9 @@ async function create(log, internal, env) {
|
|
|
1907
1854
|
});
|
|
1908
1855
|
};
|
|
1909
1856
|
}
|
|
1910
|
-
var meshRelays = ({ logger,
|
|
1857
|
+
var meshRelays = ({ logger, relays }) => {
|
|
1911
1858
|
return async (env) => {
|
|
1912
|
-
return await create(logger,
|
|
1859
|
+
return await create(logger, relays, env);
|
|
1913
1860
|
};
|
|
1914
1861
|
};
|
|
1915
1862
|
|
|
@@ -1937,10 +1884,13 @@ function onMessage(relays, log, key, node, socketsByNodeId, msg) {
|
|
|
1937
1884
|
var handlerId2 = 0;
|
|
1938
1885
|
async function create2(log, relays, env) {
|
|
1939
1886
|
const socketsByNodeId = /* @__PURE__ */ new Map();
|
|
1940
|
-
relays.
|
|
1887
|
+
relays.on("message", (k, nodeId, msg) => {
|
|
1941
1888
|
try {
|
|
1942
1889
|
const sockets = socketsByNodeId.get(nodeId);
|
|
1943
1890
|
if (sockets && sockets.size > 0) {
|
|
1891
|
+
if (log.enabledFor("trace")) {
|
|
1892
|
+
log.debug(`${k} sending message to ${[...sockets.keys()]}`);
|
|
1893
|
+
}
|
|
1944
1894
|
for (const [key, socket] of sockets) {
|
|
1945
1895
|
socket.send(msg, { binary: false }, (err) => {
|
|
1946
1896
|
if (err) {
|
|
@@ -1958,7 +1908,16 @@ async function create2(log, relays, env) {
|
|
|
1958
1908
|
} catch (ex) {
|
|
1959
1909
|
log.error(`${k} unable to process message`, ex);
|
|
1960
1910
|
}
|
|
1961
|
-
};
|
|
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
|
+
});
|
|
1962
1921
|
const id = ++handlerId2;
|
|
1963
1922
|
let keyId = 0;
|
|
1964
1923
|
return async ({ socket, handshake }) => {
|
|
@@ -2007,19 +1966,222 @@ var meshCluster = ({ logger, relays }) => {
|
|
|
2007
1966
|
|
|
2008
1967
|
// ../bridge-mesh/src/index.ts
|
|
2009
1968
|
import "@interopio/gateway-server";
|
|
2010
|
-
|
|
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
|
+
}
|
|
2011
2173
|
var mesh = async (options, configurer, config) => {
|
|
2012
|
-
const { enabled, logger } = options;
|
|
2174
|
+
const { enabled, logger, relays, connections } = options;
|
|
2013
2175
|
if (enabled !== true) {
|
|
2014
|
-
logger.debug
|
|
2176
|
+
if (logger.enabledFor("debug")) {
|
|
2177
|
+
logger.debug(`no mesh`);
|
|
2178
|
+
}
|
|
2015
2179
|
return;
|
|
2016
2180
|
}
|
|
2017
|
-
let { socket
|
|
2181
|
+
let { socket } = options;
|
|
2018
2182
|
const authorize = socket.authorize ?? { access: config.auth.type === "none" ? "permitted" : "authenticated" };
|
|
2019
2183
|
socket = { ping: 3e4, authorize, ...socket };
|
|
2020
|
-
|
|
2021
|
-
const connections = new InMemoryNodeConnections(logger, timeout);
|
|
2022
|
-
const relays = new InternalRelays(logger);
|
|
2184
|
+
connectNodeRelays(logger, relays, connections);
|
|
2023
2185
|
routes_default({ connections, authorize }, configurer);
|
|
2024
2186
|
configurer.socket(
|
|
2025
2187
|
{
|
|
@@ -2030,11 +2192,258 @@ var mesh = async (options, configurer, config) => {
|
|
|
2030
2192
|
{
|
|
2031
2193
|
path: "/relays",
|
|
2032
2194
|
options: socket,
|
|
2033
|
-
factory: meshRelays({ logger,
|
|
2195
|
+
factory: meshRelays({ logger, relays })
|
|
2034
2196
|
}
|
|
2035
2197
|
);
|
|
2036
2198
|
};
|
|
2037
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
|
+
|
|
2038
2447
|
// src/instance/BridgeNode.ts
|
|
2039
2448
|
function logStartingInfo(logger) {
|
|
2040
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()})`);
|
|
@@ -2060,12 +2469,13 @@ var BridgeNode = class {
|
|
|
2060
2469
|
config;
|
|
2061
2470
|
uuid;
|
|
2062
2471
|
discoveryService;
|
|
2472
|
+
meshChannel;
|
|
2063
2473
|
version;
|
|
2064
2474
|
server;
|
|
2065
2475
|
licenseValidator;
|
|
2066
2476
|
constructor(config) {
|
|
2067
2477
|
this.config = config;
|
|
2068
|
-
this.licenseValidator = BridgeLicenseValidator(this.getLogger("license
|
|
2478
|
+
this.licenseValidator = BridgeLicenseValidator(this.getLogger("license"));
|
|
2069
2479
|
this.licenseValidator.validate(config.license);
|
|
2070
2480
|
this.uuid = newUUID();
|
|
2071
2481
|
this.version = parseVersion(package_default.version);
|
|
@@ -2081,7 +2491,10 @@ var BridgeNode = class {
|
|
|
2081
2491
|
const joinConfig = config.network.join;
|
|
2082
2492
|
const isAutoDetectionEnabled = joinConfig.autoDetectionEnabled;
|
|
2083
2493
|
const discoveryConfig = joinConfig.discovery;
|
|
2084
|
-
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"));
|
|
2085
2498
|
}
|
|
2086
2499
|
getLogger(name) {
|
|
2087
2500
|
return getLogger(name);
|
|
@@ -2107,8 +2520,8 @@ var BridgeNode = class {
|
|
|
2107
2520
|
await mesh({
|
|
2108
2521
|
logger: this.getLogger("mesh"),
|
|
2109
2522
|
enabled: true,
|
|
2110
|
-
|
|
2111
|
-
|
|
2523
|
+
relays: this.meshChannel.relays,
|
|
2524
|
+
connections: this.meshChannel.connections,
|
|
2112
2525
|
socket: {
|
|
2113
2526
|
ping: this.config.server.wsPingInterval ?? 3e4
|
|
2114
2527
|
// 30 seconds
|
|
@@ -2116,50 +2529,17 @@ var BridgeNode = class {
|
|
|
2116
2529
|
}, configurer, config2);
|
|
2117
2530
|
},
|
|
2118
2531
|
auth: { type: "none", ...this.config.server.auth },
|
|
2119
|
-
cors: this.config.server.cors
|
|
2532
|
+
cors: this.config.server.cors.disabled ? false : this.config.server.cors
|
|
2120
2533
|
};
|
|
2121
|
-
|
|
2122
|
-
config.gateway = {
|
|
2123
|
-
clients: {
|
|
2124
|
-
inactive_seconds: 0
|
|
2125
|
-
},
|
|
2126
|
-
ping: this.config.server.wsPingInterval ?? void 0,
|
|
2127
|
-
mesh: {
|
|
2128
|
-
cluster: {
|
|
2129
|
-
endpoint: `http://localhost:${this.config.server.port}`,
|
|
2130
|
-
directory: { interval: 1e3 * 30 }
|
|
2131
|
-
// 30 seconds
|
|
2132
|
-
}
|
|
2133
|
-
},
|
|
2134
|
-
contexts: {
|
|
2135
|
-
lifetime: this.config.gateway.contexts.lifetime,
|
|
2136
|
-
visibility: [
|
|
2137
|
-
{ context: /___channel___.+/, restrictions: "cluster" },
|
|
2138
|
-
{ context: /T42\..*/, restrictions: "local" },
|
|
2139
|
-
{ context: "___platform_prefs___", restrictions: "local" },
|
|
2140
|
-
{ restrictions: "cluster" }
|
|
2141
|
-
]
|
|
2142
|
-
},
|
|
2143
|
-
methods: {
|
|
2144
|
-
visibility: [
|
|
2145
|
-
{ method: /T42\..*/, restrictions: "local" },
|
|
2146
|
-
{ restrictions: "cluster" }
|
|
2147
|
-
]
|
|
2148
|
-
},
|
|
2149
|
-
peers: {
|
|
2150
|
-
visibility: [
|
|
2151
|
-
{ domain: "context", restrictions: "cluster" },
|
|
2152
|
-
{ domain: "interop", restrictions: "cluster" },
|
|
2153
|
-
{ domain: "bus", restrictions: "local" }
|
|
2154
|
-
]
|
|
2155
|
-
}
|
|
2156
|
-
};
|
|
2157
|
-
}
|
|
2534
|
+
config.gateway = await serverGatewayConfig(this.config.gateway, { meshChannel: this.meshChannel, wsPingInterval: this.config.server.wsPingInterval });
|
|
2158
2535
|
logStartingInfo(this.getLogger("node"));
|
|
2159
2536
|
this.server = await gatewayServer(config);
|
|
2160
2537
|
if (false) {
|
|
2161
2538
|
await this.discoveryService.start();
|
|
2162
2539
|
}
|
|
2540
|
+
if (config.gateway !== void 0) {
|
|
2541
|
+
onGatewayStarted(this.getLogger("gw"))(this.server.gateway);
|
|
2542
|
+
}
|
|
2163
2543
|
await this.scheduleLicenseCheck();
|
|
2164
2544
|
}
|
|
2165
2545
|
async stop() {
|
|
@@ -2170,17 +2550,31 @@ var BridgeNode = class {
|
|
|
2170
2550
|
await this.discoveryService.close();
|
|
2171
2551
|
} catch (e) {
|
|
2172
2552
|
}
|
|
2553
|
+
this.meshChannel.close();
|
|
2173
2554
|
}
|
|
2174
2555
|
};
|
|
2175
2556
|
|
|
2176
2557
|
// src/main.mts
|
|
2177
2558
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
2559
|
+
import { format } from "node:util";
|
|
2178
2560
|
var hadFatalError = false;
|
|
2179
2561
|
var reportedErrors = /* @__PURE__ */ new Set();
|
|
2562
|
+
function getErrorMessage(error) {
|
|
2563
|
+
if (typeof error !== "object" || error === null) {
|
|
2564
|
+
return String(error);
|
|
2565
|
+
}
|
|
2566
|
+
if (typeof error["stack"] === "string") {
|
|
2567
|
+
return error["stack"];
|
|
2568
|
+
}
|
|
2569
|
+
return format("%o", error);
|
|
2570
|
+
}
|
|
2180
2571
|
function onFatalError(error) {
|
|
2181
2572
|
process.exitCode = 2;
|
|
2182
2573
|
hadFatalError = true;
|
|
2183
|
-
const errorMessage = `
|
|
2574
|
+
const errorMessage = `
|
|
2575
|
+
io.Bridge: ${package_default.version}
|
|
2576
|
+
|
|
2577
|
+
${getErrorMessage(error)}`;
|
|
2184
2578
|
if (!reportedErrors.has(errorMessage)) {
|
|
2185
2579
|
console.error(error);
|
|
2186
2580
|
reportedErrors.add(errorMessage);
|
|
@@ -2218,14 +2612,18 @@ try {
|
|
|
2218
2612
|
await import("dotenv/config");
|
|
2219
2613
|
const config = new Config();
|
|
2220
2614
|
config.license ??= loadLicense();
|
|
2221
|
-
config.server.port ??= loadConfig("server.port", NUMBER) ??
|
|
2615
|
+
config.server.port ??= loadConfig("server.port", NUMBER) ?? 8084;
|
|
2222
2616
|
config.server.host ??= loadConfig("server.host", STRING);
|
|
2223
2617
|
config.server.wsPingInterval ??= loadConfig("server.ws-ping-interval", NUMBER);
|
|
2224
2618
|
config.gateway.enabled ??= loadConfig("gateway.enabled", BOOLEAN);
|
|
2225
2619
|
config.gateway.contexts.lifetime ??= loadConfig("gateway.contexts.lifetime", STRING);
|
|
2226
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;
|
|
2227
2624
|
config.server.cors.allowOrigin = loadConfig("server.cors.allow-origin", STRING) ?? "*";
|
|
2228
2625
|
config.server.cors.allowCredentials = loadConfig("server.cors.allow-credentials", BOOLEAN) ?? true;
|
|
2626
|
+
config.server.cors.disabled = loadConfig("server.cors.disabled", BOOLEAN) ?? false ? true : void 0;
|
|
2229
2627
|
const bridge = new BridgeNode(config);
|
|
2230
2628
|
await bridge.start();
|
|
2231
2629
|
} catch (error) {
|