import { ClientContext } from '../ClientContext'; import type { ClientActionBox } from '../ClientActionBox'; import type { OutgoingContext } from '../../messages/OutgoingContext'; import { callRequest } from './callRequest'; import { destroyRequest } from './destroyRequest'; import { InstanceEventEmitter } from './InstanceEvents'; export const events = Symbol('Events of instance.'); export const destroy = Symbol('Destroy instance.'); export const getInstanceId = Symbol('Get instance id.'); export const getActionBox = Symbol('Get action box.'); export const setContextData = Symbol('Set client context data.'); export async function createClientActionProxy( actionBox: ClientActionBox, instance: T, instanceId: string, contextData: OutgoingContext, ): Promise { const instanceEvents = new InstanceEventEmitter(); const context = new ClientContext(actionBox); context.setContext(contextData); const proxy = new Proxy(instance, { get(target: T, prop: string): any { if (context.has(prop)) { return context.get(prop); } if (actionBox.hasMethod(prop)) { if (typeof target[prop as keyof T] === 'function') { return target[prop as keyof T]; } return async (...args: Array) => { const response = await callRequest(actionBox, instanceId, prop, args, context.getOutgoingContext(), instanceEvents); if (!response.success) { const err = new Error(); Object.assign(err, response.result); instanceEvents.emit('call:answer:fail', response); throw err; } context.setContext(response.context || {}, true); instanceEvents.emit('call:answer:ok', response); return response.result; }; } if (prop.length > 7 && prop.substring(prop.length - 7) === 'Request') { const p = prop.substring(0, prop.length - 7); if (actionBox.hasMethod(p)) { return (...args: Array) => callRequest(actionBox, instanceId, p, args, context.getOutgoingContext()); } } if ((prop as any) === destroy) { return () => destroyRequest(actionBox, instanceId); } if ((prop as any) === events) { return () => instanceEvents; } if ((prop as any) === getInstanceId) { return () => instanceId; } if ((prop as any) === getActionBox) { return () => actionBox; } if ((prop as any) === setContextData) { return (data: OutgoingContext, hard = false) => context.setContext(data, hard); } return target[prop as keyof T]; }, set(target: T, prop: string, value: any): boolean { return true; }, has(target: T, prop: string): boolean { if (context.has(prop)) { return true; } if (actionBox.hasMethod(prop)) { return true; } if (prop.length > 7 && prop.substring(prop.length - 7) === 'Request' && actionBox.hasMethod(prop.substring(0, prop.length - 7))) { return true; } if ((prop as any) === destroy || (prop as any) === events) { return true; } return !!target[prop as keyof T]; }, ownKeys(target: T): ArrayLike { return [ ...context.keys(), ...Object.keys(actionBox.config.methods), ]; }, getOwnPropertyDescriptor(target, prop) { return { enumerable: true, configurable: true }; }, }); await context.initSpecial(proxy); // todo события или что то такое return proxy; }