vrack2-core 0.0.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/.eslintrc.js +6 -0
- package/LICENSE +177 -0
- package/README.md +6 -0
- package/docs/RU-README.md +6 -0
- package/lib/Container.d.ts +30 -0
- package/lib/Container.js +236 -0
- package/lib/DeviceManager.d.ts +32 -0
- package/lib/DeviceManager.js +143 -0
- package/lib/IServiceStructure.d.ts +5 -0
- package/lib/IServiceStructure.js +2 -0
- package/lib/IStructureDevice.d.ts +7 -0
- package/lib/IStructureDevice.js +2 -0
- package/lib/ImportManager.d.ts +15 -0
- package/lib/ImportManager.js +145 -0
- package/lib/MainProcess.d.ts +9 -0
- package/lib/MainProcess.js +28 -0
- package/lib/Utility.d.ts +21 -0
- package/lib/Utility.js +48 -0
- package/lib/actions/Action.d.ts +4 -0
- package/lib/actions/Action.js +16 -0
- package/lib/actions/BasicAction.d.ts +15 -0
- package/lib/actions/BasicAction.js +44 -0
- package/lib/actions/GlobalAction.d.ts +4 -0
- package/lib/actions/GlobalAction.js +17 -0
- package/lib/actions/IAction.d.ts +11 -0
- package/lib/actions/IAction.js +2 -0
- package/lib/actions/ILocalAction.d.ts +11 -0
- package/lib/actions/ILocalAction.js +2 -0
- package/lib/errors/CoreError.d.ts +53 -0
- package/lib/errors/CoreError.js +81 -0
- package/lib/errors/ErrorManager.d.ts +47 -0
- package/lib/errors/ErrorManager.js +84 -0
- package/lib/index.d.ts +19 -0
- package/lib/index.js +55 -0
- package/lib/ports/BasicPort.d.ts +11 -0
- package/lib/ports/BasicPort.js +49 -0
- package/lib/ports/ILocalPort.d.ts +10 -0
- package/lib/ports/ILocalPort.js +2 -0
- package/lib/ports/IPort.d.ts +10 -0
- package/lib/ports/IPort.js +2 -0
- package/lib/ports/Port.d.ts +6 -0
- package/lib/ports/Port.js +20 -0
- package/lib/ports/ReturnPort.d.ts +6 -0
- package/lib/ports/ReturnPort.js +21 -0
- package/lib/ports/StandartPort.d.ts +4 -0
- package/lib/ports/StandartPort.js +17 -0
- package/lib/service/Device.d.ts +175 -0
- package/lib/service/Device.js +191 -0
- package/lib/service/DeviceConnect.d.ts +21 -0
- package/lib/service/DeviceConnect.js +32 -0
- package/lib/service/DevicePort.d.ts +24 -0
- package/lib/service/DevicePort.js +41 -0
- package/lib/service/IDeviceEvent.d.ts +5 -0
- package/lib/service/IDeviceEvent.js +2 -0
- package/lib/test.d.ts +1 -0
- package/lib/test.js +58 -0
- package/lib/validator/IValidationProblem.d.ts +8 -0
- package/lib/validator/IValidationProblem.js +2 -0
- package/lib/validator/IValidationRule.d.ts +9 -0
- package/lib/validator/IValidationRule.js +2 -0
- package/lib/validator/IValidationSubrule.d.ts +4 -0
- package/lib/validator/IValidationSubrule.js +2 -0
- package/lib/validator/Rule.d.ts +12 -0
- package/lib/validator/Rule.js +30 -0
- package/lib/validator/Validator.d.ts +14 -0
- package/lib/validator/Validator.js +57 -0
- package/lib/validator/types/ArrayType.d.ts +14 -0
- package/lib/validator/types/ArrayType.js +58 -0
- package/lib/validator/types/BasicType.d.ts +18 -0
- package/lib/validator/types/BasicType.js +54 -0
- package/lib/validator/types/NumberType.d.ts +19 -0
- package/lib/validator/types/NumberType.js +66 -0
- package/lib/validator/types/ObjectType.d.ts +18 -0
- package/lib/validator/types/ObjectType.js +51 -0
- package/lib/validator/types/StringType.d.ts +19 -0
- package/lib/validator/types/StringType.js +63 -0
- package/package.json +26 -0
- package/src/Container.ts +237 -0
- package/src/DeviceManager.ts +124 -0
- package/src/IServiceStructure.ts +6 -0
- package/src/IStructureDevice.ts +5 -0
- package/src/ImportManager.ts +112 -0
- package/src/MainProcess.ts +18 -0
- package/src/Utility.ts +44 -0
- package/src/actions/Action.ts +12 -0
- package/src/actions/BasicAction.ts +54 -0
- package/src/actions/GlobalAction.ts +14 -0
- package/src/actions/IAction.ts +8 -0
- package/src/actions/ILocalAction.ts +8 -0
- package/src/errors/CoreError.ts +87 -0
- package/src/errors/ErrorManager.ts +93 -0
- package/src/index.ts +30 -0
- package/src/ports/BasicPort.ts +53 -0
- package/src/ports/ILocalPort.ts +12 -0
- package/src/ports/IPort.ts +12 -0
- package/src/ports/Port.ts +17 -0
- package/src/ports/ReturnPort.ts +19 -0
- package/src/ports/StandartPort.ts +13 -0
- package/src/service/Device.ts +225 -0
- package/src/service/DeviceConnect.ts +36 -0
- package/src/service/DevicePort.ts +46 -0
- package/src/service/IDeviceEvent.ts +5 -0
- package/src/test.ts +82 -0
- package/src/validator/IValidationProblem.ts +9 -0
- package/src/validator/IValidationRule.ts +10 -0
- package/src/validator/IValidationSubrule.ts +5 -0
- package/src/validator/Rule.ts +30 -0
- package/src/validator/Validator.ts +67 -0
- package/src/validator/types/ArrayType.ts +67 -0
- package/src/validator/types/BasicType.ts +61 -0
- package/src/validator/types/NumberType.ts +86 -0
- package/src/validator/types/ObjectType.ts +58 -0
- package/src/validator/types/StringType.ts +79 -0
- package/tsconfig.json +103 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright © 2022 Boris Bobylev. All rights reserved.
|
|
4
|
+
* Licensed under the Apache License, Version 2.0
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
const ErrorManager_1 = __importDefault(require("../../errors/ErrorManager"));
|
|
11
|
+
class BasicType {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.rule = {
|
|
14
|
+
type: '',
|
|
15
|
+
require: false,
|
|
16
|
+
default: undefined,
|
|
17
|
+
rules: [],
|
|
18
|
+
example: undefined,
|
|
19
|
+
description: ''
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
require() {
|
|
23
|
+
this.rule.require = true;
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
example(ex) {
|
|
27
|
+
this.rule.example = ex;
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
description(desc) {
|
|
31
|
+
this.rule.description = desc;
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
export() {
|
|
35
|
+
return this.rule;
|
|
36
|
+
}
|
|
37
|
+
static validate(obj, key, rule) {
|
|
38
|
+
BasicType.checkDefault(obj, key, rule);
|
|
39
|
+
BasicType.checkRequire(obj, key, rule);
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
static checkDefault(obj, key, rule) {
|
|
43
|
+
if (rule.default === undefined)
|
|
44
|
+
return;
|
|
45
|
+
if (obj[key] === undefined)
|
|
46
|
+
obj[key] = rule.default;
|
|
47
|
+
}
|
|
48
|
+
static checkRequire(obj, key, rule) {
|
|
49
|
+
if (obj[key] === undefined)
|
|
50
|
+
throw ErrorManager_1.default.make('VR_ERROR_REQUAERED', { key });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.default = BasicType;
|
|
54
|
+
ErrorManager_1.default.register('Validator', 'Jwg5Mr1NqaSj', 'VR_ERROR_REQUAERED', 'A value is required', {});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import BasicType from "./BasicType";
|
|
2
|
+
import IValidationRule from "../IValidationRule";
|
|
3
|
+
import IValidationSubrule from "../IValidationSubrule";
|
|
4
|
+
export default class NumberType extends BasicType {
|
|
5
|
+
constructor();
|
|
6
|
+
default(def: number): this;
|
|
7
|
+
integer(): this;
|
|
8
|
+
max(max: number): this;
|
|
9
|
+
min(min: number): this;
|
|
10
|
+
static validate(obj: {
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}, key: string, rule: IValidationRule): boolean;
|
|
13
|
+
protected static checkMax(obj: {
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
}, key: string, sub: IValidationSubrule): void;
|
|
16
|
+
protected static checkMin(obj: {
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
}, key: string, sub: IValidationSubrule): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright © 2022 Boris Bobylev. All rights reserved.
|
|
4
|
+
* Licensed under the Apache License, Version 2.0
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
const BasicType_1 = __importDefault(require("./BasicType"));
|
|
11
|
+
const ErrorManager_1 = __importDefault(require("../../errors/ErrorManager"));
|
|
12
|
+
class NumberType extends BasicType_1.default {
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
this.rule.type = 'number';
|
|
16
|
+
}
|
|
17
|
+
default(def) {
|
|
18
|
+
this.rule.default = def;
|
|
19
|
+
return this;
|
|
20
|
+
}
|
|
21
|
+
integer() {
|
|
22
|
+
this.rule.rules.push({ name: 'integer', args: {} });
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
max(max) {
|
|
26
|
+
this.rule.rules.push({ name: 'max', args: max });
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
min(min) {
|
|
30
|
+
this.rule.rules.push({ name: 'max', args: min });
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
static validate(obj, key, rule) {
|
|
34
|
+
BasicType_1.default.validate(obj, key, rule);
|
|
35
|
+
if (typeof obj[key] !== 'number')
|
|
36
|
+
throw ErrorManager_1.default.make('VR_IS_NOT_NUMBER', { key });
|
|
37
|
+
if (!Number.isInteger(obj[key]))
|
|
38
|
+
throw ErrorManager_1.default.make('VR_NUMBER_INTEGER', {});
|
|
39
|
+
for (const subrule of rule.rules) {
|
|
40
|
+
switch (subrule.name) {
|
|
41
|
+
case 'max':
|
|
42
|
+
NumberType.checkMax(obj, key, subrule);
|
|
43
|
+
break;
|
|
44
|
+
case 'min':
|
|
45
|
+
NumberType.checkMin(obj, key, subrule);
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
static checkMax(obj, key, sub) {
|
|
52
|
+
const val = obj[key];
|
|
53
|
+
if (val.length > sub.args)
|
|
54
|
+
throw ErrorManager_1.default.make('VR_NUMBER_MAX', { limit: sub.args });
|
|
55
|
+
}
|
|
56
|
+
static checkMin(obj, key, sub) {
|
|
57
|
+
const val = obj[key];
|
|
58
|
+
if (val.length < sub.args)
|
|
59
|
+
throw ErrorManager_1.default.make('VR_NUMBER_MIN', { limit: sub.args });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.default = NumberType;
|
|
63
|
+
ErrorManager_1.default.register('Validator', 'pn7B9po1UGRp', 'VR_IS_NOT_NUMBER', 'Value must be a number', {});
|
|
64
|
+
ErrorManager_1.default.register('Validator', 'fiUqanqqFlnt', 'VR_NUMBER_INTEGER', 'Value must be a integer', {});
|
|
65
|
+
ErrorManager_1.default.register('Validator', 'ZFSMAes0qdzC', 'VR_NUMBER_MAX', 'Number out of limit', {});
|
|
66
|
+
ErrorManager_1.default.register('Validator', 'B3zqsPub40HH', 'VR_NUMBER_MIN', 'Number out of limit', {});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import BasicType from "./BasicType";
|
|
2
|
+
import IValidationRule from "../IValidationRule";
|
|
3
|
+
import IValidationSubrule from "../IValidationSubrule";
|
|
4
|
+
export default class ObjectType extends BasicType {
|
|
5
|
+
constructor();
|
|
6
|
+
fields(obj: {
|
|
7
|
+
[key: string]: BasicType;
|
|
8
|
+
}): number;
|
|
9
|
+
static validate(obj: {
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
}, key: string, rule: IValidationRule): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Validate object fields
|
|
14
|
+
*/
|
|
15
|
+
protected static subValidate(obj: {
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
}, key: string, sub: IValidationSubrule): void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright © 2022 Boris Bobylev. All rights reserved.
|
|
4
|
+
* Licensed under the Apache License, Version 2.0
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
const BasicType_1 = __importDefault(require("./BasicType"));
|
|
11
|
+
const ErrorManager_1 = __importDefault(require("../../errors/ErrorManager"));
|
|
12
|
+
const Validator_1 = __importDefault(require("../Validator"));
|
|
13
|
+
const CoreError_1 = __importDefault(require("../../errors/CoreError"));
|
|
14
|
+
class ObjectType extends BasicType_1.default {
|
|
15
|
+
constructor() {
|
|
16
|
+
super();
|
|
17
|
+
this.rule.type = 'object';
|
|
18
|
+
}
|
|
19
|
+
fields(obj) {
|
|
20
|
+
return this.rule.rules.push({ name: 'fields', args: obj });
|
|
21
|
+
}
|
|
22
|
+
static validate(obj, key, rule) {
|
|
23
|
+
BasicType_1.default.validate(obj, key, rule);
|
|
24
|
+
if (typeof obj[key] !== 'object')
|
|
25
|
+
throw ErrorManager_1.default.make('VR_IS_NOT_OBJECT', {});
|
|
26
|
+
for (const subrule of rule.rules) {
|
|
27
|
+
switch (subrule.name) {
|
|
28
|
+
case 'fields':
|
|
29
|
+
ObjectType.subValidate(obj, key, subrule);
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Validate object fields
|
|
37
|
+
*/
|
|
38
|
+
static subValidate(obj, key, sub) {
|
|
39
|
+
try {
|
|
40
|
+
Validator_1.default.validate(sub.args, obj[key]);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error instanceof CoreError_1.default) {
|
|
44
|
+
throw ErrorManager_1.default.make('VR_ERROR_OBJECT_FIELDS', { key }).add(error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.default = ObjectType;
|
|
50
|
+
ErrorManager_1.default.register('Validator', 'zOPzOab9oLum', 'VR_IS_NOT_OBJECT', 'Value must be a object', {});
|
|
51
|
+
ErrorManager_1.default.register('Validator', 'p7qSfRGixV0M', 'VR_ERROR_OBJECT_FIELDS', 'Error of validation of fields inside the object', {});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import BasicType from "./BasicType";
|
|
2
|
+
import IValidationRule from "../IValidationRule";
|
|
3
|
+
import IValidationSubrule from "../IValidationSubrule";
|
|
4
|
+
export default class StringType extends BasicType {
|
|
5
|
+
constructor();
|
|
6
|
+
example(ex: string): this;
|
|
7
|
+
default(def: string): this;
|
|
8
|
+
maxLength(max: number): this;
|
|
9
|
+
minLength(min: number): this;
|
|
10
|
+
static validate(obj: {
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}, key: string, rule: IValidationRule): boolean;
|
|
13
|
+
protected static checkMaxLength(obj: {
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
}, key: string, sub: IValidationSubrule): void;
|
|
16
|
+
protected static checkMinLength(obj: {
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
}, key: string, sub: IValidationSubrule): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright © 2022 Boris Bobylev. All rights reserved.
|
|
4
|
+
* Licensed under the Apache License, Version 2.0
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
const BasicType_1 = __importDefault(require("./BasicType"));
|
|
11
|
+
const ErrorManager_1 = __importDefault(require("../../errors/ErrorManager"));
|
|
12
|
+
class StringType extends BasicType_1.default {
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
this.rule.type = 'string';
|
|
16
|
+
}
|
|
17
|
+
example(ex) {
|
|
18
|
+
this.rule.example = ex;
|
|
19
|
+
return this;
|
|
20
|
+
}
|
|
21
|
+
default(def) {
|
|
22
|
+
this.rule.default = def;
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
maxLength(max) {
|
|
26
|
+
this.rule.rules.push({ name: 'maxLength', args: max });
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
minLength(min) {
|
|
30
|
+
this.rule.rules.push({ name: 'minLength', args: min });
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
static validate(obj, key, rule) {
|
|
34
|
+
BasicType_1.default.validate(obj, key, rule);
|
|
35
|
+
if (typeof obj[key] !== 'string')
|
|
36
|
+
throw ErrorManager_1.default.make('VR_IS_NOT_STRING', { key });
|
|
37
|
+
for (const subrule of rule.rules) {
|
|
38
|
+
switch (subrule.name) {
|
|
39
|
+
case 'maxLength':
|
|
40
|
+
StringType.checkMaxLength(obj, key, subrule);
|
|
41
|
+
break;
|
|
42
|
+
case 'minLength':
|
|
43
|
+
StringType.checkMinLength(obj, key, subrule);
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
static checkMaxLength(obj, key, sub) {
|
|
50
|
+
const val = obj[key];
|
|
51
|
+
if (val.length >= sub.args)
|
|
52
|
+
throw ErrorManager_1.default.make('VR_STRING_MAX_LENGTH', { limit: sub.args, key });
|
|
53
|
+
}
|
|
54
|
+
static checkMinLength(obj, key, sub) {
|
|
55
|
+
const val = obj[key];
|
|
56
|
+
if (val.length <= sub.args)
|
|
57
|
+
throw ErrorManager_1.default.make('VR_STRING_MIN_LENGTH', { limit: sub.args, key });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.default = StringType;
|
|
61
|
+
ErrorManager_1.default.register('Validator', 'klmjxHyQrWuH', 'VR_IS_NOT_STRING', 'Value must be a string', {});
|
|
62
|
+
ErrorManager_1.default.register('Validator', 'BL5lxR4BinkA', 'VR_STRING_MAX_LENGTH', 'The maximum string length is limited', {});
|
|
63
|
+
ErrorManager_1.default.register('Validator', 'KsijTdsbd2YN', 'VR_STRING_MIN_LENGTH', 'The minimum string length is limited', {});
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vrack2-core",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "VRack2 core utils",
|
|
5
|
+
"main": "./lib/index",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node ./lib/test.js"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://gitlab.com/vrack/core-utils.git"
|
|
12
|
+
},
|
|
13
|
+
"author": "Boris Bobylev",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://gitlab.com/vrack/core-utils/issues"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://gitlab.com/vrack/core-utils#readme",
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^18.11.17",
|
|
21
|
+
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
|
22
|
+
"@typescript-eslint/parser": "^5.45.0",
|
|
23
|
+
"eslint": "^8.29.0",
|
|
24
|
+
"typescript": "^4.9.3"
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/Container.ts
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import EventEmitter from "events";
|
|
2
|
+
import DeviceManager from "./DeviceManager";
|
|
3
|
+
|
|
4
|
+
import ErrorManager from "./errors/ErrorManager";
|
|
5
|
+
import IServiceStructure from "./IServiceStructure";
|
|
6
|
+
import IStructureDevice from "./IStructureDevice";
|
|
7
|
+
import Device from "./service/Device";
|
|
8
|
+
import Rule from "./validator/Rule";
|
|
9
|
+
import CoreError from "./errors/CoreError";
|
|
10
|
+
import Validator from "./validator/Validator";
|
|
11
|
+
import BasicAction from "./actions/BasicAction";
|
|
12
|
+
import ImportManager from "./ImportManager";
|
|
13
|
+
import DevicePort from "./service/DevicePort";
|
|
14
|
+
|
|
15
|
+
import IPort from "./ports/IPort";
|
|
16
|
+
import DeviceConnect from "./service/DeviceConnect";
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
ErrorManager.register('Container', 'FBDRkSAWnlcc', 'CTR_ERROR_INIT_DEVICE', 'Device initialization error', {
|
|
20
|
+
deviceConfig: Rule.object().description('Device configuration')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
ErrorManager.register('Container', '96UX24PTyFU7', 'CTR_ERROR_INIT_CONNECTION', 'Connection initialization error', {
|
|
24
|
+
connection: Rule.string().description('Connection string')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
ErrorManager.register('Container', '0HVa3cO1E2vB', 'CTR_INCORRECT_DEVICE_ID', 'Incorrect device id', {})
|
|
29
|
+
ErrorManager.register('Container', 'uF62e07wloS9', 'CTR_DEVICE_DUBLICATE', 'Device id is dublicated', {})
|
|
30
|
+
ErrorManager.register('Container', '2RZznI3JDNUW', 'CTR_ERROR_PREPARE_OPTIONS', 'An error occurred while preparing options', {
|
|
31
|
+
message: Rule.string().description('Exception error string')
|
|
32
|
+
})
|
|
33
|
+
ErrorManager.register('Container', 'NDW2oD7mFxqB', 'CTR_DEVICE_ACTION_NF', 'Action on device not found', {
|
|
34
|
+
action: Rule.string().description('Action name'),
|
|
35
|
+
method: Rule.string().description('Method name')
|
|
36
|
+
})
|
|
37
|
+
ErrorManager.register('Container', 'jkIpU1p4z5uz', 'CTR_INCORRECT_DYNAMIC_PN', 'Incorrect dynamic port name', {
|
|
38
|
+
port: Rule.string().description('Incorrect port name')
|
|
39
|
+
})
|
|
40
|
+
ErrorManager.register('Container', 'e8m8dUVVOEU7', 'CTR_INCORRECT_PN', 'Incorrect port name', {
|
|
41
|
+
port: Rule.string().description('Incorrect port name')
|
|
42
|
+
})
|
|
43
|
+
ErrorManager.register('Container', 'qPevPU6SRJ18', 'CTR_INPUT_HANDLER_NF', 'Port input handler not found', {
|
|
44
|
+
port: Rule.string().description('Port name for handler'),
|
|
45
|
+
handler: Rule.string().description('Handler name')
|
|
46
|
+
})
|
|
47
|
+
ErrorManager.register('Container', 'Kp74OuVGNU0u', 'CTR_CONNECTION_INCORRECT', 'Incorrect connection format', {
|
|
48
|
+
connection: Rule.string().description('Connection string'),
|
|
49
|
+
error: Rule.string().description('String of error problem'),
|
|
50
|
+
})
|
|
51
|
+
ErrorManager.register('Container', 'eMrJEISxvali', 'CTR_CONNECTION_DEVICE_NF', 'Connection device not found', {
|
|
52
|
+
connection: Rule.string().description('Connection string'),
|
|
53
|
+
device: Rule.string().description('Device name not found')
|
|
54
|
+
})
|
|
55
|
+
ErrorManager.register('Container', 'CwFj1G47H45E', 'CTR_CONNECTION_PORT_NF', 'Connection port not found', {
|
|
56
|
+
connection: Rule.string().description('Connection string'),
|
|
57
|
+
port: Rule.string().description('Port name not found')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
export default class Container extends EventEmitter {
|
|
61
|
+
protected config: IServiceStructure
|
|
62
|
+
protected DeviceManager: DeviceManager
|
|
63
|
+
protected devices: { [key: string]: Device } = {}
|
|
64
|
+
protected deviceActions: { [key: string]: { [key: string]: BasicAction } }
|
|
65
|
+
|
|
66
|
+
constructor(config: IServiceStructure, dm: DeviceManager) {
|
|
67
|
+
super()
|
|
68
|
+
this.config = config
|
|
69
|
+
this.DeviceManager = dm
|
|
70
|
+
this.deviceActions = {}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async run() {
|
|
74
|
+
|
|
75
|
+
for (const device of this.config.devices) {
|
|
76
|
+
try {
|
|
77
|
+
await this.initDevice(device)
|
|
78
|
+
} catch (error) {
|
|
79
|
+
const ner = ErrorManager.make('CTR_ERROR_INIT_DEVICE', { deviceConfig: device })
|
|
80
|
+
if (error instanceof CoreError) ner.add(error)
|
|
81
|
+
throw ner
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
for (const conn of this.config.connections) {
|
|
86
|
+
try {
|
|
87
|
+
await this.initConnection(conn)
|
|
88
|
+
} catch (error) {
|
|
89
|
+
const ner = ErrorManager.make('CTR_ERROR_INIT_CONNECTION', { connection: conn })
|
|
90
|
+
if (error instanceof CoreError) ner.add(error)
|
|
91
|
+
throw ner
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const key in this.devices) this.devices[key].process()
|
|
96
|
+
for (const key in this.devices) await this.devices[key].processPromise()
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
// const cs = await this.DeviceManager.get('vrack.Master')
|
|
100
|
+
// const cse = new cs()
|
|
101
|
+
// console.log(cse)
|
|
102
|
+
// cse.run()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
protected async initDevice(dconf: IStructureDevice) {
|
|
107
|
+
const cs = await this.DeviceManager.get(dconf.type)
|
|
108
|
+
//
|
|
109
|
+
if (dconf.id === undefined || !dconf.id || typeof dconf.id !== 'string') {
|
|
110
|
+
throw ErrorManager.make('CTR_INCORRECT_DEVICE_ID')
|
|
111
|
+
}
|
|
112
|
+
// Device id is dublicated
|
|
113
|
+
if (dconf.id in this.devices) throw ErrorManager.make('CTR_DEVICE_DUBLICATE')
|
|
114
|
+
const dev = new cs(dconf.id, dconf.type, this) as Device
|
|
115
|
+
this.devices[dconf.id] = dev
|
|
116
|
+
// Fill options
|
|
117
|
+
for (const key in dconf.options) dev.options[key] = dconf.options[key]
|
|
118
|
+
|
|
119
|
+
// try prepare options
|
|
120
|
+
try {
|
|
121
|
+
dev.prepareOptions()
|
|
122
|
+
} catch (error) {
|
|
123
|
+
let message = ''
|
|
124
|
+
if (error instanceof Error) message = error.toString()
|
|
125
|
+
const ner = ErrorManager.make('CTR_ERROR_PREPARE_OPTIONS', { message })
|
|
126
|
+
if (error instanceof CoreError) ner.add(error)
|
|
127
|
+
throw ner
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const rules = dev.checkOptions()
|
|
131
|
+
// Validating
|
|
132
|
+
Validator.validate(rules, dev.options)
|
|
133
|
+
|
|
134
|
+
dev.preProcess()
|
|
135
|
+
|
|
136
|
+
// Check actions
|
|
137
|
+
this.deviceActions[dev.id] = dev.actions()
|
|
138
|
+
for (const action in this.deviceActions[dev.id]) {
|
|
139
|
+
const method = ImportManager.camelize('action.' + action)
|
|
140
|
+
if (!(method in dev)) throw ErrorManager.make('CTR_DEVICE_ACTION_NF', { action, method })
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
// make ports
|
|
145
|
+
// prepare ports
|
|
146
|
+
|
|
147
|
+
// make inputPorts
|
|
148
|
+
const iPorts = dev.inputs()
|
|
149
|
+
for (const key in iPorts) {
|
|
150
|
+
const exp = iPorts[key].export()
|
|
151
|
+
const pList = this.getPortList(key, exp)
|
|
152
|
+
for (const subkey in pList) {
|
|
153
|
+
this.checkPortName(subkey)
|
|
154
|
+
const handler = ImportManager.camelize('input.' + subkey) as keyof Device
|
|
155
|
+
this.checkInputHandler(subkey, handler , dev)
|
|
156
|
+
const ndp = new DevicePort(subkey, pList[subkey])
|
|
157
|
+
dev.ports.input[subkey] = ndp
|
|
158
|
+
if (handler in dev) ndp.push = dev[handler].bind(dev)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const oPorts = dev.outputs()
|
|
163
|
+
for (const key in oPorts) {
|
|
164
|
+
const exp = oPorts[key].export()
|
|
165
|
+
const pList = this.getPortList(key, exp)
|
|
166
|
+
for (const subkey in pList) {
|
|
167
|
+
this.checkPortName(subkey)
|
|
168
|
+
const ndp = new DevicePort(subkey, pList[subkey])
|
|
169
|
+
dev.ports.output[subkey] = ndp
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
protected checkInputHandler(port: string, handler:string, device: Device) {
|
|
175
|
+
if (!(handler in device)) throw ErrorManager.make('CTR_INPUT_HANDLER_NF', { port, handler })
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
protected async initConnection(conn: string) {
|
|
179
|
+
const cc = this.toConnection(conn)
|
|
180
|
+
if (!(cc.outputDevice in this.devices)) throw ErrorManager.make('CTR_CONNECTION_DEVICE_NF', { connection: conn, device: cc.outputDevice })
|
|
181
|
+
if (!(cc.outputPort in this.devices[cc.outputDevice].ports.output)) throw ErrorManager.make('CTR_CONNECTION_PORT_NF', { connection: conn, port: cc.outputPort })
|
|
182
|
+
|
|
183
|
+
if (!(cc.inputDevice in this.devices)) throw ErrorManager.make('CTR_CONNECTION_DEVICE_NF', { connection: conn, device: cc.inputDevice })
|
|
184
|
+
if (!(cc.inputPort in this.devices[cc.inputDevice].ports.input)) throw ErrorManager.make('CTR_CONNECTION_PORT_NF', { connection: conn, port: cc.inputPort })
|
|
185
|
+
const outPort =this.devices[cc.outputDevice].ports.output[cc.outputPort]
|
|
186
|
+
const inPort = this.devices[cc.inputDevice].ports.input[cc.inputPort]
|
|
187
|
+
new DeviceConnect(outPort, inPort)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private toConnection(con: string) {
|
|
191
|
+
const act = con.split('->')
|
|
192
|
+
if (act.length !== 2) throw ErrorManager.make('CTR_CONNECTION_INCORRECT', { connection: con, error: "Syntax connection error, syntax have -> beetwen device" })
|
|
193
|
+
|
|
194
|
+
const outputDeviceActs = act[0].split('.')
|
|
195
|
+
const inputDeviceActs = act[1].split('.')
|
|
196
|
+
|
|
197
|
+
if (outputDeviceActs.length > 3 || inputDeviceActs.length > 3) throw ErrorManager.make('CTR_CONNECTION_INCORRECT', { connection: con, error: "Syntax connection error, syntax have more 3 actets on side" })
|
|
198
|
+
if (outputDeviceActs.length < 2 || inputDeviceActs.length < 2) throw ErrorManager.make('CTR_CONNECTION_INCORRECT', { connection: con, error: "Syntax connection error, syntax have less 2 actets on side" })
|
|
199
|
+
|
|
200
|
+
let outputDevice = outputDeviceActs.shift()?.trim()
|
|
201
|
+
const outputPort = outputDeviceActs.join('.').trim()
|
|
202
|
+
let inputDevice = inputDeviceActs.shift()?.trim()
|
|
203
|
+
const inputPort = inputDeviceActs.join('.').trim()
|
|
204
|
+
|
|
205
|
+
if (outputDevice === undefined) outputDevice = ''
|
|
206
|
+
if (inputDevice === undefined) inputDevice = ''
|
|
207
|
+
|
|
208
|
+
const result: { [key: string]: string } = {
|
|
209
|
+
outputDevice, outputPort, inputDevice, inputPort
|
|
210
|
+
}
|
|
211
|
+
return result
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
protected checkPortName(port: string) {
|
|
215
|
+
if (!port.match(/[a-zA-Z0-9.]/)) throw ErrorManager.make('CTR_INCORRECT_PN', { port })
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
protected getPortList(name: string, iPort: IPort) {
|
|
219
|
+
const result: { [key: string]: IPort } = {}
|
|
220
|
+
if (!iPort.dynamic) {
|
|
221
|
+
result[name] = iPort
|
|
222
|
+
return result
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (!name.match(/%d/)) throw ErrorManager.make('CTR_INCORRECT_DYNAMIC_PN', { port: name })
|
|
226
|
+
|
|
227
|
+
for (let i = 1; i <= iPort.count; i++) {
|
|
228
|
+
const nIPort = Object.assign({}, iPort)
|
|
229
|
+
nIPort.count = 0
|
|
230
|
+
nIPort.dynamic = false
|
|
231
|
+
const nname = name.replace(/%d/, i + '')
|
|
232
|
+
result[nname] = nIPort
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return result
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import ErrorManager from './errors/ErrorManager'
|
|
4
|
+
import Rule from './validator/Rule'
|
|
5
|
+
|
|
6
|
+
interface IDeviceGroup {
|
|
7
|
+
name: string,
|
|
8
|
+
dir: string,
|
|
9
|
+
devices: Array<any>,
|
|
10
|
+
deviceList: Array<string>,
|
|
11
|
+
errors: Array<string>,
|
|
12
|
+
description: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface IDeviceInGroup{
|
|
16
|
+
name: string,
|
|
17
|
+
errors: Array<string>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
ErrorManager.register('DeviceManager', 'S5dBTBKTnVbF', 'DM_DEVICE_NOT_FOUND','Device not found', {
|
|
21
|
+
device: Rule.string().require().description('Device request name')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
export default class DeviceManager {
|
|
25
|
+
|
|
26
|
+
dir = './devices'
|
|
27
|
+
systemDir: string
|
|
28
|
+
|
|
29
|
+
devices = new Map<string, string>()
|
|
30
|
+
deviceList: Array<IDeviceGroup> = []
|
|
31
|
+
constructor(systemDir: string, dir: string) {
|
|
32
|
+
this.systemDir = systemDir
|
|
33
|
+
this.dir = dir
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
updateList() {
|
|
38
|
+
this.deviceList = this.devicesList()
|
|
39
|
+
for (const dgroup of this.deviceList) {
|
|
40
|
+
dgroup.devices = []
|
|
41
|
+
for (const device of dgroup.deviceList) {
|
|
42
|
+
const ndevice : IDeviceInGroup = { name: device, errors: [] }
|
|
43
|
+
dgroup.devices.push(ndevice)
|
|
44
|
+
const devicePath = path.join(this.systemDir, this.dir, dgroup.name, device + '.js')
|
|
45
|
+
if (!fs.existsSync(devicePath)) { ndevice.errors.push('File of device not found'); continue }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return this.deviceList
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
devicesList() {
|
|
52
|
+
const result: Array<IDeviceGroup> = []
|
|
53
|
+
const files = fs.readdirSync(path.join(this.systemDir, this.dir))
|
|
54
|
+
const dirs = this.getOnlyDirs(files)
|
|
55
|
+
dirs.sort()
|
|
56
|
+
for (const ddir of dirs) {
|
|
57
|
+
const group: IDeviceGroup = {
|
|
58
|
+
name: ddir,
|
|
59
|
+
dir: this.dir,
|
|
60
|
+
devices: [],
|
|
61
|
+
deviceList: [],
|
|
62
|
+
errors: [],
|
|
63
|
+
description: ''
|
|
64
|
+
}
|
|
65
|
+
result.push(group)
|
|
66
|
+
const listPath = path.join(this.systemDir, this.dir, ddir, 'list.json')
|
|
67
|
+
|
|
68
|
+
if (!fs.existsSync(listPath)) {
|
|
69
|
+
group.errors.push(listPath + ' ignored - list.json not found');
|
|
70
|
+
continue
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// @todo Исправить на SAFE
|
|
74
|
+
const list: Array<string> = JSON.parse(fs.readFileSync(listPath).toString('utf-8'))
|
|
75
|
+
if (!list || !Array.isArray(list)) {
|
|
76
|
+
group.errors.push(listPath + ' ignored - list.json incorrect');
|
|
77
|
+
continue
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
for (const listKey in list) {
|
|
81
|
+
const reqPath = path.join(this.systemDir, this.dir, ddir, list[listKey])
|
|
82
|
+
const devicePath = reqPath + '.js'
|
|
83
|
+
if (fs.existsSync(devicePath)) {
|
|
84
|
+
if (!this.devices.has(ddir + '.' + list[listKey])) this.devices.set(ddir + '.' + list[listKey], reqPath)
|
|
85
|
+
else console.log(devicePath + ' ignored - device not found')
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
list.sort()
|
|
89
|
+
|
|
90
|
+
group.deviceList = list
|
|
91
|
+
}
|
|
92
|
+
return result
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Return class of device
|
|
97
|
+
*
|
|
98
|
+
* Requires special device string of path
|
|
99
|
+
* example "vrack.System" where "vrack" is vendor and "System" is device class
|
|
100
|
+
* @param {string} device Device path string
|
|
101
|
+
*/
|
|
102
|
+
async get(device:string){
|
|
103
|
+
const p: string | undefined = this.devices.get(device)
|
|
104
|
+
if (typeof p ==='string') {
|
|
105
|
+
const deviceClass = await import(p)
|
|
106
|
+
if (deviceClass.default) return deviceClass.default
|
|
107
|
+
}
|
|
108
|
+
throw ErrorManager.make('DM_DEVICE_NOT_FOUND', { device })
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
*
|
|
113
|
+
*
|
|
114
|
+
*
|
|
115
|
+
*/
|
|
116
|
+
private getOnlyDirs(files: Array<string>) {
|
|
117
|
+
const result: Array<string> = []
|
|
118
|
+
for (const i in files) {
|
|
119
|
+
if (fs.statSync(path.join(this.systemDir, this.dir, files[i])).isDirectory()) result.push(files[i])
|
|
120
|
+
}
|
|
121
|
+
result.sort()
|
|
122
|
+
return result
|
|
123
|
+
}
|
|
124
|
+
}
|