@alterior/runtime 3.5.2 → 3.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -4
- package/src/app-options.ts +72 -0
- package/src/application.ts +207 -0
- package/src/args.ts +9 -0
- package/src/expose.ts +46 -0
- package/src/index.ts +9 -0
- package/src/lifecycle.ts +26 -0
- package/src/modules.ts +325 -0
- package/src/reflector.ts +433 -0
- package/src/roles.service.ts +171 -0
- package/src/service.ts +34 -0
- package/dist.esm/module.test.js +0 -374
- package/dist.esm/test.js +0 -7
package/src/reflector.ts
ADDED
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import { Annotation, Annotations, IAnnotation } from "@alterior/annotations";
|
|
2
|
+
import { getParameterNames } from "@alterior/common";
|
|
3
|
+
|
|
4
|
+
export interface Constructor<T> {
|
|
5
|
+
new(...args) : T;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type Visibility = 'private' | 'public' | 'protected';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Represents a property on a class. A property can also be a field or a method.
|
|
12
|
+
*/
|
|
13
|
+
export class Property<T>{
|
|
14
|
+
constructor(
|
|
15
|
+
private _type : Constructor<T>,
|
|
16
|
+
private _name : string,
|
|
17
|
+
private _isStatic : boolean = false
|
|
18
|
+
) {
|
|
19
|
+
this._visibility = _name[0] === '_' ? 'private' : 'public';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private _visibility : Visibility;
|
|
23
|
+
private _descriptor : PropertyDescriptor = null;
|
|
24
|
+
private _annotations : IAnnotation[];
|
|
25
|
+
|
|
26
|
+
defineMetadata(key : string, value : string) {
|
|
27
|
+
Reflect.defineMetadata(key, value, this.type, this.name);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getMetadata(key : string): any {
|
|
31
|
+
return Reflect.getMetadata(key, this.type, this.name);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
deleteMetadata(key : string) {
|
|
35
|
+
Reflect.deleteMetadata(key, this.type, this.name);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private _valueType : Type<any>;
|
|
39
|
+
get valueType() : Type<any> {
|
|
40
|
+
if (!this._valueType) {
|
|
41
|
+
let rawType = this.getMetadata('design:type');
|
|
42
|
+
if (!rawType)
|
|
43
|
+
return undefined;
|
|
44
|
+
this._valueType = new Type<any>(rawType);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return this._valueType;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public get isStatic() {
|
|
51
|
+
return this._isStatic;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
protected get type() {
|
|
55
|
+
return this._type;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
get annotations() {
|
|
59
|
+
if (!this._annotations) {
|
|
60
|
+
if (this._name === 'constructor')
|
|
61
|
+
this._annotations = Annotations.getClassAnnotations(this._type);
|
|
62
|
+
else
|
|
63
|
+
this._annotations = Annotations.getPropertyAnnotations(this._type, this.name, this.isStatic);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return this._annotations;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
annotationsOfType<T extends Annotation>(type : Constructor<T>) : T[] {
|
|
70
|
+
return (type as any).filter(this.annotations);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
annotationOfType<T extends Annotation>(type : Constructor<T>) : T {
|
|
74
|
+
return (type as any).filter(this.annotations)[0];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
get descriptor() : PropertyDescriptor {
|
|
78
|
+
if (!this._descriptor)
|
|
79
|
+
this._descriptor = Object.getOwnPropertyDescriptor(this._type.prototype, this._name);
|
|
80
|
+
|
|
81
|
+
return this._descriptor;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
get name() {
|
|
85
|
+
return this._name;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
get visibility() {
|
|
89
|
+
return this._visibility;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Represents a method on a class. A method can be a static or instance method, and has a set of parameters
|
|
95
|
+
* and a return type.
|
|
96
|
+
*/
|
|
97
|
+
export class Method<T> extends Property<T> {
|
|
98
|
+
constructor(
|
|
99
|
+
type : Constructor<T>,
|
|
100
|
+
name : string,
|
|
101
|
+
isStatic : boolean = false
|
|
102
|
+
) {
|
|
103
|
+
super(type, name, isStatic);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private _parameterNames : string[];
|
|
107
|
+
private _implementation : Function;
|
|
108
|
+
|
|
109
|
+
private _returnType : Type<any>;
|
|
110
|
+
get returnType() : Type<any> {
|
|
111
|
+
if (!this._returnType) {
|
|
112
|
+
let rawType = this.getMetadata('design:returntype');
|
|
113
|
+
if (!rawType)
|
|
114
|
+
return undefined;
|
|
115
|
+
this._returnType = new Type<any>(rawType);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return this._returnType;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private _parameterTypes : Type<any>;
|
|
122
|
+
get parameterTypes() : Type<any> {
|
|
123
|
+
if (!this._parameterTypes) {
|
|
124
|
+
let rawTypes = this.getMetadata('design:paramtypes');
|
|
125
|
+
this._parameterTypes = rawTypes.map(x => x ? new Type<any>(x) : undefined);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return this._parameterTypes;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
get implementation() : Function {
|
|
132
|
+
return this.type[this.name];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
get parameterNames() {
|
|
136
|
+
if (!this._parameterNames)
|
|
137
|
+
this._parameterNames = getParameterNames(this.implementation);
|
|
138
|
+
|
|
139
|
+
return this._parameterNames;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
get parameters(): Parameter<T>[] {
|
|
143
|
+
let parameterNames = this.parameterNames;
|
|
144
|
+
return [...Array(this.implementation.length).keys()]
|
|
145
|
+
.map(i => new Parameter(this, i, parameterNames[i]))
|
|
146
|
+
;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private _parameterAnnotations : IAnnotation[][];
|
|
150
|
+
|
|
151
|
+
get parameterAnnotations(): IAnnotation[][] {
|
|
152
|
+
if (!this._parameterAnnotations)
|
|
153
|
+
this._parameterAnnotations = Annotations.getParameterAnnotations(this.type, this.name);
|
|
154
|
+
|
|
155
|
+
return this._parameterAnnotations;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export class Field<T> extends Property<T> {
|
|
160
|
+
constructor(
|
|
161
|
+
type : Constructor<T>,
|
|
162
|
+
name : string,
|
|
163
|
+
isStatic : boolean = false
|
|
164
|
+
) {
|
|
165
|
+
super(type, name, isStatic);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export class ConstructorMethod<T> extends Method<T> {
|
|
170
|
+
constructor(
|
|
171
|
+
type : Constructor<T>
|
|
172
|
+
) {
|
|
173
|
+
super(type, 'constructor');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private _ctorParameterAnnotations : IAnnotation[][];
|
|
177
|
+
get parameterAnnotations() {
|
|
178
|
+
if (!this._ctorParameterAnnotations)
|
|
179
|
+
this._ctorParameterAnnotations = Annotations.getConstructorParameterAnnotations(this.type);
|
|
180
|
+
|
|
181
|
+
return this._ctorParameterAnnotations;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export class Parameter<T> {
|
|
186
|
+
constructor(
|
|
187
|
+
private _method : Method<T>,
|
|
188
|
+
private _index : number,
|
|
189
|
+
private _name : string = null
|
|
190
|
+
) {
|
|
191
|
+
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private _annotations : Annotation[];
|
|
195
|
+
|
|
196
|
+
get annotations() {
|
|
197
|
+
return this.method.parameterAnnotations[this.index];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
annotationsOfType<T extends Annotation>(type : Constructor<T>) : T[] {
|
|
201
|
+
return (type as any).filter(this.annotations);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
annotationOfType<T extends Annotation>(type : Constructor<T>) : T {
|
|
205
|
+
return (type as any).filter(this.annotations)[0];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
protected get method() {
|
|
209
|
+
return this._method;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
get valueType() {
|
|
213
|
+
return this.method.parameterTypes[this.index];
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
get index() {
|
|
217
|
+
return this._index;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
get name() {
|
|
221
|
+
return this._name;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Represents a class Type and it's metadata
|
|
227
|
+
*/
|
|
228
|
+
export class Type<T extends Object> {
|
|
229
|
+
constructor(
|
|
230
|
+
private _class : Constructor<T>
|
|
231
|
+
) {
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private _propertyNames : string[];
|
|
235
|
+
private _methodNames : string[];
|
|
236
|
+
private _fieldNames : string[];
|
|
237
|
+
private _annotations : IAnnotation[];
|
|
238
|
+
|
|
239
|
+
get name() {
|
|
240
|
+
return this._class.name;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
getMetadata(key : string) {
|
|
244
|
+
Reflect.getOwnMetadata(key, this._class);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
defineMetadata(key : string, value : any) {
|
|
248
|
+
Reflect.defineMetadata(key, value, this._class.prototype);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
deleteMetadata(key : string) {
|
|
252
|
+
Reflect.deleteMetadata(key, this._class);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private _metadataKeys : string[];
|
|
256
|
+
get metadataKeys() : string[] {
|
|
257
|
+
if (!this._metadataKeys)
|
|
258
|
+
this._metadataKeys = Reflect.getOwnMetadataKeys(this._class);
|
|
259
|
+
|
|
260
|
+
return this._metadataKeys;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Get all annotations attached to this class
|
|
265
|
+
*/
|
|
266
|
+
get annotations(): IAnnotation[] {
|
|
267
|
+
if (!this._annotations)
|
|
268
|
+
this._annotations = Annotations.getClassAnnotations(this._class);
|
|
269
|
+
|
|
270
|
+
return this._annotations;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
annotationsOfType<T extends Annotation>(type : Constructor<T>) : T[] {
|
|
274
|
+
return (type as any).filter(this.annotations);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
annotationOfType<T extends Annotation>(type : Constructor<T>) : T {
|
|
278
|
+
return (type as any).filter(this.annotations)[0];
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private fetchPropertyNames() {
|
|
282
|
+
this._propertyNames = Object.getOwnPropertyNames(this._class.prototype);
|
|
283
|
+
for (let propertyName of this._propertyNames) {
|
|
284
|
+
if (typeof this._class.prototype[propertyName] === 'function') {
|
|
285
|
+
this._methodNames.push(propertyName);
|
|
286
|
+
} else {
|
|
287
|
+
this._fieldNames.push(propertyName);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private _staticPropertyNames : string[] = [];
|
|
293
|
+
private _staticMethodNames : string[] = [];
|
|
294
|
+
private _staticFieldNames : string[] = [];
|
|
295
|
+
|
|
296
|
+
private fetchStaticPropertyNames() {
|
|
297
|
+
this._staticPropertyNames = Object.getOwnPropertyNames(this._class).filter(x => !['length', 'prototype', 'name'].includes(x));
|
|
298
|
+
|
|
299
|
+
for (let propertyName of this._staticPropertyNames) {
|
|
300
|
+
if (typeof this._class[propertyName] === 'function') {
|
|
301
|
+
this._staticMethodNames.push(propertyName);
|
|
302
|
+
} else {
|
|
303
|
+
this._staticFieldNames.push(propertyName);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
get staticPropertyNames() {
|
|
309
|
+
if (!this._staticPropertyNames)
|
|
310
|
+
this.fetchStaticPropertyNames();
|
|
311
|
+
|
|
312
|
+
return this._staticPropertyNames.slice();
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
get staticMethodNames() {
|
|
316
|
+
if (!this._staticPropertyNames)
|
|
317
|
+
this.fetchStaticPropertyNames();
|
|
318
|
+
|
|
319
|
+
return this._staticMethodNames.slice();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
get staticFieldNames() {
|
|
323
|
+
if (!this._staticPropertyNames)
|
|
324
|
+
this.fetchStaticPropertyNames();
|
|
325
|
+
|
|
326
|
+
return this._staticFieldNames.slice();
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
private _staticMethods : Method<T>[];
|
|
330
|
+
get staticMethods() : Method<T>[] {
|
|
331
|
+
if (this._staticMethods)
|
|
332
|
+
return this._staticMethods;
|
|
333
|
+
|
|
334
|
+
this._staticMethods = this.staticMethodNames.map(methodName => new Method<T>(this._class, methodName, true));
|
|
335
|
+
|
|
336
|
+
return this._staticMethods;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
private _staticFields : Field<T>[];
|
|
340
|
+
get staticFields() : Field<T>[] {
|
|
341
|
+
if (this._staticFields)
|
|
342
|
+
return this._staticFields;
|
|
343
|
+
|
|
344
|
+
this._staticFields = this.staticFieldNames.map(fieldName => new Field<T>(this._class, fieldName, true));
|
|
345
|
+
|
|
346
|
+
return this._staticFields;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
private _staticProperties : Property<T>[];
|
|
350
|
+
get staticProperties() {
|
|
351
|
+
if (this._staticProperties)
|
|
352
|
+
return this._staticProperties;
|
|
353
|
+
|
|
354
|
+
this._staticProperties = [].concat(this.staticFields, this.staticMethods);
|
|
355
|
+
|
|
356
|
+
return this._staticProperties;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
get propertyNames() {
|
|
360
|
+
if (!this._propertyNames)
|
|
361
|
+
this.fetchPropertyNames();
|
|
362
|
+
|
|
363
|
+
return this._propertyNames.slice();
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
get methodNames() {
|
|
367
|
+
if (!this._propertyNames)
|
|
368
|
+
this.fetchPropertyNames();
|
|
369
|
+
|
|
370
|
+
return this._methodNames.slice();
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
get fieldNames() {
|
|
374
|
+
if (!this._propertyNames)
|
|
375
|
+
this.fetchPropertyNames();
|
|
376
|
+
|
|
377
|
+
return this._fieldNames.slice();
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
private _ctor : ConstructorMethod<T>;
|
|
381
|
+
get constructorMethod() {
|
|
382
|
+
if (!this._ctor)
|
|
383
|
+
this._ctor = new ConstructorMethod<T>(this._class);
|
|
384
|
+
|
|
385
|
+
return this._ctor;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
private _methods : Method<T>[];
|
|
389
|
+
get methods() {
|
|
390
|
+
if (this._methods)
|
|
391
|
+
return this._methods;
|
|
392
|
+
|
|
393
|
+
this._methods = this.methodNames.map(methodName => new Method<T>(this._class, methodName));
|
|
394
|
+
|
|
395
|
+
return this._methods;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
private _properties : Property<T>[];
|
|
399
|
+
|
|
400
|
+
get properties() {
|
|
401
|
+
if (this._properties)
|
|
402
|
+
return this._properties;
|
|
403
|
+
|
|
404
|
+
this._properties = [].concat(this.fields, this.methods);
|
|
405
|
+
|
|
406
|
+
return this._properties;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
private _fields : Field<T>[];
|
|
410
|
+
|
|
411
|
+
get fields() {
|
|
412
|
+
if (this._fields)
|
|
413
|
+
return this._fields;
|
|
414
|
+
|
|
415
|
+
this._fields = this.fieldNames.map(fieldName => new Field<T>(this._class, fieldName));
|
|
416
|
+
|
|
417
|
+
return this._fields;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
get base(): Type<any> {
|
|
421
|
+
return new Type<any>(Object.getPrototypeOf(this._class));
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
export class Reflector {
|
|
426
|
+
getTypeFromInstance<T extends Object = any>(instance : T) : Type<T> {
|
|
427
|
+
return this.getTypeFromClass<T>(instance.constructor as any);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
getTypeFromClass<T = any>(typeClass : Constructor<T>): Type<T> {
|
|
431
|
+
return new Type(typeClass);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { Injectable } from "@alterior/di";
|
|
2
|
+
import { timeout, InvalidOperationError, ArgumentError } from "@alterior/common";
|
|
3
|
+
|
|
4
|
+
const SUPPORTED_ROLE_MODES = ['all-except', 'only' ];
|
|
5
|
+
export type RoleConfigurationMode = 'all-except' | 'only' ;
|
|
6
|
+
|
|
7
|
+
export interface RoleConfiguration {
|
|
8
|
+
mode : RoleConfigurationMode;
|
|
9
|
+
roles : any[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Role registration information. Use this when your module provides a service which should support being turned on and
|
|
14
|
+
* off at runtime.
|
|
15
|
+
*/
|
|
16
|
+
export interface RoleRegistration {
|
|
17
|
+
/**
|
|
18
|
+
* The instance of the module being registered. This should be `this` for the caller in most cases, as it should be
|
|
19
|
+
* called from an Alterior module's `altOnInit()` method.
|
|
20
|
+
*/
|
|
21
|
+
instance : any;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The identifier that will be matched when interpreting command line role enablements.
|
|
25
|
+
*/
|
|
26
|
+
identifier : string;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The human readable name for this role.
|
|
30
|
+
*/
|
|
31
|
+
name : string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A short (one sentence) summary which may be shown in command line help output and other places.
|
|
35
|
+
*/
|
|
36
|
+
summary : string;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Start services associated with this role.
|
|
40
|
+
* For instance, an HTTP server module would start it's HTTP server.
|
|
41
|
+
*/
|
|
42
|
+
start() : Promise<void>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Stop services associated with this role.
|
|
46
|
+
*/
|
|
47
|
+
stop() : Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface RoleState extends RoleRegistration {
|
|
51
|
+
class : any;
|
|
52
|
+
running : boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Roles allow runtime configuration of which outward facing services to start.
|
|
57
|
+
* For instance WebServerModule and TasksModule both register their respective roles,
|
|
58
|
+
* so that they can be easily turned on and off when the application is called.
|
|
59
|
+
*
|
|
60
|
+
*/
|
|
61
|
+
@Injectable()
|
|
62
|
+
export class RolesService {
|
|
63
|
+
constructor() {
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
_activeRoles : any[] = null;
|
|
68
|
+
_configuration : RoleConfiguration = { mode: 'all-except', roles: [] };
|
|
69
|
+
_roles : RoleState[] = [];
|
|
70
|
+
|
|
71
|
+
get configuration() : RoleConfiguration {
|
|
72
|
+
return this._configuration;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Register a role which can be managed by this service.
|
|
77
|
+
*/
|
|
78
|
+
registerRole(role : RoleRegistration) {
|
|
79
|
+
let roleState : RoleState = Object.assign(
|
|
80
|
+
role,
|
|
81
|
+
{
|
|
82
|
+
class: role.instance.constructor,
|
|
83
|
+
running: false
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
this._roles.push(roleState);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
get roles(): RoleState[] {
|
|
91
|
+
return this._roles;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Calculate the exact list of roles the configuration currently applies to.
|
|
96
|
+
*/
|
|
97
|
+
get effectiveRoles(): RoleState[] {
|
|
98
|
+
let config = this._configuration;
|
|
99
|
+
|
|
100
|
+
if (config.mode == 'all-except')
|
|
101
|
+
return this._roles.filter(x => !config.roles.includes(x.class));
|
|
102
|
+
else if (config.mode == 'only')
|
|
103
|
+
return this._roles.filter(x => config.roles.includes(x.class));
|
|
104
|
+
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get activeRoles(): RoleState[] {
|
|
109
|
+
return this._roles.filter(x => x.running);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Configure which roles should be run by this service
|
|
114
|
+
*/
|
|
115
|
+
configure(config : RoleConfiguration) {
|
|
116
|
+
if (!SUPPORTED_ROLE_MODES.includes(config.mode))
|
|
117
|
+
throw new InvalidOperationError(`Role mode '${config.mode}' is not supported (supports 'all-except', 'only')`);
|
|
118
|
+
|
|
119
|
+
this._configuration = config;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
getForModule(roleModuleClass) {
|
|
123
|
+
let role = this._roles.find(x => x.class === roleModuleClass);
|
|
124
|
+
|
|
125
|
+
if (!role)
|
|
126
|
+
throw new ArgumentError(`Role module class ${roleModuleClass.name} is not registered`);
|
|
127
|
+
|
|
128
|
+
return role;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
getById(id : string) {
|
|
132
|
+
let role = this._roles.find(x => x.identifier === id);
|
|
133
|
+
|
|
134
|
+
if (!role)
|
|
135
|
+
throw new ArgumentError(`Role with ID '${id}' is not registered`);
|
|
136
|
+
|
|
137
|
+
return role;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async restartAll() {
|
|
141
|
+
await this.stopAll();
|
|
142
|
+
await timeout(1);
|
|
143
|
+
await this.startAll();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
silent = false;
|
|
147
|
+
|
|
148
|
+
async startAll() {
|
|
149
|
+
await Promise.all(
|
|
150
|
+
this.effectiveRoles
|
|
151
|
+
.filter(role => !role.running)
|
|
152
|
+
.map(async role => {
|
|
153
|
+
await role.start();
|
|
154
|
+
if (!this.silent)
|
|
155
|
+
console.log(`** [${role.identifier}] Started`);
|
|
156
|
+
})
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async stopAll() {
|
|
161
|
+
|
|
162
|
+
await Promise.all(
|
|
163
|
+
this.activeRoles
|
|
164
|
+
.map(async role => {
|
|
165
|
+
await role.stop();
|
|
166
|
+
if (!this.silent)
|
|
167
|
+
console.log(`** [${role.identifier}] Stopped`);
|
|
168
|
+
})
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
package/src/service.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { MetadataName, Annotation } from '@alterior/annotations';
|
|
2
|
+
import { Type } from '@alterior/di';
|
|
3
|
+
|
|
4
|
+
export interface MethodShimParam {
|
|
5
|
+
name : string;
|
|
6
|
+
type : Type;
|
|
7
|
+
default? : any;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface MethodShim {
|
|
11
|
+
name : string;
|
|
12
|
+
params : MethodShimParam[];
|
|
13
|
+
target : Type;
|
|
14
|
+
body : string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export abstract class ServiceCompiler {
|
|
18
|
+
abstract compileMethod(method : MethodShim) : void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ServiceOptions {
|
|
22
|
+
compiler: Type<ServiceCompiler>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@MetadataName('@alterior/runtime:Service')
|
|
26
|
+
export class ServiceAnnotation extends Annotation implements ServiceOptions {
|
|
27
|
+
constructor(options? : ServiceOptions) {
|
|
28
|
+
super(options);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
compiler : Type<ServiceCompiler>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const Service = ServiceAnnotation.decorator();
|