import { LSPluginUser, WithOptional } from '../LSPlugin.user' import { EventEmitter } from 'eventemitter3' export type IRequestOptions = { url: string abortable: boolean headers: Record method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' data: Object | ArrayBuffer timeout: number returnType: 'json' | 'text' | 'base64' | 'arraybuffer' success: (result: R) => void fail: (err: any) => void final: () => void } export type RequestTaskID = string | number const CLIENT_MSG_CALLBACK = '#lsp#request#callback' const genTaskCallbackType = (id: RequestTaskID) => `task_callback_${id}` /** * Request task */ export class LSPluginRequestTask { private readonly _promise: Promise private _aborted: boolean = false constructor( private _client: LSPluginRequest, private _requestId: RequestTaskID, private _requestOptions: Partial = {} ) { this._promise = new Promise((resolve, reject) => { if (!this._requestId) { return reject(null) } // task result listener this._client.once( genTaskCallbackType(this._requestId), (e) => { if (e && e instanceof Error) { reject(e) } else { resolve(e) } } ) }) const { success, fail, final } = this._requestOptions this._promise .then((res) => { success?.(res) }) .catch((e) => { fail?.(e) }) .finally(() => { final?.() }) } abort() { if ( !this._requestOptions.abortable || this._aborted ) return this._client.ctx._execCallableAPI( 'http_request_abort', this._requestId ) this._aborted = true } get promise(): Promise { return this._promise } get client(): LSPluginRequest { return this._client } get requestId(): RequestTaskID { return this._requestId } } /** * A simple request client */ export class LSPluginRequest extends EventEmitter { constructor(private _ctx: LSPluginUser) { super() // request callback listener this.ctx.caller.on( CLIENT_MSG_CALLBACK, (e: any) => { const reqId = e?.requestId if (!reqId) return this.emit(genTaskCallbackType(reqId), e?.payload) } ) } static createRequestTask( client: LSPluginRequest, requestID: RequestTaskID, requestOptions: Partial ) { return new LSPluginRequestTask( client, requestID, requestOptions ) } async _request, keyof Omit>>(options: T): Promise ? LSPluginRequestTask : R> { const pid = this.ctx.baseInfo.id const { success, fail, final, ...requestOptions } = options const reqID = this.ctx.Experiments.invokeExperMethod('request', pid, requestOptions) const task = LSPluginRequest.createRequestTask( this.ctx.Request, reqID, options ) if (!requestOptions.abortable) { return task.promise } return task as any } get ctx(): LSPluginUser { return this._ctx } }