mirror of
https://github.com/bitwarden/browser
synced 2026-01-31 00:33:33 +00:00
feat: implement function calling
This commit is contained in:
@@ -31,7 +31,7 @@ function ProxiedReference(
|
||||
}
|
||||
|
||||
// console.log(`Accessing ${reference.objectType}.${propertyName}`);
|
||||
return RpcPropertyReference.create(channel, target, propertyName);
|
||||
return RpcPropertyReference(channel, { objectReference: target, propertyName });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -39,23 +39,31 @@ function ProxiedReference(
|
||||
/**
|
||||
* A reference to a specific property on a remote object.
|
||||
*/
|
||||
export class RpcPropertyReference {
|
||||
static create(
|
||||
channel: RpcRequestChannel,
|
||||
objectReference: RpcObjectReference,
|
||||
propertyName: string,
|
||||
): RpcPropertyReference {
|
||||
return ProxiedReferenceProperty(
|
||||
channel,
|
||||
new RpcPropertyReference(objectReference, propertyName),
|
||||
);
|
||||
}
|
||||
type RpcPropertyReference = {
|
||||
objectReference: RpcObjectReference;
|
||||
propertyName: string;
|
||||
};
|
||||
|
||||
private constructor(
|
||||
public objectReference: RpcObjectReference,
|
||||
public propertyName: string,
|
||||
) {}
|
||||
}
|
||||
/**
|
||||
* A reference to a specific property on a remote object.
|
||||
*/
|
||||
// export class RpcPropertyReference {
|
||||
// static create(
|
||||
// channel: RpcRequestChannel,
|
||||
// objectReference: RpcObjectReference,
|
||||
// propertyName: string,
|
||||
// ): RpcPropertyReference {
|
||||
// return ProxiedReferenceProperty(
|
||||
// channel,
|
||||
// new RpcPropertyReference(objectReference, propertyName),
|
||||
// );
|
||||
// }
|
||||
|
||||
// private constructor(
|
||||
// public objectReference: RpcObjectReference,
|
||||
// public propertyName: string,
|
||||
// ) {}
|
||||
// }
|
||||
|
||||
/**
|
||||
* A sub-proxy for a specific property of a proxied reference
|
||||
@@ -66,13 +74,22 @@ export class RpcPropertyReference {
|
||||
* If this references a property then they'll try to await the value, triggering the `get` trap
|
||||
* when they access the `then` property.
|
||||
*/
|
||||
function ProxiedReferenceProperty(channel: RpcRequestChannel, reference: RpcPropertyReference) {
|
||||
return new Proxy(reference, {
|
||||
function RpcPropertyReference(channel: RpcRequestChannel, reference: RpcPropertyReference) {
|
||||
const target = () => {};
|
||||
Object.defineProperty(target, "name", { value: `RpcPropertyReference`, configurable: true });
|
||||
target.objectReference = reference.objectReference;
|
||||
target.propertyName = reference.propertyName;
|
||||
|
||||
return new Proxy(target, {
|
||||
get(_target, propertyName: string) {
|
||||
// console.log(
|
||||
// `Accessing ${reference.objectReference.objectType}.${reference.propertyName}.${propertyName}`,
|
||||
// );
|
||||
|
||||
if (propertyName === "call") {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (propertyName !== "then") {
|
||||
throw new Error(`Cannot access property '${propertyName}' on remote proxy synchronously`);
|
||||
}
|
||||
@@ -100,6 +117,28 @@ function ProxiedReferenceProperty(channel: RpcRequestChannel, reference: RpcProp
|
||||
})().then(onFulfilled, onRejected);
|
||||
};
|
||||
},
|
||||
apply(_target, _thisArg, argArray: unknown[]) {},
|
||||
apply(_target, _thisArg, argArray: unknown[]) {
|
||||
// console.log(`Calling ${reference.objectReference.objectType}.${reference.propertyName}`);
|
||||
|
||||
// Handle method call
|
||||
const command: Command = {
|
||||
method: "call",
|
||||
referenceId: reference.objectReference.referenceId,
|
||||
propertyName: reference.propertyName,
|
||||
args: argArray,
|
||||
};
|
||||
|
||||
return channel.sendCommand(command).then((result) => {
|
||||
if (result.status === "error") {
|
||||
throw new Error(`RPC Error: ${result.error}`);
|
||||
}
|
||||
|
||||
if (result.result.type === "value") {
|
||||
return result.result.value;
|
||||
} else if (result.result.type === "reference") {
|
||||
return RpcObjectReference.create(channel, result.result.referenceId);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ describe("RpcServer", () => {
|
||||
expect(value).toBe(42);
|
||||
});
|
||||
|
||||
it.skip("calls sync function and returns value", async () => {
|
||||
it("calls sync function and returns value", async () => {
|
||||
const remoteInstance = await firstValueFrom(client.getRoot());
|
||||
|
||||
const result = await remoteInstance.greet("World");
|
||||
|
||||
@@ -34,6 +34,28 @@ export class RpcServer<T> {
|
||||
}
|
||||
}
|
||||
|
||||
if (command.method === "call") {
|
||||
const target = this.references.get<any>(command.referenceId);
|
||||
if (!target) {
|
||||
return { status: "error", error: `[RPC] Reference ID ${command.referenceId} not found` };
|
||||
}
|
||||
|
||||
try {
|
||||
const method = target[command.propertyName];
|
||||
if (typeof method !== "function") {
|
||||
return {
|
||||
status: "error",
|
||||
error: `[RPC] Property ${command.propertyName} is not a function`,
|
||||
};
|
||||
}
|
||||
|
||||
const result = method.apply(target, command.args);
|
||||
return { status: "success", result: { type: "value", value: result } };
|
||||
} catch (error) {
|
||||
return { status: "error", error };
|
||||
}
|
||||
}
|
||||
|
||||
return { status: "error", error: `Unknown command method: ${command.method}` };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user