@hla4ts/transport 0.1.0 → 0.1.1
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 +386 -386
- package/package.json +2 -2
- package/src/constants.ts +57 -57
- package/src/frame-decoder.ts +136 -136
- package/src/index.ts +82 -82
- package/src/message-header.ts +141 -141
- package/src/message-type.ts +62 -62
- package/src/tcp-transport.ts +154 -154
- package/src/tls-transport.ts +193 -193
- package/src/transport.ts +99 -99
package/src/tls-transport.ts
CHANGED
|
@@ -1,193 +1,193 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TLS Transport Implementation
|
|
3
|
-
*
|
|
4
|
-
* Provides a TLS-encrypted TCP connection for the Federate Protocol.
|
|
5
|
-
* Uses Bun's built-in TLS support.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { connect, type Socket, type SocketHandler, type TLSOptions } from "bun";
|
|
9
|
-
import { FrameDecoder } from "./frame-decoder.ts";
|
|
10
|
-
import { Ports, Protocol } from "./constants.ts";
|
|
11
|
-
import type {
|
|
12
|
-
Transport,
|
|
13
|
-
TransportEvents,
|
|
14
|
-
TlsOptions,
|
|
15
|
-
ReceivedMessage,
|
|
16
|
-
} from "./transport.ts";
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* TLS Transport for Federate Protocol
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```ts
|
|
23
|
-
* const transport = new TlsTransport({
|
|
24
|
-
* host: 'localhost',
|
|
25
|
-
* port: 15165,
|
|
26
|
-
* });
|
|
27
|
-
*
|
|
28
|
-
* transport.setEventHandlers({
|
|
29
|
-
* onMessage: (msg) => console.log('Received:', msg.header.messageType),
|
|
30
|
-
* onClose: () => console.log('Disconnected'),
|
|
31
|
-
* onError: (err) => console.error('Error:', err),
|
|
32
|
-
* });
|
|
33
|
-
*
|
|
34
|
-
* await transport.connect();
|
|
35
|
-
* await transport.send(someData);
|
|
36
|
-
* await transport.disconnect();
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
39
|
-
export class TlsTransport implements Transport {
|
|
40
|
-
private readonly options: Required<
|
|
41
|
-
Pick<TlsOptions, "host" | "port" | "connectionTimeout" | "noDelay">
|
|
42
|
-
> &
|
|
43
|
-
Omit<TlsOptions, "host" | "port" | "connectionTimeout" | "noDelay">;
|
|
44
|
-
|
|
45
|
-
private socket: Socket<{ decoder: FrameDecoder }> | null = null;
|
|
46
|
-
private events: TransportEvents = {};
|
|
47
|
-
private decoder: FrameDecoder;
|
|
48
|
-
private connected = false;
|
|
49
|
-
|
|
50
|
-
constructor(options: TlsOptions) {
|
|
51
|
-
this.options = {
|
|
52
|
-
host: options.host,
|
|
53
|
-
port: options.port ?? Ports.TLS,
|
|
54
|
-
connectionTimeout: options.connectionTimeout ?? 10000,
|
|
55
|
-
noDelay: options.noDelay ?? true,
|
|
56
|
-
ca: options.ca,
|
|
57
|
-
cert: options.cert,
|
|
58
|
-
key: options.key,
|
|
59
|
-
rejectUnauthorized: options.rejectUnauthorized ?? true,
|
|
60
|
-
serverName: options.serverName,
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
this.decoder = new FrameDecoder();
|
|
64
|
-
this.decoder.onMessage = (msg) => this.handleMessage(msg);
|
|
65
|
-
this.decoder.onError = (err) => this.handleError(err);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async connect(): Promise<void> {
|
|
69
|
-
if (this.socket) {
|
|
70
|
-
throw new Error("Already connected");
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const decoder = this.decoder;
|
|
74
|
-
const transport = this;
|
|
75
|
-
|
|
76
|
-
return new Promise((resolve, reject) => {
|
|
77
|
-
const timeoutId = setTimeout(() => {
|
|
78
|
-
reject(new Error(`Connection timeout after ${this.options.connectionTimeout}ms`));
|
|
79
|
-
}, this.options.connectionTimeout);
|
|
80
|
-
|
|
81
|
-
const socketHandler: SocketHandler<{ decoder: FrameDecoder }> = {
|
|
82
|
-
data(_socket, data) {
|
|
83
|
-
decoder.push(new Uint8Array(data));
|
|
84
|
-
},
|
|
85
|
-
open(_socket) {
|
|
86
|
-
clearTimeout(timeoutId);
|
|
87
|
-
transport.connected = true;
|
|
88
|
-
resolve();
|
|
89
|
-
},
|
|
90
|
-
close(_socket) {
|
|
91
|
-
transport.connected = false;
|
|
92
|
-
transport.socket = null;
|
|
93
|
-
transport.events.onClose?.(false);
|
|
94
|
-
},
|
|
95
|
-
error(_socket, error) {
|
|
96
|
-
clearTimeout(timeoutId);
|
|
97
|
-
transport.connected = false;
|
|
98
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
99
|
-
transport.events.onError?.(err);
|
|
100
|
-
reject(err);
|
|
101
|
-
},
|
|
102
|
-
connectError(_socket, error) {
|
|
103
|
-
clearTimeout(timeoutId);
|
|
104
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
105
|
-
reject(err);
|
|
106
|
-
},
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// Build TLS options
|
|
110
|
-
const tlsConfig: TLSOptions = {
|
|
111
|
-
rejectUnauthorized: this.options.rejectUnauthorized,
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
// Add optional TLS settings
|
|
115
|
-
if (this.options.ca) {
|
|
116
|
-
tlsConfig.ca = Bun.file(this.options.ca);
|
|
117
|
-
}
|
|
118
|
-
if (this.options.cert) {
|
|
119
|
-
tlsConfig.cert = Bun.file(this.options.cert);
|
|
120
|
-
}
|
|
121
|
-
if (this.options.key) {
|
|
122
|
-
tlsConfig.key = Bun.file(this.options.key);
|
|
123
|
-
}
|
|
124
|
-
if (this.options.serverName) {
|
|
125
|
-
tlsConfig.serverName = this.options.serverName;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
connect({
|
|
129
|
-
hostname: this.options.host,
|
|
130
|
-
port: this.options.port,
|
|
131
|
-
socket: socketHandler,
|
|
132
|
-
data: { decoder },
|
|
133
|
-
tls: tlsConfig,
|
|
134
|
-
})
|
|
135
|
-
.then((socket) => {
|
|
136
|
-
this.socket = socket;
|
|
137
|
-
})
|
|
138
|
-
.catch(reject);
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async disconnect(): Promise<void> {
|
|
143
|
-
if (this.socket) {
|
|
144
|
-
this.socket.end();
|
|
145
|
-
this.socket = null;
|
|
146
|
-
this.connected = false;
|
|
147
|
-
this.decoder.reset();
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
isConnected(): boolean {
|
|
152
|
-
return this.connected && this.socket !== null;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
async send(data: Uint8Array): Promise<void> {
|
|
156
|
-
if (!this.socket || !this.connected) {
|
|
157
|
-
throw new Error("Not connected");
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const written = this.socket.write(data);
|
|
161
|
-
if (written < data.length) {
|
|
162
|
-
// Bun's socket.write returns the number of bytes written
|
|
163
|
-
// If not all bytes were written, we need to wait for drain
|
|
164
|
-
// For simplicity, we'll throw an error here
|
|
165
|
-
// In production, you'd want to buffer and retry
|
|
166
|
-
throw new Error(
|
|
167
|
-
`Failed to write all data: wrote ${written} of ${data.length} bytes`
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
setEventHandlers(handlers: TransportEvents): void {
|
|
173
|
-
this.events = handlers;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
getProtocolName(): string {
|
|
177
|
-
return Protocol.TLS;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
getRemoteAddress(): string | null {
|
|
181
|
-
return this.socket
|
|
182
|
-
? `${this.options.host}:${this.options.port}`
|
|
183
|
-
: null;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
private handleMessage(message: ReceivedMessage): void {
|
|
187
|
-
this.events.onMessage?.(message);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
private handleError(error: Error): void {
|
|
191
|
-
this.events.onError?.(error);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* TLS Transport Implementation
|
|
3
|
+
*
|
|
4
|
+
* Provides a TLS-encrypted TCP connection for the Federate Protocol.
|
|
5
|
+
* Uses Bun's built-in TLS support.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { connect, type Socket, type SocketHandler, type TLSOptions } from "bun";
|
|
9
|
+
import { FrameDecoder } from "./frame-decoder.ts";
|
|
10
|
+
import { Ports, Protocol } from "./constants.ts";
|
|
11
|
+
import type {
|
|
12
|
+
Transport,
|
|
13
|
+
TransportEvents,
|
|
14
|
+
TlsOptions,
|
|
15
|
+
ReceivedMessage,
|
|
16
|
+
} from "./transport.ts";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* TLS Transport for Federate Protocol
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const transport = new TlsTransport({
|
|
24
|
+
* host: 'localhost',
|
|
25
|
+
* port: 15165,
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* transport.setEventHandlers({
|
|
29
|
+
* onMessage: (msg) => console.log('Received:', msg.header.messageType),
|
|
30
|
+
* onClose: () => console.log('Disconnected'),
|
|
31
|
+
* onError: (err) => console.error('Error:', err),
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* await transport.connect();
|
|
35
|
+
* await transport.send(someData);
|
|
36
|
+
* await transport.disconnect();
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export class TlsTransport implements Transport {
|
|
40
|
+
private readonly options: Required<
|
|
41
|
+
Pick<TlsOptions, "host" | "port" | "connectionTimeout" | "noDelay">
|
|
42
|
+
> &
|
|
43
|
+
Omit<TlsOptions, "host" | "port" | "connectionTimeout" | "noDelay">;
|
|
44
|
+
|
|
45
|
+
private socket: Socket<{ decoder: FrameDecoder }> | null = null;
|
|
46
|
+
private events: TransportEvents = {};
|
|
47
|
+
private decoder: FrameDecoder;
|
|
48
|
+
private connected = false;
|
|
49
|
+
|
|
50
|
+
constructor(options: TlsOptions) {
|
|
51
|
+
this.options = {
|
|
52
|
+
host: options.host,
|
|
53
|
+
port: options.port ?? Ports.TLS,
|
|
54
|
+
connectionTimeout: options.connectionTimeout ?? 10000,
|
|
55
|
+
noDelay: options.noDelay ?? true,
|
|
56
|
+
ca: options.ca,
|
|
57
|
+
cert: options.cert,
|
|
58
|
+
key: options.key,
|
|
59
|
+
rejectUnauthorized: options.rejectUnauthorized ?? true,
|
|
60
|
+
serverName: options.serverName,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
this.decoder = new FrameDecoder();
|
|
64
|
+
this.decoder.onMessage = (msg) => this.handleMessage(msg);
|
|
65
|
+
this.decoder.onError = (err) => this.handleError(err);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async connect(): Promise<void> {
|
|
69
|
+
if (this.socket) {
|
|
70
|
+
throw new Error("Already connected");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const decoder = this.decoder;
|
|
74
|
+
const transport = this;
|
|
75
|
+
|
|
76
|
+
return new Promise((resolve, reject) => {
|
|
77
|
+
const timeoutId = setTimeout(() => {
|
|
78
|
+
reject(new Error(`Connection timeout after ${this.options.connectionTimeout}ms`));
|
|
79
|
+
}, this.options.connectionTimeout);
|
|
80
|
+
|
|
81
|
+
const socketHandler: SocketHandler<{ decoder: FrameDecoder }> = {
|
|
82
|
+
data(_socket, data) {
|
|
83
|
+
decoder.push(new Uint8Array(data));
|
|
84
|
+
},
|
|
85
|
+
open(_socket) {
|
|
86
|
+
clearTimeout(timeoutId);
|
|
87
|
+
transport.connected = true;
|
|
88
|
+
resolve();
|
|
89
|
+
},
|
|
90
|
+
close(_socket) {
|
|
91
|
+
transport.connected = false;
|
|
92
|
+
transport.socket = null;
|
|
93
|
+
transport.events.onClose?.(false);
|
|
94
|
+
},
|
|
95
|
+
error(_socket, error) {
|
|
96
|
+
clearTimeout(timeoutId);
|
|
97
|
+
transport.connected = false;
|
|
98
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
99
|
+
transport.events.onError?.(err);
|
|
100
|
+
reject(err);
|
|
101
|
+
},
|
|
102
|
+
connectError(_socket, error) {
|
|
103
|
+
clearTimeout(timeoutId);
|
|
104
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
105
|
+
reject(err);
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// Build TLS options
|
|
110
|
+
const tlsConfig: TLSOptions = {
|
|
111
|
+
rejectUnauthorized: this.options.rejectUnauthorized,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Add optional TLS settings
|
|
115
|
+
if (this.options.ca) {
|
|
116
|
+
tlsConfig.ca = Bun.file(this.options.ca);
|
|
117
|
+
}
|
|
118
|
+
if (this.options.cert) {
|
|
119
|
+
tlsConfig.cert = Bun.file(this.options.cert);
|
|
120
|
+
}
|
|
121
|
+
if (this.options.key) {
|
|
122
|
+
tlsConfig.key = Bun.file(this.options.key);
|
|
123
|
+
}
|
|
124
|
+
if (this.options.serverName) {
|
|
125
|
+
tlsConfig.serverName = this.options.serverName;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
connect({
|
|
129
|
+
hostname: this.options.host,
|
|
130
|
+
port: this.options.port,
|
|
131
|
+
socket: socketHandler,
|
|
132
|
+
data: { decoder },
|
|
133
|
+
tls: tlsConfig,
|
|
134
|
+
})
|
|
135
|
+
.then((socket) => {
|
|
136
|
+
this.socket = socket;
|
|
137
|
+
})
|
|
138
|
+
.catch(reject);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async disconnect(): Promise<void> {
|
|
143
|
+
if (this.socket) {
|
|
144
|
+
this.socket.end();
|
|
145
|
+
this.socket = null;
|
|
146
|
+
this.connected = false;
|
|
147
|
+
this.decoder.reset();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
isConnected(): boolean {
|
|
152
|
+
return this.connected && this.socket !== null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async send(data: Uint8Array): Promise<void> {
|
|
156
|
+
if (!this.socket || !this.connected) {
|
|
157
|
+
throw new Error("Not connected");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const written = this.socket.write(data);
|
|
161
|
+
if (written < data.length) {
|
|
162
|
+
// Bun's socket.write returns the number of bytes written
|
|
163
|
+
// If not all bytes were written, we need to wait for drain
|
|
164
|
+
// For simplicity, we'll throw an error here
|
|
165
|
+
// In production, you'd want to buffer and retry
|
|
166
|
+
throw new Error(
|
|
167
|
+
`Failed to write all data: wrote ${written} of ${data.length} bytes`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
setEventHandlers(handlers: TransportEvents): void {
|
|
173
|
+
this.events = handlers;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
getProtocolName(): string {
|
|
177
|
+
return Protocol.TLS;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
getRemoteAddress(): string | null {
|
|
181
|
+
return this.socket
|
|
182
|
+
? `${this.options.host}:${this.options.port}`
|
|
183
|
+
: null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private handleMessage(message: ReceivedMessage): void {
|
|
187
|
+
this.events.onMessage?.(message);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private handleError(error: Error): void {
|
|
191
|
+
this.events.onError?.(error);
|
|
192
|
+
}
|
|
193
|
+
}
|
package/src/transport.ts
CHANGED
|
@@ -1,99 +1,99 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Transport Interface
|
|
3
|
-
*
|
|
4
|
-
* Defines the contract for Federate Protocol transports (TCP, TLS, WebSocket).
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { MessageHeader } from "./message-header.ts";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Transport connection options
|
|
11
|
-
*/
|
|
12
|
-
export interface TransportOptions {
|
|
13
|
-
/** Server hostname or IP address */
|
|
14
|
-
host: string;
|
|
15
|
-
/** Server port (defaults to Ports.TCP for TCP, Ports.TLS for TLS) */
|
|
16
|
-
port?: number;
|
|
17
|
-
/** Connection timeout in milliseconds */
|
|
18
|
-
connectionTimeout?: number;
|
|
19
|
-
/** Enable TCP_NODELAY (disable Nagle's algorithm) */
|
|
20
|
-
noDelay?: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* TLS-specific options
|
|
25
|
-
*/
|
|
26
|
-
export interface TlsOptions extends TransportOptions {
|
|
27
|
-
/** Path to CA certificate file (for server verification) */
|
|
28
|
-
ca?: string;
|
|
29
|
-
/** Path to client certificate file (for mutual TLS) */
|
|
30
|
-
cert?: string;
|
|
31
|
-
/** Path to client private key file (for mutual TLS) */
|
|
32
|
-
key?: string;
|
|
33
|
-
/** Skip server certificate verification (INSECURE - for testing only) */
|
|
34
|
-
rejectUnauthorized?: boolean;
|
|
35
|
-
/** Server name for SNI */
|
|
36
|
-
serverName?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Received message with header and payload
|
|
41
|
-
*/
|
|
42
|
-
export interface ReceivedMessage {
|
|
43
|
-
header: MessageHeader;
|
|
44
|
-
payload: Uint8Array;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Transport event handlers
|
|
49
|
-
*/
|
|
50
|
-
export interface TransportEvents {
|
|
51
|
-
/** Called when a complete message is received */
|
|
52
|
-
onMessage?: (message: ReceivedMessage) => void;
|
|
53
|
-
/** Called when the connection is closed */
|
|
54
|
-
onClose?: (hadError: boolean) => void;
|
|
55
|
-
/** Called when an error occurs */
|
|
56
|
-
onError?: (error: Error) => void;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Transport interface for Federate Protocol communication
|
|
61
|
-
*/
|
|
62
|
-
export interface Transport {
|
|
63
|
-
/**
|
|
64
|
-
* Connect to the server
|
|
65
|
-
* @throws Error if connection fails
|
|
66
|
-
*/
|
|
67
|
-
connect(): Promise<void>;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Disconnect from the server
|
|
71
|
-
*/
|
|
72
|
-
disconnect(): Promise<void>;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Check if the transport is connected
|
|
76
|
-
*/
|
|
77
|
-
isConnected(): boolean;
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Send raw bytes to the server
|
|
81
|
-
* @param data The data to send
|
|
82
|
-
*/
|
|
83
|
-
send(data: Uint8Array): Promise<void>;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Set event handlers
|
|
87
|
-
*/
|
|
88
|
-
setEventHandlers(handlers: TransportEvents): void;
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Get the protocol name (tcp, tls, websocket, websocketsecure)
|
|
92
|
-
*/
|
|
93
|
-
getProtocolName(): string;
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Get the remote address
|
|
97
|
-
*/
|
|
98
|
-
getRemoteAddress(): string | null;
|
|
99
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Transport Interface
|
|
3
|
+
*
|
|
4
|
+
* Defines the contract for Federate Protocol transports (TCP, TLS, WebSocket).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { MessageHeader } from "./message-header.ts";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Transport connection options
|
|
11
|
+
*/
|
|
12
|
+
export interface TransportOptions {
|
|
13
|
+
/** Server hostname or IP address */
|
|
14
|
+
host: string;
|
|
15
|
+
/** Server port (defaults to Ports.TCP for TCP, Ports.TLS for TLS) */
|
|
16
|
+
port?: number;
|
|
17
|
+
/** Connection timeout in milliseconds */
|
|
18
|
+
connectionTimeout?: number;
|
|
19
|
+
/** Enable TCP_NODELAY (disable Nagle's algorithm) */
|
|
20
|
+
noDelay?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* TLS-specific options
|
|
25
|
+
*/
|
|
26
|
+
export interface TlsOptions extends TransportOptions {
|
|
27
|
+
/** Path to CA certificate file (for server verification) */
|
|
28
|
+
ca?: string;
|
|
29
|
+
/** Path to client certificate file (for mutual TLS) */
|
|
30
|
+
cert?: string;
|
|
31
|
+
/** Path to client private key file (for mutual TLS) */
|
|
32
|
+
key?: string;
|
|
33
|
+
/** Skip server certificate verification (INSECURE - for testing only) */
|
|
34
|
+
rejectUnauthorized?: boolean;
|
|
35
|
+
/** Server name for SNI */
|
|
36
|
+
serverName?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Received message with header and payload
|
|
41
|
+
*/
|
|
42
|
+
export interface ReceivedMessage {
|
|
43
|
+
header: MessageHeader;
|
|
44
|
+
payload: Uint8Array;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Transport event handlers
|
|
49
|
+
*/
|
|
50
|
+
export interface TransportEvents {
|
|
51
|
+
/** Called when a complete message is received */
|
|
52
|
+
onMessage?: (message: ReceivedMessage) => void;
|
|
53
|
+
/** Called when the connection is closed */
|
|
54
|
+
onClose?: (hadError: boolean) => void;
|
|
55
|
+
/** Called when an error occurs */
|
|
56
|
+
onError?: (error: Error) => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Transport interface for Federate Protocol communication
|
|
61
|
+
*/
|
|
62
|
+
export interface Transport {
|
|
63
|
+
/**
|
|
64
|
+
* Connect to the server
|
|
65
|
+
* @throws Error if connection fails
|
|
66
|
+
*/
|
|
67
|
+
connect(): Promise<void>;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Disconnect from the server
|
|
71
|
+
*/
|
|
72
|
+
disconnect(): Promise<void>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Check if the transport is connected
|
|
76
|
+
*/
|
|
77
|
+
isConnected(): boolean;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Send raw bytes to the server
|
|
81
|
+
* @param data The data to send
|
|
82
|
+
*/
|
|
83
|
+
send(data: Uint8Array): Promise<void>;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Set event handlers
|
|
87
|
+
*/
|
|
88
|
+
setEventHandlers(handlers: TransportEvents): void;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get the protocol name (tcp, tls, websocket, websocketsecure)
|
|
92
|
+
*/
|
|
93
|
+
getProtocolName(): string;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get the remote address
|
|
97
|
+
*/
|
|
98
|
+
getRemoteAddress(): string | null;
|
|
99
|
+
}
|