mirror of
https://github.com/uqbar-dao/nectar.git
synced 2025-01-08 18:52:49 +03:00
More app store stuff
This commit is contained in:
parent
59b1f6a8dc
commit
251709f297
7
modules/app_store/app_store/Cargo.lock
generated
7
modules/app_store/app_store/Cargo.lock
generated
@ -19,6 +19,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"urlencoding",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
@ -473,6 +474,12 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urlencoding"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
@ -13,6 +13,7 @@ anyhow = "1.0"
|
||||
bincode = "1.3.3"
|
||||
kinode_process_lib = { git = "https://github.com/uqbar-dao/process_lib.git", tag = "v0.5.5-alpha" }
|
||||
rand = "0.8"
|
||||
urlencoding = "2.1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
sha2 = "0.10.8"
|
||||
|
229
modules/app_store/app_store/src/http_api.rs
Normal file
229
modules/app_store/app_store/src/http_api.rs
Normal file
@ -0,0 +1,229 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use kinode_process_lib::{http::{send_response, IncomingHttpRequest, StatusCode}, Address};
|
||||
|
||||
use crate::{PackageListing, State};
|
||||
|
||||
pub fn handle_http_request(
|
||||
our: &Address,
|
||||
state: &mut State,
|
||||
req: IncomingHttpRequest,
|
||||
) -> anyhow::Result<()> {
|
||||
let path = req.path()?;
|
||||
let method = req.method()?;
|
||||
|
||||
let (status_code, headers, body) = match path.as_str() {
|
||||
"/apps" => {
|
||||
match method.as_str() {
|
||||
"GET" => {
|
||||
// TODO: Return a list of the user's apps
|
||||
(
|
||||
StatusCode::OK,
|
||||
None,
|
||||
serde_json::to_vec(&vec![
|
||||
PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: "Chess".to_string(),
|
||||
icon: "".to_string(),
|
||||
package_name: "chess".to_string(),
|
||||
description: Some("A test app".to_string()),
|
||||
website: Some("https://example.com".to_string()),
|
||||
rating: 3.0,
|
||||
versions: HashMap::new(),
|
||||
mirrors: vec![],
|
||||
},
|
||||
PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: "File Transfer".to_string(),
|
||||
icon: "".to_string(),
|
||||
package_name: "file_transfer".to_string(),
|
||||
description: Some("A test app".to_string()),
|
||||
website: Some("https://example.com".to_string()),
|
||||
rating: 3.0,
|
||||
versions: HashMap::new(),
|
||||
mirrors: vec![],
|
||||
},
|
||||
])?,
|
||||
)
|
||||
}
|
||||
"POST" => {
|
||||
// Add an app
|
||||
(StatusCode::CREATED, None, format!("Installed").into_bytes())
|
||||
}
|
||||
_ => (
|
||||
StatusCode::METHOD_NOT_ALLOWED,
|
||||
None,
|
||||
format!("Invalid method {} for {}", method, path).into_bytes(),
|
||||
),
|
||||
}
|
||||
}
|
||||
"/apps/:id" => {
|
||||
let Some(app_id) = path.split("/").last() else {
|
||||
return Err(anyhow::anyhow!("No app ID"));
|
||||
};
|
||||
|
||||
match method.as_str() {
|
||||
"PUT" => {
|
||||
// Update an app
|
||||
(
|
||||
StatusCode::NO_CONTENT,
|
||||
None,
|
||||
format!("Updated").into_bytes(),
|
||||
)
|
||||
}
|
||||
"DELETE" => {
|
||||
// Uninstall an app
|
||||
(
|
||||
StatusCode::NO_CONTENT,
|
||||
None,
|
||||
format!("Uninstalled").into_bytes(),
|
||||
)
|
||||
}
|
||||
_ => (
|
||||
StatusCode::METHOD_NOT_ALLOWED,
|
||||
None,
|
||||
format!("Invalid method {} for {}", method, path).into_bytes(),
|
||||
),
|
||||
}
|
||||
}
|
||||
"/apps/latest" => {
|
||||
match method.as_str() {
|
||||
"GET" => {
|
||||
// Return a list of latest apps
|
||||
// The first 2 will show up in "featured"
|
||||
(
|
||||
StatusCode::OK,
|
||||
None,
|
||||
serde_json::to_vec(&vec![
|
||||
PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: "Remote".to_string(),
|
||||
icon: "".to_string(),
|
||||
package_name: "remote".to_string(),
|
||||
description: Some("A test app".to_string()),
|
||||
website: Some("https://example.com".to_string()),
|
||||
rating: 3.0,
|
||||
versions: HashMap::new(),
|
||||
mirrors: vec![],
|
||||
},
|
||||
PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: "Happy Path".to_string(),
|
||||
icon: "".to_string(),
|
||||
package_name: "happy_path".to_string(),
|
||||
description: Some("A test app".to_string()),
|
||||
website: Some("https://example.com".to_string()),
|
||||
rating: 3.0,
|
||||
versions: HashMap::new(),
|
||||
mirrors: vec![],
|
||||
},
|
||||
PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: "Meme Deck".to_string(),
|
||||
icon: "".to_string(),
|
||||
package_name: "meme_deck".to_string(),
|
||||
description: Some("A test app".to_string()),
|
||||
website: Some("https://example.com".to_string()),
|
||||
rating: 3.0,
|
||||
versions: HashMap::new(),
|
||||
mirrors: vec![],
|
||||
},
|
||||
PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: "Sheep Simulator".to_string(),
|
||||
icon: "".to_string(),
|
||||
package_name: "sheep_simulator".to_string(),
|
||||
description: Some("A test app".to_string()),
|
||||
website: Some("https://example.com".to_string()),
|
||||
rating: 3.0,
|
||||
versions: HashMap::new(),
|
||||
mirrors: vec![],
|
||||
},
|
||||
])?,
|
||||
)
|
||||
}
|
||||
_ => (
|
||||
StatusCode::METHOD_NOT_ALLOWED,
|
||||
None,
|
||||
format!("Invalid method {} for {}", method, path).into_bytes(),
|
||||
),
|
||||
}
|
||||
}
|
||||
"/apps/search/:query" => {
|
||||
match method.as_str() {
|
||||
"GET" => {
|
||||
let Some(encoded_query) = path.split("/").last() else {
|
||||
return Err(anyhow::anyhow!("No query"));
|
||||
};
|
||||
let query = urlencoding::decode(encoded_query).expect("UTF-8");
|
||||
|
||||
// Return a list of apps matching the query
|
||||
// Query by name, publisher, package_name, description, website
|
||||
(
|
||||
StatusCode::OK,
|
||||
None,
|
||||
serde_json::to_vec(&vec![
|
||||
PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: "Winch".to_string(),
|
||||
icon: "".to_string(),
|
||||
package_name: "winch".to_string(),
|
||||
description: Some("A test app".to_string()),
|
||||
website: Some("https://example.com".to_string()),
|
||||
rating: 3.0,
|
||||
versions: HashMap::new(),
|
||||
mirrors: vec![],
|
||||
},
|
||||
PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: "Bucket".to_string(),
|
||||
icon: "".to_string(),
|
||||
package_name: "bucket".to_string(),
|
||||
description: Some("A test app".to_string()),
|
||||
website: Some("https://example.com".to_string()),
|
||||
rating: 3.0,
|
||||
versions: HashMap::new(),
|
||||
mirrors: vec![],
|
||||
},
|
||||
])?,
|
||||
)
|
||||
}
|
||||
_ => (
|
||||
StatusCode::METHOD_NOT_ALLOWED,
|
||||
None,
|
||||
format!("Invalid method {} for {}", method, path).into_bytes(),
|
||||
),
|
||||
}
|
||||
}
|
||||
"/apps/publish" => {
|
||||
match method.as_str() {
|
||||
"POST" => {
|
||||
// Publish an app
|
||||
(StatusCode::OK, None, format!("Success").into_bytes())
|
||||
}
|
||||
_ => (
|
||||
StatusCode::METHOD_NOT_ALLOWED,
|
||||
None,
|
||||
format!("Invalid method {} for {}", method, path).into_bytes(),
|
||||
),
|
||||
}
|
||||
}
|
||||
_ => (
|
||||
StatusCode::NOT_FOUND,
|
||||
None,
|
||||
format!("Path not found: {}", path).into_bytes(),
|
||||
),
|
||||
};
|
||||
|
||||
send_response(status_code, headers, body)?;
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use kinode_process_lib::http::{
|
||||
bind_http_path, send_response, serve_ui, HttpServerRequest, IncomingHttpRequest, StatusCode,
|
||||
bind_http_path, serve_ui, HttpServerRequest
|
||||
};
|
||||
use kinode_process_lib::kernel_types as kt;
|
||||
use kinode_process_lib::*;
|
||||
@ -21,6 +21,8 @@ mod ft_worker_lib;
|
||||
use ft_worker_lib::{
|
||||
spawn_receive_transfer, spawn_transfer, FTWorkerCommand, FTWorkerResult, FileTransferContext,
|
||||
};
|
||||
mod http_api;
|
||||
use http_api::handle_http_request;
|
||||
|
||||
/// App Store:
|
||||
/// acts as both a local package manager and a protocol to share packages across the network.
|
||||
@ -214,203 +216,6 @@ fn init(our: Address) {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_http_request(
|
||||
our: &Address,
|
||||
state: &mut State,
|
||||
req: IncomingHttpRequest,
|
||||
) -> anyhow::Result<()> {
|
||||
let path = req.path()?;
|
||||
let method = req.method()?;
|
||||
|
||||
let (status_code, headers, body) = match path.as_str() {
|
||||
"/apps" => {
|
||||
match method.as_str() {
|
||||
"GET" => {
|
||||
// TODO: Return a list of the user's apps
|
||||
(
|
||||
StatusCode::OK,
|
||||
None,
|
||||
serde_json::to_vec(&vec![
|
||||
PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: "Chess".to_string(),
|
||||
icon: "".to_string(),
|
||||
package_name: "chess".to_string(),
|
||||
description: Some("A test app".to_string()),
|
||||
website: Some("https://example.com".to_string()),
|
||||
rating: 3.0,
|
||||
versions: HashMap::new(),
|
||||
mirrors: vec![],
|
||||
},
|
||||
PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: "File Transfer".to_string(),
|
||||
icon: "".to_string(),
|
||||
package_name: "file_transfer".to_string(),
|
||||
description: Some("A test app".to_string()),
|
||||
website: Some("https://example.com".to_string()),
|
||||
rating: 3.0,
|
||||
versions: HashMap::new(),
|
||||
mirrors: vec![],
|
||||
},
|
||||
])?,
|
||||
)
|
||||
}
|
||||
"POST" => {
|
||||
// Add an app
|
||||
(StatusCode::CREATED, None, format!("Installed").into_bytes())
|
||||
}
|
||||
_ => (
|
||||
StatusCode::METHOD_NOT_ALLOWED,
|
||||
None,
|
||||
format!("Invalid method {} for {}", method, path).into_bytes(),
|
||||
),
|
||||
}
|
||||
}
|
||||
"/apps/:id" => {
|
||||
let Some(app_id) = path.split("/").last() else {
|
||||
return Err(anyhow::anyhow!("No app ID"));
|
||||
};
|
||||
|
||||
match method.as_str() {
|
||||
"PUT" => {
|
||||
// Update an app
|
||||
(
|
||||
StatusCode::NO_CONTENT,
|
||||
None,
|
||||
format!("Updated").into_bytes(),
|
||||
)
|
||||
}
|
||||
"DELETE" => {
|
||||
// Uninstall an app
|
||||
(
|
||||
StatusCode::NO_CONTENT,
|
||||
None,
|
||||
format!("Uninstalled").into_bytes(),
|
||||
)
|
||||
}
|
||||
_ => (
|
||||
StatusCode::METHOD_NOT_ALLOWED,
|
||||
None,
|
||||
format!("Invalid method {} for {}", method, path).into_bytes(),
|
||||
),
|
||||
}
|
||||
}
|
||||
"/apps/latest" => {
|
||||
match method.as_str() {
|
||||
"GET" => {
|
||||
// Return a list of latest apps
|
||||
(
|
||||
StatusCode::OK,
|
||||
None,
|
||||
serde_json::to_vec(&vec![
|
||||
PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: "Remote".to_string(),
|
||||
icon: "".to_string(),
|
||||
package_name: "remote".to_string(),
|
||||
description: Some("A test app".to_string()),
|
||||
website: Some("https://example.com".to_string()),
|
||||
rating: 3.0,
|
||||
versions: HashMap::new(),
|
||||
mirrors: vec![],
|
||||
},
|
||||
PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: "Happy Path".to_string(),
|
||||
icon: "".to_string(),
|
||||
package_name: "happy_path".to_string(),
|
||||
description: Some("A test app".to_string()),
|
||||
website: Some("https://example.com".to_string()),
|
||||
rating: 3.0,
|
||||
versions: HashMap::new(),
|
||||
mirrors: vec![],
|
||||
},
|
||||
])?,
|
||||
)
|
||||
}
|
||||
_ => (
|
||||
StatusCode::METHOD_NOT_ALLOWED,
|
||||
None,
|
||||
format!("Invalid method {} for {}", method, path).into_bytes(),
|
||||
),
|
||||
}
|
||||
}
|
||||
"/apps/search/:query" => {
|
||||
match method.as_str() {
|
||||
"GET" => {
|
||||
let Some(query) = path.split("/").last() else {
|
||||
return Err(anyhow::anyhow!("No query"));
|
||||
};
|
||||
// Return a list of apps matching the query
|
||||
// Query by name, publisher, package_name, description, website
|
||||
(
|
||||
StatusCode::OK,
|
||||
None,
|
||||
serde_json::to_vec(&vec![
|
||||
PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: "Winch".to_string(),
|
||||
icon: "".to_string(),
|
||||
package_name: "winch".to_string(),
|
||||
description: Some("A test app".to_string()),
|
||||
website: Some("https://example.com".to_string()),
|
||||
rating: 3.0,
|
||||
versions: HashMap::new(),
|
||||
mirrors: vec![],
|
||||
},
|
||||
PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: "Bucket".to_string(),
|
||||
icon: "".to_string(),
|
||||
package_name: "bucket".to_string(),
|
||||
description: Some("A test app".to_string()),
|
||||
website: Some("https://example.com".to_string()),
|
||||
rating: 3.0,
|
||||
versions: HashMap::new(),
|
||||
mirrors: vec![],
|
||||
},
|
||||
])?,
|
||||
)
|
||||
}
|
||||
_ => (
|
||||
StatusCode::METHOD_NOT_ALLOWED,
|
||||
None,
|
||||
format!("Invalid method {} for {}", method, path).into_bytes(),
|
||||
),
|
||||
}
|
||||
}
|
||||
"/apps/publish" => {
|
||||
match method.as_str() {
|
||||
"POST" => {
|
||||
// Publish an app
|
||||
(StatusCode::OK, None, format!("Success").into_bytes())
|
||||
}
|
||||
_ => (
|
||||
StatusCode::METHOD_NOT_ALLOWED,
|
||||
None,
|
||||
format!("Invalid method {} for {}", method, path).into_bytes(),
|
||||
),
|
||||
}
|
||||
}
|
||||
_ => (
|
||||
StatusCode::NOT_FOUND,
|
||||
None,
|
||||
format!("Path not found: {}", path).into_bytes(),
|
||||
),
|
||||
};
|
||||
|
||||
send_response(status_code, headers, body)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_message(our: &Address, mut state: &mut State, message: &Message) -> anyhow::Result<()> {
|
||||
match message {
|
||||
Message::Request {
|
||||
@ -631,13 +436,13 @@ fn handle_new_package(
|
||||
let metadata = String::from_utf8(blob.bytes)?;
|
||||
let metadata = serde_json::from_str::<kt::PackageMetadata>(&metadata)?;
|
||||
|
||||
let versions = HashMap::new();
|
||||
let mut versions = HashMap::new();
|
||||
versions.insert(metadata.version, version_hash);
|
||||
|
||||
let listing_data = PackageListing {
|
||||
owner: our.node.clone(),
|
||||
publisher: our.node.clone(),
|
||||
name: metadata.package,
|
||||
name: metadata.package.clone(),
|
||||
icon: "".to_string(),
|
||||
package_name: metadata.package,
|
||||
description: metadata.description,
|
||||
|
Loading…
Reference in New Issue
Block a user