Skip to content

Instantly share code, notes, and snippets.

@feelfreetofee
Created September 10, 2024 15:06
Show Gist options
  • Select an option

  • Save feelfreetofee/3313d73a30d9ffd0b83c72f24756bae3 to your computer and use it in GitHub Desktop.

Select an option

Save feelfreetofee/3313d73a30d9ffd0b83c72f24756bae3 to your computer and use it in GitHub Desktop.

Revisions

  1. feelfreetofee created this gist Sep 10, 2024.
    81 changes: 81 additions & 0 deletions index.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,81 @@
    import {JSCallback, CString} from 'bun:ffi'
    import {encodeCString, default as lib} from './lib'
    export class Webview {
    static #instances = []
    static unload() {
    for (const instance of this.#instances)
    instance.destroy()
    lib.close()
    }
    #handle
    #callbacks = {}
    constructor(debug = false, window) {
    this.#handle = lib.symbols.webview_create(Number(this.debug = debug), window)
    }
    get handle() {
    return handle
    }
    get window() {
    return lib.symbols.webview_get_window(this.#handle)
    }
    set title(title) {
    lib.symbols.webview_set_title(this.#handle, encodeCString(title))
    }
    set size({width, height, hint}) {
    lib.symbols.webview_set_size(this.#handle, width, height, hint)
    }
    set html(html) {
    lib.symbols.webview_set_html(this.#handle, encodeCString(html))
    }
    navigate(url) {
    lib.symbols.webview_navigate(this.#handle, encodeCString(url))
    }
    init(source) {
    lib.symbols.webview_init(this.#handle, encodeCString(source))
    }
    eval(source) {
    lib.symbols.webview_eval(this.#handle, encodeCString(source))
    }
    run() {
    lib.symbols.webview_run(this.#handle)
    this.destroy()
    }
    return(id, status, result = null) {
    lib.symbols.webview_return(this.#handle, encodeCString(id), status, encodeCString(result))
    }
    dispatch(name, ...arg) {
    lib.symbols.webview_dispatch(this.#handle, this.#callbacks[name], encodeCString(JSON.stringify(arg)))
    }
    destroy() {
    for (const callback of Object.keys(this.#callbacks))
    this.unbind(callback)
    lib.symbols.webview_terminate(this.#handle)
    lib.symbols.webview_destroy(this.#handle)
    this.#handle = null
    }
    bindRaw(name, callback, arg) {
    lib.symbols.webview_bind(this.#handle, encodeCString(name), (
    this.#callbacks[name] = new JSCallback((id, req, arg) => callback(new CString(id), new CString(req), arg), {
    args: ['cstring', 'cstring', 'ptr']
    })
    ).ptr, arg)
    }
    bind(name, callback) {
    this.bindRaw(name, (id, req) => {
    try {
    const result = callback(...JSON.parse(req))
    if (result instanceof Promise)
    result.then(r => this.return(id, 0, JSON.stringify(r)))
    else
    this.return(id, 0, JSON.stringify(result))
    } catch(error) {
    this.return(id, 1, error)
    }
    })
    }
    unbind(name) {
    lib.symbols.webview_unbind(this.#handle, encodeCString(name))
    this.#callbacks[name]?.close()
    delete this.#callbacks[name]
    }
    }
    55 changes: 55 additions & 0 deletions lib.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,55 @@
    import {dlopen, suffix, ptr} from 'bun:ffi'
    export const encodeCString = str => ptr(Buffer.from(str + '\0', 'utf8'))
    export default dlopen(`${import.meta.dir}/lib/libwebview.${suffix}`, {
    webview_create: {
    args: ['i32', 'ptr'],
    returns: 'ptr'
    },
    webview_destroy: {
    args: ['ptr']
    },
    webview_run: {
    args: ['ptr']
    },
    webview_terminate: {
    args: ['ptr']
    },
    webview_dispatch: {
    args: ['ptr', 'function', 'ptr']
    },
    webview_get_window: {
    args: ['ptr'],
    returns: 'ptr'
    },
    webview_get_native_handle: {
    args: ['ptr', 'i32'],
    returns: 'ptr'
    },
    webview_set_title: {
    args: ['ptr', 'cstring']
    },
    webview_set_size: {
    args: ['ptr', 'i32', 'i32', 'i32']
    },
    webview_navigate: {
    args: ['ptr', 'cstring']
    },
    webview_set_html: {
    args: ['ptr', 'cstring']
    },
    webview_init: {
    args: ['ptr', 'cstring']
    },
    webview_eval: {
    args: ['ptr', 'cstring']
    },
    webview_bind: {
    args: ['ptr', 'cstring', 'function', 'ptr']
    },
    webview_unbind: {
    args: ['ptr', 'cstring']
    },
    webview_return: {
    args: ['ptr', 'cstring', 'i32', 'cstring']
    }
    })