mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-08 00:45:54 +00:00
79 lines
2.7 KiB
TypeScript
79 lines
2.7 KiB
TypeScript
/**
|
|
* Typed access to the Rust backend.
|
|
*
|
|
* `bindings.ts` is generated by tauri-specta; never edit it. Use `call` to turn
|
|
* its `{status, data | error}` results into plain promises that reject with
|
|
* `IpcError`, and `onIdeEvent` to subscribe to the backend event bus.
|
|
*/
|
|
import type { UnlistenFn } from "@tauri-apps/api/event";
|
|
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
|
import { commands, type IdeError, type IdeEvent, type RequestId } from "@/bindings";
|
|
|
|
export { commands };
|
|
export type * from "@/bindings";
|
|
|
|
export class IpcError extends Error {
|
|
readonly kind: IdeError["kind"];
|
|
constructor(error: IdeError) {
|
|
super(error.message);
|
|
this.name = "IpcError";
|
|
this.kind = error.kind;
|
|
}
|
|
}
|
|
|
|
type Result<T> = { status: "ok"; data: T } | { status: "error"; error: IdeError };
|
|
|
|
/** Unwraps a fallible command result: `await call(commands.docOpen(path))`. */
|
|
export async function call<T>(result: Promise<Result<T>>): Promise<T> {
|
|
const r = await result;
|
|
if (r.status === "error") throw new IpcError(r.error);
|
|
return r.data;
|
|
}
|
|
|
|
export function isCancelled(e: unknown): boolean {
|
|
return e instanceof IpcError && e.kind === "cancelled";
|
|
}
|
|
|
|
let nextId = 1;
|
|
/** Allocates an id for a cancellable request (see `commands.cancelRequest`). */
|
|
export function nextRequestId(): RequestId {
|
|
return nextId++ as RequestId;
|
|
}
|
|
|
|
export const IDE_EVENT = "ide://event";
|
|
|
|
type EventOf<K extends IdeEvent["type"]> = Extract<IdeEvent, { type: K }>;
|
|
type Handler = (event: IdeEvent) => void;
|
|
|
|
const handlers = new Map<string, Set<Handler>>();
|
|
let unlisten: Promise<UnlistenFn> | null = null;
|
|
|
|
function ensureListening() {
|
|
if (unlisten || !isTauri()) return;
|
|
// Window-scoped: a global `listen` also receives events emitted to other windows.
|
|
unlisten = getCurrentWebviewWindow().listen<IdeEvent>(IDE_EVENT, ({ payload }) => {
|
|
handlers.get(payload.type)?.forEach((h) => h(payload));
|
|
handlers.get("*")?.forEach((h) => h(payload));
|
|
});
|
|
}
|
|
|
|
/** Subscribes to one backend event type (or `"*"`); returns an unsubscribe function. */
|
|
export function onIdeEvent<K extends IdeEvent["type"]>(type: K | "*", handler: (event: EventOf<K>) => void): () => void {
|
|
ensureListening();
|
|
let set = handlers.get(type);
|
|
if (!set) handlers.set(type, (set = new Set()));
|
|
const h = handler as Handler;
|
|
set.add(h);
|
|
return () => set.delete(h);
|
|
}
|
|
|
|
/** Test helper: dispatch an event as if it came from the backend. */
|
|
export function emitLocalIdeEvent(event: IdeEvent) {
|
|
handlers.get(event.type)?.forEach((h) => h(event));
|
|
handlers.get("*")?.forEach((h) => h(event));
|
|
}
|
|
|
|
export function isTauri(): boolean {
|
|
return typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
|
|
}
|