Skip to content

Commit

Permalink
feat: digitaltwin exports (#315)
Browse files Browse the repository at this point in the history
* refactor(MeasureExporter): use AbstractExporter
* feat(export): implement assets export
* feat(export): implement devices export
  • Loading branch information
sebtiz13 authored Aug 22, 2023
1 parent 05b8a53 commit aab65af
Show file tree
Hide file tree
Showing 17 changed files with 882 additions and 257 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ dist/
types/dist/

# Test files
asset.csv
/*.csv
121 changes: 90 additions & 31 deletions lib/modules/asset/AssetsController.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ControllerDefinition, HttpStream, KuzzleRequest } from "kuzzle";
import { PassThrough } from "stream";

import { MeasureExporter } from "../measure/";
import { DeviceManagerPlugin } from "../plugin";
import { DeviceManagerPlugin, InternalCollection } from "../plugin";
import { DigitalTwinExporter } from "../shared";

import { AssetService } from "./AssetService";
import { AssetSerializer } from "./model/AssetSerializer";
Expand All @@ -17,6 +17,8 @@ import {

export class AssetsController {
public definition: ControllerDefinition;
private exporter: DigitalTwinExporter;
private measureExporter: MeasureExporter;

constructor(
private plugin: DeviceManagerPlugin,
Expand Down Expand Up @@ -76,9 +78,31 @@ export class AssetsController {
},
],
},
export: {
handler: this.export.bind(this),
http: [
{
path: "device-manager/:engineId/assets/_export/:exportId",
verb: "get",
},
{
path: "device-manager/:engineId/assets/_export",
verb: "post",
},
],
},
},
};
/* eslint-enable sort-keys */

this.exporter = new DigitalTwinExporter(
this.plugin,
InternalCollection.ASSETS
);
this.measureExporter = new MeasureExporter(
this.plugin,
InternalCollection.ASSETS
);
}

async get(request: KuzzleRequest): Promise<ApiAssetGetResult> {
Expand Down Expand Up @@ -177,19 +201,21 @@ export class AssetsController {
const sort = request.input.body?.sort;
const type = request.input.args.type;

const exporter = new MeasureExporter(this.plugin, engineId, {
target: "asset",
});

const { measures, total } = await exporter.search(id, {
endAt,
from,
query,
size,
sort,
startAt,
type,
});
const { measures, total } = await this.measureExporter.search(
engineId,
{
endAt,
id,
query,
sort,
startAt,
type,
},
{
from,
size,
}
);

return { measures, total };
}
Expand All @@ -203,11 +229,7 @@ export class AssetsController {
) {
const exportId = request.getString("exportId");

const stream = new PassThrough();

const exporter = new MeasureExporter(this.plugin, engineId);

const { id } = await exporter.getExport(exportId);
const { id } = await this.measureExporter.getExport(engineId, exportId);

request.response.configure({
headers: {
Expand All @@ -216,7 +238,7 @@ export class AssetsController {
},
});

exporter.sendExport(stream, exportId);
const stream = await this.measureExporter.sendExport(engineId, exportId);

return new HttpStream(stream);
}
Expand All @@ -230,17 +252,54 @@ export class AssetsController {
const sort = request.input.body?.sort;
const type = request.input.args.type;

const exporter = new MeasureExporter(this.plugin, engineId, {
target: "asset",
});
const link = await this.measureExporter.prepareExport(
engineId,
request.getUser(),
{
endAt,
id,
query,
sort,
startAt,
type,
}
);

const { link } = await exporter.prepareExport(request.getUser(), id, {
endAt,
query,
sort,
startAt,
type,
});
return { link };
}

async export(request: KuzzleRequest) {
const engineId = request.getString("engineId");

if (
request.context.connection.protocol === "http" &&
request.context.connection.misc.verb === "GET"
) {
const exportId = request.getString("exportId");

request.response.configure({
headers: {
"Content-Disposition": `attachment; filename="${InternalCollection.ASSETS}.csv"`,
"Content-Type": "text/csv",
},
});

const stream = await this.exporter.sendExport(engineId, exportId);

return new HttpStream(stream);
}

const query = request.input.body?.query;
const sort = request.input.body?.sort;

const link = await this.exporter.prepareExport(
engineId,
request.getUser(),
{
query,
sort,
}
);

return { link };
}
Expand Down
12 changes: 12 additions & 0 deletions lib/modules/asset/types/AssetApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,15 @@ export interface ApiAssetExportMeasuresRequest extends AssetsControllerRequest {
export type ApiAssetExportMeasuresResult = {
link: string;
};

export interface ApiAssetExportRequest extends AssetsControllerRequest {
action: "export";

body?: {
query?: JSONObject;
sort?: JSONObject;
};
}
export type ApiAssetExportResult = {
link: string;
};
120 changes: 88 additions & 32 deletions lib/modules/device/DevicesController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import {
KuzzleRequest,
} from "kuzzle";
import _ from "lodash";
import { PassThrough } from "node:stream";

import { AssetSerializer } from "../asset/model/AssetSerializer";
import { MeasureExporter, DecodedMeasurement } from "../measure";
import { DeviceManagerPlugin } from "../plugin";
import { DeviceManagerPlugin, InternalCollection } from "../plugin";
import { DigitalTwinExporter } from "../shared";

import { DeviceService } from "./DeviceService";
import { DeviceSerializer } from "./model/DeviceSerializer";
Expand All @@ -29,6 +29,8 @@ import {

export class DevicesController {
public definition: ControllerDefinition;
private exporter: DigitalTwinExporter;
private measureExporter: MeasureExporter;

constructor(
private plugin: DeviceManagerPlugin,
Expand Down Expand Up @@ -136,9 +138,31 @@ export class DevicesController {
},
],
},
export: {
handler: this.export.bind(this),
http: [
{
path: "device-manager/:engineId/devices/_export/:exportId",
verb: "get",
},
{
path: "device-manager/:engineId/devices/_export",
verb: "post",
},
],
},
},
};
/* eslint-enable sort-keys */

this.exporter = new DigitalTwinExporter(
this.plugin,
InternalCollection.DEVICES
);
this.measureExporter = new MeasureExporter(
this.plugin,
InternalCollection.DEVICES
);
}

async get(request: KuzzleRequest): Promise<ApiDeviceGetResult> {
Expand Down Expand Up @@ -332,19 +356,18 @@ export class DevicesController {
const sort = request.input.body?.sort;
const type = request.input.args.type;

const exporter = new MeasureExporter(this.plugin, engineId, {
target: "device",
});

const { measures, total } = await exporter.search(id, {
endAt,
from,
query,
size,
sort,
startAt,
type,
});
const { measures, total } = await this.measureExporter.search(
engineId,
{
endAt,
id,
query,
sort,
startAt,
type,
},
{ from, size }
);

return { measures, total };
}
Expand All @@ -358,11 +381,7 @@ export class DevicesController {
) {
const exportId = request.getString("exportId");

const stream = new PassThrough();

const exporter = new MeasureExporter(this.plugin, engineId);

const { id } = await exporter.getExport(exportId);
const { id } = await this.measureExporter.getExport(engineId, exportId);

request.response.configure({
headers: {
Expand All @@ -371,7 +390,7 @@ export class DevicesController {
},
});

exporter.sendExport(stream, exportId);
const stream = await this.measureExporter.sendExport(engineId, exportId);

return new HttpStream(stream);
}
Expand All @@ -385,17 +404,18 @@ export class DevicesController {
const sort = request.input.body?.sort;
const type = request.input.args.type;

const exporter = new MeasureExporter(this.plugin, engineId, {
target: "device",
});

const { link } = await exporter.prepareExport(request.getUser(), id, {
endAt,
query,
sort,
startAt,
type,
});
const link = await this.measureExporter.prepareExport(
engineId,
request.getUser(),
{
endAt,
id,
query,
sort,
startAt,
type,
}
);

return { link };
}
Expand Down Expand Up @@ -443,4 +463,40 @@ export class DevicesController {
payloadUuids
);
}

async export(request: KuzzleRequest) {
const engineId = request.getString("engineId");

if (
request.context.connection.protocol === "http" &&
request.context.connection.misc.verb === "GET"
) {
const exportId = request.getString("exportId");

request.response.configure({
headers: {
"Content-Disposition": `attachment; filename="${InternalCollection.DEVICES}.csv"`,
"Content-Type": "text/csv",
},
});

const stream = await this.exporter.sendExport(engineId, exportId);

return new HttpStream(stream);
}

const query = request.input.body?.query;
const sort = request.input.body?.sort;

const link = await this.exporter.prepareExport(
engineId,
request.getUser(),
{
query,
sort,
}
);

return { link };
}
}
12 changes: 12 additions & 0 deletions lib/modules/device/types/DeviceApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,15 @@ export interface ApiDeviceReceiveMeasuresRequest<
};
}
export type ApiDeviceReceiveMeasuresResult = void;

export interface ApiDeviceExportRequest extends DevicesControllerRequest {
action: "export";

body?: {
query?: JSONObject;
sort?: JSONObject;
};
}
export type ApiDeviceExportResult = {
link: string;
};
Loading

0 comments on commit aab65af

Please sign in to comment.