Skip to content

Commit

Permalink
fix(microservice): resolve issue if microservice is installed for the…
Browse files Browse the repository at this point in the history
… first time on tenant
  • Loading branch information
reey committed May 15, 2024
1 parent 24f6786 commit c157e27
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 84 deletions.
242 changes: 159 additions & 83 deletions node-red-c8y-storage-plugin/src/C8yHandler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Client } from '@c8y/client';
import { defaultCollectionNames } from './constants';
import { Client } from "@c8y/client";
import { defaultCollectionNames } from "./constants";

export class C8yHandler {
url: string;
Expand All @@ -8,7 +8,13 @@ export class C8yHandler {
user: string;
password: string;
applicationId: string;
constructor(url: string, tenant: string, user: string, password: string, applicationId: string) {
constructor(
url: string,
tenant: string,
user: string,
password: string,
applicationId: string
) {
this.url = url;
this.client = null;
this.tenant = tenant;
Expand All @@ -18,13 +24,19 @@ export class C8yHandler {
}

async connect() {
console.log('Connecting..');
console.log("Connecting..");
try {
const credentials = await Client.getMicroserviceSubscriptions({tenant: this.tenant, user: this.user, password: this.password}, this.url)
const credentials = await Client.getMicroserviceSubscriptions(
{ tenant: this.tenant, user: this.user, password: this.password },
this.url
);
const client = await Client.authenticate(credentials[0], this.url);
if (process.env.APPLICATION_KEY) {
const header = {'X-Cumulocity-Application-Key': this.applicationId};
client.core.defaultHeaders = Object.assign(header, client.core.defaultHeaders);
const header = { "X-Cumulocity-Application-Key": this.applicationId };
client.core.defaultHeaders = Object.assign(
header,
client.core.defaultHeaders
);
}
this.client = client;
} catch (e) {
Expand All @@ -36,137 +48,198 @@ export class C8yHandler {
async findAllMo(collectionName: string) {
const filter = {
pageSize: 1000,
query: `$filter=(has(${collectionName}) and has(${defaultCollectionNames.nodeRedMarker}))`
}
query: `$filter=(has(${collectionName}) and has(${defaultCollectionNames.nodeRedMarker}))`,
};
try {
const response = await this.client.inventory.list(filter);
return response;
} catch (e) {
console.error(e);
console.error(`Failed to during "findAllMo" for ${collectionName}`, e);
throw e;
}
}

findAll(collectionName: string) {
return this.findAllMo(collectionName).then(result => {
return result.data.map(tmp => tmp.full);
});
async findAll(collectionName: string) {
try {
const result = await this.findAllMo(collectionName);
return result.data.map((tmp) => tmp.full);
} catch (e) {
console.error(`Failed to during "findAll" for ${collectionName}`, e);
throw e;
}
}


async saveAll(collectionName: string, objects: any[]) {
await this.dropCollectionIfExists(collectionName);
try {
await this.dropCollectionIfExists(collectionName);

if (objects.length) {
const arr = Array.from(objects);
// TODO: try to find a way of creating in parallel
for (const entry of arr) {
const create = {
type: collectionName,
[collectionName]: {},
full: entry,
[defaultCollectionNames.nodeRedMarker]: {}
if (objects.length) {
const arr = Array.from(objects);
// TODO: try to find a way of creating in parallel
for (const entry of arr) {
const create = {
type: collectionName,
[collectionName]: {},
full: entry,
[defaultCollectionNames.nodeRedMarker]: {},
};
await this.client.inventory.create(create);
}
await this.client.inventory.create(create);
}
} catch (e) {
console.error(`Failed to during "saveAll" for ${collectionName}`, e);
throw e;
}
}

async saveAsOne(collectionName: string, object: any) {
await this.dropCollectionIfExists(collectionName);
try {
await this.dropCollectionIfExists(collectionName);

const create = {
type: collectionName,
[collectionName]: {},
full: JSON.stringify(object),
[defaultCollectionNames.nodeRedMarker]: {}
const create = {
type: collectionName,
[collectionName]: {},
full: JSON.stringify(object),
[defaultCollectionNames.nodeRedMarker]: {},
};
await this.client.inventory.create(create);
} catch (e) {
console.error(`Failed to during "saveAsOne" for ${collectionName}`, e);
throw e;
}
await this.client.inventory.create(create);
}

async getAsOne(collectionName: string) {
const result = await this.findAllMo(collectionName)
async getAsOne(collectionName: string, notExistingFallBackValue?: any) {
try {
const result = await this.findAllMo(collectionName);

if (result.data.length) {
const obj = JSON.parse(result.data[0].full);
if (result.data.length) {
const obj = JSON.parse(result.data[0].full);

return obj;
} else {
throw Error('');
return obj;
} else {
if (notExistingFallBackValue !== undefined) {
return notExistingFallBackValue
}
throw Error("");
}
} catch (e) {
console.error(`Failed to during "getAsOne" for ${collectionName}`, e);
throw e;
}
}

async getFromTenantOptions(collectionName: string, encrypted = true) {
try {
const res = await this.client.options.tenant.detail({
category: this.applicationId,
key: `${encrypted ? 'credentials.' : '' }` + collectionName
key: `${encrypted ? "credentials." : ""}` + collectionName,
});
return res.data.value ? JSON.parse(res.data.value) : {};
} catch (e) {
return {}
return {};
}
}

async saveInTenantOptions(collectionName: string, object: any, encrypted = true) {
const stored = await this.client.options.tenant.detail({
category: this.applicationId,
key: `${encrypted ? 'credentials.' : '' }` + collectionName
}).then(res => res.data, err => null);
async saveInTenantOptions(
collectionName: string,
object: any,
encrypted = true
) {
try {
const stored = await this.client.options.tenant
.detail({
category: this.applicationId,
key: `${encrypted ? "credentials." : ""}` + collectionName,
})
.then(
(res) => res.data,
(err) => null
);

if (!stored) {
await this.client.options.tenant.create({
category: this.applicationId,
key: `${encrypted ? 'credentials.' : '' }` + collectionName,
value: JSON.stringify(object)
});
} else {
await this.client.options.tenant.update({
category: this.applicationId,
key: `${encrypted ? 'credentials.' : '' }` + collectionName,
value: JSON.stringify(object)
});
if (!stored) {
await this.client.options.tenant.create({
category: this.applicationId,
key: `${encrypted ? "credentials." : ""}` + collectionName,
value: JSON.stringify(object),
});
} else {
await this.client.options.tenant.update({
category: this.applicationId,
key: `${encrypted ? "credentials." : ""}` + collectionName,
value: JSON.stringify(object),
});
}
} catch (e) {
console.error(
`Failed to during "saveInTenantOptions" for ${collectionName}`,
e
);
throw e;
}
}

async dropCollectionIfExists(collectionName: string) {
const collectionList = await this.findAllMo(collectionName);
try {
const collectionList = await this.findAllMo(collectionName);

if (collectionList && collectionList.data.length) {
// TODO: try to find a way of creating in parallel
for (const mo of collectionList.data) {
await this.client.inventory.delete(mo.id);
if (collectionList && collectionList.data.length) {
// TODO: try to find a way of creating in parallel
for (const mo of collectionList.data) {
await this.client.inventory.delete(mo.id);
}
}
} catch (e) {
console.error(
`Failed to during "dropCollectionIfExists" for ${collectionName}`,
e
);
throw e;
}
}

findMoByPath(collectionName: string, path: string) {
const filter = {
pageSize: 1,
query: `$filter=(has(${collectionName}) and (path eq '${path}') and has(${defaultCollectionNames.nodeRedMarker}))`
async findMoByPath(collectionName: string, path: string) {
try {
const filter = {
pageSize: 1,
query: `$filter=(has(${collectionName}) and (path eq '${path}') and has(${defaultCollectionNames.nodeRedMarker}))`,
};
return await this.client.inventory.list(filter);
} catch (e) {
console.error(`Failed to during "findMoByPath" for ${collectionName}`, e);
throw e;
}
return this.client.inventory.list(filter);
}

async findOneByPath(collectionName: string, path: string) {
return await this.findMoByPath(collectionName, path).then(result => {
if (result.data && result.data.length) {
const body = result.data[0].body;
return body || {};
} else {
throw Error("404");
}
});
try {
const result = await this.findMoByPath(collectionName, path);
if (result.data && result.data.length) {
const body = result.data[0].body;
return body || {};
} else {
throw Error("404");
}
} catch (e) {
console.error(`Failed to during "findOneByPath" for ${collectionName}`, e);
throw e;
}
}

saveOrUpdateByPath(collectionName: string, path: string, meta: any, body: any) {
return this.findMoByPath(collectionName, path).then(result => {
async saveOrUpdateByPath(
collectionName: string,
path: string,
meta: any,
body: any
) {
try {
const result = await this.findMoByPath(collectionName, path);
if (result.data.length) {
const mo = result.data[0];
const update = {
id: mo.id,
meta,
body
body,
};
return this.client.inventory.update(update);
} else {
Expand All @@ -176,10 +249,13 @@ export class C8yHandler {
path,
meta,
body,
[defaultCollectionNames.nodeRedMarker]: {}
[defaultCollectionNames.nodeRedMarker]: {},
};
return this.client.inventory.create(create);
}
});
} catch (e) {
console.error(`Failed to during "saveOrUpdateByPath" for ${collectionName}`, e);
throw e;
}
}
};
}
2 changes: 1 addition & 1 deletion node-red-c8y-storage-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function saveCredentials(credentials: any) {
}

export function getSettings() {
return c8yHandler.getAsOne(this.collectionNames.settings);
return c8yHandler.getAsOne(this.collectionNames.settings, {});
}

export function saveSettings(newSettings: any) {
Expand Down

0 comments on commit c157e27

Please sign in to comment.