@syncbridge/net 0.4.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/LICENSE +15 -0
- package/README.md +1 -0
- package/classes/tcp-client.d.ts +48 -0
- package/classes/tcp-client.js +131 -0
- package/components/tcp-client.component.d.ts +35 -0
- package/components/tcp-client.component.js +102 -0
- package/components/tcp-client.variables.d.ts +31 -0
- package/components/tcp-client.variables.js +140 -0
- package/components/tcp-server.component.d.ts +23 -0
- package/components/tcp-server.component.js +32 -0
- package/components/tcp-server.variables.d.ts +16 -0
- package/components/tcp-server.variables.js +46 -0
- package/components/udp-client.component.d.ts +29 -0
- package/components/udp-client.component.js +119 -0
- package/components/udp-client.variables.d.ts +10 -0
- package/components/udp-client.variables.js +48 -0
- package/components/udp-listener.component.d.ts +29 -0
- package/components/udp-listener.component.js +116 -0
- package/components/udp-listener.variables.d.ts +11 -0
- package/components/udp-listener.variables.js +53 -0
- package/components.d.ts +4 -0
- package/components.js +4 -0
- package/constants.d.ts +4 -0
- package/constants.js +7 -0
- package/index.d.ts +5 -0
- package/index.js +9 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Copyright (c) 2025 Panates (Panates Teknoloji Yatirim A.S.). All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software and associated documentation files (the "Software") are
|
|
4
|
+
the proprietary property of Panates and are protected by copyright laws
|
|
5
|
+
and international copyright treaties.
|
|
6
|
+
|
|
7
|
+
Unauthorized copying, distribution, modification, reverse engineering,
|
|
8
|
+
or use of this software, in whole or in part, is strictly prohibited
|
|
9
|
+
without the express written permission of Panates.
|
|
10
|
+
|
|
11
|
+
This Software is provided solely for use in accordance with the terms
|
|
12
|
+
of a valid license agreement. Any unauthorized use may result in
|
|
13
|
+
civil and/or criminal penalties.
|
|
14
|
+
|
|
15
|
+
For licensing inquiries, please contact: info@panates.com
|
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# SyncBridge ICU Connectors
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import net from 'node:net';
|
|
3
|
+
import tls from 'node:tls';
|
|
4
|
+
import { Backoff } from 'backoff';
|
|
5
|
+
import { AsyncEventEmitter, EventMap } from 'node-events-async';
|
|
6
|
+
import reconnectCore from 'reconnect-core';
|
|
7
|
+
export declare class TcpClient<T extends TcpClient.Events = TcpClient.Events> extends AsyncEventEmitter<EventMap<T>> {
|
|
8
|
+
protected _connectionManager?: ReturnType<typeof socketReconnect>;
|
|
9
|
+
protected _socket?: net.Socket;
|
|
10
|
+
host: string;
|
|
11
|
+
port: number;
|
|
12
|
+
connectTimeout?: number;
|
|
13
|
+
reconnectOptions: TcpClient.ReconnectOptions;
|
|
14
|
+
constructor(args?: TcpClient.Options);
|
|
15
|
+
get connected(): boolean;
|
|
16
|
+
get socket(): net.Socket | undefined;
|
|
17
|
+
connect(): void;
|
|
18
|
+
disconnect(): Promise<void>;
|
|
19
|
+
write(data: string | Buffer): void;
|
|
20
|
+
}
|
|
21
|
+
export declare namespace TcpClient {
|
|
22
|
+
interface Options {
|
|
23
|
+
host: string;
|
|
24
|
+
port: number;
|
|
25
|
+
connectTimeout?: number;
|
|
26
|
+
keepAlive?: boolean;
|
|
27
|
+
reconnect?: ReconnectOptions;
|
|
28
|
+
tls?: tls.TlsOptions;
|
|
29
|
+
}
|
|
30
|
+
interface ReconnectOptions {
|
|
31
|
+
strategy?: 'fibonacci' | 'exponential' | Backoff;
|
|
32
|
+
immediate?: boolean | undefined;
|
|
33
|
+
failAfter?: number | undefined;
|
|
34
|
+
randomisationFactor?: number | undefined;
|
|
35
|
+
initialDelay?: number | undefined;
|
|
36
|
+
maxDelay?: number | undefined;
|
|
37
|
+
}
|
|
38
|
+
interface Events {
|
|
39
|
+
connect: [socket: net.Socket];
|
|
40
|
+
disconnect: [error: Error | undefined];
|
|
41
|
+
reconnecting: [n: number, delay: number];
|
|
42
|
+
reconnect: [socket: net.Socket];
|
|
43
|
+
data: [data: Buffer];
|
|
44
|
+
error: [error: Error];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
declare const socketReconnect: reconnectCore.CustomModule<net.NetConnectOpts, net.Socket>;
|
|
48
|
+
export {};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
import { AsyncEventEmitter } from 'node-events-async';
|
|
3
|
+
import reconnectCore from 'reconnect-core';
|
|
4
|
+
export class TcpClient extends AsyncEventEmitter {
|
|
5
|
+
_connectionManager;
|
|
6
|
+
_socket;
|
|
7
|
+
host;
|
|
8
|
+
port;
|
|
9
|
+
connectTimeout;
|
|
10
|
+
reconnectOptions;
|
|
11
|
+
constructor(args) {
|
|
12
|
+
super();
|
|
13
|
+
this.reconnectOptions = args?.reconnect || {};
|
|
14
|
+
this.reconnectOptions.initialDelay =
|
|
15
|
+
this.reconnectOptions.initialDelay ?? 2000;
|
|
16
|
+
this.reconnectOptions.maxDelay = this.reconnectOptions.maxDelay ?? 10000;
|
|
17
|
+
this.reconnectOptions.strategy =
|
|
18
|
+
this.reconnectOptions.strategy ?? 'fibonacci';
|
|
19
|
+
this.host = args?.host || 'localhost';
|
|
20
|
+
this.port = args?.port || 0;
|
|
21
|
+
this.connectTimeout = args?.connectTimeout;
|
|
22
|
+
}
|
|
23
|
+
get connected() {
|
|
24
|
+
return !!this._connectionManager?.connected;
|
|
25
|
+
}
|
|
26
|
+
get socket() {
|
|
27
|
+
return this._socket;
|
|
28
|
+
}
|
|
29
|
+
connect() {
|
|
30
|
+
if (this.connected)
|
|
31
|
+
return;
|
|
32
|
+
let reconnecting = false;
|
|
33
|
+
const connectionManager = (this._connectionManager = socketReconnect({
|
|
34
|
+
...this.reconnectOptions,
|
|
35
|
+
timeout: this.connectTimeout,
|
|
36
|
+
})
|
|
37
|
+
.on('error', (error) => {
|
|
38
|
+
if (!connectionManager.reconnect)
|
|
39
|
+
return;
|
|
40
|
+
error = error instanceof AggregateError ? error.errors[0] : error;
|
|
41
|
+
if (error.code === 'ECONNREFUSED')
|
|
42
|
+
error.message = `Connection refused to ${error.address}:${error.port}`;
|
|
43
|
+
this.emit('error', error);
|
|
44
|
+
})
|
|
45
|
+
.on('connect', (socket) => {
|
|
46
|
+
if (this._socket !== socket) {
|
|
47
|
+
this._socket = socket;
|
|
48
|
+
socket.on('data', (chunk) => this.emit('data', chunk));
|
|
49
|
+
}
|
|
50
|
+
if (reconnecting)
|
|
51
|
+
this.emit('reconnect', socket);
|
|
52
|
+
reconnecting = false;
|
|
53
|
+
this.emit('connect', socket);
|
|
54
|
+
})
|
|
55
|
+
.on('reconnect', (n, delay) => {
|
|
56
|
+
if (n === 0 && delay === 0)
|
|
57
|
+
return;
|
|
58
|
+
reconnecting = true;
|
|
59
|
+
this.emit('reconnecting', n, delay);
|
|
60
|
+
})
|
|
61
|
+
.on('disconnect', err => {
|
|
62
|
+
this._socket = undefined;
|
|
63
|
+
if (connectionManager.reconnect) {
|
|
64
|
+
if (err)
|
|
65
|
+
err.message = `TCP socket connection lost: ${err.message}`;
|
|
66
|
+
else
|
|
67
|
+
err = new Error('TCP socket connection lost');
|
|
68
|
+
this.emit('disconnect', err);
|
|
69
|
+
}
|
|
70
|
+
else
|
|
71
|
+
this.emit('disconnect');
|
|
72
|
+
}));
|
|
73
|
+
connectionManager.connect({
|
|
74
|
+
host: this.host,
|
|
75
|
+
port: this.port,
|
|
76
|
+
timeout: this.connectTimeout,
|
|
77
|
+
// keepAlive: this.
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
async disconnect() {
|
|
81
|
+
if (!this._connectionManager)
|
|
82
|
+
return;
|
|
83
|
+
const connectionManager = this._connectionManager;
|
|
84
|
+
this._connectionManager = undefined;
|
|
85
|
+
/** istanbul ignore else */
|
|
86
|
+
if (connectionManager.connected) {
|
|
87
|
+
connectionManager.reconnect = false;
|
|
88
|
+
return new Promise(resolve => {
|
|
89
|
+
connectionManager.once('disconnect', async () => {
|
|
90
|
+
connectionManager.reset();
|
|
91
|
+
this._connectionManager = undefined;
|
|
92
|
+
resolve();
|
|
93
|
+
});
|
|
94
|
+
connectionManager.disconnect();
|
|
95
|
+
connectionManager.reset();
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
connectionManager.disconnect();
|
|
100
|
+
connectionManager.reset();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
write(data) {
|
|
104
|
+
if (!this._socket)
|
|
105
|
+
throw new Error(`Can't write while TCP socket is not connected`);
|
|
106
|
+
this._socket.write(data);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const socketReconnect = reconnectCore(args => {
|
|
110
|
+
// implement tls
|
|
111
|
+
const socket = net.connect({
|
|
112
|
+
...args,
|
|
113
|
+
timeout: undefined,
|
|
114
|
+
});
|
|
115
|
+
if (args.timeout) {
|
|
116
|
+
const timer = setTimeout(() => {
|
|
117
|
+
socket.destroy(new Error('Connection timed out'));
|
|
118
|
+
}, args.timeout).unref();
|
|
119
|
+
const onConnect = () => {
|
|
120
|
+
clearTimeout(timer);
|
|
121
|
+
socket.removeListener('error', onError);
|
|
122
|
+
};
|
|
123
|
+
const onError = () => {
|
|
124
|
+
socket.removeListener('connect', onConnect);
|
|
125
|
+
clearTimeout(timer);
|
|
126
|
+
};
|
|
127
|
+
socket.once('connect', onConnect);
|
|
128
|
+
socket.once('error', onError);
|
|
129
|
+
}
|
|
130
|
+
return socket;
|
|
131
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import { IoClientBaseComponent } from '@syncbridge/builtins';
|
|
3
|
+
import { TcpClient } from '../classes/tcp-client.js';
|
|
4
|
+
import { TcpClientReconnectVariables, TcpClientTlsVariables, TcpClientVariables } from './tcp-client.variables.js';
|
|
5
|
+
/**
|
|
6
|
+
* TcpClient component
|
|
7
|
+
*/
|
|
8
|
+
export declare class TcpClientComponent<TEvents extends TcpClientComponent.Events = TcpClientComponent.Events> extends IoClientBaseComponent<TEvents> {
|
|
9
|
+
readonly protocol: string;
|
|
10
|
+
protected _client: TcpClient;
|
|
11
|
+
protected _stopping?: boolean;
|
|
12
|
+
protected _address?: any;
|
|
13
|
+
values: TcpClientVariables;
|
|
14
|
+
get connected(): boolean;
|
|
15
|
+
protected _init(): Promise<void>;
|
|
16
|
+
protected _start(abortSignal: AbortSignal): Promise<void>;
|
|
17
|
+
protected _stop(): Promise<void>;
|
|
18
|
+
write(data: string | Buffer): void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* @namespace
|
|
22
|
+
*/
|
|
23
|
+
export declare namespace TcpClientComponent {
|
|
24
|
+
interface Events extends IoClientBaseComponent.Events {
|
|
25
|
+
connect: [];
|
|
26
|
+
disconnect: [error: Error | undefined];
|
|
27
|
+
reconnecting: [n: number, delay: number];
|
|
28
|
+
}
|
|
29
|
+
const Variables: typeof TcpClientVariables;
|
|
30
|
+
type Variables = TcpClientVariables;
|
|
31
|
+
const ReconnectVariables: typeof TcpClientReconnectVariables;
|
|
32
|
+
type ReconnectVariables = TcpClientReconnectVariables;
|
|
33
|
+
const TlsVariables: typeof TcpClientTlsVariables;
|
|
34
|
+
type TlsVariables = TcpClientTlsVariables;
|
|
35
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { IoClientBaseComponent } from '@syncbridge/builtins';
|
|
3
|
+
import { Component, ServiceStatus } from '@syncbridge/common';
|
|
4
|
+
import colors from 'ansi-colors';
|
|
5
|
+
import { TcpClient } from '../classes/tcp-client.js';
|
|
6
|
+
import { TcpClientReconnectVariables, TcpClientTlsVariables, TcpClientVariables, } from './tcp-client.variables.js';
|
|
7
|
+
/**
|
|
8
|
+
* TcpClient component
|
|
9
|
+
*/
|
|
10
|
+
let TcpClientComponent = class TcpClientComponent extends IoClientBaseComponent {
|
|
11
|
+
protocol = 'tcp';
|
|
12
|
+
_stopping;
|
|
13
|
+
_address;
|
|
14
|
+
get connected() {
|
|
15
|
+
return this._client.connected;
|
|
16
|
+
}
|
|
17
|
+
async _init() {
|
|
18
|
+
await super._init();
|
|
19
|
+
this._client = new TcpClient({
|
|
20
|
+
host: this.values.host || 'localhost',
|
|
21
|
+
port: this.values.port || 0,
|
|
22
|
+
connectTimeout: this.values.connectTimeout,
|
|
23
|
+
keepAlive: this.values.keepAlive,
|
|
24
|
+
reconnect: this.values.reconnect,
|
|
25
|
+
tls: this.values.tls,
|
|
26
|
+
});
|
|
27
|
+
/* On connect */
|
|
28
|
+
this._client.on('connect', (socket) => {
|
|
29
|
+
this._address = { ...socket.address() };
|
|
30
|
+
this._address.toString = function () {
|
|
31
|
+
return `${this.address}:${this.port}`;
|
|
32
|
+
}.bind(this._address);
|
|
33
|
+
setImmediate(() => {
|
|
34
|
+
this.logger?.info(`TCP socket connected to ${colors.cyan(this._client.host + ':' + this._client.port)}`);
|
|
35
|
+
this.setStatus(ServiceStatus.started);
|
|
36
|
+
this.emit('connect');
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
/* On disconnect */
|
|
40
|
+
this._client.on('disconnect', (err) => {
|
|
41
|
+
if (this._stopping)
|
|
42
|
+
this.emit('disconnect');
|
|
43
|
+
else {
|
|
44
|
+
err = err || new Error('TCP socket disconnected');
|
|
45
|
+
this.logger?.error(err);
|
|
46
|
+
this.setStatus(ServiceStatus.unhealthy, err.message);
|
|
47
|
+
this.emit('disconnect');
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
/* On data */
|
|
51
|
+
this._client.on('data', (chunk) => {
|
|
52
|
+
this.emit('data', chunk, this._address);
|
|
53
|
+
});
|
|
54
|
+
/* On error */
|
|
55
|
+
this._client.on('error', (err) => {
|
|
56
|
+
this.emit('error', err);
|
|
57
|
+
});
|
|
58
|
+
/* On reconnecting */
|
|
59
|
+
this._client.on('reconnecting', (n, delay) => {
|
|
60
|
+
this.logger?.error(`Connection failed (${colors.cyan(String(n + 1))}). Will be retried after ${colors.cyan(delay + 'ms')}`);
|
|
61
|
+
this.emit('reconnecting', n, delay);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async _start(abortSignal) {
|
|
65
|
+
await super._start(abortSignal);
|
|
66
|
+
this._stopping = false;
|
|
67
|
+
this.logger?.info(`TCP socket connecting to ${colors.cyan(this._client.host + ':' + this._client.port)}`);
|
|
68
|
+
this._client.connect();
|
|
69
|
+
}
|
|
70
|
+
async _stop() {
|
|
71
|
+
this._stopping = true;
|
|
72
|
+
await this._client.disconnect();
|
|
73
|
+
}
|
|
74
|
+
write(data) {
|
|
75
|
+
if (!this.connected) {
|
|
76
|
+
throw new Error(`Can't write while TCP socket is not connected`);
|
|
77
|
+
}
|
|
78
|
+
this.emit('transmit', data, this._address);
|
|
79
|
+
this._client.write(data);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
__decorate([
|
|
83
|
+
Component.UseVariables(),
|
|
84
|
+
__metadata("design:type", TcpClientVariables)
|
|
85
|
+
], TcpClientComponent.prototype, "values", void 0);
|
|
86
|
+
TcpClientComponent = __decorate([
|
|
87
|
+
Component({
|
|
88
|
+
className: 'TcpClient',
|
|
89
|
+
displayName: 'TCP Client',
|
|
90
|
+
description: 'TCP client component',
|
|
91
|
+
tags: ['tcp', 'client', 'socket', 'connection'],
|
|
92
|
+
})
|
|
93
|
+
], TcpClientComponent);
|
|
94
|
+
export { TcpClientComponent };
|
|
95
|
+
/**
|
|
96
|
+
* @namespace
|
|
97
|
+
*/
|
|
98
|
+
(function (TcpClientComponent) {
|
|
99
|
+
TcpClientComponent.Variables = TcpClientVariables;
|
|
100
|
+
TcpClientComponent.ReconnectVariables = TcpClientReconnectVariables;
|
|
101
|
+
TcpClientComponent.TlsVariables = TcpClientTlsVariables;
|
|
102
|
+
})(TcpClientComponent || (TcpClientComponent = {}));
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { IoClientBaseComponent } from '@syncbridge/builtins';
|
|
2
|
+
/**
|
|
3
|
+
* TLS variables
|
|
4
|
+
*/
|
|
5
|
+
export declare class TcpClientTlsVariables {
|
|
6
|
+
servername?: string;
|
|
7
|
+
key: string;
|
|
8
|
+
cert: string;
|
|
9
|
+
ca?: string;
|
|
10
|
+
passphrase?: string;
|
|
11
|
+
rejectUnauthorized: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Reconnect variables
|
|
15
|
+
*/
|
|
16
|
+
export declare class TcpClientReconnectVariables {
|
|
17
|
+
strategy: 'exponential' | 'fibonacci';
|
|
18
|
+
initialDelay: number;
|
|
19
|
+
maxDelay: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Variables
|
|
23
|
+
*/
|
|
24
|
+
export declare class TcpClientVariables extends IoClientBaseComponent.Variables {
|
|
25
|
+
host: string;
|
|
26
|
+
port: number;
|
|
27
|
+
keepAlive: boolean;
|
|
28
|
+
connectTimeout: number;
|
|
29
|
+
reconnect: TcpClientReconnectVariables;
|
|
30
|
+
tls: TcpClientTlsVariables;
|
|
31
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { IoClientBaseComponent } from '@syncbridge/builtins';
|
|
3
|
+
import { DefineVariable, VariableType } from '@syncbridge/common';
|
|
4
|
+
/**
|
|
5
|
+
* TLS variables
|
|
6
|
+
*/
|
|
7
|
+
export class TcpClientTlsVariables {
|
|
8
|
+
}
|
|
9
|
+
__decorate([
|
|
10
|
+
DefineVariable({
|
|
11
|
+
label: 'SNI',
|
|
12
|
+
description: 'SNI (Server Name Indication)',
|
|
13
|
+
}),
|
|
14
|
+
__metadata("design:type", String)
|
|
15
|
+
], TcpClientTlsVariables.prototype, "servername", void 0);
|
|
16
|
+
__decorate([
|
|
17
|
+
DefineVariable({
|
|
18
|
+
label: 'Key',
|
|
19
|
+
description: 'Private keys in PEM format',
|
|
20
|
+
required: true,
|
|
21
|
+
}),
|
|
22
|
+
__metadata("design:type", String)
|
|
23
|
+
], TcpClientTlsVariables.prototype, "key", void 0);
|
|
24
|
+
__decorate([
|
|
25
|
+
DefineVariable({
|
|
26
|
+
label: 'Cert',
|
|
27
|
+
description: 'Cert chains in PEM format',
|
|
28
|
+
required: true,
|
|
29
|
+
}),
|
|
30
|
+
__metadata("design:type", String)
|
|
31
|
+
], TcpClientTlsVariables.prototype, "cert", void 0);
|
|
32
|
+
__decorate([
|
|
33
|
+
DefineVariable({
|
|
34
|
+
label: 'CA certificates',
|
|
35
|
+
description: 'Optionally override the trusted CA certificates. Default is to trust the well-known CAs ' +
|
|
36
|
+
"curated by Mozilla. Mozilla's CAs are completely replaced when CAs are explicitly specified " +
|
|
37
|
+
'using this option.',
|
|
38
|
+
required: true,
|
|
39
|
+
}),
|
|
40
|
+
__metadata("design:type", String)
|
|
41
|
+
], TcpClientTlsVariables.prototype, "ca", void 0);
|
|
42
|
+
__decorate([
|
|
43
|
+
DefineVariable({
|
|
44
|
+
type: VariableType.Secret,
|
|
45
|
+
label: 'Passphrase',
|
|
46
|
+
description: 'Passphrase to decrypt the private key',
|
|
47
|
+
}),
|
|
48
|
+
__metadata("design:type", String)
|
|
49
|
+
], TcpClientTlsVariables.prototype, "passphrase", void 0);
|
|
50
|
+
__decorate([
|
|
51
|
+
DefineVariable({
|
|
52
|
+
label: 'Reject unauthorized',
|
|
53
|
+
description: 'If true will reject any connection which is not authorized with the list of supplied CAs',
|
|
54
|
+
default: true,
|
|
55
|
+
}),
|
|
56
|
+
__metadata("design:type", Boolean)
|
|
57
|
+
], TcpClientTlsVariables.prototype, "rejectUnauthorized", void 0);
|
|
58
|
+
/**
|
|
59
|
+
* Reconnect variables
|
|
60
|
+
*/
|
|
61
|
+
export class TcpClientReconnectVariables {
|
|
62
|
+
}
|
|
63
|
+
__decorate([
|
|
64
|
+
DefineVariable({
|
|
65
|
+
type: VariableType.Enum,
|
|
66
|
+
label: 'Reconnection strategy',
|
|
67
|
+
enumValues: ['exponential', 'fibonacci'],
|
|
68
|
+
default: 'exponential',
|
|
69
|
+
}),
|
|
70
|
+
__metadata("design:type", String)
|
|
71
|
+
], TcpClientReconnectVariables.prototype, "strategy", void 0);
|
|
72
|
+
__decorate([
|
|
73
|
+
DefineVariable({
|
|
74
|
+
label: 'Initial delay',
|
|
75
|
+
description: 'Initial delay in milliseconds',
|
|
76
|
+
default: 2000,
|
|
77
|
+
}),
|
|
78
|
+
__metadata("design:type", Number)
|
|
79
|
+
], TcpClientReconnectVariables.prototype, "initialDelay", void 0);
|
|
80
|
+
__decorate([
|
|
81
|
+
DefineVariable({
|
|
82
|
+
label: 'Maximum delay',
|
|
83
|
+
description: 'Maximum delay in milliseconds',
|
|
84
|
+
default: 10000,
|
|
85
|
+
}),
|
|
86
|
+
__metadata("design:type", Number)
|
|
87
|
+
], TcpClientReconnectVariables.prototype, "maxDelay", void 0);
|
|
88
|
+
/**
|
|
89
|
+
* Variables
|
|
90
|
+
*/
|
|
91
|
+
export class TcpClientVariables extends IoClientBaseComponent.Variables {
|
|
92
|
+
}
|
|
93
|
+
__decorate([
|
|
94
|
+
DefineVariable({
|
|
95
|
+
label: 'Host',
|
|
96
|
+
description: 'Hostname or IP address to be connected to',
|
|
97
|
+
required: true,
|
|
98
|
+
}),
|
|
99
|
+
__metadata("design:type", String)
|
|
100
|
+
], TcpClientVariables.prototype, "host", void 0);
|
|
101
|
+
__decorate([
|
|
102
|
+
DefineVariable({
|
|
103
|
+
label: 'Port',
|
|
104
|
+
description: 'Port number of target listener',
|
|
105
|
+
required: true,
|
|
106
|
+
minValue: 1,
|
|
107
|
+
maxValue: 65535,
|
|
108
|
+
}),
|
|
109
|
+
__metadata("design:type", Number)
|
|
110
|
+
], TcpClientVariables.prototype, "port", void 0);
|
|
111
|
+
__decorate([
|
|
112
|
+
DefineVariable({
|
|
113
|
+
label: 'Keep alive',
|
|
114
|
+
description: 'Enables keep-alive on the TCP socket',
|
|
115
|
+
default: false,
|
|
116
|
+
}),
|
|
117
|
+
__metadata("design:type", Boolean)
|
|
118
|
+
], TcpClientVariables.prototype, "keepAlive", void 0);
|
|
119
|
+
__decorate([
|
|
120
|
+
DefineVariable({
|
|
121
|
+
label: 'Connect timeout',
|
|
122
|
+
description: 'Connection timeout in milliseconds',
|
|
123
|
+
default: 10000,
|
|
124
|
+
}),
|
|
125
|
+
__metadata("design:type", Number)
|
|
126
|
+
], TcpClientVariables.prototype, "connectTimeout", void 0);
|
|
127
|
+
__decorate([
|
|
128
|
+
DefineVariable({
|
|
129
|
+
label: 'Reconnect',
|
|
130
|
+
description: 'Reconnect options',
|
|
131
|
+
}),
|
|
132
|
+
__metadata("design:type", TcpClientReconnectVariables)
|
|
133
|
+
], TcpClientVariables.prototype, "reconnect", void 0);
|
|
134
|
+
__decorate([
|
|
135
|
+
DefineVariable({
|
|
136
|
+
label: 'TLS',
|
|
137
|
+
description: 'TLS options',
|
|
138
|
+
}),
|
|
139
|
+
__metadata("design:type", TcpClientTlsVariables)
|
|
140
|
+
], TcpClientVariables.prototype, "tls", void 0);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { IoClientBaseComponent } from '@syncbridge/builtins';
|
|
2
|
+
import { ComponentBase } from '@syncbridge/common';
|
|
3
|
+
import { TcpServerTlsVariables, TcpServerVariables } from './tcp-server.variables.js';
|
|
4
|
+
/**
|
|
5
|
+
* TcpServer component
|
|
6
|
+
* todo
|
|
7
|
+
*/
|
|
8
|
+
export declare class TcpServerComponent<TEvents extends TcpServerComponent.Events = TcpServerComponent.Events> extends ComponentBase<TEvents> {
|
|
9
|
+
values: TcpServerVariables;
|
|
10
|
+
protected _start(abortSignal: AbortSignal): Promise<void>;
|
|
11
|
+
protected _stop(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* @namespace
|
|
15
|
+
*/
|
|
16
|
+
export declare namespace TcpServerComponent {
|
|
17
|
+
interface Events extends IoClientBaseComponent.Events {
|
|
18
|
+
}
|
|
19
|
+
const Variables: typeof TcpServerVariables;
|
|
20
|
+
type Variables = TcpServerVariables;
|
|
21
|
+
const TlsVariables: typeof TcpServerTlsVariables;
|
|
22
|
+
type TlsVariables = TcpServerTlsVariables;
|
|
23
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { Component, ComponentBase } from '@syncbridge/common';
|
|
3
|
+
import { TcpServerTlsVariables, TcpServerVariables, } from './tcp-server.variables.js';
|
|
4
|
+
/**
|
|
5
|
+
* TcpServer component
|
|
6
|
+
* todo
|
|
7
|
+
*/
|
|
8
|
+
let TcpServerComponent = class TcpServerComponent extends ComponentBase {
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
10
|
+
async _start(abortSignal) { }
|
|
11
|
+
async _stop() { }
|
|
12
|
+
};
|
|
13
|
+
__decorate([
|
|
14
|
+
Component.UseVariables(),
|
|
15
|
+
__metadata("design:type", TcpServerVariables)
|
|
16
|
+
], TcpServerComponent.prototype, "values", void 0);
|
|
17
|
+
TcpServerComponent = __decorate([
|
|
18
|
+
Component({
|
|
19
|
+
className: 'TcpServer',
|
|
20
|
+
displayName: 'TCP Server',
|
|
21
|
+
description: 'TCP server component',
|
|
22
|
+
tags: ['tcp', 'server', 'socket'],
|
|
23
|
+
})
|
|
24
|
+
], TcpServerComponent);
|
|
25
|
+
export { TcpServerComponent };
|
|
26
|
+
/**
|
|
27
|
+
* @namespace
|
|
28
|
+
*/
|
|
29
|
+
(function (TcpServerComponent) {
|
|
30
|
+
TcpServerComponent.Variables = TcpServerVariables;
|
|
31
|
+
TcpServerComponent.TlsVariables = TcpServerTlsVariables;
|
|
32
|
+
})(TcpServerComponent || (TcpServerComponent = {}));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TransmitLogger } from '@syncbridge/builtins';
|
|
2
|
+
import { TcpClientTlsVariables } from './tcp-client.variables.js';
|
|
3
|
+
/**
|
|
4
|
+
* TLS variables
|
|
5
|
+
*/
|
|
6
|
+
export declare class TcpServerTlsVariables extends TcpClientTlsVariables {
|
|
7
|
+
requestCert: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Variables
|
|
11
|
+
*/
|
|
12
|
+
export declare class TcpServerVariables {
|
|
13
|
+
port: number;
|
|
14
|
+
tls: TcpServerTlsVariables;
|
|
15
|
+
communicationLogs?: TransmitLogger.Variables;
|
|
16
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { TransmitLogger } from '@syncbridge/builtins';
|
|
3
|
+
import { DefineVariable } from '@syncbridge/common';
|
|
4
|
+
import { TcpClientTlsVariables } from './tcp-client.variables.js';
|
|
5
|
+
/**
|
|
6
|
+
* TLS variables
|
|
7
|
+
*/
|
|
8
|
+
export class TcpServerTlsVariables extends TcpClientTlsVariables {
|
|
9
|
+
}
|
|
10
|
+
__decorate([
|
|
11
|
+
DefineVariable({
|
|
12
|
+
label: 'Request cert',
|
|
13
|
+
description: 'If true the server will request a certificate from clients that connect and attempt to verify that certificate',
|
|
14
|
+
default: false,
|
|
15
|
+
}),
|
|
16
|
+
__metadata("design:type", Boolean)
|
|
17
|
+
], TcpServerTlsVariables.prototype, "requestCert", void 0);
|
|
18
|
+
/**
|
|
19
|
+
* Variables
|
|
20
|
+
*/
|
|
21
|
+
export class TcpServerVariables {
|
|
22
|
+
}
|
|
23
|
+
__decorate([
|
|
24
|
+
DefineVariable({
|
|
25
|
+
label: 'Port',
|
|
26
|
+
description: 'Port number to be listen',
|
|
27
|
+
required: true,
|
|
28
|
+
minValue: 1,
|
|
29
|
+
maxValue: 65535,
|
|
30
|
+
}),
|
|
31
|
+
__metadata("design:type", Number)
|
|
32
|
+
], TcpServerVariables.prototype, "port", void 0);
|
|
33
|
+
__decorate([
|
|
34
|
+
DefineVariable({
|
|
35
|
+
label: 'TLS',
|
|
36
|
+
description: 'TLS options',
|
|
37
|
+
}),
|
|
38
|
+
__metadata("design:type", TcpServerTlsVariables)
|
|
39
|
+
], TcpServerVariables.prototype, "tls", void 0);
|
|
40
|
+
__decorate([
|
|
41
|
+
DefineVariable({
|
|
42
|
+
label: 'Communication Logs',
|
|
43
|
+
description: 'Stores communication logs if enabled',
|
|
44
|
+
}),
|
|
45
|
+
__metadata("design:type", TransmitLogger.Variables)
|
|
46
|
+
], TcpServerVariables.prototype, "communicationLogs", void 0);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import dgram from 'node:dgram';
|
|
3
|
+
import { IoClientBaseComponent } from '@syncbridge/builtins';
|
|
4
|
+
import { UdpClientVariables } from './udp-client.variables.js';
|
|
5
|
+
/**
|
|
6
|
+
* UdpClient component
|
|
7
|
+
*/
|
|
8
|
+
export declare class UdpClientComponent<TEvents extends UdpClientComponent.Events = UdpClientComponent.Events> extends IoClientBaseComponent<TEvents> {
|
|
9
|
+
readonly protocol: string;
|
|
10
|
+
socket: dgram.Socket & {
|
|
11
|
+
readonly isBroadcastEnabled: boolean;
|
|
12
|
+
};
|
|
13
|
+
protected _stopping?: boolean;
|
|
14
|
+
values: UdpClientVariables;
|
|
15
|
+
protected _start(abortSignal: AbortSignal): Promise<void>;
|
|
16
|
+
protected _stop(): Promise<void>;
|
|
17
|
+
write(data: string | Buffer, port?: number, host?: string): void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* @namespace
|
|
21
|
+
*/
|
|
22
|
+
export declare namespace UdpClientComponent {
|
|
23
|
+
interface Events extends IoClientBaseComponent.Events {
|
|
24
|
+
data: [data: Buffer, info: dgram.RemoteInfo];
|
|
25
|
+
write: [data: Buffer | string];
|
|
26
|
+
}
|
|
27
|
+
const Variables: typeof UdpClientVariables;
|
|
28
|
+
type Variables = UdpClientVariables;
|
|
29
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import dgram from 'node:dgram';
|
|
3
|
+
import { IoClientBaseComponent } from '@syncbridge/builtins';
|
|
4
|
+
import { Component, ServiceStatus } from '@syncbridge/common';
|
|
5
|
+
import { UdpClientVariables } from './udp-client.variables.js';
|
|
6
|
+
/**
|
|
7
|
+
* UdpClient component
|
|
8
|
+
*/
|
|
9
|
+
let UdpClientComponent = class UdpClientComponent extends IoClientBaseComponent {
|
|
10
|
+
protocol = 'udp';
|
|
11
|
+
_stopping;
|
|
12
|
+
async _start(abortSignal) {
|
|
13
|
+
await super._start(abortSignal);
|
|
14
|
+
this._stopping = false;
|
|
15
|
+
this.socket = dgram.createSocket('udp4');
|
|
16
|
+
let isBroadcastEnabled = false;
|
|
17
|
+
Object.defineProperty(this.socket, 'isBroadcastEnabled', {
|
|
18
|
+
get() {
|
|
19
|
+
return isBroadcastEnabled;
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
const oldSetBroadcast = this.socket.setBroadcast;
|
|
23
|
+
this.socket.setBroadcast = (value) => {
|
|
24
|
+
isBroadcastEnabled = value;
|
|
25
|
+
oldSetBroadcast.call(this.socket, value);
|
|
26
|
+
};
|
|
27
|
+
this.socket.on('connect', () => {
|
|
28
|
+
this.emit('connect');
|
|
29
|
+
this.setStatus(ServiceStatus.started);
|
|
30
|
+
});
|
|
31
|
+
this.socket.on('listening', () => {
|
|
32
|
+
const { bindInterface } = this.values;
|
|
33
|
+
const port = this.socket.address().port;
|
|
34
|
+
this.emit('listening', port);
|
|
35
|
+
this.logger?.info(`UDP socket listening on port ${port}` +
|
|
36
|
+
(bindInterface ? ` interface ${bindInterface}` : ''));
|
|
37
|
+
this.setStatus(ServiceStatus.started);
|
|
38
|
+
});
|
|
39
|
+
this.socket.on('message', (msg, info) => {
|
|
40
|
+
if (info.address === '127.0.0.1')
|
|
41
|
+
return;
|
|
42
|
+
// todo logger
|
|
43
|
+
// this.logger.debug(
|
|
44
|
+
// `Data received from ${colors.cyan(info.address + ':' + info.port)} (${msg.length} bytes)`,
|
|
45
|
+
// {
|
|
46
|
+
// host: info.address,
|
|
47
|
+
// port: info.port,
|
|
48
|
+
// size: msg.length,
|
|
49
|
+
// },
|
|
50
|
+
// );
|
|
51
|
+
const info2 = {
|
|
52
|
+
...info,
|
|
53
|
+
toString() {
|
|
54
|
+
return `${this.address}:${this.port}`;
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
this.emit('data', msg, info2);
|
|
58
|
+
});
|
|
59
|
+
if (this.values.bindInterface) {
|
|
60
|
+
this.socket.bind(this.values.port || 0, this.values.bindInterface);
|
|
61
|
+
}
|
|
62
|
+
if (this.values.port) {
|
|
63
|
+
this.socket.connect(this.values.port, this.values.host);
|
|
64
|
+
}
|
|
65
|
+
else
|
|
66
|
+
this.setStatus(ServiceStatus.started);
|
|
67
|
+
}
|
|
68
|
+
async _stop() {
|
|
69
|
+
this._stopping = true;
|
|
70
|
+
await new Promise(resolve => {
|
|
71
|
+
this.socket.close(resolve);
|
|
72
|
+
this._stopping = false;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
write(data, port, host) {
|
|
76
|
+
host = host || this.values.host;
|
|
77
|
+
port = port || this.values.port;
|
|
78
|
+
if (!host)
|
|
79
|
+
throw new Error('You must provide "host" variable to send message over UDP socket');
|
|
80
|
+
this.socket.send(data, port, host);
|
|
81
|
+
const info2 = {
|
|
82
|
+
address: host,
|
|
83
|
+
port: port,
|
|
84
|
+
size: data.length,
|
|
85
|
+
toString() {
|
|
86
|
+
return `${this.address}:${this.port}`;
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
this.emit('transmit', data, info2);
|
|
90
|
+
// todo logger
|
|
91
|
+
// if (this.socket.isBroadcastEnabled)
|
|
92
|
+
// this.logger.debug(
|
|
93
|
+
// `Broadcast message sent ${colors.cyan(host + ':' + port)} (${data.length} bytes)`,
|
|
94
|
+
// );
|
|
95
|
+
// else
|
|
96
|
+
// this.logger.debug(
|
|
97
|
+
// `Message sent to ${colors.cyan(host + ':' + port)} (${data.length} bytes)`,
|
|
98
|
+
// );
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
__decorate([
|
|
102
|
+
Component.UseVariables(),
|
|
103
|
+
__metadata("design:type", UdpClientVariables)
|
|
104
|
+
], UdpClientComponent.prototype, "values", void 0);
|
|
105
|
+
UdpClientComponent = __decorate([
|
|
106
|
+
Component({
|
|
107
|
+
className: 'UdpClient',
|
|
108
|
+
displayName: 'UDP Client',
|
|
109
|
+
description: 'UDP client component',
|
|
110
|
+
tags: ['udp', 'client', 'socket', 'connection'],
|
|
111
|
+
})
|
|
112
|
+
], UdpClientComponent);
|
|
113
|
+
export { UdpClientComponent };
|
|
114
|
+
/**
|
|
115
|
+
* @namespace
|
|
116
|
+
*/
|
|
117
|
+
(function (UdpClientComponent) {
|
|
118
|
+
UdpClientComponent.Variables = UdpClientVariables;
|
|
119
|
+
})(UdpClientComponent || (UdpClientComponent = {}));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IoClientBaseComponent } from '@syncbridge/builtins';
|
|
2
|
+
/**
|
|
3
|
+
* Variables
|
|
4
|
+
*/
|
|
5
|
+
export declare class UdpClientVariables extends IoClientBaseComponent.Variables {
|
|
6
|
+
port?: number;
|
|
7
|
+
host?: string;
|
|
8
|
+
bindInterface?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function getInterfaceAddresses(): string[];
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { IoClientBaseComponent } from '@syncbridge/builtins';
|
|
4
|
+
import { DefineVariable, VariableType } from '@syncbridge/common';
|
|
5
|
+
/**
|
|
6
|
+
* Variables
|
|
7
|
+
*/
|
|
8
|
+
export class UdpClientVariables extends IoClientBaseComponent.Variables {
|
|
9
|
+
}
|
|
10
|
+
__decorate([
|
|
11
|
+
DefineVariable({
|
|
12
|
+
label: 'Port',
|
|
13
|
+
description: 'Port number of target listener',
|
|
14
|
+
minValue: 1,
|
|
15
|
+
maxValue: 65535,
|
|
16
|
+
}),
|
|
17
|
+
__metadata("design:type", Number)
|
|
18
|
+
], UdpClientVariables.prototype, "port", void 0);
|
|
19
|
+
__decorate([
|
|
20
|
+
DefineVariable({
|
|
21
|
+
label: 'Host',
|
|
22
|
+
description: 'Hostname or IP address which udp messages will send to',
|
|
23
|
+
}),
|
|
24
|
+
__metadata("design:type", String)
|
|
25
|
+
], UdpClientVariables.prototype, "host", void 0);
|
|
26
|
+
__decorate([
|
|
27
|
+
DefineVariable({
|
|
28
|
+
label: 'Bind Interface',
|
|
29
|
+
description: 'Interface address to bind to. If not specified, will bind to all available addresses',
|
|
30
|
+
type: VariableType.Enum,
|
|
31
|
+
enumValues: getInterfaceAddresses(),
|
|
32
|
+
}),
|
|
33
|
+
__metadata("design:type", String)
|
|
34
|
+
], UdpClientVariables.prototype, "bindInterface", void 0);
|
|
35
|
+
export function getInterfaceAddresses() {
|
|
36
|
+
const interfaces = os.networkInterfaces();
|
|
37
|
+
const addresses = [];
|
|
38
|
+
for (const ifaces of Object.values(interfaces)) {
|
|
39
|
+
if (!ifaces)
|
|
40
|
+
continue;
|
|
41
|
+
for (const iface of ifaces) {
|
|
42
|
+
if (iface.family === 'IPv4' && !iface.internal) {
|
|
43
|
+
addresses.push(iface.address);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return addresses;
|
|
48
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import dgram from 'node:dgram';
|
|
3
|
+
import { IoClientBaseComponent } from '@syncbridge/builtins';
|
|
4
|
+
import { UdpListenerVariables } from './udp-listener.variables.js';
|
|
5
|
+
/**
|
|
6
|
+
* UdpClient component
|
|
7
|
+
*/
|
|
8
|
+
export declare class UdpListenerComponent<TEvents extends UdpListenerComponent.Events = UdpListenerComponent.Events> extends IoClientBaseComponent<TEvents> {
|
|
9
|
+
readonly protocol: string;
|
|
10
|
+
socket: dgram.Socket & {
|
|
11
|
+
readonly isBroadcastEnabled: boolean;
|
|
12
|
+
};
|
|
13
|
+
protected _stopping?: boolean;
|
|
14
|
+
values: UdpListenerVariables;
|
|
15
|
+
protected _start(abortSignal: AbortSignal): Promise<void>;
|
|
16
|
+
protected _stop(): Promise<void>;
|
|
17
|
+
write(data: string | Buffer, port?: number, host?: string): void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* @namespace
|
|
21
|
+
*/
|
|
22
|
+
export declare namespace UdpListenerComponent {
|
|
23
|
+
interface Events extends IoClientBaseComponent.Events {
|
|
24
|
+
data: [data: Buffer, info: dgram.RemoteInfo];
|
|
25
|
+
write: [data: Buffer | string];
|
|
26
|
+
}
|
|
27
|
+
const Variables: typeof UdpListenerVariables;
|
|
28
|
+
type Variables = UdpListenerVariables;
|
|
29
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import dgram from 'node:dgram';
|
|
3
|
+
import { IoClientBaseComponent } from '@syncbridge/builtins';
|
|
4
|
+
import { Component, ServiceStatus } from '@syncbridge/common';
|
|
5
|
+
import { UdpListenerVariables } from './udp-listener.variables.js';
|
|
6
|
+
/**
|
|
7
|
+
* UdpClient component
|
|
8
|
+
*/
|
|
9
|
+
let UdpListenerComponent = class UdpListenerComponent extends IoClientBaseComponent {
|
|
10
|
+
protocol = 'udp';
|
|
11
|
+
_stopping;
|
|
12
|
+
async _start(abortSignal) {
|
|
13
|
+
await super._start(abortSignal);
|
|
14
|
+
this._stopping = false;
|
|
15
|
+
this.socket = dgram.createSocket('udp4');
|
|
16
|
+
let isBroadcastEnabled = false;
|
|
17
|
+
Object.defineProperty(this.socket, 'isBroadcastEnabled', {
|
|
18
|
+
get() {
|
|
19
|
+
return isBroadcastEnabled;
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
const oldSetBroadcast = this.socket.setBroadcast;
|
|
23
|
+
this.socket.setBroadcast = (value) => {
|
|
24
|
+
isBroadcastEnabled = value;
|
|
25
|
+
oldSetBroadcast.call(this.socket, value);
|
|
26
|
+
};
|
|
27
|
+
this.socket.on('listening', () => {
|
|
28
|
+
const { bindInterface, multicastInterface } = this.values;
|
|
29
|
+
if (this.values.broadcast) {
|
|
30
|
+
this.logger?.debug(`Broadcast mode enabled`);
|
|
31
|
+
this.socket.setBroadcast(true);
|
|
32
|
+
}
|
|
33
|
+
if (this.values.multicastGroups)
|
|
34
|
+
this.values.multicastGroups.forEach(group => {
|
|
35
|
+
this.logger?.debug(`Joining multicast group ${group}`);
|
|
36
|
+
this.socket.addMembership(group, multicastInterface);
|
|
37
|
+
});
|
|
38
|
+
const port = this.socket.address().port;
|
|
39
|
+
this.emit('listening', port);
|
|
40
|
+
this.logger?.info(`UDP socket listening on port ${port}` +
|
|
41
|
+
(bindInterface ? ` interface ${bindInterface}` : ''));
|
|
42
|
+
this.setStatus(ServiceStatus.started);
|
|
43
|
+
});
|
|
44
|
+
this.socket.on('message', (msg, info) => {
|
|
45
|
+
if (info.address === '127.0.0.1')
|
|
46
|
+
return;
|
|
47
|
+
// todo logger
|
|
48
|
+
// this.logger.debug(
|
|
49
|
+
// `Data received from ${colors.cyan(info.address + ':' + info.port)} (${msg.length} bytes)`,
|
|
50
|
+
// {
|
|
51
|
+
// host: info.address,
|
|
52
|
+
// port: info.port,
|
|
53
|
+
// size: msg.length,
|
|
54
|
+
// },
|
|
55
|
+
// );
|
|
56
|
+
const info2 = {
|
|
57
|
+
...info,
|
|
58
|
+
toString() {
|
|
59
|
+
return `${this.address}:${this.port}`;
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
this.emit('data', msg, info2);
|
|
63
|
+
});
|
|
64
|
+
this.socket.bind(this.values.port, this.values.bindInterface || '0.0.0.0');
|
|
65
|
+
}
|
|
66
|
+
async _stop() {
|
|
67
|
+
this._stopping = true;
|
|
68
|
+
await new Promise(resolve => {
|
|
69
|
+
this.socket.close(resolve);
|
|
70
|
+
this._stopping = false;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
write(data, port, host) {
|
|
74
|
+
port = port || this.values.port;
|
|
75
|
+
if (!host)
|
|
76
|
+
throw new Error('You must provide "host" variable to send message over UDP socket');
|
|
77
|
+
this.socket.send(data, port, host);
|
|
78
|
+
const info2 = {
|
|
79
|
+
address: host,
|
|
80
|
+
port: port,
|
|
81
|
+
size: data.length,
|
|
82
|
+
toString() {
|
|
83
|
+
return `${this.address}:${this.port}`;
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
this.emit('transmit', data, info2);
|
|
87
|
+
// todo logger
|
|
88
|
+
// if (this.socket.isBroadcastEnabled)
|
|
89
|
+
// this.logger.debug(
|
|
90
|
+
// `Broadcast message sent ${colors.cyan(host + ':' + port)} (${data.length} bytes)`,
|
|
91
|
+
// );
|
|
92
|
+
// else
|
|
93
|
+
// this.logger.debug(
|
|
94
|
+
// `Message sent to ${colors.cyan(host + ':' + port)} (${data.length} bytes)`,
|
|
95
|
+
// );
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
__decorate([
|
|
99
|
+
Component.UseVariables(),
|
|
100
|
+
__metadata("design:type", UdpListenerVariables)
|
|
101
|
+
], UdpListenerComponent.prototype, "values", void 0);
|
|
102
|
+
UdpListenerComponent = __decorate([
|
|
103
|
+
Component({
|
|
104
|
+
className: 'UdpListener',
|
|
105
|
+
displayName: 'UDP Listener',
|
|
106
|
+
description: 'UDP listener component',
|
|
107
|
+
tags: ['udp', 'server', 'connection'],
|
|
108
|
+
})
|
|
109
|
+
], UdpListenerComponent);
|
|
110
|
+
export { UdpListenerComponent };
|
|
111
|
+
/**
|
|
112
|
+
* @namespace
|
|
113
|
+
*/
|
|
114
|
+
(function (UdpListenerComponent) {
|
|
115
|
+
UdpListenerComponent.Variables = UdpListenerVariables;
|
|
116
|
+
})(UdpListenerComponent || (UdpListenerComponent = {}));
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IoClientBaseComponent } from '@syncbridge/builtins';
|
|
2
|
+
/**
|
|
3
|
+
* Variables
|
|
4
|
+
*/
|
|
5
|
+
export declare class UdpListenerVariables extends IoClientBaseComponent.Variables {
|
|
6
|
+
port: number;
|
|
7
|
+
broadcast?: boolean;
|
|
8
|
+
multicastGroups?: string[];
|
|
9
|
+
bindInterface?: string;
|
|
10
|
+
multicastInterface?: string;
|
|
11
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { IoClientBaseComponent } from '@syncbridge/builtins';
|
|
3
|
+
import { DefineVariable, VariableType } from '@syncbridge/common';
|
|
4
|
+
import { getInterfaceAddresses } from './udp-client.variables.js';
|
|
5
|
+
/**
|
|
6
|
+
* Variables
|
|
7
|
+
*/
|
|
8
|
+
export class UdpListenerVariables extends IoClientBaseComponent.Variables {
|
|
9
|
+
}
|
|
10
|
+
__decorate([
|
|
11
|
+
DefineVariable({
|
|
12
|
+
label: 'Port',
|
|
13
|
+
description: 'Port number of target listener',
|
|
14
|
+
required: true,
|
|
15
|
+
minValue: 1,
|
|
16
|
+
maxValue: 65535,
|
|
17
|
+
}),
|
|
18
|
+
__metadata("design:type", Number)
|
|
19
|
+
], UdpListenerVariables.prototype, "port", void 0);
|
|
20
|
+
__decorate([
|
|
21
|
+
DefineVariable({
|
|
22
|
+
label: 'Broadcast',
|
|
23
|
+
description: "Sets the SO_BROADCAST socket option. When set to true, UDP packets may be sent to a local interface's broadcast address.",
|
|
24
|
+
}),
|
|
25
|
+
__metadata("design:type", Boolean)
|
|
26
|
+
], UdpListenerVariables.prototype, "broadcast", void 0);
|
|
27
|
+
__decorate([
|
|
28
|
+
DefineVariable({
|
|
29
|
+
label: 'Multicast Groups',
|
|
30
|
+
description: 'Multicast groups to be joined',
|
|
31
|
+
type: VariableType.String,
|
|
32
|
+
isArray: true,
|
|
33
|
+
}),
|
|
34
|
+
__metadata("design:type", Array)
|
|
35
|
+
], UdpListenerVariables.prototype, "multicastGroups", void 0);
|
|
36
|
+
__decorate([
|
|
37
|
+
DefineVariable({
|
|
38
|
+
label: 'Bind Interface',
|
|
39
|
+
description: 'Interface address to bind to. If not specified, will bind to all available addresses',
|
|
40
|
+
type: VariableType.Enum,
|
|
41
|
+
enumValues: getInterfaceAddresses(),
|
|
42
|
+
}),
|
|
43
|
+
__metadata("design:type", String)
|
|
44
|
+
], UdpListenerVariables.prototype, "bindInterface", void 0);
|
|
45
|
+
__decorate([
|
|
46
|
+
DefineVariable({
|
|
47
|
+
label: 'Multicast Interface',
|
|
48
|
+
description: 'Interface address to bind for multicast packages',
|
|
49
|
+
type: VariableType.Enum,
|
|
50
|
+
enumValues: getInterfaceAddresses(),
|
|
51
|
+
}),
|
|
52
|
+
__metadata("design:type", String)
|
|
53
|
+
], UdpListenerVariables.prototype, "multicastInterface", void 0);
|
package/components.d.ts
ADDED
package/components.js
ADDED
package/constants.d.ts
ADDED
package/constants.js
ADDED
package/index.d.ts
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { makeExtensionPackage } from '@syncbridge/common';
|
|
2
|
+
import * as components from './components.js';
|
|
3
|
+
export { components };
|
|
4
|
+
export * from './components.js';
|
|
5
|
+
const cfg = makeExtensionPackage({
|
|
6
|
+
processors: [],
|
|
7
|
+
components: Object.values(components),
|
|
8
|
+
});
|
|
9
|
+
export default cfg;
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@syncbridge/net",
|
|
3
|
+
"version": "0.4.1",
|
|
4
|
+
"description": "SyncBridge builtin net (socket) extensions",
|
|
5
|
+
"author": "Panates Inc",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@ngrok/ngrok": "^1.7.0",
|
|
9
|
+
"@pinggy/pinggy": "^0.3.2",
|
|
10
|
+
"@serialport/bindings-interface": "^1.2.2",
|
|
11
|
+
"@sqb/connect": "^4.19.6",
|
|
12
|
+
"@sqb/oracle": "^4.21.1",
|
|
13
|
+
"@sqb/postgres": "^4.21.1",
|
|
14
|
+
"ansi-colors": "^4.1.3",
|
|
15
|
+
"backoff": "^2.5.0",
|
|
16
|
+
"date-fns": "^4.1.0",
|
|
17
|
+
"fast-tokenizer": "^1.9.0",
|
|
18
|
+
"file-stream-rotator": "^1.0.0",
|
|
19
|
+
"hl7v2": "^1.7.0",
|
|
20
|
+
"hl7v2-net": "^1.7.0",
|
|
21
|
+
"kafkajs": "^2.2.4",
|
|
22
|
+
"lightning-pool": "^4.12.0",
|
|
23
|
+
"node-events-async": "^1.5.0",
|
|
24
|
+
"oracledb": "^6.10.0",
|
|
25
|
+
"putil-varhelpers": "^1.7.0",
|
|
26
|
+
"reconnect-core": "^1.3.0",
|
|
27
|
+
"serialport": "^13.0.0"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@syncbridge/common": "^0.4.1",
|
|
31
|
+
"@syncbridge/builtins": "^0.4.1",
|
|
32
|
+
"@sqb/builder": ">=4.19.6 <5",
|
|
33
|
+
"@sqb/connect": ">=4.19.6 <5"
|
|
34
|
+
},
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./index.d.ts",
|
|
38
|
+
"default": "./index.js"
|
|
39
|
+
},
|
|
40
|
+
"./package.json": "./package.json"
|
|
41
|
+
},
|
|
42
|
+
"type": "module",
|
|
43
|
+
"module": "./index.js",
|
|
44
|
+
"types": "./index.d.ts",
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=20.0"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
}
|
|
51
|
+
}
|