@interopio/gateway-server 0.4.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +94 -0
- package/dist/gateway-ent.cjs +305 -0
- package/dist/gateway-ent.cjs.map +7 -0
- package/dist/gateway-ent.js +277 -0
- package/dist/gateway-ent.js.map +7 -0
- package/dist/index.cjs +1713 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.js +1682 -0
- package/dist/index.js.map +7 -0
- package/dist/metrics-rest.cjs +21440 -0
- package/dist/metrics-rest.cjs.map +7 -0
- package/dist/metrics-rest.js +21430 -0
- package/dist/metrics-rest.js.map +7 -0
- package/gateway-server.d.ts +69 -0
- package/package.json +66 -0
- package/readme.md +9 -0
- package/src/common/compose.ts +40 -0
- package/src/gateway/ent/config.ts +174 -0
- package/src/gateway/ent/index.ts +18 -0
- package/src/gateway/ent/logging.ts +89 -0
- package/src/gateway/ent/server.ts +34 -0
- package/src/gateway/metrics/rest.ts +20 -0
- package/src/gateway/ws/core.ts +90 -0
- package/src/index.ts +3 -0
- package/src/logger.ts +6 -0
- package/src/mesh/connections.ts +101 -0
- package/src/mesh/rest-directory/routes.ts +38 -0
- package/src/mesh/ws/broker/core.ts +163 -0
- package/src/mesh/ws/cluster/core.ts +107 -0
- package/src/mesh/ws/relays/core.ts +159 -0
- package/src/metrics/routes.ts +86 -0
- package/src/server/address.ts +47 -0
- package/src/server/cors.ts +311 -0
- package/src/server/exchange.ts +379 -0
- package/src/server/monitoring.ts +167 -0
- package/src/server/types.ts +69 -0
- package/src/server/ws-client-verify.ts +79 -0
- package/src/server.ts +316 -0
- package/src/utils.ts +10 -0
- package/types/gateway-ent.d.ts +212 -0
package/src/server.ts
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import {WebSocketServer} from 'ws';
|
|
2
|
+
import http from 'node:http';
|
|
3
|
+
import https from 'node:https';
|
|
4
|
+
import {SecureContextOptions} from 'node:tls';
|
|
5
|
+
import {AddressInfo} from 'node:net';
|
|
6
|
+
import {readFileSync} from 'node:fs';
|
|
7
|
+
import {AsyncLocalStorage} from 'node:async_hooks';
|
|
8
|
+
import {IOGateway} from '@interopio/gateway';
|
|
9
|
+
import wsGateway from './gateway/ws/core.js';
|
|
10
|
+
import NodeConnections from './mesh/connections.js';
|
|
11
|
+
import restDirectory from './mesh/rest-directory/routes.js';
|
|
12
|
+
import meshBroker from './mesh/ws/broker/core.js';
|
|
13
|
+
import meshRelays from './mesh/ws/relays/core.js';
|
|
14
|
+
import meshCluster from './mesh/ws/cluster/core.js';
|
|
15
|
+
import metrics from './metrics/routes.js';
|
|
16
|
+
import {compose} from './common/compose.js';
|
|
17
|
+
import {WebExchange, Middleware} from './server/types.js';
|
|
18
|
+
import {DefaultWebExchange, HttpServerRequest, HttpServerResponse} from './server/exchange.js';
|
|
19
|
+
import {socketKey} from './utils.js';
|
|
20
|
+
import getLogger from './logger.js';
|
|
21
|
+
import {localIp, portRange} from './server/address.js';
|
|
22
|
+
import * as monitoring from './server/monitoring.js';
|
|
23
|
+
import {acceptsOrigin, ProcessedOriginFilters, regexifyOriginFilters} from './server/ws-client-verify.js';
|
|
24
|
+
import {GatewayServer} from '../gateway-server';
|
|
25
|
+
import cors from './server/cors.ts';
|
|
26
|
+
|
|
27
|
+
const logger = getLogger('app');
|
|
28
|
+
|
|
29
|
+
function secureContextOptions(ssl: GatewayServer.SslConfig): SecureContextOptions {
|
|
30
|
+
const options: SecureContextOptions = {};
|
|
31
|
+
if (ssl.key) options.key = readFileSync(ssl.key);
|
|
32
|
+
if (ssl.cert) options.cert = readFileSync(ssl.cert);
|
|
33
|
+
if (ssl.ca) options.ca = readFileSync(ssl.ca);
|
|
34
|
+
return options;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type RequestHandler = (req: http.IncomingMessage, res: http.ServerResponse) => void;
|
|
38
|
+
|
|
39
|
+
function createListener(middleware: Middleware<HttpServerRequest, HttpServerResponse>,
|
|
40
|
+
routes: Map<string, RouteInfo>) {
|
|
41
|
+
const storage = new AsyncLocalStorage();
|
|
42
|
+
|
|
43
|
+
const listener = compose<WebExchange<HttpServerRequest, HttpServerResponse>>(
|
|
44
|
+
async ({response}, next) => {
|
|
45
|
+
response.headers.set('server', 'gateway-server');
|
|
46
|
+
await next();
|
|
47
|
+
},
|
|
48
|
+
...cors({
|
|
49
|
+
origins: {allow: [/http:\/\/localhost(:\d+)?/]},
|
|
50
|
+
methods: {allow: ['GET', 'HEAD', 'POST', 'DELETE']},
|
|
51
|
+
headers: {allow: '*'},
|
|
52
|
+
credentials: {allow: true}
|
|
53
|
+
}),
|
|
54
|
+
...middleware,
|
|
55
|
+
async ({request, response}, next) => {
|
|
56
|
+
if (request.method === 'GET' && request.path === '/health') {
|
|
57
|
+
response.statusCode = 200;
|
|
58
|
+
response._res.end(http.STATUS_CODES[200]);
|
|
59
|
+
} else {
|
|
60
|
+
await next();
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
async ({request, response}, next) => {
|
|
64
|
+
if (request.method === 'GET' && request.path === '/') {
|
|
65
|
+
response._res.end(`io.Gateway Server`);
|
|
66
|
+
} else {
|
|
67
|
+
await next();
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
async ({request, response}, _next) => {
|
|
71
|
+
const route = routes.get(request.path);
|
|
72
|
+
if (route) {
|
|
73
|
+
response.statusCode = 426;
|
|
74
|
+
response._res
|
|
75
|
+
.appendHeader('Upgrade', 'websocket')
|
|
76
|
+
.appendHeader('Connection', 'Upgrade')
|
|
77
|
+
.appendHeader('Content-Type', 'text/plain');
|
|
78
|
+
response._res.end(`This service [${request.path}] requires use of the websocket protocol.`);
|
|
79
|
+
} else {
|
|
80
|
+
response.statusCode = 404;
|
|
81
|
+
response._res.end(http.STATUS_CODES[404]);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
return (request: http.IncomingMessage, response: http.ServerResponse) => {
|
|
87
|
+
const exchange = new DefaultWebExchange(new HttpServerRequest(request), new HttpServerResponse(response));
|
|
88
|
+
return storage.run(exchange, async () => {
|
|
89
|
+
if (logger.enabledFor('debug')) {
|
|
90
|
+
const socket = exchange.request._req.socket;
|
|
91
|
+
if (logger.enabledFor('debug')) {
|
|
92
|
+
logger.debug(`received ${exchange.method} request for ${exchange.path} from ${socket.remoteAddress}:${socket.remotePort}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return await listener(exchange);
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function promisify<T>(fn: (callback?: (err?: Error) => void) => T): Promise<T> {
|
|
101
|
+
return new Promise<T>((resolve, reject) => {
|
|
102
|
+
const r = fn((err?: Error) => {
|
|
103
|
+
if (err) {
|
|
104
|
+
reject(err);
|
|
105
|
+
} else {
|
|
106
|
+
resolve(r);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
type RouteInfo = {
|
|
113
|
+
readonly default?: boolean,
|
|
114
|
+
readonly ping?: number,
|
|
115
|
+
readonly maxConnections?: number
|
|
116
|
+
readonly originFilters?: ProcessedOriginFilters
|
|
117
|
+
readonly factory: (server: { endpoint: string, wss: WebSocketServer }) => Promise<{
|
|
118
|
+
info?: string,
|
|
119
|
+
close?: () => Promise<void>
|
|
120
|
+
}>,
|
|
121
|
+
// set later in listening
|
|
122
|
+
wss?: WebSocketServer,
|
|
123
|
+
close?: () => Promise<void>
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function memoryMonitor(config?: GatewayServer.ServerConfig['memory']) {
|
|
127
|
+
if (config) {
|
|
128
|
+
return monitoring.start({
|
|
129
|
+
memoryLimit: config.memory_limit,
|
|
130
|
+
dumpLocation: config.dump_location,
|
|
131
|
+
dumpPrefix: config.dump_prefix,
|
|
132
|
+
reportInterval: config.report_interval,
|
|
133
|
+
maxBackups: config.max_backups
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function regexAwareReplacer<T>(_key: string, value: T): string | T {
|
|
139
|
+
return value instanceof RegExp ? value.toString() : value;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export const Factory = async (options: GatewayServer.ServerConfig): Promise<GatewayServer.Server> => {
|
|
143
|
+
const ssl = options.ssl;
|
|
144
|
+
const createServer = ssl ? (options: http.ServerOptions, handler: RequestHandler) => https.createServer({...options, ...secureContextOptions(ssl)}, handler) : (options: http.ServerOptions, handler: RequestHandler) => http.createServer(options, handler);
|
|
145
|
+
const monitor = memoryMonitor(options.memory);
|
|
146
|
+
const middleware: Middleware<HttpServerRequest, HttpServerResponse> = [];
|
|
147
|
+
const routes: Map<string, RouteInfo> = new Map<string, RouteInfo>();
|
|
148
|
+
const gw = IOGateway.Factory({...options.gateway});
|
|
149
|
+
if (options.gateway) {
|
|
150
|
+
const config = options.gateway;
|
|
151
|
+
routes.set(config.route ?? '/', {
|
|
152
|
+
default: config.route === undefined,
|
|
153
|
+
ping: options.gateway.ping,
|
|
154
|
+
factory: wsGateway.bind(gw),
|
|
155
|
+
maxConnections: config.limits?.max_connections,
|
|
156
|
+
originFilters: regexifyOriginFilters(config.origins)
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
if (options.mesh) {
|
|
160
|
+
const connections = new NodeConnections(options.mesh.timeout ?? 60000);
|
|
161
|
+
middleware.push(...restDirectory(connections));
|
|
162
|
+
const ping = options.mesh.ping ?? 30000;
|
|
163
|
+
routes.set('/broker', {factory: meshBroker, ping: ping});
|
|
164
|
+
routes.set('/cluster', {factory: meshCluster, ping: ping});
|
|
165
|
+
routes.set('/relays', {factory: meshRelays, ping: ping});
|
|
166
|
+
}
|
|
167
|
+
if (options.metrics) {
|
|
168
|
+
middleware.push(...(await metrics(options.metrics)));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const ports = portRange(options.port ?? 0);
|
|
172
|
+
const host = options.host;
|
|
173
|
+
const serverP: Promise<http.Server> = new Promise((resolve, reject) => {
|
|
174
|
+
const onSocketError = (err: Error) => logger.error(`socket error: ${err}`, err);
|
|
175
|
+
const server = createServer(
|
|
176
|
+
{},
|
|
177
|
+
createListener(middleware, routes));
|
|
178
|
+
|
|
179
|
+
server.on('error', (e: Error) => {
|
|
180
|
+
if (e['code'] === 'EADDRINUSE') {
|
|
181
|
+
logger.debug(`port ${e['port']} already in use on address ${e['address']}`);
|
|
182
|
+
const {value: port} = ports.next();
|
|
183
|
+
if (port) {
|
|
184
|
+
logger.info(`retry starting server on port ${port} and host ${host ?? '<unspecified>'}`);
|
|
185
|
+
server.close();
|
|
186
|
+
server.listen(port, host);
|
|
187
|
+
} else {
|
|
188
|
+
logger.warn(`all configured port(s) ${options.port} are in use. closing...`);
|
|
189
|
+
server.close();
|
|
190
|
+
reject(e);
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
logger.error(`server error: ${e.message}`, e);
|
|
194
|
+
reject(e);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
server
|
|
198
|
+
.on('listening', async () => {
|
|
199
|
+
const info = server.address() as AddressInfo;
|
|
200
|
+
for (const [path, route] of routes) {
|
|
201
|
+
try {
|
|
202
|
+
logger.info(`creating ws server for [${path}]. max connections: ${route.maxConnections ?? '<unlimited>'}, origin filters: ${route.originFilters ? JSON.stringify(route.originFilters, regexAwareReplacer) : '<none>'}`);
|
|
203
|
+
const wss = new WebSocketServer({noServer: true});
|
|
204
|
+
const endpoint = `${ssl ? 'wss' : 'ws'}://${localIp}:${info.port}${path}`;
|
|
205
|
+
const handler = await route.factory({endpoint, wss});
|
|
206
|
+
const pingInterval = route.ping;
|
|
207
|
+
if (pingInterval) {
|
|
208
|
+
const pingIntervalId = setInterval(() => {
|
|
209
|
+
for (const client of wss.clients) {
|
|
210
|
+
if (client['connected'] === false) {
|
|
211
|
+
client.terminate();
|
|
212
|
+
}
|
|
213
|
+
client['connected'] = false;
|
|
214
|
+
client.ping();
|
|
215
|
+
}
|
|
216
|
+
}, pingInterval);
|
|
217
|
+
wss.on('close', () => {
|
|
218
|
+
clearInterval(pingIntervalId);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
route.wss = wss;
|
|
222
|
+
route.close = handler.close?.bind(handler);
|
|
223
|
+
} catch (e) {
|
|
224
|
+
logger.warn(`failed to init route ${path}`, e);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
logger.info(`http server listening on ${info.address}:${info.port}`);
|
|
228
|
+
resolve(server);
|
|
229
|
+
});
|
|
230
|
+
server
|
|
231
|
+
.on('upgrade', (req, socket, head) => {
|
|
232
|
+
socket.addListener('error', onSocketError);
|
|
233
|
+
try {
|
|
234
|
+
const request = new HttpServerRequest(req);
|
|
235
|
+
const path = request.path ?? '/';
|
|
236
|
+
const route = (routes.get(path) ?? Array.from(routes.values()).find(route => {
|
|
237
|
+
if (path === '/' && route.default === true) {
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
}));
|
|
241
|
+
const host = request.host;
|
|
242
|
+
const info = socketKey(request.socket);
|
|
243
|
+
if (route?.wss) {
|
|
244
|
+
socket.removeListener('error', onSocketError);
|
|
245
|
+
const wss = route.wss;
|
|
246
|
+
if (route.maxConnections !== undefined && wss.clients?.size >= route.maxConnections) {
|
|
247
|
+
logger.warn(`${info} dropping ws connection request from ${host} on ${path}. max connections exceeded.`);
|
|
248
|
+
socket.destroy();
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const origin = request.headers['origin'];
|
|
253
|
+
if (!acceptsOrigin(origin, route.originFilters)) {
|
|
254
|
+
logger.info(`${info} dropping ws connection request from ${host} on ${path}. origin ${origin ?? '<missing>'}`);
|
|
255
|
+
socket.destroy();
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (logger.enabledFor('debug')) {
|
|
259
|
+
logger.debug(`${info} accepted new ws connection request from ${host} on ${path}`);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
263
|
+
ws.on('pong', () => ws['connected'] = true);
|
|
264
|
+
ws.on('ping', () => {
|
|
265
|
+
});
|
|
266
|
+
wss.emit('connection', ws, req);
|
|
267
|
+
});
|
|
268
|
+
} else {
|
|
269
|
+
logger.warn(`${info} rejected upgrade request from ${host} on ${path}`);
|
|
270
|
+
socket.destroy();
|
|
271
|
+
}
|
|
272
|
+
} catch (err) {
|
|
273
|
+
logger.error(`upgrade error: ${err}`, err);
|
|
274
|
+
}
|
|
275
|
+
})
|
|
276
|
+
.on('close', async () => {
|
|
277
|
+
logger.info(`http server closed.`);
|
|
278
|
+
});
|
|
279
|
+
try {
|
|
280
|
+
const {value: port} = ports.next();
|
|
281
|
+
server.listen(port, host);
|
|
282
|
+
} catch (e) {
|
|
283
|
+
logger.error(`error starting web socket server`, e);
|
|
284
|
+
reject(e instanceof Error ? e : new Error(`listen failed: ${e}`));
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
const server = await serverP;
|
|
288
|
+
return new class implements GatewayServer.Server {
|
|
289
|
+
readonly gateway = gw;
|
|
290
|
+
|
|
291
|
+
async close(): Promise<void> {
|
|
292
|
+
for (const [path, route] of routes) {
|
|
293
|
+
try {
|
|
294
|
+
if (route.close) {
|
|
295
|
+
await route.close();
|
|
296
|
+
}
|
|
297
|
+
logger.info(`stopping ws server for [${path}]. clients: ${route.wss?.clients?.size ?? 0}`);
|
|
298
|
+
route.wss?.clients?.forEach(client => {
|
|
299
|
+
client.terminate();
|
|
300
|
+
});
|
|
301
|
+
route.wss?.close();
|
|
302
|
+
} catch (e) {
|
|
303
|
+
logger.warn(`error closing route ${path}`, e);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
await promisify(cb => {
|
|
307
|
+
server.closeAllConnections();
|
|
308
|
+
server.close(cb);
|
|
309
|
+
});
|
|
310
|
+
if (monitor) {
|
|
311
|
+
await monitoring.stop(monitor);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
type LogLevel
|
|
2
|
+
= "trace"
|
|
3
|
+
| "debug"
|
|
4
|
+
| "info"
|
|
5
|
+
| "warn"
|
|
6
|
+
| "error"
|
|
7
|
+
| "fatal"
|
|
8
|
+
| "report";
|
|
9
|
+
|
|
10
|
+
interface LogInfo {
|
|
11
|
+
time: Date;
|
|
12
|
+
level: LogLevel;
|
|
13
|
+
namespace?: string;
|
|
14
|
+
file?: string;
|
|
15
|
+
line?: number;
|
|
16
|
+
stacktrace?: Error
|
|
17
|
+
message: string
|
|
18
|
+
output: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function configure_logging(config: { level: LogLevel, appender: (logInfo: LogInfo) => void, disabled_action_groups?: string[] }): void;
|
|
22
|
+
|
|
23
|
+
type AuthenticatorConfig = {
|
|
24
|
+
timeout?: number // defaults to 5000
|
|
25
|
+
"max-pending-requests"?: number // defaults to 20000
|
|
26
|
+
}
|
|
27
|
+
type AuthenticationRequest
|
|
28
|
+
= {method: 'secret', login: string, secret: string}
|
|
29
|
+
| {method: 'access-token', token: string};
|
|
30
|
+
type AuthenticationResponse
|
|
31
|
+
= {type: 'success', user: string, login?: string}
|
|
32
|
+
| {type: 'continue', authentication: {token?: string}}
|
|
33
|
+
| { type: 'failure', message?: string };
|
|
34
|
+
type AuthenticatorImpl = (request: AuthenticationRequest) => Promise<AuthenticationResponse>
|
|
35
|
+
|
|
36
|
+
type MetricsPublisherConfig = {
|
|
37
|
+
filters?: {
|
|
38
|
+
"non-matched": 'whitelist' | 'blacklist'
|
|
39
|
+
publishers: [{
|
|
40
|
+
publisher: Record<string, string | RegExp>,
|
|
41
|
+
metrics: {
|
|
42
|
+
blacklist?: (string | RegExp)[],
|
|
43
|
+
whitelist?: (string | RegExp)[]
|
|
44
|
+
}
|
|
45
|
+
}]
|
|
46
|
+
}
|
|
47
|
+
heartbeats?: number // defaults to 1000
|
|
48
|
+
buffer_size?: number; // defaults to 10000
|
|
49
|
+
conflation?: {
|
|
50
|
+
max_size?: number // defaults to 0
|
|
51
|
+
interval?: number // defaults to 1000
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Gateway Config
|
|
57
|
+
*/
|
|
58
|
+
type GatewayConfig = {
|
|
59
|
+
ip?: string; // defaults to '0.0.0.0'
|
|
60
|
+
port?: number | string; // defaults to 3434
|
|
61
|
+
route?: string;
|
|
62
|
+
authentication?: {
|
|
63
|
+
token_ttl?: number
|
|
64
|
+
default?: string // defaults to 'basic'
|
|
65
|
+
available?: string[] // defaults to ['basic']
|
|
66
|
+
win?: AuthenticatorConfig
|
|
67
|
+
basic?: AuthenticatorConfig & {
|
|
68
|
+
ttl?: number
|
|
69
|
+
}
|
|
70
|
+
} | (Partial<Record<string, (AuthenticatorConfig & {authenticator: AuthenticatorImpl})>>);
|
|
71
|
+
metrics?: {
|
|
72
|
+
publishers?: ('file' | 'raw' | 'rest' | 'kafka' | {
|
|
73
|
+
startup?: () => Promise<unknown>,
|
|
74
|
+
function: (value: unknown) => Promise<void> | void,
|
|
75
|
+
cleanup?: (arg?: unknown) => Promise<void> | void,
|
|
76
|
+
context?: unknown,
|
|
77
|
+
configuration?: MetricsPublisherConfig & {
|
|
78
|
+
'split-size'?: number // defaults to 1
|
|
79
|
+
}
|
|
80
|
+
})[];
|
|
81
|
+
file?: MetricsPublisherConfig & {
|
|
82
|
+
location: string;
|
|
83
|
+
append?: boolean; // defaults to false
|
|
84
|
+
'skip-status'?: boolean // defaults to false
|
|
85
|
+
conflation: MetricsPublisherConfig['conflation'] & {
|
|
86
|
+
'max-datapoints-repo': number // defaults to 50
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
raw?: {
|
|
90
|
+
location: string
|
|
91
|
+
}
|
|
92
|
+
rest?: MetricsPublisherConfig & {
|
|
93
|
+
endpoint: string;
|
|
94
|
+
authentication?: false | {
|
|
95
|
+
user?: string
|
|
96
|
+
password?: string,
|
|
97
|
+
path?: string
|
|
98
|
+
};
|
|
99
|
+
"user-agent"?: string // defaults to "metrics-rest/0.1.x"
|
|
100
|
+
headers?: { [key:string]: string };
|
|
101
|
+
timeout?: number; //defaults to 1000
|
|
102
|
+
conflation?: MetricsPublisherConfig['conflation'] & {
|
|
103
|
+
"max-datapoints-repo"?: number // defaults 50
|
|
104
|
+
};
|
|
105
|
+
client?: {
|
|
106
|
+
sspi?: boolean //
|
|
107
|
+
"max-in-flight"?: number //
|
|
108
|
+
"log-level"?: LogLevel // defaults to warn
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
kafka: {
|
|
112
|
+
topic: string;
|
|
113
|
+
"publisher-config": object;
|
|
114
|
+
conflation?: MetricsPublisherConfig['conflation'] & {
|
|
115
|
+
"max-datapoints-repo"?: number // defaults 50
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
filters?: MetricsPublisherConfig['filters']
|
|
119
|
+
identity?: {
|
|
120
|
+
system?: string // defaults to Glue
|
|
121
|
+
service?: string // defaults to Gateway
|
|
122
|
+
};
|
|
123
|
+
interop?: {
|
|
124
|
+
enabled?: boolean;
|
|
125
|
+
invoke: {
|
|
126
|
+
filters: {
|
|
127
|
+
methods: [{
|
|
128
|
+
name: (string | RegExp)
|
|
129
|
+
arguments: {
|
|
130
|
+
whitelist: (string | RegExp)[]
|
|
131
|
+
blacklist: (string | RegExp)[]
|
|
132
|
+
}
|
|
133
|
+
}]
|
|
134
|
+
"non-matched": 'whitelist' | 'blacklist'
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
cluster?: {
|
|
140
|
+
enabled?: boolean
|
|
141
|
+
configuration?: {
|
|
142
|
+
node_id?: string
|
|
143
|
+
},
|
|
144
|
+
type: 'p2p' | 'broker',
|
|
145
|
+
p2p?: {
|
|
146
|
+
directory: {
|
|
147
|
+
type: 'static' | 'rest',
|
|
148
|
+
members?: {node: string, endpoint: string}[],
|
|
149
|
+
config?: {
|
|
150
|
+
directory_uri: string,
|
|
151
|
+
announce_interval?: number, // defaults to 10000
|
|
152
|
+
authentication?: 'no-auth' | 'kerberos' | 'negotiate'
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
binding?: {
|
|
156
|
+
port?: number //defaults to 0
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
broker?: {
|
|
160
|
+
endpoint?: string
|
|
161
|
+
},
|
|
162
|
+
embedded_broker?: {
|
|
163
|
+
enabled?: boolean,
|
|
164
|
+
route?: string // defaults to /mesh-broker
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
limits?: {
|
|
168
|
+
max_connections?: number;
|
|
169
|
+
large_msg_threshold?: number; // 20000
|
|
170
|
+
node_buffer_size?: number; // 20000
|
|
171
|
+
}
|
|
172
|
+
security?: {
|
|
173
|
+
origin_filters?: {
|
|
174
|
+
non_matched: string
|
|
175
|
+
missing: string
|
|
176
|
+
blacklist?: []
|
|
177
|
+
whitelist?: []
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
memory?: {
|
|
181
|
+
memory_limit?: number, // defaults to 1073741824 bytes (1GB)
|
|
182
|
+
dump_location?: string, // defaults to current directory
|
|
183
|
+
dump_prefix?: string, // defaults to 'Heap'
|
|
184
|
+
report_interval?: number, // report schedule interval in ms. defaults to 600000 ms (10 min)
|
|
185
|
+
max_backups?: number, // defaults to 10
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
interface Gateway {
|
|
190
|
+
start(): Promise<Gateway>;
|
|
191
|
+
|
|
192
|
+
stop(): Promise<Gateway>;
|
|
193
|
+
|
|
194
|
+
info(): { endpoint: string };
|
|
195
|
+
|
|
196
|
+
connect(cb: (client: GatewayClient, msg: GatewayMessage) => void): Promise<GatewayClient>;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
interface GatewayClient {
|
|
200
|
+
send(message: GatewayMessage): void;
|
|
201
|
+
|
|
202
|
+
disconnect(): Promise<boolean>;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
interface GatewayMessage {
|
|
206
|
+
type: string
|
|
207
|
+
domain: string
|
|
208
|
+
destination: string
|
|
209
|
+
peer_id: string
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function create(config: GatewayConfig): Gateway;
|