Skip to content

Commit 2de97a4

Browse files
authored
Dynamically pull down binary (#28)
* Dynamically pull down binary Pull the binary from GitHub releases unless the WEBVIEW_BIN env var is provided. * Bump cargo version * Delete misc file * Add mechanism to automatically upgrade version
1 parent 89256bb commit 2de97a4

File tree

10 files changed

+137
-35
lines changed

10 files changed

+137
-35
lines changed

.vscode/settings.json

+3
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@
22
"editor.semanticHighlighting.enabled": true,
33
"[typescript]": {
44
"editor.defaultFormatter": "denoland.vscode-deno"
5+
},
6+
"[json]": {
7+
"editor.defaultFormatter": "denoland.vscode-deno"
58
}
69
}

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "deno-webview"
3-
version = "0.1.3"
3+
version = "0.1.4"
44
edition = "2021"
55

66
[profile.release]

ClientEvent.json

-24
This file was deleted.

deno.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
},
66
"tasks": {
77
"dev": "deno run --watch main.ts",
8-
"gen": "cargo test && deno run -A scripts/generate-zod.ts",
8+
"gen": "cargo test && deno run -A scripts/generate-zod.ts && deno run -A scripts/sync-versions.ts",
99
"build": "deno task gen && cargo build -F transparent",
1010
"example:simple": "deno run -A examples/simple.ts"
1111
}

deno.lock

+23
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/simple.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { WebView } from "../src/lib.ts";
1+
import { createWebView } from "../src/lib.ts";
22

3-
const webview = new WebView({
3+
using webview = await createWebView({
44
title: "Simple",
55
html: "<h1>Hello, World!</h1>",
66
});

scripts/sync-versions.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Keeps the version of the WebView binary in sync with the version in Cargo.toml.
3+
*/
4+
5+
import { parse } from "jsr:@std/toml";
6+
7+
const latestVersion = await Deno
8+
.readTextFile("./Cargo.toml").then((text) =>
9+
parse(text) as { package: { version: string } }
10+
).then((config) => config.package.version);
11+
12+
// Read the content of src/lib.ts
13+
const libPath = "./src/lib.ts";
14+
const libContent = await Deno.readTextFile(libPath);
15+
16+
// Replace the version in the URL
17+
const updatedContent = libContent.replace(
18+
/releases\/download\/v\d+\.\d+\.\d+\/deno-webview/,
19+
`releases/download/v${latestVersion}/deno-webview`,
20+
);
21+
22+
// Write the updated content back to src/lib.ts
23+
await Deno.writeTextFile(libPath, updatedContent);
24+
25+
console.log(`Updated WebView binary version to ${latestVersion} in src/lib.ts`);

src/lib.ts

+81-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import {
77
} from "./schemas.ts";
88
import { monotonicUlid as ulid } from "jsr:@std/ulid";
99
import type { Except } from "npm:type-fest";
10+
import { join } from "jsr:@std/path";
11+
import { ensureDir } from "jsr:@std/fs";
12+
import { exists } from "jsr:@std/fs";
1013

1114
type JSON =
1215
| string
@@ -68,7 +71,82 @@ const returnAck = (result: WebViewResponse) => {
6871
}
6972
};
7073

71-
export class WebView implements Disposable {
74+
async function getWebViewBin(options: WebViewOptions) {
75+
if (Deno.permissions.querySync({ name: "env" }).state === "granted") {
76+
const binPath = Deno.env.get("WEBVIEW_BIN");
77+
if (binPath) return binPath;
78+
}
79+
80+
const flags = options.devtools
81+
? "-devtools"
82+
: options.transparent && Deno.build.os === "darwin"
83+
? "-transparent"
84+
: "";
85+
86+
const cacheDir = getCacheDir();
87+
const fileName = `deno-webview${flags}${
88+
Deno.build.os === "windows" ? ".exe" : ""
89+
}`;
90+
const filePath = join(cacheDir, fileName);
91+
92+
// Check if the file already exists in cache
93+
if (await exists(filePath)) {
94+
return filePath;
95+
}
96+
97+
// If not in cache, download it
98+
let url =
99+
"https://github.com/zephraph/webview/releases/download/v0.1.4/deno-webview";
100+
switch (Deno.build.os) {
101+
case "darwin": {
102+
url += "-mac" + flags;
103+
break;
104+
}
105+
case "linux": {
106+
url += "-linux" + flags;
107+
break;
108+
}
109+
case "windows": {
110+
url += "-windows" + flags + ".exe";
111+
break;
112+
}
113+
default:
114+
throw new Error("unsupported OS");
115+
}
116+
117+
const res = await fetch(url);
118+
119+
// Ensure the cache directory exists
120+
await ensureDir(cacheDir);
121+
122+
// Write the binary to disk
123+
await Deno.writeFile(filePath, new Uint8Array(await res.arrayBuffer()), {
124+
mode: 0o755,
125+
});
126+
127+
return filePath;
128+
}
129+
130+
// Helper function to get the OS-specific cache directory
131+
function getCacheDir(): string {
132+
switch (Deno.build.os) {
133+
case "darwin":
134+
return join(Deno.env.get("HOME")!, "Library", "Caches", "deno-webview");
135+
case "linux":
136+
return join(Deno.env.get("HOME")!, ".cache", "deno-webview");
137+
case "windows":
138+
return join(Deno.env.get("LOCALAPPDATA")!, "deno-webview", "Cache");
139+
default:
140+
throw new Error("Unsupported OS");
141+
}
142+
}
143+
144+
export async function createWebView(options: WebViewOptions) {
145+
const binPath = await getWebViewBin(options);
146+
return new WebView(options, binPath);
147+
}
148+
149+
class WebView implements Disposable {
72150
#process: Deno.ChildProcess;
73151
#stdin: WritableStreamDefaultWriter;
74152
#stdout: ReadableStreamDefaultReader;
@@ -77,8 +155,8 @@ export class WebView implements Disposable {
77155
#externalEvent = new EventEmitter();
78156
#messageLoop: Promise<void>;
79157

80-
constructor(options: WebViewOptions) {
81-
this.#process = new Deno.Command("./target/debug/deno-webview", {
158+
constructor(options: WebViewOptions, binPath: string) {
159+
this.#process = new Deno.Command(binPath, {
82160
args: [JSON.stringify(options)],
83161
stdin: "piped",
84162
stdout: "piped",

src/main.rs

-3
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,6 @@ fn main() -> wry::Result<()> {
137137
}
138138
let window = window_builder.build(&event_loop).unwrap();
139139

140-
eprintln!("transparent: {:?}", webview_options.transparent);
141-
142140
let webview_builder = match webview_options.target {
143141
WebViewTarget::Url(url) => WebViewBuilder::new(&window).with_url(url),
144142
WebViewTarget::Html(html) => WebViewBuilder::new(&window).with_html(html),
@@ -171,7 +169,6 @@ fn main() -> wry::Result<()> {
171169
let mut stdout_lock = stdout.lock();
172170

173171
while let Ok(event) = to_deno.recv() {
174-
eprintln!("Sending event: {:?}", event);
175172
match serde_json::to_string(&event) {
176173
Ok(json) => {
177174
let mut buffer = json.replace("\0", "").into_bytes();

0 commit comments

Comments
 (0)