@rookdaemon/agora 0.1.2 → 0.1.5
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/README.md +265 -1
- package/dist/cli.js +481 -36
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +44 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +74 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/message/envelope.d.ts +1 -1
- package/dist/message/envelope.d.ts.map +1 -1
- package/dist/message/envelope.js.map +1 -1
- package/dist/message/types/paper-discovery.d.ts +28 -0
- package/dist/message/types/paper-discovery.d.ts.map +1 -0
- package/dist/message/types/paper-discovery.js +2 -0
- package/dist/message/types/paper-discovery.js.map +1 -0
- package/dist/peer/client.d.ts +50 -0
- package/dist/peer/client.d.ts.map +1 -0
- package/dist/peer/client.js +138 -0
- package/dist/peer/client.js.map +1 -0
- package/dist/peer/manager.d.ts +65 -0
- package/dist/peer/manager.d.ts.map +1 -0
- package/dist/peer/manager.js +153 -0
- package/dist/peer/manager.js.map +1 -0
- package/dist/peer/server.d.ts +65 -0
- package/dist/peer/server.d.ts.map +1 -0
- package/dist/peer/server.js +154 -0
- package/dist/peer/server.js.map +1 -0
- package/dist/relay/client.d.ts +112 -0
- package/dist/relay/client.d.ts.map +1 -0
- package/dist/relay/client.js +281 -0
- package/dist/relay/client.js.map +1 -0
- package/dist/relay/server.d.ts +60 -0
- package/dist/relay/server.d.ts.map +1 -0
- package/dist/relay/server.js +266 -0
- package/dist/relay/server.js.map +1 -0
- package/dist/relay/types.d.ts +35 -0
- package/dist/relay/types.d.ts.map +1 -0
- package/dist/relay/types.js +2 -0
- package/dist/relay/types.js.map +1 -0
- package/dist/transport/peer-config.d.ts +3 -2
- package/dist/transport/peer-config.d.ts.map +1 -1
- package/dist/transport/peer-config.js.map +1 -1
- package/dist/transport/relay.d.ts +23 -0
- package/dist/transport/relay.d.ts.map +1 -0
- package/dist/transport/relay.js +85 -0
- package/dist/transport/relay.js.map +1 -0
- package/package.json +1 -38
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { PeerServer } from './server.js';
|
|
3
|
+
import { PeerClient } from './client.js';
|
|
4
|
+
/**
|
|
5
|
+
* Manages both server (incoming connections) and client (outbound connections)
|
|
6
|
+
*/
|
|
7
|
+
export class PeerManager extends EventEmitter {
|
|
8
|
+
server = null;
|
|
9
|
+
clients = new Map();
|
|
10
|
+
identity;
|
|
11
|
+
announcePayload;
|
|
12
|
+
constructor(identity, announcePayload) {
|
|
13
|
+
super();
|
|
14
|
+
this.identity = identity;
|
|
15
|
+
this.announcePayload = announcePayload;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Start listening for incoming peer connections
|
|
19
|
+
* @param port - Port to listen on
|
|
20
|
+
*/
|
|
21
|
+
async start(port) {
|
|
22
|
+
if (this.server) {
|
|
23
|
+
throw new Error('Server already started');
|
|
24
|
+
}
|
|
25
|
+
this.server = new PeerServer(this.identity, this.announcePayload);
|
|
26
|
+
// Forward server events
|
|
27
|
+
this.server.on('peer-connected', (publicKey, _peer) => {
|
|
28
|
+
this.emit('peer-connected', publicKey);
|
|
29
|
+
});
|
|
30
|
+
this.server.on('peer-disconnected', (publicKey) => {
|
|
31
|
+
this.emit('peer-disconnected', publicKey);
|
|
32
|
+
});
|
|
33
|
+
this.server.on('message-received', (envelope, fromPublicKey) => {
|
|
34
|
+
this.emit('message-received', envelope, fromPublicKey);
|
|
35
|
+
});
|
|
36
|
+
this.server.on('error', (error) => {
|
|
37
|
+
this.emit('error', error);
|
|
38
|
+
});
|
|
39
|
+
await this.server.start(port);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Stop the server and disconnect all clients
|
|
43
|
+
*/
|
|
44
|
+
async stop() {
|
|
45
|
+
// Disconnect all clients
|
|
46
|
+
for (const client of this.clients.values()) {
|
|
47
|
+
client.disconnect();
|
|
48
|
+
}
|
|
49
|
+
this.clients.clear();
|
|
50
|
+
// Stop server
|
|
51
|
+
if (this.server) {
|
|
52
|
+
await this.server.stop();
|
|
53
|
+
this.server = null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Connect to a peer at the given URL
|
|
58
|
+
* @param url - WebSocket URL of the peer (e.g., ws://localhost:8080)
|
|
59
|
+
*/
|
|
60
|
+
connect(url) {
|
|
61
|
+
// Check if already connected to this URL
|
|
62
|
+
if (this.clients.has(url)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const client = new PeerClient(url, this.identity, this.announcePayload);
|
|
66
|
+
// Forward client events
|
|
67
|
+
client.on('connected', (publicKey) => {
|
|
68
|
+
this.emit('peer-connected', publicKey);
|
|
69
|
+
});
|
|
70
|
+
client.on('disconnected', () => {
|
|
71
|
+
const publicKey = client.getPeerPublicKey();
|
|
72
|
+
if (publicKey) {
|
|
73
|
+
this.emit('peer-disconnected', publicKey);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
client.on('message-received', (envelope) => {
|
|
77
|
+
const publicKey = client.getPeerPublicKey();
|
|
78
|
+
if (publicKey) {
|
|
79
|
+
this.emit('message-received', envelope, publicKey);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
client.on('error', (error) => {
|
|
83
|
+
this.emit('error', error);
|
|
84
|
+
});
|
|
85
|
+
this.clients.set(url, client);
|
|
86
|
+
client.connect();
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Broadcast a message to all connected peers (both incoming and outgoing)
|
|
90
|
+
* @param envelope - The envelope to broadcast
|
|
91
|
+
*/
|
|
92
|
+
broadcast(envelope) {
|
|
93
|
+
// Broadcast to server peers
|
|
94
|
+
if (this.server) {
|
|
95
|
+
this.server.broadcast(envelope);
|
|
96
|
+
}
|
|
97
|
+
// Broadcast to client peers
|
|
98
|
+
for (const client of this.clients.values()) {
|
|
99
|
+
if (client.isConnected()) {
|
|
100
|
+
client.send(envelope);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get list of all connected peers with their public keys
|
|
106
|
+
* @returns Array of peer information
|
|
107
|
+
*/
|
|
108
|
+
getPeers() {
|
|
109
|
+
const peers = [];
|
|
110
|
+
// Get server peers
|
|
111
|
+
if (this.server) {
|
|
112
|
+
for (const [publicKey, peer] of this.server.getPeers()) {
|
|
113
|
+
peers.push({
|
|
114
|
+
publicKey,
|
|
115
|
+
metadata: peer.metadata,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Get client peers
|
|
120
|
+
for (const client of this.clients.values()) {
|
|
121
|
+
if (client.isConnected()) {
|
|
122
|
+
const publicKey = client.getPeerPublicKey();
|
|
123
|
+
if (publicKey) {
|
|
124
|
+
// Avoid duplicates (same peer might be connected via both server and client)
|
|
125
|
+
if (!peers.find(p => p.publicKey === publicKey)) {
|
|
126
|
+
peers.push({ publicKey });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return peers;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Send a message to a specific peer by public key
|
|
135
|
+
* @param publicKey - The peer's public key
|
|
136
|
+
* @param envelope - The envelope to send
|
|
137
|
+
* @returns true if sent successfully, false otherwise
|
|
138
|
+
*/
|
|
139
|
+
send(publicKey, envelope) {
|
|
140
|
+
// Try to send via server
|
|
141
|
+
if (this.server && this.server.send(publicKey, envelope)) {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
// Try to send via clients
|
|
145
|
+
for (const client of this.clients.values()) {
|
|
146
|
+
if (client.getPeerPublicKey() === publicKey && client.isConnected()) {
|
|
147
|
+
return client.send(envelope);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/peer/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { WebSocket } from 'ws';
|
|
3
|
+
import type { KeyPair } from '../identity/keypair.js';
|
|
4
|
+
import type { Envelope } from '../message/envelope.js';
|
|
5
|
+
import type { AnnouncePayload } from '../registry/messages.js';
|
|
6
|
+
/**
|
|
7
|
+
* Represents a connected peer
|
|
8
|
+
*/
|
|
9
|
+
export interface ConnectedPeer {
|
|
10
|
+
/** Peer's public key */
|
|
11
|
+
publicKey: string;
|
|
12
|
+
/** WebSocket connection */
|
|
13
|
+
socket: WebSocket;
|
|
14
|
+
/** Whether the peer has been announced */
|
|
15
|
+
announced: boolean;
|
|
16
|
+
/** Peer metadata from announce message */
|
|
17
|
+
metadata?: {
|
|
18
|
+
name?: string;
|
|
19
|
+
version?: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Events emitted by PeerServer
|
|
24
|
+
*/
|
|
25
|
+
export interface PeerServerEvents {
|
|
26
|
+
'peer-connected': (publicKey: string, peer: ConnectedPeer) => void;
|
|
27
|
+
'peer-disconnected': (publicKey: string) => void;
|
|
28
|
+
'message-received': (envelope: Envelope, fromPublicKey: string) => void;
|
|
29
|
+
'error': (error: Error) => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* WebSocket server for accepting peer connections
|
|
33
|
+
*/
|
|
34
|
+
export declare class PeerServer extends EventEmitter {
|
|
35
|
+
private wss;
|
|
36
|
+
private peers;
|
|
37
|
+
private identity;
|
|
38
|
+
private announcePayload;
|
|
39
|
+
constructor(identity: KeyPair, announcePayload: AnnouncePayload);
|
|
40
|
+
/**
|
|
41
|
+
* Start the WebSocket server
|
|
42
|
+
*/
|
|
43
|
+
start(port: number): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Stop the WebSocket server
|
|
46
|
+
*/
|
|
47
|
+
stop(): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Get all connected peers
|
|
50
|
+
*/
|
|
51
|
+
getPeers(): Map<string, ConnectedPeer>;
|
|
52
|
+
/**
|
|
53
|
+
* Send a message to a specific peer
|
|
54
|
+
*/
|
|
55
|
+
send(publicKey: string, envelope: Envelope): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Broadcast a message to all connected peers
|
|
58
|
+
*/
|
|
59
|
+
broadcast(envelope: Envelope): void;
|
|
60
|
+
/**
|
|
61
|
+
* Handle incoming connection
|
|
62
|
+
*/
|
|
63
|
+
private handleConnection;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/peer/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAmB,SAAS,EAAE,MAAM,IAAI,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,MAAM,EAAE,SAAS,CAAC;IAClB,0CAA0C;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IACnE,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IACxE,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACjC;AAED;;GAEG;AACH,qBAAa,UAAW,SAAQ,YAAY;IAC1C,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,eAAe,CAAkB;gBAE7B,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,eAAe;IAM/D;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBlC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB3B;;OAEG;IACH,QAAQ,IAAI,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC;IAItC;;OAEG;IACH,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO;IAepD;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAQnC;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAkEzB"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
3
|
+
import { createEnvelope, verifyEnvelope } from '../message/envelope.js';
|
|
4
|
+
/**
|
|
5
|
+
* WebSocket server for accepting peer connections
|
|
6
|
+
*/
|
|
7
|
+
export class PeerServer extends EventEmitter {
|
|
8
|
+
wss = null;
|
|
9
|
+
peers = new Map();
|
|
10
|
+
identity;
|
|
11
|
+
announcePayload;
|
|
12
|
+
constructor(identity, announcePayload) {
|
|
13
|
+
super();
|
|
14
|
+
this.identity = identity;
|
|
15
|
+
this.announcePayload = announcePayload;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Start the WebSocket server
|
|
19
|
+
*/
|
|
20
|
+
start(port) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
try {
|
|
23
|
+
this.wss = new WebSocketServer({ port });
|
|
24
|
+
this.wss.on('error', (error) => {
|
|
25
|
+
this.emit('error', error);
|
|
26
|
+
reject(error);
|
|
27
|
+
});
|
|
28
|
+
this.wss.on('listening', () => {
|
|
29
|
+
resolve();
|
|
30
|
+
});
|
|
31
|
+
this.wss.on('connection', (socket) => {
|
|
32
|
+
this.handleConnection(socket);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
reject(error);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Stop the WebSocket server
|
|
42
|
+
*/
|
|
43
|
+
async stop() {
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
if (!this.wss) {
|
|
46
|
+
resolve();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// Close all peer connections
|
|
50
|
+
for (const peer of this.peers.values()) {
|
|
51
|
+
peer.socket.close();
|
|
52
|
+
}
|
|
53
|
+
this.peers.clear();
|
|
54
|
+
this.wss.close((err) => {
|
|
55
|
+
if (err) {
|
|
56
|
+
reject(err);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
this.wss = null;
|
|
60
|
+
resolve();
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get all connected peers
|
|
67
|
+
*/
|
|
68
|
+
getPeers() {
|
|
69
|
+
return new Map(this.peers);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Send a message to a specific peer
|
|
73
|
+
*/
|
|
74
|
+
send(publicKey, envelope) {
|
|
75
|
+
const peer = this.peers.get(publicKey);
|
|
76
|
+
if (!peer || peer.socket.readyState !== WebSocket.OPEN) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
peer.socket.send(JSON.stringify(envelope));
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
this.emit('error', error);
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Broadcast a message to all connected peers
|
|
90
|
+
*/
|
|
91
|
+
broadcast(envelope) {
|
|
92
|
+
for (const [publicKey, peer] of this.peers) {
|
|
93
|
+
if (peer.socket.readyState === WebSocket.OPEN) {
|
|
94
|
+
this.send(publicKey, envelope);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Handle incoming connection
|
|
100
|
+
*/
|
|
101
|
+
handleConnection(socket) {
|
|
102
|
+
let peerPublicKey = null;
|
|
103
|
+
// Send announce message immediately
|
|
104
|
+
const announceEnvelope = createEnvelope('announce', this.identity.publicKey, this.identity.privateKey, this.announcePayload);
|
|
105
|
+
socket.send(JSON.stringify(announceEnvelope));
|
|
106
|
+
socket.on('message', (data) => {
|
|
107
|
+
try {
|
|
108
|
+
const envelope = JSON.parse(data.toString());
|
|
109
|
+
// Verify envelope signature
|
|
110
|
+
const verification = verifyEnvelope(envelope);
|
|
111
|
+
if (!verification.valid) {
|
|
112
|
+
// Drop invalid messages
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
// First message should be an announce
|
|
116
|
+
if (!peerPublicKey) {
|
|
117
|
+
if (envelope.type === 'announce') {
|
|
118
|
+
peerPublicKey = envelope.sender;
|
|
119
|
+
const payload = envelope.payload;
|
|
120
|
+
const peer = {
|
|
121
|
+
publicKey: peerPublicKey,
|
|
122
|
+
socket,
|
|
123
|
+
announced: true,
|
|
124
|
+
metadata: payload.metadata,
|
|
125
|
+
};
|
|
126
|
+
this.peers.set(peerPublicKey, peer);
|
|
127
|
+
this.emit('peer-connected', peerPublicKey, peer);
|
|
128
|
+
}
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
// Verify the message is from the announced peer
|
|
132
|
+
if (envelope.sender !== peerPublicKey) {
|
|
133
|
+
// Drop messages from wrong sender
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
// Emit message-received event
|
|
137
|
+
this.emit('message-received', envelope, peerPublicKey);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// Invalid JSON or other parsing errors - drop the message
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
socket.on('close', () => {
|
|
144
|
+
if (peerPublicKey) {
|
|
145
|
+
this.peers.delete(peerPublicKey);
|
|
146
|
+
this.emit('peer-disconnected', peerPublicKey);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
socket.on('error', (error) => {
|
|
150
|
+
this.emit('error', error);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/peer/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { type Envelope } from '../message/envelope.js';
|
|
3
|
+
import type { RelayPeer } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Configuration for RelayClient
|
|
6
|
+
*/
|
|
7
|
+
export interface RelayClientConfig {
|
|
8
|
+
/** WebSocket URL of the relay server */
|
|
9
|
+
relayUrl: string;
|
|
10
|
+
/** Agent's public key */
|
|
11
|
+
publicKey: string;
|
|
12
|
+
/** Agent's private key (for signing) */
|
|
13
|
+
privateKey: string;
|
|
14
|
+
/** Optional name for this agent */
|
|
15
|
+
name?: string;
|
|
16
|
+
/** Keepalive ping interval in milliseconds (default: 30000) */
|
|
17
|
+
pingInterval?: number;
|
|
18
|
+
/** Maximum reconnection delay in milliseconds (default: 60000) */
|
|
19
|
+
maxReconnectDelay?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Events emitted by RelayClient
|
|
23
|
+
*/
|
|
24
|
+
export interface RelayClientEvents {
|
|
25
|
+
/** Emitted when successfully connected and registered */
|
|
26
|
+
'connected': () => void;
|
|
27
|
+
/** Emitted when disconnected from relay */
|
|
28
|
+
'disconnected': () => void;
|
|
29
|
+
/** Emitted when a verified message is received */
|
|
30
|
+
'message': (envelope: Envelope, from: string, fromName?: string) => void;
|
|
31
|
+
/** Emitted when a peer comes online */
|
|
32
|
+
'peer_online': (peer: RelayPeer) => void;
|
|
33
|
+
/** Emitted when a peer goes offline */
|
|
34
|
+
'peer_offline': (peer: RelayPeer) => void;
|
|
35
|
+
/** Emitted on errors */
|
|
36
|
+
'error': (error: Error) => void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Persistent WebSocket client for the Agora relay server.
|
|
40
|
+
* Maintains a long-lived connection, handles reconnection, and routes messages.
|
|
41
|
+
*/
|
|
42
|
+
export declare class RelayClient extends EventEmitter {
|
|
43
|
+
private ws;
|
|
44
|
+
private config;
|
|
45
|
+
private reconnectAttempts;
|
|
46
|
+
private reconnectTimeout;
|
|
47
|
+
private pingInterval;
|
|
48
|
+
private isConnected;
|
|
49
|
+
private isRegistered;
|
|
50
|
+
private shouldReconnect;
|
|
51
|
+
private onlinePeers;
|
|
52
|
+
constructor(config: RelayClientConfig);
|
|
53
|
+
/**
|
|
54
|
+
* Connect to the relay server
|
|
55
|
+
*/
|
|
56
|
+
connect(): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Disconnect from the relay server
|
|
59
|
+
*/
|
|
60
|
+
disconnect(): void;
|
|
61
|
+
/**
|
|
62
|
+
* Check if currently connected and registered
|
|
63
|
+
*/
|
|
64
|
+
connected(): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Send a message to a specific peer
|
|
67
|
+
*/
|
|
68
|
+
send(to: string, envelope: Envelope): Promise<{
|
|
69
|
+
ok: boolean;
|
|
70
|
+
error?: string;
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* Broadcast a message to all connected peers
|
|
74
|
+
*/
|
|
75
|
+
broadcast(envelope: Envelope): Promise<{
|
|
76
|
+
ok: boolean;
|
|
77
|
+
error?: string;
|
|
78
|
+
}>;
|
|
79
|
+
/**
|
|
80
|
+
* Get list of currently online peers
|
|
81
|
+
*/
|
|
82
|
+
getOnlinePeers(): RelayPeer[];
|
|
83
|
+
/**
|
|
84
|
+
* Check if a specific peer is online
|
|
85
|
+
*/
|
|
86
|
+
isPeerOnline(publicKey: string): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Internal: Perform connection
|
|
89
|
+
*/
|
|
90
|
+
private doConnect;
|
|
91
|
+
/**
|
|
92
|
+
* Handle incoming message from relay
|
|
93
|
+
*/
|
|
94
|
+
private handleMessage;
|
|
95
|
+
/**
|
|
96
|
+
* Schedule reconnection with exponential backoff
|
|
97
|
+
*/
|
|
98
|
+
private scheduleReconnect;
|
|
99
|
+
/**
|
|
100
|
+
* Start periodic ping messages
|
|
101
|
+
*/
|
|
102
|
+
private startPingInterval;
|
|
103
|
+
/**
|
|
104
|
+
* Stop ping interval
|
|
105
|
+
*/
|
|
106
|
+
private stopPingInterval;
|
|
107
|
+
/**
|
|
108
|
+
* Cleanup resources
|
|
109
|
+
*/
|
|
110
|
+
private cleanup;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/relay/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,KAAK,EAA0C,SAAS,EAAE,MAAM,YAAY,CAAC;AAEpF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,yDAAyD;IACzD,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,2CAA2C;IAC3C,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,kDAAkD;IAClD,SAAS,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,uCAAuC;IACvC,aAAa,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IACzC,uCAAuC;IACvC,cAAc,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IAC1C,wBAAwB;IACxB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACjC;AAED;;;GAGG;AACH,qBAAa,WAAY,SAAQ,YAAY;IAC3C,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,gBAAgB,CAA+B;IACvD,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,WAAW,CAAgC;gBAEvC,MAAM,EAAE,iBAAiB;IASrC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B;;OAEG;IACH,UAAU,IAAI,IAAI;IASlB;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAmBpF;;OAEG;IACG,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAkB7E;;OAEG;IACH,cAAc,IAAI,SAAS,EAAE;IAI7B;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAIxC;;OAEG;YACW,SAAS;IAoEvB;;OAEG;IACH,OAAO,CAAC,aAAa;IAoErB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAuBzB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAUzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;OAEG;IACH,OAAO,CAAC,OAAO;CAQhB"}
|