2025-07-08 15:53:01 +02:00

206 lines
6.6 KiB
TypeScript

import { v4 as uuidv4 } from 'uuid';
import MessageBus from 'src/sdk/MessageBus';
import User from 'src/sdk/User';
export default class DocumentService {
private static readonly messageBus: MessageBus = MessageBus.getInstance();
private static readonly CACHE_TTL = 5 * 60 * 1000; // 5 minutes cache TTL
private constructor() { }
public static createDocument(documentData: any, validatorId: string): Promise<any> {
const ownerId = User.getInstance().getPairingId()!;
const processData: any = {
uid: uuidv4(),
utype: 'document',
isDeleted: 'false',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
...documentData,
};
const privateFields: string[] = Object.keys(processData);
privateFields.splice(privateFields.indexOf('uid'), 1);
privateFields.splice(privateFields.indexOf('utype'), 1);
privateFields.splice(privateFields.indexOf('isDeleted'), 1);
const roles: any = {
demiurge: {
members: [...[ownerId], validatorId],
validation_rules: [],
storages: []
},
owner: {
members: [ownerId],
validation_rules: [
{
quorum: 0.5,
fields: [...privateFields, 'roles', 'uid', 'utype'],
min_sig_member: 1,
},
],
storages: []
},
validator: {
members: [validatorId],
validation_rules: [
{
quorum: 0.5,
fields: ['idCertified', 'roles'],
min_sig_member: 1,
},
{
quorum: 0.0,
fields: [...privateFields],
min_sig_member: 0,
},
],
storages: []
},
apophis: {
members: [ownerId],
validation_rules: [],
storages: []
}
};
return new Promise<any>((resolve: (processCreated: any) => void, reject: (error: string) => void) => {
this.messageBus.createProcess(processData, privateFields, roles).then((processCreated: any) => {
this.messageBus.notifyUpdate(processCreated.processId, processCreated.process.states[0].state_id).then(() => {
this.messageBus.validateState(processCreated.processId, processCreated.process.states[0].state_id).then((_stateValidated: any) => {
this.getDocumentByUid(processCreated.processData.uid).then(resolve).catch(reject);
}).catch(reject);
}).catch(reject);
}).catch(reject);
});
}
public static getDocuments(): Promise<any[]> {
// Check if we have valid cache
const cacheProcesses: any[] = [];
const now = Date.now();
const customers: any[] = JSON.parse(sessionStorage.getItem('_documents') || '[]');
for (const customer of customers) {
if (now - customer.timestamp < this.CACHE_TTL) {
cacheProcesses.push(customer.process);
}
}
const cacheUids: string[] = cacheProcesses.map((process: any) => process.processData.uid);
return this.messageBus.getProcessesDecoded((publicValues: any) =>
publicValues['uid'] &&
publicValues['utype'] &&
publicValues['utype'] === 'document' &&
publicValues['isDeleted'] &&
publicValues['isDeleted'] === 'false' &&
!cacheUids.includes(publicValues['uid'])
).then((processes: any[]) => {
if (processes.length === 0) {
return cacheProcesses;
} else {
for (const process of processes) {
// Update cache
this.setCache(process);
cacheProcesses.push(process);
}
return cacheProcesses;
}
});
}
public static getDocumentByUid(uid: string): Promise<any> {
// Check if we have valid cache
const now = Date.now();
const cache: any = this.getCache(uid);
if (cache && (now - cache.timestamp) < this.CACHE_TTL) {
return Promise.resolve(cache.process);
}
return new Promise<any>((resolve: (process: any) => void, reject: (error: string) => void) => {
this.messageBus.getProcessesDecoded((publicValues: any) =>
publicValues['uid'] &&
publicValues['uid'] === uid &&
publicValues['utype'] &&
publicValues['utype'] === 'document' &&
publicValues['isDeleted'] &&
publicValues['isDeleted'] === 'false'
).then((processes: any[]) => {
if (processes.length === 0) {
resolve(null);
} else {
const process: any = processes[0];
// Update cache
this.setCache(process);
resolve(process);
}
}).catch(reject);
});
}
public static updateDocument(process: any, newData: any): Promise<void> {
return new Promise<void>((resolve: () => void, reject: (error: string) => void) => {
this.messageBus.updateProcess(process.processId, { updated_at: new Date().toISOString(), ...newData }, [], null).then((processUpdated: any) => {
const newStateId: string = processUpdated.diffs[0]?.state_id;
this.messageBus.notifyUpdate(process.processId, newStateId).then(() => {
this.messageBus.validateState(process.processId, newStateId).then((_stateValidated) => {
const documentUid: string = process.processData.uid;
this.removeCache(documentUid);
this.getDocumentByUid(documentUid).then(resolve).catch(reject);
}).catch(reject);
}).catch(reject);
}).catch(reject);
});
}
private static setCache(process: any): void {
const key: string = '_documents_';
const documents: any[] = JSON.parse(sessionStorage.getItem(key) || '[]');
const index: number = documents.findIndex((document: any) => document.process.processData.uid === process.processData.uid);
if (index !== -1) {
documents[index] = {
process: process,
timestamp: Date.now()
};
} else {
documents.push({
process: process,
timestamp: Date.now()
});
}
sessionStorage.setItem(key, JSON.stringify(documents));
}
private static getCache(uid: string): any {
const key: string = '_documents_';
const documents: any[] = JSON.parse(sessionStorage.getItem(key) || '[]');
if (documents.length === 0) {
return null;
}
return documents.find((document: any) => document.process.processData.uid === uid);
}
private static removeCache(uid: string): void {
const key: string = '_documents_';
const documents: any[] = JSON.parse(sessionStorage.getItem(key) || '[]');
const index: number = documents.findIndex((document: any) => document.process.processData.uid === uid);
if (index !== -1) {
documents.splice(index, 1);
}
sessionStorage.setItem(key, JSON.stringify(documents));
}
}