UNPKG

wowok_agent

Version:

Agent for WoWok: Unlock Co-Creation, Lighting Transaction, Empower Potential.

379 lines (350 loc) 18.9 kB
import { PassportObject, Errors, ERROR, Permission, PermissionIndex, TransactionBlock, TxbAddress, PermissionIndexType, Machine, Machine_Forward as Wowok_Machine_Forward, Machine_Node_Pair as Wowok_Machine_Node_Pair, Machine_Node as Wowok_Machine_Node, ParentProgress, Progress, ProgressNext, PermissionObject, OrderWrap, Service, ServiceWrap, } from 'wowok'; import { AccountOrMark_Address, CallBase, CallResult, GetManyAccountOrMark_Address, GetObjectExisted, GetObjectMain, GetObjectParam, Namedbject, ObjectMain, ObjectsOp, TypeNamedObjectWithPermission } from "./base.js"; import { ObjectMachine, query_objects } from '../query/objects.js'; import { LocalMark } from '../local/local.js'; import { Account } from '../local/account.js'; export interface Supply { service: string; bRequired?: boolean; // If true, An order at least must be placed from this service provider } export interface Machine_Forward { name: string; // foward name namedOperator?: string; // dynamic operator permission?: PermissionIndexType; // this.permission-index or named-operator MUST one defined. weight?: number; guard?: string; suppliers?: Supply[]; // List of service providers } export interface Machine_Node_Pair { prior_node: string; forwards: Machine_Forward[]; threshold?: number; } export interface Machine_Node { name: string; pairs: Machine_Node_Pair[]; } export interface ProgressDeliverable { msg: string; orders: string[]; } /// The execution priority is determined by the order in which the object attributes are arranged export interface CallMachine_Data { object?: ObjectMain; progress_new?: {task_address?:string, namedNew?: Namedbject}; progress_context_repository?: {progress?:string; repository:string | null}; progress_namedOperator?: {progress?:string; data:{name:string, operators:AccountOrMark_Address[]}[]}; progress_parent?: {progress?:string, parent:ParentProgress | null}; progress_hold?: {progress?:string; operation:ProgressNext; bHold:boolean; adminUnhold?:boolean}; progress_task?: {progress:string; task_address:string}; progress_next?: {progress:string; operation:ProgressNext; deliverable:ProgressDeliverable}; description?: string; endpoint?: string; consensus_repository?: ObjectsOp; nodes?: {op: 'add'; data: Machine_Node[]} | {op: 'remove'; names: string[], bTransferMyself?:boolean} | {op:'rename node'; data:{old:string; new:string}[]} | {op:'add from myself'; addresses: string[]} | {op:'remove pair'; pairs: {prior_node_name:string; node_name:string}[]} | {op:'add forward'; data: {prior_node_name:string; node_name:string; forward:Machine_Forward; threshold?:number; remove_forward?:string}[]} | {op:'remove forward'; data:{prior_node_name:string; node_name:string; forward_name:string}[]} bPublished?: boolean; bPaused?: boolean; clone_new?: {namedNew?: Namedbject/*, description?:string*/}; } export class CallMachine extends CallBase { //@ todo self-owned node operate data: CallMachine_Data; object_address: string | undefined = undefined; permission_address: string | undefined = undefined; constructor(data:CallMachine_Data) { super(); this.data = data; } private async resolveForward(forward:Machine_Forward) : Promise<Wowok_Machine_Forward> { const res:ServiceWrap[] = []; if (forward?.suppliers && forward.suppliers?.length > 0) { const r = await query_objects({objects:forward.suppliers.map(v=>v.service)}); for (let i=0; r.objects && i<r.objects?.length; ++ i) { if (r.objects[i]?.type === 'Service') { res.push({object:r.objects[i].object, bRequired:forward.suppliers[i].bRequired, pay_token_type:Service.parseObjectType(r.objects[i].type_raw)}); } } } return {name:forward.name, namedOperator:forward.namedOperator, permission:forward.permission, weight:forward.weight, guard:forward.guard, suppliers:res.length > 0 ? res: undefined}; } protected async prepare() { if (!this.object_address) { this.object_address = (await LocalMark.Instance().get_address(GetObjectExisted(this.data?.object))); } if (this.object_address) { await this.update_content('Machine', this.object_address); if (!this.content) ERROR(Errors.InvalidParam, 'CallMachine_Data.data.object:' + this.object_address); this.permission_address = (this.content as ObjectMachine).permission; } else { const n = GetObjectMain(this.data?.object) as TypeNamedObjectWithPermission; this.permission_address = (await LocalMark.Instance().get_address(GetObjectExisted(n?.permission))); } } async call(account?:string) : Promise<CallResult> { var checkOwner = false; const guards : string[] = []; const perms : PermissionIndexType[] = []; await this.prepare(); if (this.permission_address) { if (!this.data?.object) { perms.push(PermissionIndex.machine) } if (this.data?.description != null && this.object_address) { perms.push(PermissionIndex.machine_description) } if (this.data?.endpoint != null && this.object_address) { perms.push(PermissionIndex.machine_endpoint) } if (this.data?.consensus_repository != null) { perms.push(PermissionIndex.machine_repository) } if (this.data?.nodes != null) { perms.push(PermissionIndex.machine_node) } if (this.data?.bPublished) { // publish is an irreversible one-time operation perms.push(PermissionIndex.machine_publish) } if (this.data?.progress_new != null) { perms.push(PermissionIndex.progress) } if (this.data?.progress_context_repository != null) { perms.push(PermissionIndex.progress_context_repository) } if (this.data?.progress_namedOperator != null) { perms.push(PermissionIndex.progress_namedOperator) } if (this.data?.progress_parent != null) { perms.push(PermissionIndex.progress_parent) } if (this.data?.progress_task != null) { perms.push(PermissionIndex.progress_bind_task) } if (this.data?.progress_hold != null) { if (this.data.progress_hold.adminUnhold) { perms.push(PermissionIndex.progress_unhold) } } if (this.data?.bPaused != null) { perms.push(PermissionIndex.machine_pause) } if (this.data?.clone_new!= null) { perms.push(PermissionIndex.machine_clone) } if (this.data?.progress_next != null) { if (this.object_address) { // fetch guard const [p, acc] = await Promise.all([ await LocalMark.Instance().get_address(this.data?.progress_next.progress), await Account.Instance().get(account)]); if (!p) ERROR(Errors.InvalidParam, 'CallMachine_Data.data.progress_next.progress'); if (!acc) ERROR(Errors.InvalidParam, 'CallMachine_Data.account'); const guard = await Progress.QueryForwardGuard(p, this.object_address, acc.address, this.data.progress_next.operation.next_node_name, this.data.progress_next.operation.forward); if (guard) { guards.push(guard); } } } return await this.check_permission_and_call(this.permission_address, perms, guards, checkOwner, undefined, account) } return await this.exec(account); } protected async operate(txb:TransactionBlock, passport?:PassportObject, account?:string) { let obj : Machine | undefined ; let perm: Permission | undefined; let permission : PermissionObject | undefined; if (this.object_address) { obj = Machine.From(txb, this.permission_address!, this.object_address); permission = this.permission_address; } else { const n = GetObjectMain(this.data?.object) as TypeNamedObjectWithPermission; permission = await LocalMark.Instance().get_address(GetObjectExisted(n?.permission)); if (!permission) { perm = Permission.New(txb, GetObjectParam(n?.permission)?.description ?? ''); permission = perm.get_object(); } obj = Machine.New(txb, permission, this.data?.description??'', this.data?.endpoint, permission?undefined:passport); } if (!obj) ERROR(Errors.InvalidParam, 'CallMachine_Data.data.object'); if (!permission) ERROR(Errors.InvalidParam, 'CallMachine_Data.data.object.permission'); const pst = perm?undefined:passport; var new_progress : Progress | undefined; if (this.data?.progress_new != null) { const task = await LocalMark.Instance().get_address(this.data?.progress_new?.task_address); new_progress = Progress?.New(txb, obj?.get_object(), permission, task, pst); } if (this.data?.progress_context_repository != null) { const p = this.data?.progress_context_repository.progress ? await LocalMark.Instance().get_address(this.data?.progress_context_repository.progress) : new_progress?.get_object(); if (!p) ERROR(Errors.InvalidParam, 'CallMachine_Data.data.progress_context_repository.progress'); const rep = await LocalMark.Instance().get_address(this.data?.progress_context_repository.repository); Progress.From(txb, obj?.get_object(), permission, p!).set_context_repository(rep, pst) } if (this.data?.progress_namedOperator != null) { const p = this.data?.progress_namedOperator.progress ? await LocalMark.Instance().get_address(this.data?.progress_namedOperator.progress) : new_progress?.get_object(); if (!p) ERROR(Errors.InvalidParam, 'CallMachine_Data.data.progress_namedOperator.progress'); let pp = Progress.From(txb, obj?.get_object(), permission, p!); for(let i=0; i<this.data.progress_namedOperator.data.length; i++) { const v = this.data.progress_namedOperator.data[i]; const addrs = await GetManyAccountOrMark_Address(v.operators); pp.set_namedOperator(v.name, addrs, pst); } } if (this.data?.progress_parent != null) { const p = this.data?.progress_parent.progress ? await LocalMark.Instance().get_address(this.data?.progress_parent.progress) : new_progress?.get_object(); if (!p) ERROR(Errors.InvalidParam, 'CallMachine_Data.data.progress_parent.progress'); if (this.data.progress_parent.parent) { const parent = await LocalMark.Instance().get_address(this.data.progress_parent.parent?.parent_id); if (parent) { this.data.progress_parent.parent.parent_id = parent; Progress.From(txb, obj?.get_object(), permission, p!).parent(this.data.progress_parent.parent); } } else { Progress.From(txb, obj?.get_object(), permission, p!).parent_none(); } } if (this.data?.progress_hold != null) { const p = this.data?.progress_hold.progress ? await LocalMark.Instance().get_address(this.data?.progress_hold.progress) : new_progress?.get_object(); if (!p) ERROR(Errors.InvalidParam, 'CallMachine_Data.data.progress_hold.progress'); if (this.data?.progress_hold.adminUnhold) { Progress.From(txb, obj?.get_object(), permission, p!).unhold(this.data.progress_hold.operation, pst) } else { Progress.From(txb, obj?.get_object(), permission, p!).hold(this.data.progress_hold.operation, this.data.progress_hold.bHold) } } if (this.data?.progress_task != null) { const [p, task] = await LocalMark.Instance().get_many_address([this.data?.progress_task.progress, this.data?.progress_task.task_address]); if (p && task) Progress.From(txb, obj?.get_object(), permission, p).bind_task(task, pst); } if (this.data?.progress_next != null) { const p = await LocalMark.Instance().get_address(this.data?.progress_next.progress); if (!p) ERROR(Errors.InvalidParam, 'CallMachine_Data.data.progress_next.progress'); var t: OrderWrap[] = []; if (this.data.progress_next.deliverable.orders.length > 0) { const o = await query_objects({objects:this.data.progress_next.deliverable.orders}); if (o?.objects?.length !== this.data.progress_next.deliverable.orders.length) { ERROR(Errors.InvalidParam, 'CallMachine_Data.data.progress_next.deliverable.orders'); } t = o.objects.map(v => { if (v.type !== 'Order') { ERROR(Errors.InvalidParam, 'CallMachine_Data.data.progress_next.deliverable.orders'); } return {object:v.object, pay_token_type:Service.parseOrderObjectType(v.type_raw)} }) } Progress.From(txb, obj?.get_object(), permission, p!).next(this.data.progress_next.operation, {msg:this.data.progress_next.deliverable.msg, orders:t}, pst); } const addr = new_progress?.launch(); if (addr) { await this.new_with_mark('Progress', txb, addr, this.data?.progress_new?.namedNew, account); } if (this.data?.description != null && this.object_address) { obj?.set_description(this.data.description, pst); } if (this.data?.endpoint != null && this.object_address) { obj?.set_endpoint(this.data.endpoint, pst) } if (this.data?.consensus_repository != null) { switch (this.data.consensus_repository.op) { case 'add': case 'set': if (this.data.consensus_repository.op === 'set') { obj?.remove_repository([], true, pst); } var reps = await LocalMark.Instance().get_many_address2(this.data.consensus_repository.objects); reps.forEach(v=>obj?.add_repository(v, pst)) ; break; case 'remove': var reps = await LocalMark.Instance().get_many_address2(this.data.consensus_repository.objects); if (reps.length > 0) { obj?.remove_repository(reps, false, pst); } break; case 'removeall': obj?.remove_repository([], true, pst); break; } } if (this.data?.nodes != null) { switch (this.data?.nodes?.op) { case 'add': { const nodes:Wowok_Machine_Node[] = []; for (let i = 0; i < this.data.nodes.data.length; ++ i) { const v = this.data.nodes.data[i]; const pairs : Wowok_Machine_Node_Pair[] = []; for (let j = 0; j < v.pairs.length; ++ j) { const f : Wowok_Machine_Forward[] = []; for(let k = 0; k < v.pairs[j].forwards.length; ++ k) { f.push(await this.resolveForward(v.pairs[j].forwards[k])); } pairs.push({ prior_node: v.pairs[j].prior_node, threshold: v.pairs[j].threshold, forwards: f, }) } nodes.push({ name: v.name, pairs: pairs, }) } obj?.add_node(nodes, pst); break; } case 'remove': obj?.remove_node(this.data.nodes.names, this.data.nodes?.bTransferMyself, pst) break; case 'rename node': this.data.nodes.data.forEach(v => obj?.rename_node(v.old, v.new, pst)); break; case 'add from myself': obj?.add_node2(this.data.nodes.addresses, pst); break; case 'add forward': for (let i = 0; i < this.data.nodes.data.length; ++ i) { const v = this.data.nodes.data[i]; obj?.add_forward(v.prior_node_name, v.node_name, await this.resolveForward(v.forward), v.threshold, v.remove_forward, pst); } break; case 'remove forward': this.data.nodes.data.forEach(v => obj?.remove_forward(v.prior_node_name, v.node_name, v.forward_name, pst)) break; case 'remove pair': this.data.nodes.pairs.forEach(v => obj?.remove_pair(v.prior_node_name, v.node_name, pst)); break; } } if (this.data?.bPublished ) { obj?.publish(passport) } if (this.data?.bPaused != null) { obj?.pause(this.data.bPaused, pst) } if (this.data?.clone_new != null && this.object_address) { await this.new_with_mark('Machine', txb, obj?.clone(true, pst) as TxbAddress, (this.data?.clone_new as any)?.namedNew, account); } if (perm) { const n = GetObjectMain(this.data?.object) as TypeNamedObjectWithPermission; await this.new_with_mark('Permission', txb, perm.launch(), GetObjectParam(n?.permission), account); } if (!this.object_address) { await this.new_with_mark('Machine', txb, obj.launch(), GetObjectMain(this.data?.object), account); } } }