@elysiumjs/core 0.4.0 → 0.4.2
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/package.json +6 -9
- package/src/app.ts +31 -1
- package/src/database.ts +0 -1
- package/src/http.ts +5 -5
- package/src/module.ts +11 -5
- package/src/redis.ts +4 -3
- package/src/wamp.ts +292 -147
package/package.json
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elysiumjs/core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "A super-charged web framework for Bun, built on top of ElysiaJS.",
|
|
6
6
|
"private": false,
|
|
7
|
-
"author":
|
|
8
|
-
"name": "Axel Nana",
|
|
9
|
-
"email": "axel.nana@workbud.com"
|
|
10
|
-
},
|
|
7
|
+
"author": "Workbud Technologies Inc.",
|
|
11
8
|
"repository": {
|
|
12
9
|
"type": "git",
|
|
13
10
|
"url": "https://github.com/Workerly/elysium"
|
|
@@ -26,9 +23,9 @@
|
|
|
26
23
|
"module": "index.ts",
|
|
27
24
|
"type": "module",
|
|
28
25
|
"dependencies": {
|
|
29
|
-
"@elysiajs/swagger": "^1.
|
|
30
|
-
"cache-manager": "^6.4.
|
|
31
|
-
"cacheable": "^1.
|
|
26
|
+
"@elysiajs/swagger": "^1.3.0",
|
|
27
|
+
"cache-manager": "^6.4.3",
|
|
28
|
+
"cacheable": "^1.9.0",
|
|
32
29
|
"drizzle-orm": "0.43.1-4aa795a",
|
|
33
30
|
"elysia": "latest",
|
|
34
31
|
"radash": "^12.1.0",
|
|
@@ -37,7 +34,7 @@
|
|
|
37
34
|
},
|
|
38
35
|
"devDependencies": {
|
|
39
36
|
"@ianvs/prettier-plugin-sort-imports": "^4.4.1",
|
|
40
|
-
"type-fest": "^4.
|
|
37
|
+
"type-fest": "^4.41.0",
|
|
41
38
|
"@types/bun": "latest"
|
|
42
39
|
},
|
|
43
40
|
"peerDependencies": {
|
package/src/app.ts
CHANGED
|
@@ -19,6 +19,7 @@ import type { DatabaseConnectionProps } from './database';
|
|
|
19
19
|
import type { Route } from './http';
|
|
20
20
|
import type { ModuleClass } from './module';
|
|
21
21
|
import type { RedisConnectionProps } from './redis';
|
|
22
|
+
import type { WampClientProps } from './wamp';
|
|
22
23
|
|
|
23
24
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
24
25
|
import { parseArgs } from 'node:util';
|
|
@@ -35,6 +36,7 @@ import { applyMiddlewares } from './middleware';
|
|
|
35
36
|
import { Redis } from './redis';
|
|
36
37
|
import { Service } from './service';
|
|
37
38
|
import { deepMerge, Symbols } from './utils';
|
|
39
|
+
import { Wamp } from './wamp';
|
|
38
40
|
|
|
39
41
|
/**
|
|
40
42
|
* An application plugin, consisting of a function that returns an Elysia instance.
|
|
@@ -65,6 +67,21 @@ export type AppProps = {
|
|
|
65
67
|
port?: number;
|
|
66
68
|
};
|
|
67
69
|
|
|
70
|
+
/**
|
|
71
|
+
* The wamp client configuration for the app.
|
|
72
|
+
*/
|
|
73
|
+
wamp?: {
|
|
74
|
+
/**
|
|
75
|
+
* The default connection name.
|
|
76
|
+
*/
|
|
77
|
+
default: string;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The list of connections.
|
|
81
|
+
*/
|
|
82
|
+
connections: Record<string, WampClientProps>;
|
|
83
|
+
};
|
|
84
|
+
|
|
68
85
|
/**
|
|
69
86
|
* The list of modules provided the app.
|
|
70
87
|
*/
|
|
@@ -217,7 +234,10 @@ export abstract class Application extends InteractsWithConsole {
|
|
|
217
234
|
|
|
218
235
|
Service.instance('elysium.app', this);
|
|
219
236
|
|
|
220
|
-
const { database, redis } = Reflect.getMetadata(
|
|
237
|
+
const { database, redis, wamp } = Reflect.getMetadata(
|
|
238
|
+
Symbols.app,
|
|
239
|
+
this.constructor
|
|
240
|
+
) as AppProps;
|
|
221
241
|
|
|
222
242
|
if (redis) {
|
|
223
243
|
for (const connectionName in redis.connections) {
|
|
@@ -239,6 +259,16 @@ export abstract class Application extends InteractsWithConsole {
|
|
|
239
259
|
}
|
|
240
260
|
}
|
|
241
261
|
|
|
262
|
+
if (wamp) {
|
|
263
|
+
for (const connectionName in wamp.connections) {
|
|
264
|
+
Wamp.registerConnection(connectionName, wamp.connections[connectionName]);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (Wamp.connectionExists(wamp.default)) {
|
|
268
|
+
Wamp.setDefaultConnection(wamp.default);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
242
272
|
// Run the application
|
|
243
273
|
this.run()
|
|
244
274
|
.then(() => Event.emit('elysium:app:launched', this, this))
|
package/src/database.ts
CHANGED
|
@@ -119,7 +119,6 @@ export class DatabaseCache extends DrizzleCache {
|
|
|
119
119
|
isTag: boolean,
|
|
120
120
|
config?: CacheConfig
|
|
121
121
|
): Promise<void> {
|
|
122
|
-
console.log({ key, response, tables, isTag, config });
|
|
123
122
|
await this.#cache.set(key, response, (config?.ex ?? this.globalTtl) * 1000);
|
|
124
123
|
for (const table of tables) {
|
|
125
124
|
const keys = this.usedTablesPerKey[table];
|
package/src/http.ts
CHANGED
|
@@ -334,7 +334,7 @@ export namespace Http {
|
|
|
334
334
|
return function (target: Class<any>) {
|
|
335
335
|
async function handleHttp(): Promise<ElysiaApp> {
|
|
336
336
|
// TODO: Use the logger service here
|
|
337
|
-
console.log(`Registering HTTP
|
|
337
|
+
console.log(`Registering HTTP controller for ${props.path} using ${target.name}`);
|
|
338
338
|
await nextTick();
|
|
339
339
|
|
|
340
340
|
props = assign({ path: '/', scope: HttpControllerScope.SERVER, tags: [] }, props);
|
|
@@ -346,9 +346,9 @@ export namespace Http {
|
|
|
346
346
|
|
|
347
347
|
if (props.scope === HttpControllerScope.SERVER) {
|
|
348
348
|
const controller = Service.make(target);
|
|
349
|
-
app.
|
|
349
|
+
app.resolve({ as: 'local' }, () => ({ controller: () => controller }));
|
|
350
350
|
} else if (props.scope === HttpControllerScope.REQUEST) {
|
|
351
|
-
app.
|
|
351
|
+
app.resolve({ as: 'local' }, () => ({ controller: () => Service.make(target) }));
|
|
352
352
|
}
|
|
353
353
|
|
|
354
354
|
const onRequest = Reflect.getMetadata('http:onRequest', target) ?? {};
|
|
@@ -480,7 +480,7 @@ export namespace Http {
|
|
|
480
480
|
return await handler(...(await getParameters(c)));
|
|
481
481
|
}
|
|
482
482
|
|
|
483
|
-
throw c.
|
|
483
|
+
throw c.status(400, 'Invalid request body');
|
|
484
484
|
};
|
|
485
485
|
}
|
|
486
486
|
|
|
@@ -503,7 +503,7 @@ export namespace Http {
|
|
|
503
503
|
config: {},
|
|
504
504
|
async transform(c) {
|
|
505
505
|
if (isValidator && !(await route.body!.validator!.authorize(c as Context))) {
|
|
506
|
-
throw c.
|
|
506
|
+
throw c.status(401, 'Unauthorized');
|
|
507
507
|
}
|
|
508
508
|
|
|
509
509
|
return executeMiddlewareChain(mi, c, 'onTransform');
|
package/src/module.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
|
|
15
15
|
import type { Class } from 'type-fest';
|
|
16
|
-
import type { Route } from './http';
|
|
16
|
+
import type { ElysiaApp, Route } from './http';
|
|
17
17
|
|
|
18
18
|
import { Elysia } from 'elysia';
|
|
19
19
|
import { assign } from 'radash';
|
|
@@ -30,6 +30,12 @@ export type ModuleProps = {
|
|
|
30
30
|
* The list of controllers provided by the module.
|
|
31
31
|
*/
|
|
32
32
|
controllers?: Class<any>[];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The base path for all the controllers registered by this module.
|
|
36
|
+
* This value will be prefixed to each controllers path.
|
|
37
|
+
*/
|
|
38
|
+
prefix?: Route;
|
|
33
39
|
};
|
|
34
40
|
|
|
35
41
|
/**
|
|
@@ -52,15 +58,15 @@ export abstract class Module {
|
|
|
52
58
|
*/
|
|
53
59
|
public static register(options: ModuleProps = {}) {
|
|
54
60
|
return function (target: ModuleClass) {
|
|
55
|
-
async function handleModule(m: Module): Promise<
|
|
61
|
+
async function handleModule(m: Module): Promise<ElysiaApp> {
|
|
56
62
|
// TODO: Use the logger service here
|
|
57
63
|
console.log(`Registering module ${target.name}`);
|
|
58
64
|
await nextTick();
|
|
59
65
|
|
|
60
66
|
const props = assign({ controllers: [] }, options) as Required<ModuleProps>;
|
|
61
67
|
|
|
62
|
-
const plugin:
|
|
63
|
-
plugin.
|
|
68
|
+
const plugin: ElysiaApp = new Elysia({ name: target.name, prefix: options.prefix });
|
|
69
|
+
plugin.resolve({ as: 'local' }, () => ({ module: m }));
|
|
64
70
|
|
|
65
71
|
const middlewares = Reflect.getMetadata(Symbols.middlewares, target) ?? [];
|
|
66
72
|
applyMiddlewares(middlewares, plugin);
|
|
@@ -70,7 +76,7 @@ export abstract class Module {
|
|
|
70
76
|
if (app === undefined) {
|
|
71
77
|
// TODO: Use the logger service here
|
|
72
78
|
console.error(
|
|
73
|
-
`Invalid controller class ${controller.name} registered in module ${target.name}. Ensure that you either used the @
|
|
79
|
+
`Invalid controller class ${controller.name} registered in module ${target.name}. Ensure that you either used the @Http.controller(), the @Websocket.controller(), or the @Wamp.controller() decorators on the class.`
|
|
74
80
|
);
|
|
75
81
|
process.exit(1);
|
|
76
82
|
} else {
|
package/src/redis.ts
CHANGED
|
@@ -342,7 +342,7 @@ export namespace Redis {
|
|
|
342
342
|
if (!Service.exists(getConnectionName(name))) {
|
|
343
343
|
// TODO: Use logger service here
|
|
344
344
|
console.error(
|
|
345
|
-
`No connection with name ${name} found. Please make sure to register the connection before using it.`
|
|
345
|
+
`No Redis connection with name ${name} found. Please make sure to register the connection before using it.`
|
|
346
346
|
);
|
|
347
347
|
process.exit(1);
|
|
348
348
|
}
|
|
@@ -352,11 +352,12 @@ export namespace Redis {
|
|
|
352
352
|
|
|
353
353
|
/**
|
|
354
354
|
* Creates and registers a new redis connection.
|
|
355
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
356
355
|
*
|
|
357
356
|
* This will make the registered connection available for dependency injection with
|
|
358
357
|
* the key `redis.connection.{name}`, where `{name}` is replaced with the given name.
|
|
359
358
|
*
|
|
359
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
360
|
+
*
|
|
360
361
|
* @param name The name of the connection.
|
|
361
362
|
* @param config The configuration for the redis connection.
|
|
362
363
|
* @returns The newly created and registered redis connection.
|
|
@@ -364,7 +365,7 @@ export namespace Redis {
|
|
|
364
365
|
export const registerConnection = (name: string, config: RedisConnectionProps) => {
|
|
365
366
|
if (Service.exists(getConnectionName(name))) {
|
|
366
367
|
// TODO: Use logger service here
|
|
367
|
-
console.error(`A connection with the name ${name} has already been registered.`);
|
|
368
|
+
console.error(`A Redis connection with the name ${name} has already been registered.`);
|
|
368
369
|
process.exit(1);
|
|
369
370
|
}
|
|
370
371
|
|
package/src/wamp.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// See the License for the specific language governing permissions and
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
|
|
15
|
-
import type { Class } from 'type-fest';
|
|
15
|
+
import type { Class, Primitive } from 'type-fest';
|
|
16
16
|
|
|
17
17
|
import { Elysia } from 'elysia';
|
|
18
18
|
import { omit } from 'radash';
|
|
@@ -66,6 +66,18 @@ export type WampSubscriptionOptions = Omit<WampRegistrationOptions, 'invoke'>;
|
|
|
66
66
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
67
67
|
*/
|
|
68
68
|
export type WampProps = {
|
|
69
|
+
/**
|
|
70
|
+
* The name of the connection to use. This connection must be registered in the application properties.
|
|
71
|
+
* @default 'default'
|
|
72
|
+
*/
|
|
73
|
+
connection?: string;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Properties required when declaring a WAMP client in the application properties.
|
|
78
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
79
|
+
*/
|
|
80
|
+
export type WampClientProps = {
|
|
69
81
|
/**
|
|
70
82
|
* The URL to the WAMP server.
|
|
71
83
|
*/
|
|
@@ -100,6 +112,131 @@ export type WampProps = {
|
|
|
100
112
|
* An array of supported authentication methods.
|
|
101
113
|
*/
|
|
102
114
|
authmethods?: string[];
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Callback for handling WAMP authentication challenges.
|
|
118
|
+
* @param method The authentication method.
|
|
119
|
+
* @param extra Authentication metadata.
|
|
120
|
+
*/
|
|
121
|
+
onChallenge?(method: string, extra: any): string | null;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Callback for handling the WAMP connection open event.
|
|
125
|
+
*/
|
|
126
|
+
onOpen?(): void;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Callback for handling the WAMP connection close event.
|
|
130
|
+
*/
|
|
131
|
+
onClose?(): void;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Callback for handling the WAMP connection error event.
|
|
135
|
+
*/
|
|
136
|
+
onError?(): void;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Callback for handling the WAMP connection reconnect event.
|
|
140
|
+
*/
|
|
141
|
+
onReconnect?(): void;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Callback for handling the WAMP connection reconnect success event.
|
|
145
|
+
*/
|
|
146
|
+
onReconnectSuccess?(): void;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export type WampClient = {
|
|
150
|
+
/**
|
|
151
|
+
* Disconnects from WAMP server. Clears all queues, subscriptions and calls.
|
|
152
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
153
|
+
*/
|
|
154
|
+
disconnect(): Promise<void>;
|
|
155
|
+
|
|
156
|
+
subscribe(
|
|
157
|
+
topic: string,
|
|
158
|
+
handler: WampSubscriptionHandler,
|
|
159
|
+
options?: WampSubscriptionOptions
|
|
160
|
+
): Promise<{
|
|
161
|
+
topic: string;
|
|
162
|
+
requestId: string;
|
|
163
|
+
subscriptionId: string;
|
|
164
|
+
subscriptionKey: string;
|
|
165
|
+
}>;
|
|
166
|
+
|
|
167
|
+
unsubscribe(
|
|
168
|
+
subscriptionIdOrKey: string,
|
|
169
|
+
handler?: WampSubscriptionHandler
|
|
170
|
+
): Promise<{
|
|
171
|
+
topic: string;
|
|
172
|
+
requestId: string;
|
|
173
|
+
}>;
|
|
174
|
+
|
|
175
|
+
publish(
|
|
176
|
+
topic: string,
|
|
177
|
+
params?:
|
|
178
|
+
| Primitive
|
|
179
|
+
| Array<any>
|
|
180
|
+
| Record<string, Primitive | Array<any>>
|
|
181
|
+
| { argsList: Array<any>; argsDict: Record<string, any> },
|
|
182
|
+
options?: {
|
|
183
|
+
exclude?: number | number[];
|
|
184
|
+
exclude_authid?: string | string[];
|
|
185
|
+
exclude_authrole?: string | string[];
|
|
186
|
+
eligible?: number | number[];
|
|
187
|
+
eligible_authid?: string | string[];
|
|
188
|
+
eligible_authrole?: string | string[];
|
|
189
|
+
exclude_me?: boolean;
|
|
190
|
+
disclose_me?: boolean;
|
|
191
|
+
ppt_scheme?: string;
|
|
192
|
+
ppt_serializer?: string;
|
|
193
|
+
ppt_cipher?: string;
|
|
194
|
+
ppt_keyid?: string;
|
|
195
|
+
}
|
|
196
|
+
): Promise<{
|
|
197
|
+
topic: string;
|
|
198
|
+
requestId: string;
|
|
199
|
+
publicationId: string;
|
|
200
|
+
}>;
|
|
201
|
+
|
|
202
|
+
call(
|
|
203
|
+
procedure: string,
|
|
204
|
+
params?:
|
|
205
|
+
| Primitive
|
|
206
|
+
| Array<any>
|
|
207
|
+
| Record<string, Primitive | Array<any>>
|
|
208
|
+
| { argsList: Array<any>; argsDict: Record<string, any> },
|
|
209
|
+
options?: {
|
|
210
|
+
disclose_me?: boolean;
|
|
211
|
+
progress_callback?(args: { argsList: Array<any>; argsDict: Record<string, any> }): void;
|
|
212
|
+
timeout?: number;
|
|
213
|
+
ppt_scheme?: string;
|
|
214
|
+
ppt_serializer?: string;
|
|
215
|
+
ppt_cipher?: string;
|
|
216
|
+
ppt_keyid?: string;
|
|
217
|
+
}
|
|
218
|
+
): Promise<{
|
|
219
|
+
details: Record<string, any>;
|
|
220
|
+
argsList?: Array<any>;
|
|
221
|
+
argsDict?: Record<string, any>;
|
|
222
|
+
}>;
|
|
223
|
+
|
|
224
|
+
cancel(requestId: string, options?: { mode?: 'kill' | 'killnowait' | 'skip' }): true;
|
|
225
|
+
|
|
226
|
+
register(
|
|
227
|
+
topic: string,
|
|
228
|
+
handler: WampRegistrationHandler,
|
|
229
|
+
options?: WampRegistrationOptions
|
|
230
|
+
): Promise<{
|
|
231
|
+
topic: string;
|
|
232
|
+
requestId: string;
|
|
233
|
+
registrationId: string;
|
|
234
|
+
}>;
|
|
235
|
+
|
|
236
|
+
unregister(registrationId: string): Promise<{
|
|
237
|
+
topic: string;
|
|
238
|
+
requestId: string;
|
|
239
|
+
}>;
|
|
103
240
|
};
|
|
104
241
|
|
|
105
242
|
/**
|
|
@@ -204,6 +341,127 @@ type WampSubscription = {
|
|
|
204
341
|
};
|
|
205
342
|
|
|
206
343
|
export namespace Wamp {
|
|
344
|
+
/**
|
|
345
|
+
* Creates a service name for a WAMP connection.
|
|
346
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
347
|
+
* @param name The name of the connection.
|
|
348
|
+
* @returns A service name for the connection.
|
|
349
|
+
*/
|
|
350
|
+
const getConnectionName = (name: string) => {
|
|
351
|
+
return `wamp.connection.${name}`;
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Retrieves the client for a WAMP connection.
|
|
356
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
357
|
+
* @param name The name of the connection.
|
|
358
|
+
* @returns The Wampy client for the connection with the given name.
|
|
359
|
+
*/
|
|
360
|
+
export const getConnection = (name: string) => {
|
|
361
|
+
if (!Service.exists(getConnectionName(name))) {
|
|
362
|
+
// TODO: Use logger service here
|
|
363
|
+
console.error(
|
|
364
|
+
`No WAMP connection with name ${name} found. Please make sure to register the connection before using it.`
|
|
365
|
+
);
|
|
366
|
+
process.exit(1);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return Service.get<WampClient>(getConnectionName(name))!;
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Creates and registers a new WAMP client.
|
|
374
|
+
*
|
|
375
|
+
* This will make the registered connection available for dependency injection with
|
|
376
|
+
* the key `wamp.connection.{name}`, where `{name}` is replaced with the given name.
|
|
377
|
+
*
|
|
378
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
379
|
+
*
|
|
380
|
+
* @param name The name of the connection.
|
|
381
|
+
* @param config The configuration for the WAMP client.
|
|
382
|
+
* @returns The newly created and configured WAMP client for the given connection.
|
|
383
|
+
*/
|
|
384
|
+
export const registerConnection = (name: string, config: WampClientProps) => {
|
|
385
|
+
if (Service.exists(getConnectionName(name))) {
|
|
386
|
+
// TODO: Use logger service here
|
|
387
|
+
console.error(
|
|
388
|
+
`A WAMP connection with name ${name} already exists. Please ensure to register a new connection before overwriting it.`
|
|
389
|
+
);
|
|
390
|
+
process.exit(1);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const client = new Wampy(config.url, {
|
|
394
|
+
ws: WampWebsocket,
|
|
395
|
+
...omit(config, ['url']),
|
|
396
|
+
onError() {
|
|
397
|
+
config.onError?.();
|
|
398
|
+
// TODO: Add more details like controller name and url
|
|
399
|
+
Event.emit('elysium:error', new Error(`An error occurred in WAMP connection ${name}`));
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
const maxRetries = config.maxRetries ?? 5;
|
|
404
|
+
const retryInterval = config.retryInterval ?? 5000;
|
|
405
|
+
let retryCount = 0;
|
|
406
|
+
|
|
407
|
+
const tryConnect = async () => {
|
|
408
|
+
try {
|
|
409
|
+
await client.connect();
|
|
410
|
+
} catch (e) {
|
|
411
|
+
console.error(
|
|
412
|
+
`Failed to connect to WAMP server (attempt ${retryCount + 1}/${maxRetries}):`,
|
|
413
|
+
e
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
if (retryCount < maxRetries) {
|
|
417
|
+
retryCount++;
|
|
418
|
+
setTimeout(tryConnect, retryInterval);
|
|
419
|
+
} else {
|
|
420
|
+
console.error(`Max retry attempts (${maxRetries}) reached. Giving up.`);
|
|
421
|
+
Event.emit(
|
|
422
|
+
'elysium:error',
|
|
423
|
+
new Error(`Failed to establish WAMP connection ${name} after ${maxRetries} attempts`)
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
tryConnect();
|
|
430
|
+
|
|
431
|
+
return Service.instance<WampClient>(getConnectionName(name), client);
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Checks if a WAMP connection with the given name exists.
|
|
436
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
437
|
+
* @param name The name of the connection.
|
|
438
|
+
* @returns `true` if the connection exists, `false` otherwise.
|
|
439
|
+
*/
|
|
440
|
+
export const connectionExists = (name: string) => {
|
|
441
|
+
return Service.exists(getConnectionName(name));
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Retrieves the default WAMP connection.
|
|
446
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
447
|
+
* @returns The default WAMP connection.
|
|
448
|
+
*/
|
|
449
|
+
export const getDefaultConnection = () => {
|
|
450
|
+
return getConnection('default');
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Sets the default WAMP connection.
|
|
455
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
456
|
+
* @param name The name of the connection to set as default.
|
|
457
|
+
* @returns The default WAMP connection.
|
|
458
|
+
*/
|
|
459
|
+
export const setDefaultConnection = (name: string) => {
|
|
460
|
+
const serviceName = getConnectionName('default');
|
|
461
|
+
Service.remove(serviceName);
|
|
462
|
+
return Service.instance<WampClient>(serviceName, getConnection(name));
|
|
463
|
+
};
|
|
464
|
+
|
|
207
465
|
/**
|
|
208
466
|
* Marks a class as a WAMP controller.
|
|
209
467
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
@@ -213,67 +471,50 @@ export namespace Wamp {
|
|
|
213
471
|
return function (target: Class<any>) {
|
|
214
472
|
async function handleWamp(): Promise<Elysia> {
|
|
215
473
|
// TODO: Use the logger service here
|
|
216
|
-
console.log(
|
|
474
|
+
console.log(
|
|
475
|
+
`Registering Wamp controller for connection ${options.connection} using ${target.name}`
|
|
476
|
+
);
|
|
217
477
|
await nextTick();
|
|
218
478
|
|
|
219
479
|
const controller = Service.make(target);
|
|
220
480
|
|
|
221
481
|
const metadata = Reflect.getMetadata(Symbols.wamp, target) ?? {};
|
|
222
482
|
|
|
223
|
-
const w =
|
|
224
|
-
ws: WampWebsocket,
|
|
225
|
-
...omit(options, ['url']),
|
|
226
|
-
onChallenge: metadata.challenge?.bind(controller),
|
|
227
|
-
onClose: metadata.close?.bind(controller),
|
|
228
|
-
onError() {
|
|
229
|
-
metadata.error?.call(controller);
|
|
230
|
-
// TODO: Add more details like controller name and url
|
|
231
|
-
Event.emit('elysium:error', new Error('Wamp connection error'));
|
|
232
|
-
},
|
|
233
|
-
onReconnect: metadata.reconnect?.bind(controller),
|
|
234
|
-
onReconnectSuccess: metadata.reconnectSuccess?.bind(controller)
|
|
235
|
-
});
|
|
483
|
+
const w = Wamp.getConnection(options.connection ?? 'default');
|
|
236
484
|
|
|
237
485
|
const app = new Elysia();
|
|
238
486
|
|
|
239
487
|
app.onStart(async (_) => {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
488
|
+
const registrations: WampRegistration[] = metadata.registrations ?? [];
|
|
489
|
+
const subscriptions: WampSubscription[] = metadata.subscriptions ?? [];
|
|
490
|
+
|
|
491
|
+
for (const registration of registrations) {
|
|
492
|
+
w.register(
|
|
493
|
+
registration.topic,
|
|
494
|
+
registration.handler.bind(controller),
|
|
495
|
+
registration.options
|
|
496
|
+
).then((r: { topic: string; requestId: string; registrationId: string }) => {
|
|
497
|
+
// TODO: Use the logger service here
|
|
498
|
+
console.log(`Registered ${registration.topic} with id ${r.registrationId}`);
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
for (const subscription of subscriptions) {
|
|
503
|
+
w.subscribe(
|
|
504
|
+
subscription.topic,
|
|
505
|
+
subscription.handler.bind(controller),
|
|
506
|
+
subscription.options
|
|
507
|
+
).then(
|
|
508
|
+
(s: {
|
|
509
|
+
topic: string;
|
|
510
|
+
requestId: string;
|
|
511
|
+
subscriptionId: string;
|
|
512
|
+
subscriptionKey: string;
|
|
513
|
+
}) => {
|
|
253
514
|
// TODO: Use the logger service here
|
|
254
|
-
console.log(`
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
for (const subscription of subscriptions) {
|
|
259
|
-
w.subscribe(
|
|
260
|
-
subscription.topic,
|
|
261
|
-
subscription.handler.bind(controller),
|
|
262
|
-
subscription.options
|
|
263
|
-
).then(
|
|
264
|
-
(s: {
|
|
265
|
-
topic: string;
|
|
266
|
-
requestId: string;
|
|
267
|
-
subscriptionId: string;
|
|
268
|
-
subscriptionKey: string;
|
|
269
|
-
}) => {
|
|
270
|
-
// TODO: Use the logger service here
|
|
271
|
-
console.log(`Subscribed ${subscription.topic} with id ${s.subscriptionId}`);
|
|
272
|
-
}
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
} catch (error) {
|
|
276
|
-
// noop
|
|
515
|
+
console.log(`Subscribed ${subscription.topic} with id ${s.subscriptionId}`);
|
|
516
|
+
}
|
|
517
|
+
);
|
|
277
518
|
}
|
|
278
519
|
});
|
|
279
520
|
|
|
@@ -325,100 +566,4 @@ export namespace Wamp {
|
|
|
325
566
|
Reflect.defineMetadata(Symbols.wamp, metadata, target.constructor);
|
|
326
567
|
};
|
|
327
568
|
};
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* Marks a method as the WAMP "challenge" event handler.
|
|
331
|
-
*
|
|
332
|
-
* This decorator should be used on a WAMP controller method. Only one "challenge" event handler
|
|
333
|
-
* can be defined per WAMP controller.
|
|
334
|
-
*
|
|
335
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
336
|
-
*/
|
|
337
|
-
export const onChallenge = (): MethodDecorator => {
|
|
338
|
-
return function (target, _propertyKey, descriptor) {
|
|
339
|
-
const metadata = Reflect.getMetadata(Symbols.wamp, target.constructor) ?? {};
|
|
340
|
-
metadata.challenge = descriptor.value;
|
|
341
|
-
Reflect.defineMetadata(Symbols.wamp, metadata, target.constructor);
|
|
342
|
-
};
|
|
343
|
-
};
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Marks a method as the WAMP "open" event handler.
|
|
347
|
-
*
|
|
348
|
-
* This decorator should be used on a WAMP controller method. Only one "open" event handler
|
|
349
|
-
* can be defined per WAMP controller.
|
|
350
|
-
*
|
|
351
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
352
|
-
*/
|
|
353
|
-
export const onOpen = (): MethodDecorator => {
|
|
354
|
-
return function (target, _propertyKey, descriptor) {
|
|
355
|
-
const metadata = Reflect.getMetadata(Symbols.wamp, target.constructor) ?? {};
|
|
356
|
-
metadata.open = descriptor.value;
|
|
357
|
-
Reflect.defineMetadata(Symbols.wamp, metadata, target.constructor);
|
|
358
|
-
};
|
|
359
|
-
};
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* Marks a method as the WAMP "close" event handler.
|
|
363
|
-
*
|
|
364
|
-
* This decorator should be used on a WAMP controller method. Only one "close" event handler
|
|
365
|
-
* can be defined per WAMP controller.
|
|
366
|
-
*
|
|
367
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
368
|
-
*/
|
|
369
|
-
export const onClose = (): MethodDecorator => {
|
|
370
|
-
return function (target, _propertyKey, descriptor) {
|
|
371
|
-
const metadata = Reflect.getMetadata(Symbols.wamp, target.constructor) ?? {};
|
|
372
|
-
metadata.close = descriptor.value;
|
|
373
|
-
Reflect.defineMetadata(Symbols.wamp, metadata, target.constructor);
|
|
374
|
-
};
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* Marks a method as the WAMP "error" event handler.
|
|
379
|
-
*
|
|
380
|
-
* This decorator should be used on a WAMP controller method. Only one "error" event handler
|
|
381
|
-
* can be defined per WAMP controller.
|
|
382
|
-
*
|
|
383
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
384
|
-
*/
|
|
385
|
-
export const onError = (): MethodDecorator => {
|
|
386
|
-
return function (target, _propertyKey, descriptor) {
|
|
387
|
-
const metadata = Reflect.getMetadata(Symbols.wamp, target.constructor) ?? {};
|
|
388
|
-
metadata.error = descriptor.value;
|
|
389
|
-
Reflect.defineMetadata(Symbols.wamp, metadata, target.constructor);
|
|
390
|
-
};
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
/**
|
|
394
|
-
* Marks a method as the WAMP "reconnect" event handler.
|
|
395
|
-
*
|
|
396
|
-
* This decorator should be used on a WAMP controller method. Only one "reconnect" event handler
|
|
397
|
-
* can be defined per WAMP controller.
|
|
398
|
-
*
|
|
399
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
400
|
-
*/
|
|
401
|
-
export const onReconnect = (): MethodDecorator => {
|
|
402
|
-
return function (target, _propertyKey, descriptor) {
|
|
403
|
-
const metadata = Reflect.getMetadata(Symbols.wamp, target.constructor) ?? {};
|
|
404
|
-
metadata.reconnect = descriptor.value;
|
|
405
|
-
Reflect.defineMetadata(Symbols.wamp, metadata, target.constructor);
|
|
406
|
-
};
|
|
407
|
-
};
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Marks a method as the WAMP "reconnectSuccess" event handler.
|
|
411
|
-
*
|
|
412
|
-
* This decorator should be used on a WAMP controller method. Only one "reconnectSuccess" event handler
|
|
413
|
-
* can be defined per WAMP controller.
|
|
414
|
-
*
|
|
415
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
416
|
-
*/
|
|
417
|
-
export const onReconnectSuccess = (): MethodDecorator => {
|
|
418
|
-
return function (target, _propertyKey, descriptor) {
|
|
419
|
-
const metadata = Reflect.getMetadata(Symbols.wamp, target.constructor) ?? {};
|
|
420
|
-
metadata.reconnectSuccess = descriptor.value;
|
|
421
|
-
Reflect.defineMetadata(Symbols.wamp, metadata, target.constructor);
|
|
422
|
-
};
|
|
423
|
-
};
|
|
424
569
|
}
|