-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
wapm.io integration #43
base: main
Are you sure you want to change the base?
Changes from 10 commits
7840960
28bc11c
0d6e80e
8c1cff4
37427df
d8c0b49
33af993
c9c7345
c43b2bb
d58d3bf
08589ab
ce757ca
1bfc363
d6fc005
7f4f2c3
007d98e
82dc7dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ use humansize::{format_size, BINARY}; | |
use owo_colors::OwoColorize; | ||
use prettytable::{row, Table}; | ||
use tokio::runtime::Runtime; | ||
use utils::registry::{download_module, gen_manifest, PackageRegistry, PackageSpec}; | ||
use utils::structs::Manifest; | ||
use uuid::Uuid; | ||
|
||
|
@@ -70,6 +71,12 @@ pub enum Command { | |
History, | ||
/// Liveness check: ping at least one node on the mesh. | ||
Ping, | ||
/// Highly experimental: Pull a package from WAPM.io and store it in Serval Mesh | ||
Pull { | ||
/// The name of the software package, formatted as | ||
/// [[protocol://]registry.tld/]author/packagename[@version][:module] | ||
identifer: String, | ||
}, | ||
} | ||
|
||
static SERVAL_NODE_URL: Mutex<Option<String>> = Mutex::new(None); | ||
|
@@ -289,6 +296,95 @@ fn blocking_maybe_discover_service_url( | |
Ok(format!("http://{addr}:{port}")) | ||
} | ||
|
||
/// Pull a Wasm package from a package manager, generate its manifest, and store it. | ||
fn pull(identifer: String) -> Result<()> { | ||
let pkg_spec = PackageSpec::try_from(identifer).unwrap(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will teach you a new trick with Rust! Or maybe you already know this one, but here is let-else: let pkg_spec = Ok(PackageSpec::try_from(identifer)) else {
// tell the user what they got wrong
// then exit with a non-zero code
} This is nicer than panicking here if the format is wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ahhhh... nice. I was theoretically aware of let else but did not grok the specific usage. Will hunt down a bunch of |
||
log::debug!("{:#?}", pkg_spec); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is absolutely zero reason to change this, but I note that the dbg!() macro is another option for this kind of fast printf debugging. |
||
println!( | ||
"📦 Identified package {}", | ||
pkg_spec.profile_url().bold().blue() | ||
); | ||
println!("🏷 Using module {}", pkg_spec.module.bold().blue()); | ||
if pkg_spec.is_binary_cached() { | ||
println!( | ||
"✅ Binary for {} ({}) available locally.", | ||
pkg_spec.fq_name().bold().green(), | ||
pkg_spec.fq_digest() | ||
); | ||
// Creating a temporary manifest file | ||
let manifest_path = gen_manifest(&pkg_spec).unwrap(); | ||
// Handing over to existing storage logic | ||
upload_manifest(manifest_path)?; | ||
} else { | ||
println!( | ||
"⌛️ Binary for {} not available locally, downloading...", | ||
pkg_spec.fq_name().blue() | ||
); | ||
let mod_dl = download_module(&pkg_spec); | ||
match mod_dl { | ||
// This means the download function did not break. It does not mean that | ||
// the executable was downloaded successfully... check HTTP status code. | ||
Ok(status_code) => { | ||
if status_code.is_success() { | ||
println!( | ||
"✅ Downloaded {} ({}) successfully.", | ||
pkg_spec.fq_name().bold().green(), | ||
pkg_spec.fq_digest() | ||
); | ||
// Creating a temporary manifest file | ||
let manifest_path = gen_manifest(&pkg_spec).unwrap(); | ||
// Handing over to existing storage logic | ||
upload_manifest(manifest_path)?; | ||
} else if status_code.is_server_error() { | ||
println!("🛑 Server error: {}", status_code); | ||
println!(" There may be an issue with this package manager."); | ||
} else if status_code.is_client_error() { | ||
println!("🛑 Client error: {}", status_code); | ||
println!("{:#?}", status_code); | ||
if status_code == 404 { | ||
println!(" Failed to download from {:?}", pkg_spec.download_urls()); | ||
} | ||
println!(); | ||
if pkg_spec.version == "latest" && pkg_spec.registry == PackageRegistry::Wapm { | ||
jkbecker marked this conversation as resolved.
Show resolved
Hide resolved
|
||
println!( | ||
"💡 Please note that wapm.io does not properly alias the `{}` version tag.", | ||
"latest".bold().yellow() | ||
); | ||
println!(" You might want to look up the package and explicitly provide its most recent version:"); | ||
println!(" \t{}", pkg_spec.profile_url()); | ||
println!(); | ||
} | ||
// Currently, a 404 is very likely if a package only contains modules that have names other than | ||
// the package name (which the module name defaults to if not provided). | ||
// TODO: retrieve available modules and interactively ask which module should be downloaded | ||
// Quick fix is to point this out to the user: | ||
if pkg_spec.name == pkg_spec.module { | ||
println!( | ||
"💡 Please verify that this package actually contains a `{}` module", | ||
pkg_spec.module.bold().yellow() | ||
); | ||
println!(" by checking the MODULES section on its profile page:"); | ||
println!(" \t{}", pkg_spec.profile_url()); | ||
println!( | ||
" If the module name differs from the package name, you need to provide it with" | ||
); | ||
println!( | ||
" \tserval pull {}:{}", | ||
pkg_spec.profile_url(), | ||
"<module>".bold().yellow() | ||
); | ||
} | ||
} else { | ||
println!("😵💫 Something else happened. Status: {:?}", status_code); | ||
} | ||
} | ||
// Something went horribly wrong. | ||
Err(err) => println!("{:#?}", err), | ||
} | ||
} | ||
Ok(()) | ||
} | ||
|
||
/// Parse command-line arguments and act. | ||
fn main() -> Result<()> { | ||
let args = Args::parse(); | ||
|
@@ -320,6 +416,7 @@ fn main() -> Result<()> { | |
Command::Status { id } => status(id)?, | ||
Command::History => history()?, | ||
Command::Ping => ping()?, | ||
Command::Pull { identifer } => pull(identifer)?, | ||
}; | ||
|
||
Ok(()) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,5 @@ pub mod errors; | |
pub mod futures; | ||
pub mod mdns; | ||
pub mod networking; | ||
pub mod registry; | ||
pub mod structs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can eventually make the identifier a type more specific than a string and have clap parse it for us. Some examples here. There is no need to do that in this PR, however.