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.
Webview binding for Bun in JS https://github.com/webview/webview
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]
}
}
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']
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment