|
1 | 1 | use clap::Parser; |
2 | | -use std::{env, error::Error, fs::File, path::PathBuf}; |
| 2 | +use serde::Deserialize; |
| 3 | +use std::{ |
| 4 | + env, |
| 5 | + error::Error, |
| 6 | + fs::{self, File}, |
| 7 | + io::Write, |
| 8 | + path::PathBuf, |
| 9 | +}; |
3 | 10 | use wasmtime::{Engine, Linker, Module, Store}; |
4 | 11 | use wasmtime_wasi::WasiCtxBuilder; |
5 | 12 |
|
@@ -34,10 +41,13 @@ fn main() -> Result<(), Box<dyn Error>> { |
34 | 41 | }) |
35 | 42 | .ok_or("default runtime directory unavailable. please specify an alternate manually.")?; |
36 | 43 |
|
37 | | - // TODO: download the wasm binary if not available locally |
38 | | - let codegen_wasm_path = runtime_dir.join(format!("jsoncodegen-{}.wasm", args.lang)); |
| 44 | + let codegen_wasm_path = |
| 45 | + runtime_dir.join(format!("jsoncodegen-{}-wasm32-wasip1.wasm", args.lang)); |
| 46 | + |
| 47 | + // Check if WASM binary exists locally, if not download it |
39 | 48 | if !codegen_wasm_path.is_file() { |
40 | | - return Err("unsupported language".into()); |
| 49 | + eprintln!("WASM binary not found locally"); |
| 50 | + fetch_latest_wasm_release(&args.lang, &codegen_wasm_path)?; |
41 | 51 | } |
42 | 52 |
|
43 | 53 | let ctx = { |
@@ -74,3 +84,78 @@ fn main() -> Result<(), Box<dyn Error>> { |
74 | 84 |
|
75 | 85 | Ok(()) |
76 | 86 | } |
| 87 | + |
| 88 | +#[derive(Debug, Deserialize)] |
| 89 | +struct Release { |
| 90 | + tag_name: String, |
| 91 | + assets: Vec<Asset>, |
| 92 | +} |
| 93 | + |
| 94 | +#[derive(Debug, Deserialize)] |
| 95 | +struct Asset { |
| 96 | + name: String, |
| 97 | + browser_download_url: String, |
| 98 | +} |
| 99 | + |
| 100 | +fn fetch_latest_wasm_release(lang: &str, dest_path: &PathBuf) -> Result<(), Box<dyn Error>> { |
| 101 | + eprintln!("Fetching latest WASM release info for language `{}`", lang); |
| 102 | + |
| 103 | + let client = reqwest::blocking::Client::builder() |
| 104 | + .user_agent("jsoncodegen") |
| 105 | + .build()?; |
| 106 | + let mut releases: Vec<Release> = client |
| 107 | + .get("https://api.github.com/repos/zahash/jsoncodegen/releases") |
| 108 | + .send()? |
| 109 | + .json()?; |
| 110 | + |
| 111 | + // Filter releases that match the pattern: jsoncodegen-{lang}-wasm32-wasip1-{version} |
| 112 | + let tag_prefix = format!("jsoncodegen-{}-wasm32-wasip1-", lang); |
| 113 | + releases.retain(|release| release.tag_name.starts_with(&tag_prefix)); |
| 114 | + |
| 115 | + // Sort by version number (descending) - extract the number after the last dash |
| 116 | + let latest_release = releases |
| 117 | + .into_iter() |
| 118 | + .max_by_key(|release| { |
| 119 | + release |
| 120 | + .tag_name |
| 121 | + .strip_prefix(&tag_prefix) |
| 122 | + .and_then(|version| version.parse::<usize>().ok()) |
| 123 | + .unwrap_or(0) |
| 124 | + }) |
| 125 | + .ok_or_else(|| format!("No WASM releases found for language `{}`", lang))?; |
| 126 | + |
| 127 | + eprintln!("latest release found: {}", latest_release.tag_name); |
| 128 | + |
| 129 | + let asset_name = format!("jsoncodegen-{}-wasm32-wasip1.wasm", lang); |
| 130 | + let asset = latest_release |
| 131 | + .assets |
| 132 | + .into_iter() |
| 133 | + .find(|a| a.name == asset_name) |
| 134 | + .ok_or_else(|| { |
| 135 | + format!( |
| 136 | + "WASM asset `{}` not found in release `{}`", |
| 137 | + asset_name, latest_release.tag_name |
| 138 | + ) |
| 139 | + })?; |
| 140 | + |
| 141 | + eprintln!( |
| 142 | + "Downloading WASM binary from: {}", |
| 143 | + asset.browser_download_url |
| 144 | + ); |
| 145 | + |
| 146 | + let response = client.get(asset.browser_download_url).send()?; |
| 147 | + if !response.status().is_success() { |
| 148 | + return Err(format!("Failed to download: HTTP {}", response.status()).into()); |
| 149 | + } |
| 150 | + let bytes = response.bytes()?; |
| 151 | + |
| 152 | + // Ensure the parent directory exists |
| 153 | + if let Some(parent) = dest_path.parent() { |
| 154 | + fs::create_dir_all(parent)?; |
| 155 | + } |
| 156 | + let mut file = File::create(dest_path)?; |
| 157 | + file.write_all(&bytes)?; |
| 158 | + |
| 159 | + eprintln!("Successfully downloaded to: {}", dest_path.display()); |
| 160 | + Ok(()) |
| 161 | +} |
0 commit comments