import { DispatchMsg } from './create_dispatch_fn.js'; import { TransportClient } from '../transport_client.js'; import { EventEmitter } from 'events'; import { isTransferDescriptor, TransferDescriptor } from '../interface/transferable.js'; type FilterOutAttributes = { [Key in keyof Base]: Base[Key] extends (...any) => any ? Base[Key] : never; }; type PromisifyFunction any> = (...args: Parameters) => Promise>; type Promisify any }> = { [Key in keyof Base]: ReturnType extends Promise ? Base[Key] : PromisifyFunction; }; type TransferTypes = { [Index in keyof Tuple]: Tuple[Index] | (Tuple[Index] extends Transferable ? TransferDescriptor : never); }; /** * Annoying: https://github.com/microsoft/TypeScript/issues/29919 * There's a bug that means we can't map over the tuple or function parameter types to make them transferrable, if * we use the Parameters builtin, and then try to map. * So instead we inline the Parameters builtin and apply the TransferTypes to the parameters within the inline. * Once the above is fixed we could in theory just do: * * type MakeFunctionTransferrable any> = ( * ...args: TransferTypes> * ) => ReturnType; */ type MakeFunctionTransferrable any> = ( ...args: TFunction extends (...args: infer P) => any ? TransferTypes

: never ) => ReturnType; type Transferrable any }> = { [Key in keyof Base]: MakeFunctionTransferrable; }; export type Proxify = Promisify>>; export function createDispatchProxyFromFn( class_: { new (...args: any[]): T }, requestFn: (fn: string) => (...args: any[]) => Promise, ): Proxify { const proxy: any = class_.prototype instanceof EventEmitter ? new EventEmitter() : {}; for (const fn of Object.getOwnPropertyNames(class_.prototype)) { if (fn === 'constructor') { continue; } proxy[fn] = requestFn(fn); } return proxy; } export function createDispatchProxy( class_: { new (...args: any[]): T }, transportClient: TransportClient, ): Proxify { // Create a proxy of class_ that passes along methods over our transportClient const proxy = createDispatchProxyFromFn(class_, (fn: string) => (...args: any[]) => { // Pass our proxied function name and arguments over our transport client const transfer: Transferable[] = args.reduce( (acc, a) => (isTransferDescriptor(a) ? [...acc, ...a.transferables] : acc), [] as Transferable[], ); args = args.map(a => (isTransferDescriptor(a) ? a.send : a)); return transportClient.request({ fn, args }, transfer); }); if (proxy instanceof EventEmitter) { // Handle proxied 'emit' calls if our proxy object is an EventEmitter transportClient.on('event_msg', ({ fn, args }) => { if (fn === 'emit') { const [eventName, ...restArgs] = args; proxy.emit(eventName, ...restArgs); } }); } return proxy; }