@arcblock/event-hub 1.28.8 → 1.29.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/esm/client.d.mts +43 -0
- package/esm/client.mjs +134 -0
- package/esm/constant.d.mts +7 -0
- package/esm/constant.mjs +8 -0
- package/esm/index.d.mts +7 -0
- package/esm/index.mjs +28 -0
- package/esm/rpc.d.mts +51 -0
- package/esm/rpc.mjs +106 -0
- package/esm/server-abtnode.d.mts +6 -0
- package/esm/server-abtnode.mjs +11 -0
- package/esm/server.d.mts +55 -0
- package/esm/server.mjs +142 -0
- package/esm/single.d.mts +10 -0
- package/esm/single.mjs +16 -0
- package/lib/_virtual/rolldown_runtime.cjs +29 -0
- package/lib/client.cjs +139 -0
- package/lib/client.d.cts +43 -0
- package/lib/constant.cjs +12 -0
- package/lib/constant.d.cts +7 -0
- package/lib/index.cjs +31 -0
- package/lib/index.d.cts +7 -0
- package/lib/rpc.cjs +110 -0
- package/lib/rpc.d.cts +51 -0
- package/lib/server-abtnode.cjs +12 -0
- package/lib/server-abtnode.d.cts +6 -0
- package/lib/server.cjs +147 -0
- package/lib/server.d.cts +55 -0
- package/lib/single.cjs +19 -0
- package/lib/single.d.cts +10 -0
- package/package.json +33 -6
- package/lib/client-fallback.js +0 -13
- package/lib/client.js +0 -183
- package/lib/constant.js +0 -6
- package/lib/index.js +0 -26
- package/lib/rpc.js +0 -119
- package/lib/server-abtnode.js +0 -9
- package/lib/server.js +0 -155
- package/single.js +0 -3
package/lib/client.cjs
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
3
|
+
const require_constant = require('./constant.cjs');
|
|
4
|
+
let node_events = require("node:events");
|
|
5
|
+
let _arcblock_did = require("@arcblock/did");
|
|
6
|
+
let _ocap_wallet = require("@ocap/wallet");
|
|
7
|
+
let axon = require("axon");
|
|
8
|
+
axon = require_rolldown_runtime.__toESM(axon);
|
|
9
|
+
let axon_lib_plugins_queue = require("axon/lib/plugins/queue");
|
|
10
|
+
axon_lib_plugins_queue = require_rolldown_runtime.__toESM(axon_lib_plugins_queue);
|
|
11
|
+
let axon_lib_plugins_round_robin = require("axon/lib/plugins/round-robin");
|
|
12
|
+
axon_lib_plugins_round_robin = require_rolldown_runtime.__toESM(axon_lib_plugins_round_robin);
|
|
13
|
+
|
|
14
|
+
//#region src/client.ts
|
|
15
|
+
const checkEvent = (event) => {
|
|
16
|
+
if (event.startsWith(require_constant.RESERVED_EVENT_PREFIX)) throw new Error(`event cannot start with ${require_constant.RESERVED_EVENT_PREFIX}`);
|
|
17
|
+
};
|
|
18
|
+
const getWallet = (appSk, type) => {
|
|
19
|
+
let t = type;
|
|
20
|
+
let sk = appSk;
|
|
21
|
+
if ((0, _arcblock_did.isEthereumType)((0, _arcblock_did.DidType)(type))) {
|
|
22
|
+
sk = appSk.slice(0, 66);
|
|
23
|
+
t = (0, _ocap_wallet.WalletType)(type);
|
|
24
|
+
}
|
|
25
|
+
return (0, _ocap_wallet.fromSecretKey)(sk, t);
|
|
26
|
+
};
|
|
27
|
+
const defaultOpts = {
|
|
28
|
+
port: void 0,
|
|
29
|
+
hostname: "0.0.0.0",
|
|
30
|
+
autoConnect: false,
|
|
31
|
+
wallet: void 0,
|
|
32
|
+
did: void 0,
|
|
33
|
+
sk: void 0
|
|
34
|
+
};
|
|
35
|
+
var Socket = class extends axon.default.SubEmitterSocket {
|
|
36
|
+
constructor(opts) {
|
|
37
|
+
super();
|
|
38
|
+
const wallet = opts.wallet || getWallet(opts.sk, (0, _arcblock_did.toTypeInfo)(opts.did));
|
|
39
|
+
this._authenticated = false;
|
|
40
|
+
this._pendingMessages = [];
|
|
41
|
+
this._wallet = wallet;
|
|
42
|
+
this.sock.use((sock) => {
|
|
43
|
+
sock.on("connect", async () => {
|
|
44
|
+
this._authenticated = false;
|
|
45
|
+
const token = await wallet.signJWT();
|
|
46
|
+
sock.send(require_constant.EVENT_AUTH, {
|
|
47
|
+
pk: wallet.publicKey,
|
|
48
|
+
token
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
sock.on("close", () => {
|
|
52
|
+
this._authenticated = false;
|
|
53
|
+
this._pendingMessages = [];
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
this.on(require_constant.EVENT_AUTH_SUCCESS, () => {
|
|
57
|
+
this._authenticated = true;
|
|
58
|
+
const pending = this._pendingMessages.slice();
|
|
59
|
+
this._pendingMessages = [];
|
|
60
|
+
pending.forEach(([event, data]) => this.sock.send(event, data));
|
|
61
|
+
});
|
|
62
|
+
this.on(require_constant.EVENT_AUTH_FAIL, ({ msg } = {}) => {
|
|
63
|
+
this.emit("error", { msg });
|
|
64
|
+
this._authenticated = false;
|
|
65
|
+
this._pendingMessages = [];
|
|
66
|
+
this.sock.socks.forEach((s) => s.close());
|
|
67
|
+
});
|
|
68
|
+
this.sock.use((0, axon_lib_plugins_queue.default)());
|
|
69
|
+
this.sock.use((0, axon_lib_plugins_round_robin.default)({ fallback: this.sock.enqueue }));
|
|
70
|
+
const originalSend = this.sock.send.bind(this.sock);
|
|
71
|
+
this.send = (event, data) => {
|
|
72
|
+
const hasConnection = this.sock.socks && this.sock.socks.length > 0;
|
|
73
|
+
if (this._authenticated && hasConnection) originalSend(event, data);
|
|
74
|
+
else this._pendingMessages.push([event, data]);
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var Client = class extends node_events.EventEmitter {
|
|
79
|
+
constructor(opts = {}) {
|
|
80
|
+
super();
|
|
81
|
+
if (!opts.port) throw new Error("port should not be empty");
|
|
82
|
+
if (!opts.wallet) {
|
|
83
|
+
if (!opts.did) throw new Error("did should not be empty when wallet is not provided");
|
|
84
|
+
if (!opts.sk) throw new Error("Either wallet or sk should be provided");
|
|
85
|
+
}
|
|
86
|
+
const wallet = opts.wallet || getWallet(opts.sk, (0, _arcblock_did.toTypeInfo)(opts.did));
|
|
87
|
+
const did = opts.wallet ? opts.wallet.address : opts.did;
|
|
88
|
+
if (wallet.address !== did) throw new Error("did does not match the provided wallet/sk");
|
|
89
|
+
this.opts = Object.assign({}, defaultOpts, opts, {
|
|
90
|
+
wallet,
|
|
91
|
+
did
|
|
92
|
+
});
|
|
93
|
+
this._client = new Socket(this.opts);
|
|
94
|
+
this._wallet = wallet;
|
|
95
|
+
this._bindEvent();
|
|
96
|
+
if (this.opts.autoConnect) this.connect();
|
|
97
|
+
}
|
|
98
|
+
connect() {
|
|
99
|
+
const { port, hostname } = this.opts;
|
|
100
|
+
this._client.connect(port, hostname);
|
|
101
|
+
}
|
|
102
|
+
close() {
|
|
103
|
+
this._client._authenticated = false;
|
|
104
|
+
this._client._pendingMessages = [];
|
|
105
|
+
this._client.close();
|
|
106
|
+
}
|
|
107
|
+
broadcast(event, data) {
|
|
108
|
+
checkEvent(event);
|
|
109
|
+
this._client.send(event, data);
|
|
110
|
+
}
|
|
111
|
+
on(name, fn) {
|
|
112
|
+
checkEvent(name);
|
|
113
|
+
super.on(name, fn);
|
|
114
|
+
this._client.on(name, fn);
|
|
115
|
+
return this;
|
|
116
|
+
}
|
|
117
|
+
off(name, fn) {
|
|
118
|
+
checkEvent(name);
|
|
119
|
+
this._client.off(name);
|
|
120
|
+
if (fn) super.off(name, fn);
|
|
121
|
+
else super.removeAllListeners(name);
|
|
122
|
+
return this;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get the wallet instance
|
|
126
|
+
* Business can override wallet.signJWT() for remote signing
|
|
127
|
+
* @returns {WalletObject}
|
|
128
|
+
*/
|
|
129
|
+
getWallet() {
|
|
130
|
+
return this._wallet;
|
|
131
|
+
}
|
|
132
|
+
_bindEvent() {
|
|
133
|
+
this._client.on("error", this.emit.bind(this, "error"));
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
var client_default = Client;
|
|
137
|
+
|
|
138
|
+
//#endregion
|
|
139
|
+
exports.default = client_default;
|
package/lib/client.d.cts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { fromSecretKey } from "@ocap/wallet";
|
|
3
|
+
import axon from "axon";
|
|
4
|
+
|
|
5
|
+
//#region src/client.d.ts
|
|
6
|
+
interface ClientOptions {
|
|
7
|
+
port?: number;
|
|
8
|
+
hostname?: string;
|
|
9
|
+
autoConnect?: boolean;
|
|
10
|
+
wallet?: ReturnType<typeof fromSecretKey>;
|
|
11
|
+
did?: string;
|
|
12
|
+
sk?: string;
|
|
13
|
+
}
|
|
14
|
+
declare class Socket extends axon.SubEmitterSocket {
|
|
15
|
+
_authenticated: boolean;
|
|
16
|
+
_pendingMessages: [string, unknown][];
|
|
17
|
+
_wallet: ReturnType<typeof fromSecretKey>;
|
|
18
|
+
send: (event: string, data: unknown) => void;
|
|
19
|
+
constructor(opts: ClientOptions);
|
|
20
|
+
}
|
|
21
|
+
declare class Client extends EventEmitter {
|
|
22
|
+
opts: ClientOptions & {
|
|
23
|
+
wallet: ReturnType<typeof fromSecretKey>;
|
|
24
|
+
did: string;
|
|
25
|
+
};
|
|
26
|
+
_client: Socket;
|
|
27
|
+
_wallet: ReturnType<typeof fromSecretKey>;
|
|
28
|
+
constructor(opts?: ClientOptions);
|
|
29
|
+
connect(): void;
|
|
30
|
+
close(): void;
|
|
31
|
+
broadcast(event: string, data: unknown): void;
|
|
32
|
+
on(name: string, fn: (...args: unknown[]) => void): this;
|
|
33
|
+
off(name: string, fn?: (...args: unknown[]) => void): this;
|
|
34
|
+
/**
|
|
35
|
+
* Get the wallet instance
|
|
36
|
+
* Business can override wallet.signJWT() for remote signing
|
|
37
|
+
* @returns {WalletObject}
|
|
38
|
+
*/
|
|
39
|
+
getWallet(): ReturnType<typeof fromSecretKey>;
|
|
40
|
+
_bindEvent(): void;
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { Client as default };
|
package/lib/constant.cjs
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/constant.ts
|
|
3
|
+
const RESERVED_EVENT_PREFIX = "EVENT_HUB:";
|
|
4
|
+
const EVENT_AUTH = "EVENT_HUB:AUTH";
|
|
5
|
+
const EVENT_AUTH_SUCCESS = "EVENT_HUB:AUTH_SUCCESS";
|
|
6
|
+
const EVENT_AUTH_FAIL = "EVENT_HUB:AUTH_FAIL";
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
exports.EVENT_AUTH = EVENT_AUTH;
|
|
10
|
+
exports.EVENT_AUTH_FAIL = EVENT_AUTH_FAIL;
|
|
11
|
+
exports.EVENT_AUTH_SUCCESS = EVENT_AUTH_SUCCESS;
|
|
12
|
+
exports.RESERVED_EVENT_PREFIX = RESERVED_EVENT_PREFIX;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
//#region src/constant.d.ts
|
|
2
|
+
declare const RESERVED_EVENT_PREFIX = "EVENT_HUB:";
|
|
3
|
+
declare const EVENT_AUTH = "EVENT_HUB:AUTH";
|
|
4
|
+
declare const EVENT_AUTH_SUCCESS = "EVENT_HUB:AUTH_SUCCESS";
|
|
5
|
+
declare const EVENT_AUTH_FAIL = "EVENT_HUB:AUTH_FAIL";
|
|
6
|
+
//#endregion
|
|
7
|
+
export { EVENT_AUTH, EVENT_AUTH_FAIL, EVENT_AUTH_SUCCESS, RESERVED_EVENT_PREFIX };
|
package/lib/index.cjs
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
const require_client = require('./client.cjs');
|
|
3
|
+
const require_single = require('./single.cjs');
|
|
4
|
+
|
|
5
|
+
//#region src/index.ts
|
|
6
|
+
const port = Number(process.env.ABT_NODE_EVENT_PORT);
|
|
7
|
+
const hostname = process.env.ABT_NODE_EVENT_HOSTNAME || "127.0.0.1";
|
|
8
|
+
let did;
|
|
9
|
+
let sk;
|
|
10
|
+
if (process.env.BLOCKLET_APP_SK && process.env.BLOCKLET_APP_ID) {
|
|
11
|
+
sk = process.env.BLOCKLET_APP_SK;
|
|
12
|
+
did = process.env.BLOCKLET_APP_ID;
|
|
13
|
+
} else if (process.env.ABT_NODE_SK && process.env.ABT_NODE_DID) {
|
|
14
|
+
sk = process.env.ABT_NODE_SK;
|
|
15
|
+
did = process.env.ABT_NODE_DID;
|
|
16
|
+
}
|
|
17
|
+
let defaultExport;
|
|
18
|
+
if (port && did && sk) defaultExport = new require_client.default({
|
|
19
|
+
port,
|
|
20
|
+
hostname,
|
|
21
|
+
did,
|
|
22
|
+
sk,
|
|
23
|
+
autoConnect: true
|
|
24
|
+
});
|
|
25
|
+
else defaultExport = new require_single.Client();
|
|
26
|
+
var src_default = defaultExport;
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
exports.Client = require_client.default;
|
|
30
|
+
exports.ClientFallback = require_single.Client;
|
|
31
|
+
exports.default = src_default;
|
package/lib/index.d.cts
ADDED
package/lib/rpc.cjs
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
3
|
+
let axon = require("axon");
|
|
4
|
+
axon = require_rolldown_runtime.__toESM(axon);
|
|
5
|
+
let node_crypto = require("node:crypto");
|
|
6
|
+
let amp_message = require("amp-message");
|
|
7
|
+
amp_message = require_rolldown_runtime.__toESM(amp_message);
|
|
8
|
+
|
|
9
|
+
//#region src/rpc.ts
|
|
10
|
+
var Client = class extends axon.default.Socket {
|
|
11
|
+
/**
|
|
12
|
+
* @param {number} port
|
|
13
|
+
* @param {string} host
|
|
14
|
+
*/
|
|
15
|
+
constructor(port, host = "127.0.0.1") {
|
|
16
|
+
super();
|
|
17
|
+
this.port = port;
|
|
18
|
+
this.host = host;
|
|
19
|
+
this.online = false;
|
|
20
|
+
this.connectPromise = null;
|
|
21
|
+
this.inflight = /* @__PURE__ */ new Map();
|
|
22
|
+
this.on("connect", () => {
|
|
23
|
+
this.online = true;
|
|
24
|
+
});
|
|
25
|
+
this.on("reconnect attempt", () => {
|
|
26
|
+
this.online = false;
|
|
27
|
+
});
|
|
28
|
+
this.on("disconnect", () => {
|
|
29
|
+
this.online = false;
|
|
30
|
+
});
|
|
31
|
+
this.on("error", () => {});
|
|
32
|
+
}
|
|
33
|
+
onmessage() {
|
|
34
|
+
return (buf) => {
|
|
35
|
+
try {
|
|
36
|
+
const [event, data] = new amp_message.default(buf).args;
|
|
37
|
+
if (data && typeof data === "object" && data.reqId) {
|
|
38
|
+
const entry = this.inflight.get(data.reqId);
|
|
39
|
+
if (entry) {
|
|
40
|
+
clearTimeout(entry.to);
|
|
41
|
+
this.inflight.delete(data.reqId);
|
|
42
|
+
if (data.ok === false) entry.reject(new Error(entry.errorPrefix ? `${entry.errorPrefix}: ${data.error}` : data.error || "request failed"));
|
|
43
|
+
else entry.resolve(data.data);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
this.emit(event, data);
|
|
48
|
+
} catch (e) {
|
|
49
|
+
console.error("[axon] decode error", e);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
sendEvent(event, data) {
|
|
54
|
+
const buf = this.pack([event, data]);
|
|
55
|
+
const s = this.socks[0];
|
|
56
|
+
if (s?.writable) s.write(buf);
|
|
57
|
+
else throw new Error("axon socket not writable/connected");
|
|
58
|
+
}
|
|
59
|
+
async ensureOnline() {
|
|
60
|
+
if (!this.port || !this.host) throw new Error("PORT and HOST must be set via constructor: new Client(port, host)");
|
|
61
|
+
if (!this.connectPromise) this.connectPromise = new Promise((resolve, reject) => {
|
|
62
|
+
this.connect(this.port, this.host, (err) => err ? reject(err) : resolve(this));
|
|
63
|
+
});
|
|
64
|
+
await this.connectPromise;
|
|
65
|
+
if (this.online) return this;
|
|
66
|
+
await new Promise((r) => this.once("connect", r));
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 通用 RPC:发送 event,等待响应(默认只按 reqId 匹配)
|
|
71
|
+
* @param {string} event 例如 'pm2/start'
|
|
72
|
+
* @param {object} payload 发送为 { reqId, payload }
|
|
73
|
+
* @param {object} [opts]
|
|
74
|
+
* @param {number} [opts.timeoutMs=120000]
|
|
75
|
+
* @param {string} [opts.respEvent] // 可选:仅用于调试;匹配靠 reqId,不强依赖此项
|
|
76
|
+
* @param {string} [opts.errorPrefix] // 统一错误前缀
|
|
77
|
+
* @returns {Promise<any>}
|
|
78
|
+
*/
|
|
79
|
+
async rpc(event, payload = {}, { timeoutMs = 12e4, respEvent, errorPrefix } = {}) {
|
|
80
|
+
await this.ensureOnline();
|
|
81
|
+
const reqId = (0, node_crypto.randomUUID)();
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
const to = setTimeout(() => {
|
|
84
|
+
this.inflight.delete(reqId);
|
|
85
|
+
reject(/* @__PURE__ */ new Error(`${errorPrefix || "request"} timeout`));
|
|
86
|
+
}, timeoutMs);
|
|
87
|
+
this.inflight.set(reqId, {
|
|
88
|
+
resolve,
|
|
89
|
+
reject,
|
|
90
|
+
to,
|
|
91
|
+
errorPrefix
|
|
92
|
+
});
|
|
93
|
+
this.sendEvent(event, {
|
|
94
|
+
reqId,
|
|
95
|
+
payload
|
|
96
|
+
});
|
|
97
|
+
if (respEvent) {
|
|
98
|
+
const once = (data) => {
|
|
99
|
+
if (!data || data.reqId !== reqId) return;
|
|
100
|
+
this.off(respEvent, once);
|
|
101
|
+
};
|
|
102
|
+
this.on(respEvent, once);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
var rpc_default = Client;
|
|
108
|
+
|
|
109
|
+
//#endregion
|
|
110
|
+
exports.default = rpc_default;
|
package/lib/rpc.d.cts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import axon from "axon";
|
|
2
|
+
|
|
3
|
+
//#region src/rpc.d.ts
|
|
4
|
+
interface InflightEntry {
|
|
5
|
+
resolve: (value: unknown) => void;
|
|
6
|
+
reject: (reason: Error) => void;
|
|
7
|
+
to: ReturnType<typeof setTimeout>;
|
|
8
|
+
errorPrefix?: string;
|
|
9
|
+
}
|
|
10
|
+
interface RpcOptions {
|
|
11
|
+
timeoutMs?: number;
|
|
12
|
+
respEvent?: string;
|
|
13
|
+
errorPrefix?: string;
|
|
14
|
+
}
|
|
15
|
+
interface SocketLike {
|
|
16
|
+
writable: boolean;
|
|
17
|
+
write(buf: Buffer): void;
|
|
18
|
+
}
|
|
19
|
+
declare class Client extends axon.Socket {
|
|
20
|
+
socks: SocketLike[];
|
|
21
|
+
port: number;
|
|
22
|
+
host: string;
|
|
23
|
+
online: boolean;
|
|
24
|
+
connectPromise: Promise<this> | null;
|
|
25
|
+
inflight: Map<string, InflightEntry>;
|
|
26
|
+
/**
|
|
27
|
+
* @param {number} port
|
|
28
|
+
* @param {string} host
|
|
29
|
+
*/
|
|
30
|
+
constructor(port: number, host?: string);
|
|
31
|
+
onmessage(): (buf: Buffer) => void;
|
|
32
|
+
sendEvent(event: string, data: unknown): void;
|
|
33
|
+
ensureOnline(): Promise<this>;
|
|
34
|
+
/**
|
|
35
|
+
* 通用 RPC:发送 event,等待响应(默认只按 reqId 匹配)
|
|
36
|
+
* @param {string} event 例如 'pm2/start'
|
|
37
|
+
* @param {object} payload 发送为 { reqId, payload }
|
|
38
|
+
* @param {object} [opts]
|
|
39
|
+
* @param {number} [opts.timeoutMs=120000]
|
|
40
|
+
* @param {string} [opts.respEvent] // 可选:仅用于调试;匹配靠 reqId,不强依赖此项
|
|
41
|
+
* @param {string} [opts.errorPrefix] // 统一错误前缀
|
|
42
|
+
* @returns {Promise<any>}
|
|
43
|
+
*/
|
|
44
|
+
rpc(event: string, payload?: unknown, {
|
|
45
|
+
timeoutMs,
|
|
46
|
+
respEvent,
|
|
47
|
+
errorPrefix
|
|
48
|
+
}?: RpcOptions): Promise<unknown>;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { Client as default };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
const require_server = require('./server.cjs');
|
|
3
|
+
|
|
4
|
+
//#region src/server-abtnode.ts
|
|
5
|
+
const port = Number(process.env.ABT_NODE_EVENT_PORT);
|
|
6
|
+
const hostname = Number(process.env.ABT_NODE_EVENT_HOSTNAME) || "127.0.0.1";
|
|
7
|
+
const server = new require_server.default();
|
|
8
|
+
server.bind(port, hostname);
|
|
9
|
+
var server_abtnode_default = server;
|
|
10
|
+
|
|
11
|
+
//#endregion
|
|
12
|
+
exports.default = server_abtnode_default;
|
package/lib/server.cjs
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
3
|
+
const require_constant = require('./constant.cjs');
|
|
4
|
+
let axon = require("axon");
|
|
5
|
+
axon = require_rolldown_runtime.__toESM(axon);
|
|
6
|
+
let amp_message = require("amp-message");
|
|
7
|
+
amp_message = require_rolldown_runtime.__toESM(amp_message);
|
|
8
|
+
let _arcblock_jwt = require("@arcblock/jwt");
|
|
9
|
+
_arcblock_jwt = require_rolldown_runtime.__toESM(_arcblock_jwt);
|
|
10
|
+
|
|
11
|
+
//#region src/server.ts
|
|
12
|
+
const getDid = (jwt) => jwt.iss.replace(/^did:abt:/, "");
|
|
13
|
+
function normalizeReq(input) {
|
|
14
|
+
if (input && typeof input === "object" && ("payload" in input || "reqId" in input)) {
|
|
15
|
+
const { reqId, payload } = input;
|
|
16
|
+
return {
|
|
17
|
+
reqId,
|
|
18
|
+
payload
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
reqId: void 0,
|
|
23
|
+
payload: input
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function normalizeRes(result) {
|
|
27
|
+
if (result && typeof result === "object" && ("ok" in result || "data" in result || "error" in result)) return result;
|
|
28
|
+
return {
|
|
29
|
+
ok: true,
|
|
30
|
+
data: result
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
var Server = class extends axon.default.Socket {
|
|
34
|
+
constructor(opts = {}) {
|
|
35
|
+
super();
|
|
36
|
+
this.jwt = opts?.jwt || _arcblock_jwt;
|
|
37
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
38
|
+
this.on("message", async (event, data, sock) => {
|
|
39
|
+
const route = this.handlers.get(event);
|
|
40
|
+
if (route) {
|
|
41
|
+
const { fn, authRequired } = route;
|
|
42
|
+
if (authRequired && !sock.channel) {
|
|
43
|
+
console.error(`unauthenticated socket blocked for event "${event}"`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const { reqId, payload } = normalizeReq(data);
|
|
47
|
+
try {
|
|
48
|
+
const res = normalizeRes(await fn(payload, {
|
|
49
|
+
sock,
|
|
50
|
+
channel: sock.channel,
|
|
51
|
+
event,
|
|
52
|
+
server: this
|
|
53
|
+
}));
|
|
54
|
+
const replyEvent = `${event}:res`;
|
|
55
|
+
if (sock.channel) this.send(replyEvent, {
|
|
56
|
+
reqId,
|
|
57
|
+
...res
|
|
58
|
+
}, sock.channel);
|
|
59
|
+
else {
|
|
60
|
+
const buf = this.pack([replyEvent, {
|
|
61
|
+
reqId,
|
|
62
|
+
...res
|
|
63
|
+
}]);
|
|
64
|
+
if (sock.writable) sock.write(buf);
|
|
65
|
+
}
|
|
66
|
+
} catch (err) {
|
|
67
|
+
const replyEvent = `${event}:res`;
|
|
68
|
+
const payloadErr = {
|
|
69
|
+
reqId,
|
|
70
|
+
ok: false,
|
|
71
|
+
error: err?.message || String(err)
|
|
72
|
+
};
|
|
73
|
+
if (sock.channel) this.send(replyEvent, payloadErr, sock.channel);
|
|
74
|
+
else {
|
|
75
|
+
const buf = this.pack([replyEvent, payloadErr]);
|
|
76
|
+
if (sock.writable) sock.write(buf);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (!sock.channel) {
|
|
82
|
+
console.error("skip message of unauthenticated socket");
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
this.send(event, data, sock.channel);
|
|
86
|
+
});
|
|
87
|
+
this.on("connect", (socket) => {
|
|
88
|
+
console.log("event-hub client connected", socket._peername);
|
|
89
|
+
});
|
|
90
|
+
this.on("reconnect attempt", (socket) => {
|
|
91
|
+
console.log("event-hub client reconnect", socket._peername);
|
|
92
|
+
});
|
|
93
|
+
this.on("disconnect", (socket) => {
|
|
94
|
+
console.log("event-hub client disconnected", socket._peername);
|
|
95
|
+
});
|
|
96
|
+
this.on("drop", (args) => {
|
|
97
|
+
console.log("event-hub server drop message", args);
|
|
98
|
+
});
|
|
99
|
+
this.on("error", (err) => {
|
|
100
|
+
console.log("event-hub server error", err);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
onmessage(sock) {
|
|
104
|
+
return (buf) => {
|
|
105
|
+
const [event, data] = new amp_message.default(buf).args;
|
|
106
|
+
if (event === require_constant.EVENT_AUTH) {
|
|
107
|
+
const { pk, token } = data;
|
|
108
|
+
this.jwt.verify(token, pk).then((valid) => {
|
|
109
|
+
if (!valid) throw new Error("token verify failed");
|
|
110
|
+
sock.channel = getDid(this.jwt.decode(token));
|
|
111
|
+
const successBuf = this.pack([require_constant.EVENT_AUTH_SUCCESS, {}]);
|
|
112
|
+
sock.write(successBuf);
|
|
113
|
+
}).catch((err) => {
|
|
114
|
+
console.error(err);
|
|
115
|
+
const resBuf = this.pack([require_constant.EVENT_AUTH_FAIL, { msg: err.message }]);
|
|
116
|
+
sock.write(resBuf);
|
|
117
|
+
});
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
this.emit("message", event, data, sock);
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
send(event, data, channel) {
|
|
124
|
+
const { socks } = this;
|
|
125
|
+
const buf = this.pack([event, data]);
|
|
126
|
+
for (const sock of socks) if (sock.channel === channel && sock.writable) sock.write(buf);
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* 注册路由
|
|
131
|
+
* @param {string} event
|
|
132
|
+
* @param {(payload:any, ctx:{sock:any, channel?:string, event:string, server:Server})=>any|Promise<any>} handler
|
|
133
|
+
* @param {{authRequired?: boolean}} [opts] - 默认 true;设为 false 则该事件免鉴权
|
|
134
|
+
*/
|
|
135
|
+
register(event, handler, opts = {}) {
|
|
136
|
+
const authRequired = opts.authRequired !== false;
|
|
137
|
+
this.handlers.set(event, {
|
|
138
|
+
fn: handler,
|
|
139
|
+
authRequired
|
|
140
|
+
});
|
|
141
|
+
return this;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
var server_default = Server;
|
|
145
|
+
|
|
146
|
+
//#endregion
|
|
147
|
+
exports.default = server_default;
|
package/lib/server.d.cts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import axon from "axon";
|
|
2
|
+
|
|
3
|
+
//#region src/server.d.ts
|
|
4
|
+
interface JwtLike {
|
|
5
|
+
verify(token: string, pk: string): Promise<boolean>;
|
|
6
|
+
decode(token: string): {
|
|
7
|
+
iss: string;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
interface ServerOptions {
|
|
11
|
+
jwt?: JwtLike;
|
|
12
|
+
}
|
|
13
|
+
interface SocketWithChannel {
|
|
14
|
+
channel?: string;
|
|
15
|
+
writable: boolean;
|
|
16
|
+
write(buf: Buffer): void;
|
|
17
|
+
_peername?: {
|
|
18
|
+
family: string;
|
|
19
|
+
address: string;
|
|
20
|
+
port: number;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
interface RouteHandler {
|
|
24
|
+
fn: (payload: unknown, ctx: {
|
|
25
|
+
sock: SocketWithChannel;
|
|
26
|
+
channel?: string;
|
|
27
|
+
event: string;
|
|
28
|
+
server: Server;
|
|
29
|
+
}) => unknown | Promise<unknown>;
|
|
30
|
+
authRequired: boolean;
|
|
31
|
+
}
|
|
32
|
+
declare class Server extends axon.Socket {
|
|
33
|
+
jwt: JwtLike;
|
|
34
|
+
handlers: Map<string, RouteHandler>;
|
|
35
|
+
socks: SocketWithChannel[];
|
|
36
|
+
constructor(opts?: ServerOptions);
|
|
37
|
+
onmessage(sock: SocketWithChannel): (buf: Buffer) => void;
|
|
38
|
+
send(event: string, data: unknown, channel: string): this;
|
|
39
|
+
/**
|
|
40
|
+
* 注册路由
|
|
41
|
+
* @param {string} event
|
|
42
|
+
* @param {(payload:any, ctx:{sock:any, channel?:string, event:string, server:Server})=>any|Promise<any>} handler
|
|
43
|
+
* @param {{authRequired?: boolean}} [opts] - 默认 true;设为 false 则该事件免鉴权
|
|
44
|
+
*/
|
|
45
|
+
register(event: string, handler: (payload: unknown, ctx: {
|
|
46
|
+
sock: SocketWithChannel;
|
|
47
|
+
channel?: string;
|
|
48
|
+
event: string;
|
|
49
|
+
server: Server;
|
|
50
|
+
}) => unknown | Promise<unknown>, opts?: {
|
|
51
|
+
authRequired?: boolean;
|
|
52
|
+
}): this;
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { Server as default };
|
package/lib/single.cjs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
3
|
+
let node_events = require("node:events");
|
|
4
|
+
|
|
5
|
+
//#region src/single.ts
|
|
6
|
+
var Client = class extends node_events.EventEmitter {
|
|
7
|
+
broadcast(...args) {
|
|
8
|
+
return this.emit(...args);
|
|
9
|
+
}
|
|
10
|
+
off(event) {
|
|
11
|
+
this.removeAllListeners(event);
|
|
12
|
+
return this;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var single_default = new Client();
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
exports.Client = Client;
|
|
19
|
+
exports.default = single_default;
|
package/lib/single.d.cts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
|
|
3
|
+
//#region src/single.d.ts
|
|
4
|
+
declare class Client extends EventEmitter {
|
|
5
|
+
broadcast(...args: Parameters<EventEmitter['emit']>): boolean;
|
|
6
|
+
off(event: string | symbol): this;
|
|
7
|
+
}
|
|
8
|
+
declare const _default: Client;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { Client, _default as default };
|