Webview: Add async method handling
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { FromSchema } from "json-schema-to-ts";
|
import { FromSchema } from "json-schema-to-ts";
|
||||||
import { schema } from "@/api";
|
import { schema } from "@/api";
|
||||||
|
import { nanoid } from "nanoid";
|
||||||
|
|
||||||
export type API = FromSchema<typeof schema>;
|
export type API = FromSchema<typeof schema>;
|
||||||
|
|
||||||
@@ -41,47 +42,44 @@ const operations = schema.properties;
|
|||||||
const operationNames = Object.keys(operations) as OperationNames[];
|
const operationNames = Object.keys(operations) as OperationNames[];
|
||||||
|
|
||||||
type ObserverRegistry = {
|
type ObserverRegistry = {
|
||||||
[K in OperationNames]: ((response: OperationResponse<K>) => void)[];
|
[K in OperationNames]: Record<
|
||||||
|
string,
|
||||||
|
(response: OperationResponse<K>) => void
|
||||||
|
>;
|
||||||
};
|
};
|
||||||
const obs: ObserverRegistry = operationNames.reduce(
|
const registry: ObserverRegistry = operationNames.reduce(
|
||||||
(acc, opName) => ({
|
(acc, opName) => ({
|
||||||
...acc,
|
...acc,
|
||||||
[opName]: [],
|
[opName]: {},
|
||||||
}),
|
}),
|
||||||
{} as ObserverRegistry
|
{} as ObserverRegistry
|
||||||
);
|
);
|
||||||
|
|
||||||
interface ReceiveOptions {
|
|
||||||
/**
|
|
||||||
* Calls only the registered function that has the same key as used with dispatch
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
fnKey: string;
|
|
||||||
}
|
|
||||||
function createFunctions<K extends OperationNames>(
|
function createFunctions<K extends OperationNames>(
|
||||||
operationName: K
|
operationName: K
|
||||||
): {
|
): {
|
||||||
dispatch: (args: OperationArgs<K>) => void;
|
dispatch: (args: OperationArgs<K>) => void;
|
||||||
receive: (fn: (response: OperationResponse<K>) => void) => void;
|
receive: (fn: (response: OperationResponse<K>) => void, id: string) => void;
|
||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
dispatch: (args: OperationArgs<K>) => {
|
dispatch: (args: OperationArgs<K>) => {
|
||||||
// console.log(
|
|
||||||
// `Operation: ${String(operationName)}, Arguments: ${JSON.stringify(args)}`
|
|
||||||
// );
|
|
||||||
// Send the data to the gtk app
|
// Send the data to the gtk app
|
||||||
window.webkit.messageHandlers.gtk.postMessage({
|
window.webkit.messageHandlers.gtk.postMessage({
|
||||||
method: operationName,
|
method: operationName,
|
||||||
data: args,
|
data: args,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
receive: (
|
receive: (fn: (response: OperationResponse<K>) => void, id: string) => {
|
||||||
fn: (response: OperationResponse<K>) => void
|
// @ts-expect-error: This should work although typescript doesn't let us write
|
||||||
// options?: ReceiveOptions
|
registry[operationName][id] = fn;
|
||||||
) => {
|
|
||||||
obs[operationName].push(fn);
|
|
||||||
window.clan[operationName] = (s: string) => {
|
window.clan[operationName] = (s: string) => {
|
||||||
obs[operationName].forEach((f) => deserialize(f)(s));
|
const f = (response: OperationResponse<K>) => {
|
||||||
|
if (response.op_key === id) {
|
||||||
|
registry[operationName][id](response);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
deserialize(f)(s);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -90,7 +88,7 @@ function createFunctions<K extends OperationNames>(
|
|||||||
type PyApi = {
|
type PyApi = {
|
||||||
[K in OperationNames]: {
|
[K in OperationNames]: {
|
||||||
dispatch: (args: OperationArgs<K>) => void;
|
dispatch: (args: OperationArgs<K>) => void;
|
||||||
receive: (fn: (response: OperationResponse<K>) => void) => void;
|
receive: (fn: (response: OperationResponse<K>) => void, id: string) => void;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -110,6 +108,23 @@ function download(filename: string, text: string) {
|
|||||||
document.body.removeChild(element);
|
document.body.removeChild(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const callApi = <K extends OperationNames>(
|
||||||
|
method: K,
|
||||||
|
args: OperationArgs<K>
|
||||||
|
) => {
|
||||||
|
return new Promise<OperationResponse<K>>((resolve, reject) => {
|
||||||
|
const id = nanoid();
|
||||||
|
pyApi[method].receive((response) => {
|
||||||
|
if (response.status === "error") {
|
||||||
|
reject(response);
|
||||||
|
}
|
||||||
|
resolve(response);
|
||||||
|
}, id);
|
||||||
|
|
||||||
|
pyApi[method].dispatch({ ...args, op_key: id });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const deserialize =
|
const deserialize =
|
||||||
<T>(fn: (response: T) => void) =>
|
<T>(fn: (response: T) => void) =>
|
||||||
(str: string) => {
|
(str: string) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user