feat: add ipc
parent
abb46979da
commit
259aa852d8
|
|
@ -32,6 +32,7 @@
|
|||
"https://deno.land/std@0.160.0/path/posix.ts": "6b63de7097e68c8663c84ccedc0fd977656eb134432d818ecd3a4e122638ac24",
|
||||
"https://deno.land/std@0.160.0/path/separator.ts": "fe1816cb765a8068afb3e8f13ad272351c85cbc739af56dacfc7d93d710fe0f9",
|
||||
"https://deno.land/std@0.160.0/path/win32.ts": "ee8826dce087d31c5c81cd414714e677eb68febc40308de87a2ce4b40e10fb8d",
|
||||
"https://deno.land/std@0.160.0/streams/conversion.ts": "328afbedee0a7e0c330ac4c7b4c1af569ee53974f970230f6a78f545b93abb9b",
|
||||
"https://deno.land/std@0.160.0/testing/_diff.ts": "a23e7fc2b4d8daa3e158fa06856bedf5334ce2a2831e8bf9e509717f455adb2c",
|
||||
"https://deno.land/std@0.160.0/testing/_format.ts": "cd11136e1797791045e639e9f0f4640d5b4166148796cad37e6ef75f7d7f3832",
|
||||
"https://deno.land/std@0.160.0/testing/asserts.ts": "1e340c589853e82e0807629ba31a43c84ebdcdeca910c4a9705715dfdb0f5ce8",
|
||||
|
|
|
|||
1
deps.ts
1
deps.ts
|
|
@ -13,3 +13,4 @@ export * as path from "https://deno.land/std@0.160.0/path/mod.ts";
|
|||
export { MultiProgressBar } from "https://deno.land/x/progress@v1.2.8/mod.ts";
|
||||
export { Mutex } from "https://deno.land/x/semaphore@v1.1.1/mod.ts";
|
||||
export type { DeepReadonly } from "https://deno.land/x/ts_essentials@v9.1.2/mod.ts";
|
||||
export { writeAll } from "https://deno.land/std@0.160.0/streams/conversion.ts";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
export { IPC } from './stdio';
|
||||
export type { Command } from './types';
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import { ExtractType } from "./types";
|
||||
import { Command, Child } from '@tauri-apps/api/shell'
|
||||
|
||||
export class IPC<T extends { type: string }> {
|
||||
queue: T[] = [];
|
||||
waiting: ((value: T) => void)[] = [];
|
||||
callback = (data: unknown) => {
|
||||
const waiting = this.waiting.shift();
|
||||
if (waiting) {
|
||||
waiting(data as T);
|
||||
} else {
|
||||
this.queue.push(data as T);
|
||||
}
|
||||
};
|
||||
child: Promise<Child>;
|
||||
|
||||
constructor() {
|
||||
const command = Command.sidecar('../binaries/s3si', ['--daemon']);
|
||||
command.stdout.on('data', line => {
|
||||
this.callback(JSON.parse(line))
|
||||
})
|
||||
this.child = command.spawn()
|
||||
}
|
||||
|
||||
async recvType<K extends T["type"]>(
|
||||
type: K,
|
||||
): Promise<ExtractType<T, K>> {
|
||||
const data = await this.recv();
|
||||
if (data.type !== type) {
|
||||
throw new Error(`Unexpected type: ${data.type}`);
|
||||
}
|
||||
return data as ExtractType<T, K>;
|
||||
}
|
||||
async recv(): Promise<T> {
|
||||
return new Promise<T>((resolve) => {
|
||||
const data = this.queue.shift();
|
||||
if (data) {
|
||||
resolve(data);
|
||||
} else {
|
||||
this.waiting.push(resolve);
|
||||
}
|
||||
});
|
||||
}
|
||||
async send(data: T) {
|
||||
const child = await this.child;
|
||||
await child.write(JSON.stringify(data) + "\n")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
export type { Command, ExtractType } from '../../../src/ipc/types';
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
import React from 'react'
|
||||
import { WebviewWindow } from '@tauri-apps/api/window'
|
||||
import { Loading } from 'components/Loading'
|
||||
import React from 'react'
|
||||
import { IPC, Command } from 'ipc';
|
||||
|
||||
const ipc = new IPC<Command>();
|
||||
|
||||
export const Home: React.FC = ({ }) => {
|
||||
const onClick = () => {
|
||||
|
|
@ -10,8 +13,14 @@ export const Home: React.FC = ({ }) => {
|
|||
focus: true,
|
||||
})
|
||||
};
|
||||
const onHello = async () => {
|
||||
await ipc.send({ type: 'hello', data: '1234' });
|
||||
const data = await ipc.recvType('hello');
|
||||
console.log(`hello`, data)
|
||||
}
|
||||
return <>
|
||||
Hello world! <Loading />
|
||||
<button onClick={onClick}>Open the window!</button>
|
||||
<button onClick={onHello}>Hello</button>
|
||||
</>
|
||||
}
|
||||
|
|
|
|||
8
s3si.ts
8
s3si.ts
|
|
@ -1,11 +1,12 @@
|
|||
import { App, DEFAULT_OPTS } from "./src/app.ts";
|
||||
import { runDaemon } from "./src/daemon.ts";
|
||||
import { showError } from "./src/utils.ts";
|
||||
import { flags } from "./deps.ts";
|
||||
|
||||
const parseArgs = (args: string[]) => {
|
||||
const parsed = flags.parse(args, {
|
||||
string: ["profilePath", "exporter", "skipMode"],
|
||||
boolean: ["help", "noProgress", "monitor", "withSummary"],
|
||||
boolean: ["help", "noProgress", "monitor", "withSummary", "daemon"],
|
||||
alias: {
|
||||
"help": "h",
|
||||
"profilePath": ["p", "profile-path"],
|
||||
|
|
@ -38,6 +39,11 @@ Options:
|
|||
);
|
||||
Deno.exit(0);
|
||||
}
|
||||
if (opts.daemon) {
|
||||
await runDaemon();
|
||||
|
||||
Deno.exit(0);
|
||||
}
|
||||
|
||||
const app = new App({
|
||||
...DEFAULT_OPTS,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
import { IPC } from "./ipc/mod.ts";
|
||||
import { Command } from "./ipc/types.ts";
|
||||
|
||||
export async function runDaemon() {
|
||||
const ipc = new IPC<Command>({
|
||||
reader: Deno.stdin,
|
||||
writer: Deno.stdout,
|
||||
});
|
||||
|
||||
while (true) {
|
||||
const cmd = await ipc.recv();
|
||||
switch (cmd.type) {
|
||||
case "hello":
|
||||
await ipc.send(cmd);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/// <reference no-default-lib="true" />
|
||||
/// <reference lib="ESNext" />
|
||||
/// <reference lib="dom" />
|
||||
/// <reference lib="dom.iterable" />
|
||||
/// <reference lib="dom.asynciterable" />
|
||||
|
||||
import type { ExtractType } from "./types.ts";
|
||||
|
||||
export class WorkerChannel<T extends { type: string }> {
|
||||
queue: T[] = [];
|
||||
waiting: ((value: T) => void)[] = [];
|
||||
|
||||
constructor(private worker?: Worker) {
|
||||
const callback = ({ data }: { data: unknown }) => {
|
||||
const waiting = this.waiting.shift();
|
||||
if (waiting) {
|
||||
waiting(data as T);
|
||||
} else {
|
||||
this.queue.push(data as T);
|
||||
}
|
||||
};
|
||||
if (worker) {
|
||||
worker.addEventListener("message", callback);
|
||||
} else {
|
||||
self.addEventListener("message", callback);
|
||||
}
|
||||
}
|
||||
async recvType<K extends T["type"]>(
|
||||
type: K,
|
||||
): Promise<ExtractType<T, K>> {
|
||||
const data = await this.recv();
|
||||
if (data.type !== type) {
|
||||
throw new Error(`Unexpected type: ${data.type}`);
|
||||
}
|
||||
return data as ExtractType<T, K>;
|
||||
}
|
||||
recv(): Promise<T> {
|
||||
return new Promise<T>((resolve) => {
|
||||
const data = this.queue.shift();
|
||||
if (data) {
|
||||
resolve(data);
|
||||
} else {
|
||||
this.waiting.push(resolve);
|
||||
}
|
||||
});
|
||||
}
|
||||
send(data: T) {
|
||||
if (this.worker) {
|
||||
this.worker.postMessage(data);
|
||||
} else {
|
||||
self.postMessage(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
export { IPC } from "./stdio.ts";
|
||||
export { WorkerChannel } from "./channel.ts";
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/// <reference lib="deno.ns" />
|
||||
|
||||
import { io, writeAll } from "../../deps.ts";
|
||||
import type { ExtractType } from "./types.ts";
|
||||
|
||||
export class IPC<T extends { type: string }> {
|
||||
lines: AsyncIterableIterator<string>;
|
||||
writer: Deno.Writer;
|
||||
constructor({ reader, writer }: {
|
||||
reader: Deno.Reader;
|
||||
writer: Deno.Writer;
|
||||
}) {
|
||||
this.lines = io.readLines(reader);
|
||||
this.writer = writer;
|
||||
}
|
||||
async recvType<K extends T["type"]>(
|
||||
type: K,
|
||||
): Promise<ExtractType<T, K>> {
|
||||
const data = await this.recv();
|
||||
if (data.type !== type) {
|
||||
throw new Error(`Unexpected type: ${data.type}`);
|
||||
}
|
||||
return data as ExtractType<T, K>;
|
||||
}
|
||||
async recv(): Promise<T> {
|
||||
const result = await this.lines.next();
|
||||
|
||||
if (!result.done) {
|
||||
return JSON.parse(result.value);
|
||||
}
|
||||
|
||||
throw new Error("EOF");
|
||||
}
|
||||
async send(data: T) {
|
||||
await writeAll(
|
||||
this.writer,
|
||||
new TextEncoder().encode(JSON.stringify(data) + "\n"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
export type Command = {
|
||||
type: "hello";
|
||||
data: string;
|
||||
};
|
||||
|
||||
export type ExtractType<T extends { type: string }, K extends T["type"]> =
|
||||
Extract<
|
||||
T,
|
||||
{ type: K }
|
||||
>;
|
||||
Loading…
Reference in New Issue