feat: enhance callRequest method with options validation and hook execution

This commit is contained in:
2025-11-27 22:31:06 +08:00
parent 720a79ca7a
commit ebb9ed21ad

View File

@@ -1,4 +1,4 @@
import { isPublicMethod, ToDeepPromise } from "@/utils/utils";
import { isArray, isObject, isPublicMethod, ToDeepPromise } from "@/utils/utils";
import { RPCConnection } from "./RPCConnection";
import { RPCHandler } from "./RPCHandler";
import { RPCProvider } from "./RPCProvider";
@@ -8,6 +8,7 @@ import { RPCError, RPCErrorCode } from "./RPCError";
import { makeCallPacket, makeCallResponsePacket, parseCallPacket, parseCallResponsePacket } from "./RPCCommon";
import { RPCPacket } from "./RPCPacket";
import { EventEmitter } from "@/utils/EventEmitter";
import { createHookRunner } from "./RPCPlugin";
function getProviderFunction(provider: RPCProvider, fnPath: string):
[(...args: any[]) => Promise<any>, object] | null {
@@ -111,6 +112,45 @@ export class RPCSession {
});
}
function setOptions(opt: unknown) {
if (!isObject(opt)) {
return;
}
if ('fnPath' in opt && 'args' in opt && 'timeout' in opt) {
const { fnPath, args, timeout } = opt;
if (typeof fnPath !== 'string') {
return;
}
if (!isArray(args)) {
return;
}
if (typeof timeout !== 'number') {
return;
}
options = {
...options,
fnPath,
args,
timeout,
}
}
}
const hookRunner = createHookRunner(this.rpcHandler.getPlugins(), 'onCallOutgoingBefore');
await hookRunner({
session: this,
options: { ...options },
setOptions,
});
/** due to `await hookRunner` */
if (this.connection.closed) {
throw new RPCError({
errorCode: RPCErrorCode.CONNECTION_DISCONNECTED,
});
}
const { fnPath, args } = options;
const packet = makeCallPacket({
fnPath,
@@ -135,28 +175,75 @@ export class RPCSession {
})();
const handleCallResponsePacket = (packet: RPCPacket) => {
const result = parseCallResponsePacket(packet);
if (result === null) {
return reject(new RPCError({
let result = parseCallResponsePacket(packet);
function setResult(res: unknown) {
if (!isObject(res)) {
return;
}
const { success, error } = res;
if (typeof success === 'object' && typeof error === 'object') {
if (success && !error) {
if ('data' in success) {
result = {
success: { data: success.data },
error: null,
}
}
} else if (!success && error) {
const { errorCode, reason } = error;
if (typeof errorCode === 'number' && typeof reason === 'string') {
result = {
success: null,
error: {
errorCode,
reason,
},
}
}
}
}
}
const hookRunner = createHookRunner(this.rpcHandler.getPlugins(), 'onCallOutgoing');
hookRunner({
session: this,
options: { ...options },
setOptions,
result,
setResult,
}).then(() => {
if (result === null) {
return reject(new RPCError({
errorCode: RPCErrorCode.UNKNOWN_ERROR,
}));;
}
const { success, error } = result;
if (success) {
return resolve(success.data);
}
if (error) {
return reject(new RPCError({
errorCode: error.errorCode,
reason: error.reason
}));
}
reject(new RPCError({
errorCode: RPCErrorCode.UNKNOWN_ERROR,
}));;
}
}).catch((e) => {
if (e instanceof RPCError) {
return reject(e);
}
const { success, error } = result;
if (success) {
return resolve(success.data);
}
if (error) {
return reject(new RPCError({
errorCode: error.errorCode,
reason: error.reason
}));
}
return reject(new RPCError({
errorCode: RPCErrorCode.UNKNOWN_ERROR,
}));;
reject(new RPCError({
errorCode: RPCErrorCode.UNKNOWN_ERROR,
}))
})
}
this.callResponseEmitter.once(packet.id, handleCallResponsePacket);