From b7cc5e79b3c599eea05c870c2baabf5c06f4ff87 Mon Sep 17 00:00:00 2001 From: alemi <me@alemi.dev> Date: Tue, 21 Jan 2025 02:39:43 +0100 Subject: [PATCH] feat: use cargo-leptos for all-in-one ssr binary.. ... that doesn't work?!? spent hours getting this to compile, it munched 20GB like it was nothing, took its damn time just to then crash while running because "cannot access imported statics on non-wasm targets" ?!?!!?? no clue, also not super sold on this SSR thing because it adds so much complexity, will probably leave this branch up here for future reference in case i want to try this again, and go back to trunk + include! static assets and full CSR for leptos --- .tci | 2 +- Cargo.lock | 72 +++++------------------------------ Cargo.toml | 12 ++++-- build.rs | 12 ------ core/Cargo.toml | 6 +++ core/src/context.rs | 27 +++++++++++++ routes/Cargo.toml | 16 +++----- routes/src/activitypub/mod.rs | 72 +++++++++++++++++------------------ routes/src/auth.rs | 1 + routes/src/lib.rs | 7 ++-- routes/src/web.rs | 27 ------------- routes/src/web/mod.rs | 11 ++++++ utils/httpsign/Cargo.toml | 2 +- web/Cargo.toml | 11 +++++- web/src/lib.rs | 2 + 15 files changed, 122 insertions(+), 158 deletions(-) delete mode 100644 build.rs delete mode 100644 routes/src/web.rs create mode 100644 routes/src/web/mod.rs diff --git a/.tci b/.tci index 5cc5043..ed53713 100755 --- a/.tci +++ b/.tci @@ -12,7 +12,7 @@ echo "restarting service" systemctl --user start upub echo "rebuilding frontend" cd web -CARGO_BUILD_JOBS=4 /opt/bin/trunk build --release --public-url 'https://dev.upub.social/web' +CARGO_BUILD_JOBS=4 /opt/bin/trunk build --profile=wasm-release --public-url 'https://dev.upub.social/web' echo "deploying frontend" rm /srv/http/upub/dev/web/* mv ./dist/* /srv/http/upub/dev/web/ diff --git a/Cargo.lock b/Cargo.lock index c8b4da0..c736f71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -270,44 +270,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", - "axum-core 0.4.5", + "axum-core", "bytes", "futures-util", "http 1.2.0", "http-body", "http-body-util", - "itoa", - "matchit 0.7.3", - "memchr", - "mime", - "multer", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8" -dependencies = [ - "axum-core 0.5.0", - "bytes", - "form_urlencoded", - "futures-util", - "http 1.2.0", - "http-body", - "http-body-util", "hyper", "hyper-util", "itoa", - "matchit 0.8.4", + "matchit", "memchr", "mime", "multer", @@ -344,25 +316,6 @@ dependencies = [ "sync_wrapper", "tower-layer", "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733" -dependencies = [ - "bytes", - "futures-util", - "http 1.2.0", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", "tracing", ] @@ -1710,7 +1663,7 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" name = "httpsign" version = "0.1.0" dependencies = [ - "axum 0.8.1", + "axum", "base64", "openssl", "thiserror 2.0.11", @@ -2137,7 +2090,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b613d5784037baee42a11d21bc263adfc1a55e416556a3d5bfe39c7b87fadf" dependencies = [ "any_spawner", - "axum 0.7.9", + "axum", "dashmap", "futures", "hydration_context", @@ -2452,12 +2405,6 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" -[[package]] -name = "matchit" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" - [[package]] name = "md-5" version = "0.10.6" @@ -3881,7 +3828,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5dd7fcccd3ef2081da086c1f8595b506627abbbbc9f64be0141d2251219570e" dependencies = [ - "axum 0.7.9", + "axum", "bytes", "const_format", "dashmap", @@ -5124,11 +5071,13 @@ dependencies = [ "apb", "async-recursion", "async-trait", + "axum", "base64", "chrono", "hmac", "httpsign", "jrd", + "leptos_config", "mdhtml", "nodeinfo", "openssl", @@ -5197,14 +5146,12 @@ name = "upub-routes" version = "0.3.0" dependencies = [ "apb", - "axum 0.8.1", + "axum", "chrono", "httpsign", "jrd", - "leptos", "leptos_axum", - "leptos_meta", - "leptos_router", + "leptos_config", "mastodon-async-entities", "nodeinfo", "rand", @@ -5219,6 +5166,7 @@ dependencies = [ "tower-http", "tracing", "upub", + "upub-web", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e1a094b..6805f36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ repository = "https://git.alemi.dev/upub.git" readme = "README.md" [[bin]] -name = "upub" +name = "upub-bin" path = "main.rs" [dependencies] @@ -50,8 +50,14 @@ serve = ["dep:upub-routes"] migrate = ["dep:upub-migrations"] cli = ["dep:upub-cli"] worker = ["dep:upub-worker"] -web = [] -web-build-fe = [] +web = ["upub/web", "upub-routes?/web"] + +[[workspace.metadata.leptos]] +name = "upub" +bin-package = "upub-bin" +bin-features = ["serve", "migrate", "cli", "worker", "web"] +lib-package = "upub-web" +lib-features = ["leptos-hydrate"] [profile.wasm-release] inherits = "release" diff --git a/build.rs b/build.rs deleted file mode 100644 index 3511eff..0000000 --- a/build.rs +++ /dev/null @@ -1,12 +0,0 @@ -fn main() { - #[cfg(all(feature = "web", feature = "web-build-fe"))] - { - println!("cargo:warning=running sub-process to build frontend"); - let status = std::process::Command::new("cargo") - .current_dir("web") - .args(["build", "--profile=wasm-release", "--target=wasm32-unknown-unknown"]) - .status() - .unwrap(); - assert!(status.success(), "failed building wasm bundle"); - } -} diff --git a/core/Cargo.toml b/core/Cargo.toml index d1a5547..a935bae 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -36,3 +36,9 @@ reqwest = { version = "0.12", features = ["json"] } apb = { path = "../apb", features = ["unstructured", "orm", "did-core", "activitypub-miscellaneous-terms", "activitypub-fe", "activitypub-counters", "litepub", "ostatus", "toot"] } # nodeinfo = "0.0.2" # the version on crates.io doesn't re-export necessary types to build the struct!!! nodeinfo = { git = "https://codeberg.org/thefederationinfo/nodeinfo-rs", rev = "e865094804" } +leptos_config = { version = "0.7", optional = true } +axum = { version = "0.7", optional = true } + +[features] +default = [] +web = ["dep:leptos_config", "dep:axum"] diff --git a/core/src/context.rs b/core/src/context.rs index e066bcc..cd84d62 100644 --- a/core/src/context.rs +++ b/core/src/context.rs @@ -193,3 +193,30 @@ pub enum Internal { Activity(i64), Actor(i64), } + +#[cfg(feature = "web")] +mod leptos_state { + impl axum::extract::FromRef<super::Context> for leptos_config::LeptosOptions { + fn from_ref(_ctx: &super::Context) -> leptos_config::LeptosOptions { + static CONF: std::sync::OnceLock<leptos_config::LeptosOptions> = std::sync::OnceLock::new(); + CONF.get_or_init(|| + leptos_config::LeptosOptions { + env: { + #[cfg(debug_assertions)]{ leptos_config::Env::DEV } + #[cfg(not(debug_assertions))] { leptos_config::Env::PROD } + }, + output_name: "upub_web".into(), + site_root: "web/dist".into(), + site_pkg_dir: "pkg".into(), + site_addr: "127.0.0.1:3000/web".parse().expect("could not create socket addr"), // TODO we don't want to serve? what is this for?? + reload_port: 3001, + reload_external_port: None, + reload_ws_protocol: leptos_config::ReloadWSProtocol::WS, + not_found_path: "web/404.html".into(), + hash_file: "hash.txt".into(), + hash_files: true, + } + ).clone() + } + } +} diff --git a/routes/Cargo.toml b/routes/Cargo.toml index f2bd787..ccbefda 100644 --- a/routes/Cargo.toml +++ b/routes/Cargo.toml @@ -22,7 +22,7 @@ jrd = "0.1" tracing = "0.1" tokio = "1.43" reqwest = { version = "0.12", features = ["json"] } -axum = { version = "0.8", features = ["multipart"] } +axum = { version = "0.7", features = ["multipart"] } tower-http = { version = "0.6", features = ["cors", "trace"] } httpsign = { path = "../utils/httpsign/", features = ["axum"] } apb = { path = "../apb", features = ["unstructured", "orm", "activitypub-fe", "activitypub-counters", "litepub", "ostatus", "toot", "jsonld"] } @@ -33,18 +33,12 @@ nodeinfo = { git = "https://codeberg.org/thefederationinfo/nodeinfo-rs", rev = " mastodon-async-entities = { version = "1.1.0", optional = true } time = { version = "0.3", features = ["serde"], optional = true } # frontend -leptos = { version = "0.7", optional = true } -leptos_router = { version = "0.7", optional = true } leptos_axum = { version = "0.7", optional = true } -leptos_meta = { version = "0.7", optional = true } +leptos_config = { version = "0.7", optional = true } +upub-web = { path = "../web", default-features = false, optional = true } [features] -default = ["activitypub", "web"] +default = ["activitypub"] activitypub = [] mastodon = ["dep:mastodon-async-entities"] -web = [ - "dep:leptos", - "dep:leptos_router", - "dep:leptos_axum", - "dep:leptos_meta" -] +web = ["dep:leptos_axum", "dep:leptos_config", "dep:upub-web", "upub-web?/leptos-ssr", "upub/web"] diff --git a/routes/src/activitypub/mod.rs b/routes/src/activitypub/mod.rs index 523d855..4ff0414 100644 --- a/routes/src/activitypub/mod.rs +++ b/routes/src/activitypub/mod.rs @@ -22,7 +22,7 @@ impl super::ActivityPubRouter for Router<upub::Context> { // fetch route, to debug and retreive remote objects .route("/search", get(ap::application::search)) .route("/fetch", get(ap::application::ap_fetch)) - .route("/proxy/{hmac}/{uri}", get(ap::application::cloak_proxy)) + .route("/proxy/:hmac/:uri", get(ap::application::cloak_proxy)) .route("/inbox", post(ap::inbox::post)) .route("/inbox", get(ap::inbox::get)) .route("/inbox/page", get(ap::inbox::page)) @@ -39,49 +39,49 @@ impl super::ActivityPubRouter for Router<upub::Context> { .route("/.well-known/host-meta", get(ap::well_known::host_meta)) .route("/.well-known/nodeinfo", get(ap::well_known::nodeinfo_discovery)) .route("/.well-known/oauth-authorization-server", get(ap::well_known::oauth_authorization_server)) - .route("/nodeinfo/{version}", get(ap::well_known::nodeinfo)) + .route("/nodeinfo/:version", get(ap::well_known::nodeinfo)) // actor routes - .route("/actors/{id}", get(ap::actor::view)) - .route("/actors/{id}/inbox", post(ap::actor::inbox::post)) - .route("/actors/{id}/inbox", get(ap::actor::inbox::get)) - .route("/actors/{id}/inbox/page", get(ap::actor::inbox::page)) - .route("/actors/{id}/outbox", post(ap::actor::outbox::post)) - .route("/actors/{id}/outbox", get(ap::actor::outbox::get)) - .route("/actors/{id}/outbox/page", get(ap::actor::outbox::page)) - .route("/actors/{id}/notifications", get(ap::actor::notifications::get)) - .route("/actors/{id}/notifications/page", get(ap::actor::notifications::page)) - .route("/actors/{id}/followers", get(ap::actor::following::get::<false>)) - .route("/actors/{id}/followers/page", get(ap::actor::following::page::<false>)) - .route("/actors/{id}/following", get(ap::actor::following::get::<true>)) - .route("/actors/{id}/following/page", get(ap::actor::following::page::<true>)) - .route("/actors/{id}/likes", get(ap::actor::likes::get)) - .route("/actors/{id}/likes/page", get(ap::actor::likes::page)) + .route("/actors/:id", get(ap::actor::view)) + .route("/actors/:id/inbox", post(ap::actor::inbox::post)) + .route("/actors/:id/inbox", get(ap::actor::inbox::get)) + .route("/actors/:id/inbox/page", get(ap::actor::inbox::page)) + .route("/actors/:id/outbox", post(ap::actor::outbox::post)) + .route("/actors/:id/outbox", get(ap::actor::outbox::get)) + .route("/actors/:id/outbox/page", get(ap::actor::outbox::page)) + .route("/actors/:id/notifications", get(ap::actor::notifications::get)) + .route("/actors/:id/notifications/page", get(ap::actor::notifications::page)) + .route("/actors/:id/followers", get(ap::actor::following::get::<false>)) + .route("/actors/:id/followers/page", get(ap::actor::following::page::<false>)) + .route("/actors/:id/following", get(ap::actor::following::get::<true>)) + .route("/actors/:id/following/page", get(ap::actor::following::page::<true>)) + .route("/actors/:id/likes", get(ap::actor::likes::get)) + .route("/actors/:id/likes/page", get(ap::actor::likes::page)) .route("/groups", get(ap::groups::get)) .route("/groups/page", get(ap::groups::page)) - // .route("/actors/{id}/audience", get(ap::actor::audience::get)) - // .route("/actors/{id}/audience/page", get(ap::actor::audience::page)) + // .route("/actors/:id/audience", get(ap::actor::audience::get)) + // .route("/actors/:id/audience/page", get(ap::actor::audience::page)) // activities - .route("/activities/{id}", get(ap::activity::view)) + .route("/activities/:id", get(ap::activity::view)) // hashtags - .route("/tags/{id}", get(ap::tags::get)) - .route("/tags/{id}/page", get(ap::tags::page)) + .route("/tags/:id", get(ap::tags::get)) + .route("/tags/:id/page", get(ap::tags::page)) // specific object routes - .route("/objects/{id}", get(ap::object::view)) - .route("/objects/{id}/replies", get(ap::object::replies::get)) - .route("/objects/{id}/replies/page", get(ap::object::replies::page)) - .route("/objects/{id}/context", get(ap::object::context::get)) - .route("/objects/{id}/context/page", get(ap::object::context::page)) - .route("/objects/{id}/likes", get(ap::object::likes::get)) - .route("/objects/{id}/likes/page", get(ap::object::likes::page)) - .route("/objects/{id}/shares", get(ap::object::shares::get)) - .route("/objects/{id}/shares/page", get(ap::object::shares::page)) + .route("/objects/:id", get(ap::object::view)) + .route("/objects/:id/replies", get(ap::object::replies::get)) + .route("/objects/:id/replies/page", get(ap::object::replies::page)) + .route("/objects/:id/context", get(ap::object::context::get)) + .route("/objects/:id/context/page", get(ap::object::context::page)) + .route("/objects/:id/likes", get(ap::object::likes::get)) + .route("/objects/:id/likes/page", get(ap::object::likes::page)) + .route("/objects/:id/shares", get(ap::object::shares::get)) + .route("/objects/:id/shares/page", get(ap::object::shares::page)) // file routes .route("/file", post(ap::file::upload)) - .route("/file/{id}", get(ap::file::download)) - //.route("/objects/{id}/likes", get(ap::object::likes::get)) - //.route("/objects/{id}/likes/page", get(ap::object::likes::page)) - //.route("/objects/{id}/shares", get(ap::object::announces::get)) - //.route("/objects/{id}/shares/page", get(ap::object::announces::page)) + .route("/file/:id", get(ap::file::download)) + //.route("/objects/:id/likes", get(ap::object::likes::get)) + //.route("/objects/:id/likes/page", get(ap::object::likes::page)) + //.route("/objects/:id/shares", get(ap::object::announces::get)) + //.route("/objects/:id/shares/page", get(ap::object::announces::page)) } } diff --git a/routes/src/auth.rs b/routes/src/auth.rs index 67bef69..e0e8a93 100644 --- a/routes/src/auth.rs +++ b/routes/src/auth.rs @@ -82,6 +82,7 @@ impl Identity { pub struct AuthIdentity(pub Identity); +#[axum::async_trait] impl<S> FromRequestParts<S> for AuthIdentity where upub::Context: FromRef<S>, diff --git a/routes/src/lib.rs b/routes/src/lib.rs index da97e3a..ec5fad8 100644 --- a/routes/src/lib.rs +++ b/routes/src/lib.rs @@ -32,7 +32,7 @@ pub mod mastodon { impl super::MastodonRouter for axum::Router<upub::Context> {} pub trait WebRouter { - fn web_routes(self) -> Self where Self: Sized { self } + fn web_routes(self, _ctx: &upub::Context) -> Self where Self: Sized { self } } #[cfg(feature = "web")] @@ -43,7 +43,6 @@ pub mod web { impl super::WebRouter for axum::Router<upub::Context> {} } - pub async fn serve(ctx: upub::Context, bind: String, shutdown: impl ShutdownToken) -> Result<(), std::io::Error> { use tower_http::{cors::CorsLayer, trace::TraceLayer}; @@ -62,8 +61,8 @@ pub async fn serve(ctx: upub::Context, bind: String, shutdown: impl ShutdownToke }) ) .ap_routes() - .mastodon_routes() // no-op if mastodon feature is disabled - .web_routes() // no-op if web feature is disabled + .mastodon_routes() + .web_routes(&ctx) .layer(CorsLayer::permissive()) .with_state(ctx); diff --git a/routes/src/web.rs b/routes/src/web.rs deleted file mode 100644 index a7fff3d..0000000 --- a/routes/src/web.rs +++ /dev/null @@ -1,27 +0,0 @@ -use axum::{response::IntoResponse, routing::get, Router}; - - -impl super::WebRouter for Router<upub::Context> { - fn web_routes(self) -> Self { - self - .route("/web/assets/upub-web.wasm", get(upub_web_wasm)) - .route("/web/assets/style.css", get(upub_style_css)) - .route("/web", get(upub_web_index)) - .route("/web/", get(upub_web_index)) - .route("/web/{*any}", get(upub_web_index)) - } -} - - - -async fn upub_web_wasm() -> impl IntoResponse { - include_bytes!("../../target/wasm32-unknown-unknown/wasm-release/upub-web.wasm") -} - -async fn upub_style_css() -> impl IntoResponse { - include_str!("../../web/assets/style.css") -} - -async fn upub_web_index() -> impl IntoResponse { - include_str!("../../web/index.html") -} diff --git a/routes/src/web/mod.rs b/routes/src/web/mod.rs new file mode 100644 index 0000000..97753b4 --- /dev/null +++ b/routes/src/web/mod.rs @@ -0,0 +1,11 @@ +use leptos_axum::LeptosRoutes; + +impl super::WebRouter for axum::Router<upub::Context> { + fn web_routes(self, ctx: &upub::Context) -> Self where Self: Sized { + self.leptos_routes( + ctx, + leptos_axum::generate_route_list(upub_web::App), + move || "" + ) + } +} diff --git a/utils/httpsign/Cargo.toml b/utils/httpsign/Cargo.toml index 4ed58ae..205b9b3 100644 --- a/utils/httpsign/Cargo.toml +++ b/utils/httpsign/Cargo.toml @@ -19,7 +19,7 @@ thiserror = "2.0" tracing = "0.1" base64 = "0.22" openssl = "0.10" # TODO handle pubkeys with a smaller crate -axum = { version = "0.8", optional = true } +axum = { version = "0.7", optional = true } [features] default = [] diff --git a/web/Cargo.toml b/web/Cargo.toml index d75ede5..d35393c 100644 --- a/web/Cargo.toml +++ b/web/Cargo.toml @@ -9,6 +9,9 @@ keywords = ["activitypub", "upub", "json", "web", "wasm"] repository = "https://git.alemi.dev/upub.git" #readme = "README.md" +[lib] +crate-type = ["rlib", "cdylib"] + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] @@ -24,7 +27,7 @@ serde_json = "1.0" serde_default = "0.2" serde-inline-default = "0.2" dashmap = "6.1" -leptos = { version = "0.7", features = ["csr", "tracing"] } +leptos = { version = "0.7", features = ["tracing"] } leptos_router = { version = "0.7", features = ["tracing"] } leptos-use = "0.15" codee = { version = "0.2", features = ["json_serde"] } # WHYYY LEPTOS-USE AKSJFOASHGOAEG @@ -38,3 +41,9 @@ jrd = "0.1" tld = "2.36" web-sys = { version = "0.3", features = ["Screen"] } regex = "1.11" + +[features] +default = ["leptos-csr"] +leptos-ssr = ["leptos/ssr"] +leptos-csr = ["leptos/csr"] +leptos-hydrate = ["leptos/hydrate"] diff --git a/web/src/lib.rs b/web/src/lib.rs index 3ec9508..a35be0b 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -1,3 +1,5 @@ +#![recursion_limit = "256"] // oh nooo leptos... + mod auth; mod app; mod components;