import {Id, isId} from "../shared"; export * from './pipe'; import {AccessOptions, LayerProfile, readLayerProfile, SystemClient, SystemError} from "../system"; import {ServiceClient, ServiceError} from "../service"; import {loadNode, loadUniverseYaml, Universe} from "../modeling"; import {Subject} from "rxjs"; import {Pipe} from "./pipe"; export interface VyzeInterface { _?: T; } type UniverseEvent = [Universe, 'load' | 'refresh']; export class Client { private readonly _serviceClient: ServiceClient; private readonly _systemClient: SystemClient; private _selectedUniverse?: string; private _universes: Map; private _universe: Subject<[Universe, 'load' | 'refresh']>; public constructor(serviceClient: ServiceClient, systemClient: SystemClient) { this._serviceClient = serviceClient; this._systemClient = systemClient; this._universes = new Map(); this._universe = new Subject(); } public get service(): ServiceClient { return this._serviceClient; } public get system(): SystemClient { return this._systemClient; } public async loadUniverse(universe: string | Universe): Promise { let _name: string; let _universe: Universe | undefined; if (typeof universe === 'string') { if (universe.length > 128) { // Try to parse universe _universe = loadUniverseYaml(universe); } if (_universe) { _name = _universe.name; } else { // Treat it as universe name or id let universeId: string | undefined; if (isId(universe)) { universeId = universe; } else { const universeResponse = await this.service.resolveUniverse(universe); if (!(universeResponse instanceof ServiceError)) { universeId = universeResponse; } } if (!universeId) { return undefined; } _universe = await this.service.loadUniverse(universeId); if (!_universe) { return; } _name = _universe.name; } } else { _name = universe.name; _universe = universe; } if (!_universe) { return undefined; } this._universes.set(_name, _universe); this._selectedUniverse = _name; this._universe.next([_universe, 'load']); return _universe; } public async refreshUniverse(): Promise { if (!this.universe) { return undefined; } const universe = await this.service.loadUniverse(this.universe.id!, false); if (!universe) { return undefined; } this._universes.set(this.universe.name, universe); this._universe.next([universe, 'refresh']); return universe; } public get universe(): Universe | undefined { if (!this._selectedUniverse) { return undefined; } return this._universes.get(this._selectedUniverse); } public async loadProfile(profile: string | LayerProfile): Promise { let _profile: LayerProfile | undefined; if (typeof profile === 'string') { if (profile.length > 32) { _profile = readLayerProfile(profile); } if (!_profile) { const profileResponse = await this.service.getLayerProfile(profile); if (!(profileResponse instanceof ServiceError)) { _profile = profileResponse; } } } else { _profile = profile; } if (!_profile) { return undefined; } this.system.layerProfile = _profile; return _profile; } public get universeEvent(): Subject { return this._universe; } /** * @deprecated */ public async getTypedNode>(nodeName: N['_'] & string, id: Id): Promise { return await this.getNode(nodeName, id); } /** * @deprecated */ public async putTypedNode>(nodeName: N['_'] & string, node: N, id?: Id): Promise { return await this.putNode(nodeName, node, id); } /** * @deprecated */ public async getNode(nodeName: string, id: Id): Promise { if (!this.universe) { throw new Error('no universe selected'); } const entryNode = this.universe.getEndpoint(nodeName); if (!entryNode) { throw new Error(`node ${nodeName} could not be found`); } const nodeDef = entryNode.resolveDefinition(this.universe); if (!nodeDef) { throw new Error(`node def could not be obtained`); } return await this.system.getNode({ type: 'context', context: { context: { environment: { type: 'primitive', }, value: id, }, node: nodeDef, } }); } /** * @deprecated */ public async getNodes(nodeName: string, absId?: Id): Promise { if (!this.universe) { throw new Error('no universe selected'); } const entryNode = this.universe.getEndpoint(nodeName); if (!entryNode) { throw new Error(`node ${nodeName} could not be found`); } const nodeDef = entryNode.resolveDefinition(this.universe); if (!nodeDef) { throw new Error(`node def could not be obtained`); } if (absId) { absId = this.universe.resolve(absId); if (!absId) { throw new Error(`model "${absId}" could not be resolved`); } } else { absId = entryNode.context?.environment.model?.object; if (!absId) { throw new Error(`could not determine abstract ID`); } } return await this.system.getNode({ type: 'context', context: { context: { environment: { type: 'primitive', }, value: absId, }, node: { type: 'specials', specials: { type: 'list', direct: true, indirect: true, node: { type: 'list', list: { entry: nodeDef, } }, }, }, } }); } /** * @deprecated */ public async putNode(nodeName: string, node: N, absId?: Id): Promise { if (!this.universe) { throw new Error('no universe selected'); } const entryNode = this.universe.getEndpoint(nodeName); if (!entryNode) { throw new Error(`node ${nodeName} could not be found`); } if (!entryNode.context?.environment.model) { throw new Error(`node model could not be found`); } const nodeDef = entryNode.resolveDefinition(this.universe); if (!nodeDef) { throw new Error(`node def could not be obtained`); } if (absId) { return await this.system.putNode({ type: 'context', context: { context: { environment: { type: 'primitive', }, value: absId, }, node: { type: 'specials', specials: { type: 'primitive', direct: true, indirect: true, node: nodeDef, }, } }, }, node); } else { return await this.system.putNode(nodeDef, node); } } public async getObjects(pipe: Pipe, accessOptions?: AccessOptions) { if (!this.universe) { throw new Error('require universe'); } await pipe.loadPipe(this.universe); const listNodeDef = pipe.listNode(); if (!listNodeDef) { throw new Error('node is undefined'); } const listNode = loadNode(listNodeDef, this.universe); const listNodeResolved = listNode.resolveDefinition(this.universe); if (!listNodeResolved) { throw new Error('could not resolve node'); } return this.system.getNode(listNodeResolved, accessOptions); } public async getObject(pipe: Pipe, accessOptions?: AccessOptions) { if (!this.universe) { throw new Error('require universe'); } await pipe.loadPipe(this.universe); const objectNodeDef = pipe.objectNode(); if (!objectNodeDef) { throw new Error('node is undefined'); } const objectNode = loadNode(objectNodeDef, this.universe); const objectNodeResolved = objectNode.resolveDefinition(this.universe); if (!objectNodeResolved) { throw new Error('could not resolve node'); } return this.system.getNode(objectNodeResolved, accessOptions); } public async putObjects(pipe: Pipe, values: any[], accessName?: string, accessOptions?: AccessOptions) { if (!this.universe) { throw new Error('require universe'); } await pipe.loadPipe(this.universe); const listNodeDef = pipe.listNode(); if (!listNodeDef) { throw new Error('node is undefined'); } const listNode = loadNode(listNodeDef, this.universe); const listNodeResolved = listNode.resolveDefinition(this.universe); if (!listNodeResolved) { throw new Error('could not resolve node'); } return this.system.putNode(listNodeResolved, values, accessName, accessOptions); } public async putObject(pipe: Pipe, value: any, accessName?: string, accessOptions?: AccessOptions) { if (!this.universe) { throw new Error('require universe'); } await pipe.loadPipe(this.universe); const objectNodeDef = pipe.objectNode(); if (!objectNodeDef) { throw new Error('node is undefined'); } const objectNode = loadNode(objectNodeDef, this.universe); const objectNodeResolved = objectNode.resolveDefinition(this.universe); if (!objectNodeResolved) { throw new Error('could not resolve node'); } return this.system.putNode(objectNodeResolved, value, accessName, accessOptions); } }