From 458a5cb60f68a5ca075adc60e174cef359eab295 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 23 Feb 2022 09:06:15 +0530 Subject: [PATCH] Use Deno FFI (#5) --- .github/workflows/checks.yml | 24 ++++++++++----------- .github/workflows/release.yml | 5 ----- Cargo.toml | 5 +---- bindings/bindings.ts | 33 +++++++++++++++++++++++++++++ core_type.ts | 10 --------- detect.ts | 14 ------------ lib.rs | 40 ++++++++--------------------------- mod.ts | 2 +- op.ts | 20 ------------------ plugin.ts | 24 --------------------- 10 files changed, 56 insertions(+), 121 deletions(-) create mode 100644 bindings/bindings.ts delete mode 100644 core_type.ts delete mode 100644 detect.ts delete mode 100644 op.ts delete mode 100644 plugin.ts diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 5d05235..2e0730c 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -1,4 +1,4 @@ -name: Release CI +name: CI on: [push, pull_request] @@ -26,6 +26,13 @@ jobs: toolchain: stable override: true + - uses: denoland/setup-deno@v1 + with: + deno-version: canary + + - name: Install deno_bindgen + run: deno install -Afq -n deno_bindgen https://raw.githubusercontent.com/littledivy/deno_bindgen/main/cli.ts + - name: Log versions run: | rustc --version @@ -46,18 +53,11 @@ jobs: path: target key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} - - name: Remove Some Cache - if: matrix.os == 'windows-latest' - run: | - rm target/release/gn_root -Recurse -ErrorAction Ignore - rm target/debug/gn_root -Recurse -ErrorAction Ignore - - name: Install webkit2gtk + - name: Install libasound2-dev if: matrix.os == 'ubuntu-latest' run: | sudo apt-get update sudo apt-get install libasound2-dev - - name: Run cargo build - uses: actions-rs/cargo@v1 - with: - command: build - args: --release + + - name: Build + run: deno_bindgen --release diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7db228f..979bf58 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -47,11 +47,6 @@ jobs: path: target key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} - - name: Remove Some Cache - if: matrix.os == 'windows-latest' - run: | - rm target/release/gn_root -Recurse -ErrorAction Ignore - rm target/debug/gn_root -Recurse -ErrorAction Ignore - name: Install webkit2gtk if: matrix.os == 'ubuntu-latest' run: | diff --git a/Cargo.toml b/Cargo.toml index be1277c..b428c73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,4 @@ crate-type = ["cdylib"] [dependencies] rodio = "0.12.0" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -futures = "0.3.4" -deno_core = "0.61.0" +deno_bindgen = "0.5.0" diff --git a/bindings/bindings.ts b/bindings/bindings.ts new file mode 100644 index 0000000..2d17194 --- /dev/null +++ b/bindings/bindings.ts @@ -0,0 +1,33 @@ +// Auto-generated with deno_bindgen +import { CachePolicy, prepare } from "https://deno.land/x/plug@0.5.1/plug.ts" +function encode(v: string | Uint8Array): Uint8Array { + if (typeof v !== "string") return v + return new TextEncoder().encode(v) +} +function decode(v: Uint8Array): string { + return new TextDecoder().decode(v) +} +function readPointer(v: any): Uint8Array { + const ptr = new Deno.UnsafePointerView(v as Deno.UnsafePointer) + const lengthBe = new Uint8Array(4) + const view = new DataView(lengthBe.buffer) + ptr.copyInto(lengthBe, 0) + const buf = new Uint8Array(view.getUint32(0)) + ptr.copyInto(buf, 4) + return buf +} +const opts = { + name: "deno_audio", + url: (new URL("../target/release", import.meta.url)).toString(), + policy: undefined, +} +const _lib = await prepare(opts, { + play: { parameters: ["pointer", "usize"], result: "void", nonblocking: true }, +}) + +export function play(a0: string) { + const a0_buf = encode(a0) + let rawResult = _lib.symbols.play(a0_buf, a0_buf.byteLength) + const result = rawResult + return result +} diff --git a/core_type.ts b/core_type.ts deleted file mode 100644 index 1582095..0000000 --- a/core_type.ts +++ /dev/null @@ -1,10 +0,0 @@ -// @ts-ignore -export const core = Deno.core as { - ops: () => { [key: string]: number }; - setAsyncHandler(rid: number, handler: (response: Uint8Array) => void): void; - dispatch( - rid: number, - msg?: any, - buf?: ArrayBufferView, - ): Uint8Array | undefined; -}; diff --git a/detect.ts b/detect.ts deleted file mode 100644 index bcdc7e4..0000000 --- a/detect.ts +++ /dev/null @@ -1,14 +0,0 @@ -export default function filename(filenameBase: string): string { - let filenameSuffix = ".so"; - let filenamePrefix = "lib"; - - if (Deno.build.os === "windows") { - filenameSuffix = ".dll"; - filenamePrefix = ""; - } - if (Deno.build.os === "darwin") { - filenameSuffix = ".dylib"; - } - - return `${filenamePrefix}${filenameBase}${filenameSuffix}`; -} diff --git a/lib.rs b/lib.rs index a0c9562..2f018c0 100644 --- a/lib.rs +++ b/lib.rs @@ -10,37 +10,15 @@ //! ``` use std::io::BufReader; +use deno_bindgen::deno_bindgen; -use deno_core::plugin_api::Interface; -use deno_core::plugin_api::Op; -use deno_core::plugin_api::ZeroCopyBuf; -use futures::future::FutureExt; +#[deno_bindgen(non_blocking)] +pub fn play(filename: &str) { + let (_stream, handle) = rodio::OutputStream::try_default().unwrap(); + let sink = rodio::Sink::try_new(&handle).unwrap(); -#[no_mangle] -pub fn deno_plugin_init(interface: &mut dyn Interface) { - interface.register_op("play", op_play); -} - -fn op_play(_interface: &mut dyn Interface, zero_copy: &mut [ZeroCopyBuf]) -> Op { - let data = &zero_copy[0][..]; - let data_str = std::str::from_utf8(&data[..]).unwrap().to_string(); - let fut = async move { - let (tx, rx) = futures::channel::oneshot::channel::>(); - std::thread::spawn(move || { - let (_stream, handle) = rodio::OutputStream::try_default().unwrap(); - let sink = rodio::Sink::try_new(&handle).unwrap(); - - let file = std::fs::File::open(&data_str).unwrap(); - sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap()); - - sink.sleep_until_end(); - tx.send(Ok(())); - }); - let result_box = serde_json::to_vec(&rx.await.unwrap()) - .unwrap() - .into_boxed_slice(); - result_box - }; - - Op::Async(fut.boxed()) + let file = std::fs::File::open(&filename).unwrap(); + sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap()); + // `play` runs from a different thread. + sink.sleep_until_end(); } diff --git a/mod.ts b/mod.ts index 651d720..831cb97 100644 --- a/mod.ts +++ b/mod.ts @@ -1 +1 @@ -export { play } from "./op.ts"; +export { play } from "./bindings/bindings.ts"; diff --git a/op.ts b/op.ts deleted file mode 100644 index b1cc1e9..0000000 --- a/op.ts +++ /dev/null @@ -1,20 +0,0 @@ -import "./plugin.ts"; -import { core } from "./core_type.ts"; - -const { - play: op_play, -} = core.ops(); - -const textDecoder = new TextDecoder(); -const decoder = new TextDecoder(); - -export async function play(file: string) { - const encoder = new TextEncoder(); - const view = encoder.encode(file); - return new Promise((resolve, reject) => { - core.setAsyncHandler(op_play, (bytes) => { - resolve(textDecoder.decode(bytes)); - }); - core.dispatch(op_play, view); - }); -} diff --git a/plugin.ts b/plugin.ts deleted file mode 100644 index 77fd3f0..0000000 --- a/plugin.ts +++ /dev/null @@ -1,24 +0,0 @@ -import filename from "./detect.ts"; -import { prepare } from "https://deno.land/x/plugin_prepare@v0.8.0/mod.ts"; - -const { filenameBase, pluginBase } = { - "filenameBase": "deno_audio", - "pluginBase": - "https://github.com/littledivy/deno_audio/releases/latest/download", -}; - -const isDev = Deno.env.get("DEV"); - -if (isDev) { - const rid = Deno.openPlugin("./target/debug/" + filename(filenameBase)); -} else { - // logger.info(`Downloading latest Autopilot release from Github`); - const pluginId = await prepare({ - name: "deno_audio", - urls: { - darwin: `${pluginBase}/libdeno_audio.dylib`, - windows: `${pluginBase}/deno_audio.dll`, - linux: `${pluginBase}/libdeno_audio.so`, - }, - }); -}