kuzzle-device-manager 0.4.8 → 0.4.9

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.
Files changed (61) hide show
  1. package/index.d.ts +4 -0
  2. package/index.js +17 -0
  3. package/lib/DeviceManagerPlugin.d.ts +100 -0
  4. package/lib/DeviceManagerPlugin.js +237 -0
  5. package/lib/controllers/AssetController.d.ts +7 -0
  6. package/lib/controllers/AssetController.js +53 -0
  7. package/lib/controllers/CRUDController.d.ts +34 -0
  8. package/lib/controllers/CRUDController.js +65 -0
  9. package/lib/controllers/DeviceController.d.ts +56 -0
  10. package/lib/controllers/DeviceController.js +218 -0
  11. package/lib/controllers/index.d.ts +3 -0
  12. package/lib/controllers/index.js +16 -0
  13. package/lib/core-classes/BatchProcessing/BatchController.d.ts +32 -0
  14. package/lib/core-classes/BatchProcessing/BatchController.js +86 -0
  15. package/lib/core-classes/BatchProcessing/BatchWriter.d.ts +110 -0
  16. package/lib/core-classes/BatchProcessing/BatchWriter.js +264 -0
  17. package/lib/core-classes/BatchProcessing/InstrumentablePromise.d.ts +6 -0
  18. package/lib/core-classes/BatchProcessing/InstrumentablePromise.js +13 -0
  19. package/lib/core-classes/BatchProcessing/index.d.ts +3 -0
  20. package/lib/core-classes/BatchProcessing/index.js +16 -0
  21. package/lib/core-classes/CustomMappings/AssetMappingsManager.d.ts +31 -0
  22. package/lib/core-classes/CustomMappings/AssetMappingsManager.js +79 -0
  23. package/lib/core-classes/CustomMappings/DeviceMappingsManager.d.ts +43 -0
  24. package/lib/core-classes/CustomMappings/DeviceMappingsManager.js +71 -0
  25. package/lib/core-classes/Decoder.d.ts +133 -0
  26. package/lib/core-classes/Decoder.js +166 -0
  27. package/lib/core-classes/DeviceManagerEngine.d.ts +21 -0
  28. package/lib/core-classes/DeviceManagerEngine.js +64 -0
  29. package/lib/core-classes/DeviceService.d.ts +41 -0
  30. package/lib/core-classes/DeviceService.js +264 -0
  31. package/lib/core-classes/MigrationService.d.ts +13 -0
  32. package/lib/core-classes/MigrationService.js +49 -0
  33. package/lib/core-classes/PayloadService.d.ts +43 -0
  34. package/lib/core-classes/PayloadService.js +191 -0
  35. package/lib/core-classes/index.d.ts +8 -0
  36. package/lib/core-classes/index.js +21 -0
  37. package/lib/models/BaseAsset.d.ts +56 -0
  38. package/lib/models/BaseAsset.js +58 -0
  39. package/lib/models/Catalog.d.ts +55 -0
  40. package/lib/models/Catalog.js +38 -0
  41. package/lib/models/Config.d.ts +33 -0
  42. package/lib/models/Config.js +26 -0
  43. package/lib/models/Device.d.ts +102 -0
  44. package/lib/models/Device.js +91 -0
  45. package/lib/models/index.d.ts +3 -0
  46. package/lib/models/index.js +16 -0
  47. package/lib/types/AssetsHistoryContent.d.ts +9 -0
  48. package/lib/types/AssetsHistoryContent.js +3 -0
  49. package/lib/types/BaseAssetContent.d.ts +8 -0
  50. package/lib/types/BaseAssetContent.js +3 -0
  51. package/lib/types/DeviceContent.d.ts +62 -0
  52. package/lib/types/DeviceContent.js +3 -0
  53. package/lib/types/Measure.d.ts +54 -0
  54. package/lib/types/Measure.js +3 -0
  55. package/lib/types/index.d.ts +3 -0
  56. package/lib/types/index.js +16 -0
  57. package/lib/utils/events.d.ts +8 -0
  58. package/lib/utils/events.js +17 -0
  59. package/lib/utils/index.d.ts +1 -0
  60. package/lib/utils/index.js +14 -0
  61. package/package.json +1 -1
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Decoder = void 0;
7
+ const kuzzle_1 = require("kuzzle");
8
+ const lodash_1 = __importDefault(require("lodash"));
9
+ /* eslint-disable @typescript-eslint/no-unused-vars */
10
+ /* eslint-disable @typescript-eslint/no-empty-function */
11
+ /**
12
+ * Base class to implement a decoder for a device model.
13
+ * The device model must be passed to the parent constructor.
14
+ * The abstract "decode" method must be implemented.
15
+ */
16
+ class Decoder {
17
+ /**
18
+ * @param deviceModel Device model for this decoder
19
+ */
20
+ constructor(deviceModel) {
21
+ /**
22
+ * Custom mappings for the payload collection.
23
+ * It will be injected in the "payload" property and it should allows to index
24
+ * the device model unique identifier field.
25
+ *
26
+ * @example
27
+ * this.payloadsMappings = {
28
+ * device_properties: {
29
+ * properties: {
30
+ * deveui: { type: 'keyword' }
31
+ * }
32
+ * }
33
+ * }
34
+ */
35
+ this.payloadsMappings = {};
36
+ this.deviceModel = deviceModel;
37
+ }
38
+ /**
39
+ * Define custom HTTP routes
40
+ *
41
+ * @param http HttpRoute array
42
+ */
43
+ set http(http) {
44
+ this._http = http;
45
+ }
46
+ get http() {
47
+ return this._http || [{ verb: 'post', path: `device-manager/payload/${this.action}` }];
48
+ }
49
+ /**
50
+ * Validate the payload format before processing.
51
+ *
52
+ * If the method:
53
+ * - return true: the payload will be processed (status 200)
54
+ * - return false: the payload will be skipped (status 200)
55
+ * - throw an error: the payload will be skipped (status 4** or 5**)
56
+ *
57
+ * @param payload Raw payload received in the API action body
58
+ * @param request Original request
59
+ *
60
+ * @return A boolean indicating if the payload is valid
61
+ */
62
+ async validate(payload, request) {
63
+ return true;
64
+ }
65
+ /**
66
+ * Hook executed before processing the payload but after validation
67
+ *
68
+ * @param payload Raw payload received in the API action body
69
+ * @param request Original request
70
+ */
71
+ async beforeProcessing(payload, request) {
72
+ }
73
+ /**
74
+ * Enrichment hook executed before registering a device
75
+ *
76
+ * @param device Densor before being persisted
77
+ * @param request Original request
78
+ *
79
+ * @returns Enriched device
80
+ */
81
+ async beforeRegister(device, request) {
82
+ return device;
83
+ }
84
+ /**
85
+ * Hook executed after registering a device.
86
+ * Return value of this method will be returned in the API action result.
87
+ *
88
+ * @param device Device after being persisted
89
+ * @param request Original request
90
+ *
91
+ * @returns Result of the corresponding API action
92
+ */
93
+ async afterRegister(device, request) {
94
+ return {
95
+ tenantId: device._source.tenantId,
96
+ device: device.serialize(),
97
+ asset: null,
98
+ };
99
+ }
100
+ /**
101
+ * Enrichment hook executed before updating a device
102
+ *
103
+ * @param device Device before being updated
104
+ * @param request Original request
105
+ *
106
+ * @returns Enriched device
107
+ */
108
+ async beforeUpdate(device, request) {
109
+ return device;
110
+ }
111
+ /**
112
+ * Hook executed after updating a device.
113
+ * Return value of this method will be returned in the API action result.
114
+ *
115
+ * @param device Device after being updated
116
+ * @param request Original request
117
+ *
118
+ * @returns Result of the corresponding API action
119
+ */
120
+ async afterUpdate(device, asset, request) {
121
+ return {
122
+ tenantId: device._source.tenantId,
123
+ device: device.serialize(),
124
+ asset: asset ? asset.serialize() : null,
125
+ };
126
+ }
127
+ /**
128
+ * Build the "measures" property that will be persisted in the asset document
129
+ *
130
+ * @param device Device after being updated
131
+ *
132
+ * @returns Content of the "measures" property
133
+ */
134
+ async copyToAsset(device) {
135
+ const measures = {};
136
+ for (const [measureType, measure] of Object.entries(device._source.measures)) {
137
+ measures[measureType] = {
138
+ id: device._id,
139
+ model: device._source.model,
140
+ reference: device._source.reference,
141
+ ...measure,
142
+ qos: device._source.qos,
143
+ };
144
+ }
145
+ return measures;
146
+ }
147
+ /**
148
+ * Checks if the provided properties are present in the payload
149
+ *
150
+ * @param payload Raw payload received in the API action body
151
+ * @param paths Paths of properties (lodash style)
152
+ *
153
+ * @throws
154
+ */
155
+ ensureProperties(payload, paths) {
156
+ for (const path of paths) {
157
+ if (!lodash_1.default.has(payload, path)) {
158
+ throw new kuzzle_1.PreconditionError(`Missing property "${path}" in payload`);
159
+ }
160
+ }
161
+ }
162
+ }
163
+ exports.Decoder = Decoder;
164
+ /* eslint-enable @typescript-eslint/no-unused-vars */
165
+ /* eslint-enable @typescript-eslint/no-empty-function */
166
+ //# sourceMappingURL=Decoder.js.map
@@ -0,0 +1,21 @@
1
+ import { Plugin } from 'kuzzle';
2
+ import { AbstractEngine } from 'kuzzle-plugin-commons';
3
+ import { DeviceManagerConfig, DeviceManagerPlugin } from '../DeviceManagerPlugin';
4
+ import { AssetMappingsManager } from './CustomMappings/AssetMappingsManager';
5
+ import { DeviceMappingsManager } from './CustomMappings/DeviceMappingsManager';
6
+ export declare class DeviceManagerEngine extends AbstractEngine<DeviceManagerPlugin> {
7
+ config: DeviceManagerConfig;
8
+ private assetMappings;
9
+ private deviceMappings;
10
+ constructor(plugin: Plugin, assetMappings: AssetMappingsManager, deviceMappings: DeviceMappingsManager);
11
+ onCreate(index: string, group?: string): Promise<{
12
+ collections: string[];
13
+ }>;
14
+ onUpdate(index: string, group?: string): Promise<{
15
+ collections: string[];
16
+ }>;
17
+ onDelete(index: string): Promise<{
18
+ collections: string[];
19
+ }>;
20
+ private getAssetsHistoryMappings;
21
+ }
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DeviceManagerEngine = void 0;
4
+ const kuzzle_plugin_commons_1 = require("kuzzle-plugin-commons");
5
+ const models_1 = require("../models");
6
+ class DeviceManagerEngine extends kuzzle_plugin_commons_1.AbstractEngine {
7
+ constructor(plugin, assetMappings, deviceMappings) {
8
+ super('device-manager', plugin, plugin.config.adminIndex, plugin.config.configCollection);
9
+ this.assetMappings = assetMappings;
10
+ this.deviceMappings = deviceMappings;
11
+ }
12
+ async onCreate(index, group = 'commons') {
13
+ const promises = [];
14
+ promises.push(this.sdk.collection.create(index, 'assets', {
15
+ mappings: this.assetMappings.get(group)
16
+ }));
17
+ promises.push(this.sdk.collection.create(index, 'asset-history', {
18
+ mappings: this.getAssetsHistoryMappings(group)
19
+ }));
20
+ promises.push(this.sdk.collection.create(index, 'devices', {
21
+ mappings: this.deviceMappings.get()
22
+ }));
23
+ promises.push(this.sdk.collection.create(index, this.config.configCollection, {
24
+ mappings: {
25
+ dynamic: 'strict',
26
+ properties: {
27
+ type: { type: 'keyword' },
28
+ catalog: models_1.catalogMappings,
29
+ }
30
+ }
31
+ }));
32
+ await Promise.all(promises);
33
+ return { collections: ['assets', 'asset-history', this.config.configCollection, 'devices'] };
34
+ }
35
+ async onUpdate(index, group = 'commons') {
36
+ const promises = [];
37
+ promises.push(this.sdk.collection.create(index, 'assets', {
38
+ mappings: this.assetMappings.get(group)
39
+ }));
40
+ promises.push(this.sdk.collection.create(index, 'asset-history', {
41
+ mappings: this.getAssetsHistoryMappings(group)
42
+ }));
43
+ promises.push(this.sdk.collection.create(index, 'devices', {
44
+ mappings: this.deviceMappings.get()
45
+ }));
46
+ await Promise.all(promises);
47
+ return { collections: ['assets', 'asset-history', 'devices'] };
48
+ }
49
+ async onDelete(index) {
50
+ const promises = [];
51
+ promises.push(this.sdk.collection.delete(index, 'assets'));
52
+ promises.push(this.sdk.collection.delete(index, 'asset-history'));
53
+ promises.push(this.sdk.collection.delete(index, 'devices'));
54
+ await Promise.all(promises);
55
+ return { collections: ['assets', 'asset-history', 'devices'] };
56
+ }
57
+ getAssetsHistoryMappings(group) {
58
+ const mappings = JSON.parse(JSON.stringify(this.config.collections['asset-history']));
59
+ mappings.properties.asset = this.assetMappings.get(group);
60
+ return mappings;
61
+ }
62
+ }
63
+ exports.DeviceManagerEngine = DeviceManagerEngine;
64
+ //# sourceMappingURL=DeviceManagerEngine.js.map
@@ -0,0 +1,41 @@
1
+ import { JSONObject, EmbeddedSDK, Plugin } from 'kuzzle';
2
+ import { DeviceBulkContent, DeviceMAttachementContent } from '../types';
3
+ import { Decoder } from './Decoder';
4
+ import { Device } from '../models';
5
+ export declare class DeviceService {
6
+ private config;
7
+ private context;
8
+ private decoders;
9
+ get sdk(): EmbeddedSDK;
10
+ constructor(plugin: Plugin, decoders: Map<string, Decoder>);
11
+ mAttach(devices: Device[], bulkData: DeviceBulkContent[], { strict, options }: {
12
+ strict?: boolean;
13
+ options?: JSONObject;
14
+ }): Promise<DeviceMAttachementContent>;
15
+ mDetach(devices: Device[], bulkData: DeviceBulkContent[], { strict, options }: {
16
+ strict?: boolean;
17
+ options?: JSONObject;
18
+ }): Promise<{
19
+ errors: any[];
20
+ successes: any[];
21
+ }>;
22
+ mLink(devices: Device[], bulkData: DeviceBulkContent[], { strict, options }: {
23
+ strict?: boolean;
24
+ options?: JSONObject;
25
+ }): Promise<{
26
+ errors: any[];
27
+ successes: any[];
28
+ }>;
29
+ mUnlink(devices: Device[], { strict, options }: {
30
+ strict?: boolean;
31
+ options?: JSONObject;
32
+ }): Promise<{
33
+ errors: any[];
34
+ successes: any[];
35
+ }>;
36
+ private eraseAssetMeasure;
37
+ private tenantExists;
38
+ private buildBulkDevices;
39
+ private formatDevicesContent;
40
+ private writeToDatabase;
41
+ }
@@ -0,0 +1,264 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DeviceService = void 0;
4
+ const kuzzle_1 = require("kuzzle");
5
+ class DeviceService {
6
+ constructor(plugin, decoders) {
7
+ this.config = plugin.config;
8
+ this.context = plugin.context;
9
+ this.decoders = decoders;
10
+ }
11
+ get sdk() {
12
+ return this.context.accessors.sdk;
13
+ }
14
+ async mAttach(devices, bulkData, { strict, options }) {
15
+ const attachedDevices = devices.filter(device => device._source.tenantId);
16
+ if (strict && attachedDevices.length > 0) {
17
+ const ids = attachedDevices.map(device => device._id).join(',');
18
+ throw new kuzzle_1.BadRequestError(`These devices "${ids}" are already attached to a tenant`);
19
+ }
20
+ const documents = this.buildBulkDevices(bulkData);
21
+ const results = {
22
+ errors: [],
23
+ successes: [],
24
+ };
25
+ for (let i = 0; i < documents.length; i++) {
26
+ const document = documents[i];
27
+ const tenantExists = await this.tenantExists(document.tenantId);
28
+ if (strict && !tenantExists) {
29
+ throw new kuzzle_1.BadRequestError(`Tenant "${document.tenantId}" does not have a device-manager engine`);
30
+ }
31
+ else if (!strict && !tenantExists) {
32
+ results.errors.push(`Tenant "${document.tenantId}" does not have a device-manager engine`);
33
+ continue;
34
+ }
35
+ const deviceDocuments = this.formatDevicesContent(devices, document);
36
+ const { errors, successes } = await this.writeToDatabase(deviceDocuments, async (deviceDocuments) => {
37
+ const updated = await this.sdk.document.mUpdate(this.config.adminIndex, 'devices', deviceDocuments, { strict, ...options });
38
+ await this.sdk.document.mCreate(document.tenantId, 'devices', deviceDocuments, { strict, ...options });
39
+ return {
40
+ successes: results.successes.concat(updated.successes),
41
+ errors: results.errors.concat(updated.errors)
42
+ };
43
+ });
44
+ results.successes.concat(successes);
45
+ results.errors.concat(errors);
46
+ }
47
+ return results;
48
+ }
49
+ async mDetach(devices, bulkData, { strict, options }) {
50
+ const detachedDevices = devices.filter(device => {
51
+ return !device._source.tenantId || device._source.tenantId === null;
52
+ });
53
+ if (strict && detachedDevices.length > 0) {
54
+ const ids = detachedDevices.map(device => device._id).join(',');
55
+ throw new kuzzle_1.BadRequestError(`Devices "${ids}" are not attached to a tenant`);
56
+ }
57
+ const linkedAssets = devices.filter(device => device._source.assetId);
58
+ if (strict && linkedAssets.length > 0) {
59
+ const ids = linkedAssets.map(device => device._id).join(',');
60
+ throw new kuzzle_1.BadRequestError(`Devices "${ids}" are still linked to an asset`);
61
+ }
62
+ const builder = bulkData.map(data => {
63
+ const { deviceId } = data;
64
+ const device = devices.find(s => s._id === deviceId);
65
+ return { tenantId: device._source.tenantId, deviceId };
66
+ });
67
+ const documents = this.buildBulkDevices(builder);
68
+ const results = {
69
+ errors: [],
70
+ successes: [],
71
+ };
72
+ for (let i = 0; i < documents.length; i++) {
73
+ const document = documents[i];
74
+ const devicesContent = devices.filter(({ _id }) => document.deviceIds.includes(_id));
75
+ const deviceDocuments = devicesContent.map(device => {
76
+ return { _id: device._id, body: { tenantId: null } };
77
+ });
78
+ const { errors, successes } = await this.writeToDatabase(deviceDocuments, async (deviceDocuments) => {
79
+ const updated = await this.sdk.document.mUpdate(this.config.adminIndex, 'devices', deviceDocuments, { strict, ...options });
80
+ await this.sdk.document.mDelete(document.tenantId, 'devices', deviceDocuments.map(device => device._id), { strict, ...options });
81
+ return {
82
+ successes: results.successes.concat(updated.successes),
83
+ errors: results.errors.concat(updated.errors)
84
+ };
85
+ });
86
+ results.successes.concat(successes);
87
+ results.errors.concat(errors);
88
+ }
89
+ return results;
90
+ }
91
+ async mLink(devices, bulkData, { strict, options }) {
92
+ const detachedDevices = devices.filter(device => {
93
+ return !device._source.tenantId || device._source.tenantId === null;
94
+ });
95
+ if (strict && detachedDevices.length > 0) {
96
+ const ids = detachedDevices.map(device => device._id).join(',');
97
+ throw new kuzzle_1.PreconditionError(`Devices "${ids}" are not attached to a tenant`);
98
+ }
99
+ const builder = bulkData.map(data => {
100
+ const { deviceId, assetId } = data;
101
+ const device = devices.find(s => s._id === deviceId);
102
+ return { tenantId: device._source.tenantId, deviceId, assetId };
103
+ });
104
+ const documents = this.buildBulkDevices(builder);
105
+ const results = {
106
+ errors: [],
107
+ successes: [],
108
+ };
109
+ for (let i = 0; i < documents.length; i++) {
110
+ const document = documents[i];
111
+ const existingAssets = await this.sdk.document.mGet(document.tenantId, 'assets', document.assetIds);
112
+ if (strict && existingAssets.errors.length > 0) {
113
+ throw new kuzzle_1.NotFoundError(`Assets "${existingAssets.errors}" do not exist`);
114
+ }
115
+ const devicesContent = devices.filter(({ _id }) => document.deviceIds.includes(_id));
116
+ const deviceDocuments = [];
117
+ const assetDocuments = [];
118
+ for (const device of devicesContent) {
119
+ const decoder = this.decoders.get(device._source.model);
120
+ const measures = await decoder.copyToAsset(device);
121
+ const { assetId } = bulkData.find(data => data.deviceId === device._id);
122
+ deviceDocuments.push({ _id: device._id, body: { assetId } });
123
+ assetDocuments.push({ _id: assetId, body: { measures } });
124
+ }
125
+ const updatedDevice = await this.writeToDatabase(deviceDocuments, async (deviceDocuments) => {
126
+ const updated = await this.sdk.document.mUpdate(this.config.adminIndex, 'devices', deviceDocuments, { strict, ...options });
127
+ await this.sdk.document.mUpdate(document.tenantId, 'devices', deviceDocuments, { strict, ...options });
128
+ return {
129
+ successes: results.successes.concat(updated.successes),
130
+ errors: results.errors.concat(updated.errors)
131
+ };
132
+ });
133
+ const updatedAssets = await this.writeToDatabase(assetDocuments, async (assetDocuments) => {
134
+ const updated = await this.sdk.document.mUpdate(document.tenantId, 'assets', assetDocuments, { strict, ...options });
135
+ return {
136
+ successes: results.successes.concat(updated.successes),
137
+ errors: results.errors.concat(updated.errors)
138
+ };
139
+ });
140
+ results.successes.concat(updatedDevice.successes, updatedAssets.successes);
141
+ results.errors.concat(updatedDevice.errors, updatedDevice.errors);
142
+ }
143
+ return results;
144
+ }
145
+ async mUnlink(devices, { strict, options }) {
146
+ const unlinkedDevices = devices.filter(device => !device._source.assetId);
147
+ if (strict && unlinkedDevices.length > 0) {
148
+ const ids = unlinkedDevices.map(d => d._id);
149
+ throw new kuzzle_1.BadRequestError(`Devices "${ids}" are not linked to an asset`);
150
+ }
151
+ const builder = devices.map(device => {
152
+ const { _id, _source } = device;
153
+ return { tenantId: _source.tenantId, deviceId: _id, assetId: _source.assetId };
154
+ });
155
+ const documents = this.buildBulkDevices(builder);
156
+ const results = {
157
+ errors: [],
158
+ successes: [],
159
+ };
160
+ for (let i = 0; i < documents.length; i++) {
161
+ const document = documents[i];
162
+ const devicesContent = devices.filter(({ _id }) => document.deviceIds.includes(_id));
163
+ const deviceDocuments = [];
164
+ const assetDocuments = [];
165
+ for (const device of devicesContent) {
166
+ deviceDocuments.push({ _id: device._id, body: { assetId: null } });
167
+ const measures = await this.eraseAssetMeasure(document.tenantId, device);
168
+ assetDocuments.push({ _id: device._source.assetId, body: { measures } });
169
+ }
170
+ const updatedDevice = await this.writeToDatabase(deviceDocuments, async (deviceDocuments) => {
171
+ const updated = await this.sdk.document.mUpdate(this.config.adminIndex, 'devices', deviceDocuments, { strict, ...options });
172
+ await this.sdk.document.mUpdate(document.tenantId, 'devices', deviceDocuments, { strict, ...options });
173
+ return {
174
+ successes: results.successes.concat(updated.successes),
175
+ errors: results.errors.concat(updated.errors)
176
+ };
177
+ });
178
+ const updatedAssets = await this.writeToDatabase(assetDocuments, async (assetDocuments) => {
179
+ const updated = await this.sdk.document.mUpdate(document.tenantId, 'assets', assetDocuments, { strict, ...options });
180
+ return {
181
+ successes: results.successes.concat(updated.successes),
182
+ errors: results.errors.concat(updated.errors)
183
+ };
184
+ });
185
+ results.successes.concat(updatedDevice.successes, updatedAssets.successes);
186
+ results.errors.concat(updatedDevice.errors, updatedDevice.errors);
187
+ }
188
+ return results;
189
+ }
190
+ async eraseAssetMeasure(tenantId, device) {
191
+ const { _source: { measures } } = await this.sdk.document.get(tenantId, 'assets', device._source.assetId);
192
+ for (const [measureName] of Object.entries(device._source.measures)) {
193
+ if (measures[measureName]) {
194
+ measures[measureName] = undefined;
195
+ }
196
+ }
197
+ return measures;
198
+ }
199
+ async tenantExists(tenantId) {
200
+ const { result: tenantExists } = await this.sdk.query({
201
+ controller: 'device-manager/engine',
202
+ action: 'exists',
203
+ index: tenantId,
204
+ });
205
+ return tenantExists;
206
+ }
207
+ buildBulkDevices(bulkData) {
208
+ const documents = [];
209
+ for (let i = 0; i < bulkData.length; i++) {
210
+ const { tenantId, deviceId, assetId } = bulkData[i];
211
+ const document = documents.find(doc => doc.tenantId === tenantId);
212
+ if (document) {
213
+ document.deviceIds.push(deviceId);
214
+ document.assetIds.push(assetId);
215
+ }
216
+ else {
217
+ documents.push({ tenantId, deviceIds: [deviceId], assetIds: [assetId] });
218
+ }
219
+ }
220
+ return documents;
221
+ }
222
+ formatDevicesContent(devices, document) {
223
+ const devicesContent = devices.filter(device => document.deviceIds.includes(device._id));
224
+ const devicesDocuments = devicesContent.map(device => {
225
+ device._source.tenantId = document.tenantId;
226
+ return { _id: device._id, body: device._source };
227
+ });
228
+ return devicesDocuments;
229
+ }
230
+ async writeToDatabase(deviceDocuments, writer) {
231
+ const results = {
232
+ errors: [],
233
+ successes: [],
234
+ };
235
+ const limit = global.kuzzle.config.limits.documentsWriteCount;
236
+ if (deviceDocuments.length <= limit) {
237
+ const { successes, errors } = await writer(deviceDocuments);
238
+ results.successes.push(successes);
239
+ results.errors.push(errors);
240
+ return results;
241
+ }
242
+ const writeMany = async (start, end) => {
243
+ const devices = deviceDocuments.slice(start, end);
244
+ const { successes, errors } = await writer(devices);
245
+ results.successes.push(successes);
246
+ results.errors.push(errors);
247
+ };
248
+ let offset = 0;
249
+ let offsetLimit = limit;
250
+ let done = false;
251
+ while (!done) {
252
+ await writeMany(offset, offsetLimit);
253
+ offset += limit;
254
+ offsetLimit += limit;
255
+ if (offsetLimit >= deviceDocuments.length) {
256
+ done = true;
257
+ await writeMany(offset, deviceDocuments.length);
258
+ }
259
+ }
260
+ return results;
261
+ }
262
+ }
263
+ exports.DeviceService = DeviceService;
264
+ //# sourceMappingURL=DeviceService.js.map
@@ -0,0 +1,13 @@
1
+ import { Plugin } from 'kuzzle';
2
+ export declare class MigrationService {
3
+ private config;
4
+ private context;
5
+ private prefix;
6
+ get sdk(): import("kuzzle").EmbeddedSDK;
7
+ constructor(pluginName: string, plugin: Plugin);
8
+ run(): Promise<void>;
9
+ /**
10
+ * Migrate the engine documents into the new config collection
11
+ */
12
+ private engineCollection;
13
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MigrationService = void 0;
4
+ class MigrationService {
5
+ constructor(pluginName, plugin) {
6
+ this.config = plugin.config;
7
+ this.context = plugin.context;
8
+ this.prefix = pluginName;
9
+ }
10
+ get sdk() {
11
+ return this.context.accessors.sdk;
12
+ }
13
+ async run() {
14
+ global.app.install(`${this.prefix}-O.3.0`, async () => {
15
+ await this.engineCollection();
16
+ });
17
+ }
18
+ /**
19
+ * Migrate the engine documents into the new config collection
20
+ */
21
+ async engineCollection() {
22
+ if (!await this.sdk.collection.exists(this.config.adminIndex, 'engines')) {
23
+ return;
24
+ }
25
+ this.context.log.info('Migrate engine documents into the config collection...');
26
+ let result = await this.sdk.document.search(this.config.adminIndex, 'engines', {}, { scroll: '1s', size: 100 });
27
+ let count = 0;
28
+ while (result) {
29
+ const documents = [];
30
+ for (const { _id, _source } of result.hits) {
31
+ documents.push({
32
+ _id,
33
+ body: {
34
+ type: 'engine-device-manager',
35
+ engine: { index: _source.index },
36
+ },
37
+ });
38
+ }
39
+ await this.sdk.document.mCreate(this.config.adminIndex, this.config.configCollection, documents, {
40
+ strict: true,
41
+ });
42
+ count += documents.length;
43
+ result = await result.next();
44
+ }
45
+ this.context.log.info(`Successfully migrated ${count} documents.`);
46
+ }
47
+ }
48
+ exports.MigrationService = MigrationService;
49
+ //# sourceMappingURL=MigrationService.js.map
@@ -0,0 +1,43 @@
1
+ import { KuzzleRequest, EmbeddedSDK, Plugin } from 'kuzzle';
2
+ import { Decoder } from './Decoder';
3
+ import { BatchWriter } from './BatchProcessing';
4
+ export declare type PayloadHandler = (request: KuzzleRequest, decoder: Decoder) => Promise<any>;
5
+ export declare class PayloadService {
6
+ private config;
7
+ private context;
8
+ private batchController;
9
+ get sdk(): EmbeddedSDK;
10
+ constructor(plugin: Plugin, batchWriter: BatchWriter);
11
+ process(request: KuzzleRequest, decoder: Decoder, { refresh }?: {
12
+ refresh?: any;
13
+ }): Promise<any>;
14
+ private register;
15
+ /**
16
+ * Device provisioning strategy.
17
+ *
18
+ * If autoProvisionning is on, device is automatically registered, otherwise
19
+ * we request the admin provisioning catalog to ensure this device is allowed
20
+ * to register.
21
+ *
22
+ * After registration, we look at the admin provisioning catalog entry to:
23
+ * - attach the device to a tenant
24
+ * - link the device to an asset of this tenant
25
+ *
26
+ * Then we look into the tenant provisioning catalog entry to:
27
+ * - link the device to an asset of this tenant
28
+ */
29
+ private deviceProvisionning;
30
+ /**
31
+ * Get the device entry from the provisioning catalog in corresponding index
32
+ */
33
+ private getCatalogEntry;
34
+ private update;
35
+ /**
36
+ * Propagate the measures inside the asset document.
37
+ */
38
+ private propagateToAsset;
39
+ /**
40
+ * Creates an history entry for an asset
41
+ */
42
+ private historizeAsset;
43
+ }