wowok_agent
Version:
Agent for WoWok: Unlock Co-Creation, Lighting Transaction, Empower Potential.
207 lines (192 loc) • 9.62 kB
text/typescript
import { TransactionBlock, PassportObject, Errors, ERROR, Permission, PermissionIndex,
PermissionIndexType, Repository, Repository_Policy_Mode, Repository_Value as Wowok_Repository_Value,
PermissionObject, uint2address, IsValidU256, ValueType, Repository_Policy, Repository_Value2,
} from 'wowok';
import { AccountOrMark_Address, CallBase, CallResult, GetAccountOrMark_Address, GetObjectExisted, GetObjectMain, GetObjectParam, ObjectMain, ObjectsOp, TypeNamedObjectWithPermission} from "./base.js";
import { LocalMark } from '../local/local.js';
import { ObjectRepository } from '../query/objects.js';
// Account name, or local mark name, or address, or u256 number|bigint(eg. time number) that can be converted to address.
export type AddressID = AccountOrMark_Address | number | bigint;
export const GetAddressID = async(key:AddressID) : Promise<string | undefined> =>{
if (typeof(key) === 'number' || typeof(key) === 'bigint') {
if (IsValidU256(key)) {
return uint2address(key);
}
} else {
return await GetAccountOrMark_Address(key)
}
}
export interface Repository_Value {
address: AddressID; // UID: address or objectid
bcsBytes: Uint8Array; // BCS contents. Notice that: First Byte be the Type by caller, or specify type with 'Repository_Policy_Data.value_type' field.
}
export interface Repository_Policy_Data {
key: string;
data: Repository_Value[];
value_type?: ValueType; // Specifies a data type prefix; If the data prefix is already included in the data byte stream, there is no need to specify it.
}
export interface Repository_Policy_Data2 {
address: AddressID;
data: Repository_Value2[];
value_type?: ValueType;
}
export interface Repository_Policy_Data_Remove {
key: string;
address: AddressID;
}
/// The execution priority is determined by the order in which the object attributes are arranged
export interface CallRepository_Data {
object?: ObjectMain;
description?: string;
reference?: ObjectsOp;
mode?: Repository_Policy_Mode; // default: 'Relax' (POLICY_MODE_FREE)
policy?: {op:'add' | 'set'; data:Repository_Policy[]} | {op:'remove'; keys:string[]} | {op:'removeall'} | {op:'rename'; data:{old:string; new:string}[]};
data?: {op:'add', data: Repository_Policy_Data | Repository_Policy_Data2} | {op:'remove'; data: Repository_Policy_Data_Remove[]};
}
export class CallRepository extends CallBase {
data: CallRepository_Data;
object_address: string | undefined = undefined;
permission_address: string | undefined = undefined;
constructor(data:CallRepository_Data) {
super();
this.data = data;
}
protected async prepare(): Promise<void> {
if (!this.object_address) {
this.object_address = (await LocalMark.Instance().get(GetObjectExisted(this.data?.object)))?.address;
}
if (this.object_address) {
await this.update_content('Repository', this.object_address);
if (!this.content) ERROR(Errors.InvalidParam, 'CallRepository_Data.data.object:' + this.object_address);
this.permission_address = (this.content as ObjectRepository).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 perms : PermissionIndexType[] = [];
await this.prepare();
if (this.permission_address) {
if (!this.data?.object) {
perms.push(PermissionIndex.repository)
}
if (this.data?.description != null && this.object_address) {
perms.push(PermissionIndex.repository_description)
}
if (this.data?.mode != null && this.object_address) {
perms.push(PermissionIndex.repository_mode)
}
if (this.data?.reference != null) {
perms.push(PermissionIndex.repository_reference)
}
if (this.data?.policy != null) {
perms.push(PermissionIndex.repository_policies)
}
return await this.check_permission_and_call(this.permission_address, perms, [], checkOwner, undefined, account)
}
return await this.exec(account);
}
protected async operate(txb:TransactionBlock, passport?:PassportObject, account?:string) {
let obj : Repository | undefined ; let perm: Permission | undefined;
let permission : PermissionObject | undefined;
if (this.object_address) {
obj = Repository.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 = Repository.New(txb, permission, this.data?.description??'',
this.data.mode, perm?undefined:passport);
}
if (!obj) ERROR(Errors.InvalidParam, 'CallRepository_Data.object:' + this.object_address);
if (!permission) ERROR(Errors.InvalidParam, 'CallRepository_Data.permission:' + this.permission_address);
const pst = perm?undefined:passport;
if (this.data?.description != null && this.object_address) {
obj?.set_description(this.data.description, pst);
}
if (this.data?.reference != null) {
switch (this.data.reference.op) {
case 'set':
case 'add':
if (this.data.reference.op === 'set') obj?.remove_reference([], true, pst);
obj?.add_reference(await LocalMark.Instance().get_many_address2(this.data.reference.objects), pst);
break;
case 'remove':
obj?.remove_reference(await LocalMark.Instance().get_many_address2(this.data.reference.objects), false, pst);
break;
case 'removeall':
obj?.remove_reference([], true, pst);
break;
}
}
if (this.data?.mode != null && this.object_address) { //@ priority??
obj?.set_policy_mode(this.data.mode, pst)
}
if (this.data?.policy != null) {
switch(this.data.policy.op) {
case 'set':
obj?.remove_policies([], true, pst);
obj?.add_policies(this.data.policy.data, pst);
break;
case 'add':
obj?.add_policies(this.data.policy.data, pst);
break;
case 'remove':
obj?.remove_policies(this.data.policy.keys, false, pst);
break;
case 'removeall':
obj?.remove_policies([], true, pst);
break;
case 'rename':
this.data.policy.data.forEach((v) => {
obj?.rename_policy(v.old, v.new, pst);
})
break;
}
}
if (this.data?.data != null) {
switch(this.data.data.op) {
case 'add':
if ((this.data.data?.data as any)?.key != null) {
const d = (this.data.data.data as Repository_Policy_Data).data;
const add: Wowok_Repository_Value[] = [];
for (let i=0; i<d.length; ++i) {
const addr = await GetAddressID(d[i].address);
if (addr) {
add.push({address:addr, bcsBytes:d[i].bcsBytes});
}
}
obj?.add_data({key:(this.data.data.data as Repository_Policy_Data).key, data:add, value_type:(this.data.data.data as Repository_Policy_Data).value_type});
} else if ((this.data.data?.data as any)?.address != null) {
const d = this.data.data.data as Repository_Policy_Data2;
const addr = await GetAddressID(d.address);
if (addr) {
obj?.add_data2({address:addr, data:d.data, value_type:d.value_type})
}
}
break;
case 'remove':
for (let i=0; i<this.data.data.data.length; ++i) {
const addr = await GetAddressID(this.data.data.data[i].address);
if (addr) {
obj?.remove(addr, this.data.data.data[i].key);
}
}
break;
}
}
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('Repository', txb, obj.launch(), GetObjectMain(this.data?.object), account);
}
}
}