feat: added Leptos server

This commit is contained in:
Andrew Rioux 2025-01-20 22:22:48 -05:00
parent b2cec71667
commit 5ee8802607
Signed by: andrew.rioux
GPG Key ID: 9B8BAC47C17ABB94
16 changed files with 2632 additions and 26 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/target /target
.direnv .direnv
/result /result
.sass-cache

2222
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
[workspace] [workspace]
members = ["sparse-beacon", "nl-sys", "packets", "pcap-sys"] members = ["sparse-*", "*-sys", "packets"]
resolver = "2" resolver = "2"
package.version = "2.0.0" package.version = "2.0.0"
metadata.crane.name = "sparse" metadata.crane.name = "sparse"
@ -10,3 +10,10 @@ opt-level = "z"
lto = true lto = true
codegen-units = 1 codegen-units = 1
panic = "abort" panic = "abort"
[profile.wasm-release]
inherits = "release"
opt-level = 'z'
lto = true
codegen-units = 1
panic = "abort"

View File

@ -58,25 +58,39 @@
libpcap-linux-musl libpcap-freebsd; libpcap-linux-musl libpcap-freebsd;
buildTools = with pkgs; [ buildTools = with pkgs; [
# Tools for local compilation
lld lld
zig zig
clang clang
glibc glibc
# Tools for cross compilation
pkgsCross.x86_64-freebsd.buildPackages.clang pkgsCross.x86_64-freebsd.buildPackages.clang
pkgsCross.mingwW64.stdenv.cc pkgsCross.mingwW64.stdenv.cc
pkgsCross.mingwW64.windows.pthreads pkgsCross.mingwW64.windows.pthreads
# Tools for building the web UI
cargo-leptos
wasm-bindgen-cli
dart-sass
binaryen
]; ];
devShellTools = with pkgs; [ rust-analyzer taplo cargo-deny ]; devShellTools = with pkgs; [
rust-analyzer
taplo
cargo-deny
cargo-generate
];
craneLib = (crane.mkLib pkgs).overrideToolchain (p: craneLib = (crane.mkLib pkgs).overrideToolchain (p:
p.rust-bin.stable.latest.default.override { p.rust-bin.nightly.latest.default.override {
targets = [ targets = [
"x86_64-unknown-linux-gnu" "x86_64-unknown-linux-gnu"
"x86_64-unknown-linux-musl" "x86_64-unknown-linux-musl"
"x86_64-pc-windows-gnu" "x86_64-pc-windows-gnu"
"x86_64-unknown-freebsd" "x86_64-unknown-freebsd"
"wasm32-unknown-unknown"
]; ];
}); });

View File

@ -29,7 +29,42 @@ let
buildInputs = buildTools; buildInputs = buildTools;
}; };
fileSetForBeaconCrate = pkgs.lib.fileset.toSource {
root = ./.;
fileset = pkgs.lib.fileset.unions [
./.cargo/config.toml
./Cargo.toml
./Cargo.lock
./build_common.rs
(craneLib.fileset.commonCargoSources ./sparse-actions)
(craneLib.fileset.commonCargoSources ./pcap-sys)
(craneLib.fileset.commonCargoSources ./nl-sys)
./nl-sys/src/bridge.c
(craneLib.fileset.commonCargoSources ./packets)
(craneLib.fileset.commonCargoSources ./sparse-beacon)
];
};
fileSetForWebCrate = pkgs.lib.fileset.toSource {
root = ./.;
fileset = pkgs.lib.fileset.unions [
./.cargo/config.toml
./Cargo.toml
./Cargo.lock
./build_common.rs
(craneLib.fileset.commonCargoSources ./pcap-sys)
(craneLib.fileset.commonCargoSources ./nl-sys)
./nl-sys/src/bridge.c
(craneLib.fileset.commonCargoSources ./packets)
(craneLib.fileset.commonCargoSources ./sparse-actions)
(craneLib.fileset.commonCargoSources ./sparse-server)
./sparse-server/style
./sparse-server/public
];
};
freebsdArgs = commonArgs // { freebsdArgs = commonArgs // {
src = fileSetForBeaconCrate;
# Sigh... # Sigh...
# For some reason, crane and cargo don't run the build script for FreeBSD # For some reason, crane and cargo don't run the build script for FreeBSD
# It runs it with the dev shell for all 3 targets, and runs it in the # It runs it with the dev shell for all 3 targets, and runs it in the
@ -40,7 +75,10 @@ let
doCheck = false; doCheck = false;
}; };
windowsArgs = commonArgs // { doCheck = false; }; windowsArgs = commonArgs // {
src = fileSetForBeaconCrate;
doCheck = false;
};
linuxCargoArtifacts = craneLib.buildDepsOnly (commonArgs // { linuxCargoArtifacts = craneLib.buildDepsOnly (commonArgs // {
name = "sparse-deps-linux"; name = "sparse-deps-linux";
@ -48,40 +86,25 @@ let
}); });
freebsdCargoArtifacts = craneLib.buildDepsOnly (freebsdArgs // { freebsdCargoArtifacts = craneLib.buildDepsOnly (freebsdArgs // {
name = "sparse-deps-freebsd"; name = "sparse-deps-freebsd";
cargoExtraArgs = "--target=x86_64-unknown-freebsd --locked"; cargoExtraArgs =
"--target=x86_64-unknown-freebsd --locked -p sparse-beacon";
}); });
windowsCargoArtifacts = craneLib.buildDepsOnly (windowsArgs // { windowsCargoArtifacts = craneLib.buildDepsOnly (windowsArgs // {
name = "sparse-deps-windows"; name = "sparse-deps-windows";
cargoExtraArgs = "--target=x86_64-pc-windows-gnu --locked"; cargoExtraArgs = "--target=x86_64-pc-windows-gnu --locked -p sparse-beacon";
}); });
fileSetForCrate = crate:
pkgs.lib.fileset.toSource {
root = ./.;
fileset = pkgs.lib.fileset.unions [
./.cargo/config.toml
./Cargo.toml
./Cargo.lock
./build_common.rs
(craneLib.fileset.commonCargoSources ./pcap-sys)
(craneLib.fileset.commonCargoSources ./nl-sys)
(craneLib.fileset.commonCargoSources ./packets)
(craneLib.fileset.commonCargoSources crate)
];
};
sparse-beacon-linux = craneLib.buildPackage (commonArgs // { sparse-beacon-linux = craneLib.buildPackage (commonArgs // {
cargoArtifacts = linuxCargoArtifacts; cargoArtifacts = linuxCargoArtifacts;
name = "sparse-beacon-linux"; name = "sparse-beacon-linux";
cargoExtraArgs = "-p sparse-beacon"; cargoExtraArgs = "-p sparse-beacon";
src = fileSetForCrate ./sparse-beacon; src = fileSetForBeaconCrate;
CARGO_BUILD_TARGET = "x86_64-unknown-linux-musl"; CARGO_BUILD_TARGET = "x86_64-unknown-linux-musl";
CARGO_BUILD_RUSTFLAGS = "-Ctarget-feature=+crt-static"; CARGO_BUILD_RUSTFLAGS = "-Ctarget-feature=+crt-static";
}); });
sparse-beacon-freebsd-sysv = craneLib.buildPackage (freebsdArgs // { sparse-beacon-freebsd-sysv = craneLib.buildPackage (freebsdArgs // {
inherit src;
cargoArtifacts = freebsdCargoArtifacts; cargoArtifacts = freebsdCargoArtifacts;
name = "sparse-beacon-freebsd"; name = "sparse-beacon-freebsd";
cargoExtraArgs = "-p sparse-beacon"; cargoExtraArgs = "-p sparse-beacon";
@ -99,16 +122,38 @@ let
cargoArtifacts = windowsCargoArtifacts; cargoArtifacts = windowsCargoArtifacts;
name = "sparse-beacon-windows"; name = "sparse-beacon-windows";
cargoExtraArgs = "-p sparse-beacon"; cargoExtraArgs = "-p sparse-beacon";
src = fileSetForCrate ./sparse-beacon;
CARGO_BUILD_TARGET = "x86_64-pc-windows-gnu"; CARGO_BUILD_TARGET = "x86_64-pc-windows-gnu";
CARGO_BUILD_RUSTFLAGS = "-Ctarget-feature=+crt-static"; CARGO_BUILD_RUSTFLAGS = "-Ctarget-feature=+crt-static";
}); });
sparse-server = craneLib.buildPackage (commonArgs // {
src = fileSetForWebCrate;
cargoArtifacts = linuxCargoArtifacts;
name = "sparse-server-webclient";
buildPhaseCargoCommand = ''
cargo leptos build \
--release \
--project=sparse-server
'';
doNotPostBuildInstallCargoBinaries = true;
installPhase = ''
mkdir -p $out/bin
cp target/x86_64-unknown-linux-musl/release/sparse-server $out/bin
'';
SPARSE_BEACON_LINUX = "${sparse-beacon-linux}/bin/sparse-beacon";
SPARSE_BEACON_WINDOWS = "${sparse-beacon-windows}/bin/sparse-beacon.exe";
SPARSE_BEACON_FREEBSD = "${sparse-beacon-freebsd}/bin/sparse-beacon";
});
outputs = rec { outputs = rec {
packages = { packages = {
inherit sparse-beacon-linux sparse-beacon-windows inherit sparse-beacon-linux sparse-beacon-windows sparse-beacon-freebsd
sparse-beacon-freebsd-sysv sparse-beacon-freebsd; sparse-server;
}; };
checks = outputs.packages // { checks = outputs.packages // {
rs-fmt = craneLib.cargoFmt { inherit src; }; rs-fmt = craneLib.cargoFmt { inherit src; };

View File

@ -0,0 +1,6 @@
[package]
name = "sparse-actions"
edition = "2021"
version.workspace = true
[dependencies]

14
sparse-actions/src/lib.rs Normal file
View File

@ -0,0 +1,14 @@
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}

14
sparse-server/.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

58
sparse-server/Cargo.toml Normal file
View File

@ -0,0 +1,58 @@
[package]
name = "sparse-server"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
leptos = { version = "0.7.0", features = ["nightly"] }
leptos_router = { version = "0.7.0", features = ["nightly"] }
axum = { version = "0.7", optional = true }
console_error_panic_hook = "0.1"
leptos_axum = { version = "0.7.0", optional = true }
leptos_meta = { version = "0.7.0" }
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
wasm-bindgen = "=0.2.95"
thiserror = "1"
http = "1"
[features]
hydrate = ["leptos/hydrate"]
ssr = [
"dep:axum",
"dep:tokio",
"dep:tower",
"dep:tower-http",
"dep:leptos_axum",
"leptos/ssr",
"leptos_meta/ssr",
"leptos_router/ssr",
]
[package.metadata.leptos]
output-name = "sparse-server"
site-root = "target/site"
site-pkg-dir = "pkg"
style-file = "style/main.scss"
assets-dir = "public"
site-addr = "127.0.0.1:3000"
reload-port = 3001
browserquery = "defaults"
# The environment Leptos will run in, usually either "DEV" or "PROD"
env = "DEV"
bin-features = ["ssr"]
bin-default-features = false
bin-target-triple = "x86_64-unknown-linux-musl"
lib-features = ["hydrate"]
lib-default-features = false
lib-profile-release = "wasm-release"

24
sparse-server/LICENSE Normal file
View File

@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org>

91
sparse-server/README.md Normal file
View File

@ -0,0 +1,91 @@
<picture>
<source srcset="https://raw.githubusercontent.com/leptos-rs/leptos/main/docs/logos/Leptos_logo_Solid_White.svg" media="(prefers-color-scheme: dark)">
<img src="https://raw.githubusercontent.com/leptos-rs/leptos/main/docs/logos/Leptos_logo_RGB.svg" alt="Leptos Logo">
</picture>
# Leptos Axum Starter Template
This is a template for use with the [Leptos](https://github.com/leptos-rs/leptos) web framework and the [cargo-leptos](https://github.com/akesson/cargo-leptos) tool using [Axum](https://github.com/tokio-rs/axum).
## Creating your template repo
If you don't have `cargo-leptos` installed you can install it with
```bash
cargo install cargo-leptos --locked
```
Then run
```bash
cargo leptos new --git https://github.com/leptos-rs/start-axum-0.7
```
to generate a new project template.
```bash
cd sparse-server
```
to go to your newly created project.
Feel free to explore the project structure, but the best place to start with your application code is in `src/app.rs`.
Addtionally, Cargo.toml may need updating as new versions of the dependencies are released, especially if things are not working after a `cargo update`.
## Running your project
```bash
cargo leptos watch
```
## Installing Additional Tools
By default, `cargo-leptos` uses `nightly` Rust, `cargo-generate`, and `sass`. If you run into any trouble, you may need to install one or more of these tools.
1. `rustup toolchain install nightly --allow-downgrade` - make sure you have Rust nightly
2. `rustup target add wasm32-unknown-unknown` - add the ability to compile Rust to WebAssembly
3. `cargo install cargo-generate` - install `cargo-generate` binary (should be installed automatically in future)
4. `npm install -g sass` - install `dart-sass` (should be optional in future
5. Run `npm install` in end2end subdirectory before test
## Compiling for Release
```bash
cargo leptos build --release
```
Will generate your server binary in target/server/release and your site package in target/site
## Testing Your Project
```bash
cargo leptos end-to-end
```
```bash
cargo leptos end-to-end --release
```
Cargo-leptos uses Playwright as the end-to-end test tool.
Tests are located in end2end/tests directory.
## Executing a Server on a Remote Machine Without the Toolchain
After running a `cargo leptos build --release` the minimum files needed are:
1. The server binary located in `target/server/release`
2. The `site` directory and all files within located in `target/site`
Copy these files to your remote server. The directory structure should be:
```text
sparse-server
site/
```
Set the following environment variables (updating for your project as needed):
```sh
export LEPTOS_OUTPUT_NAME="sparse-server"
export LEPTOS_SITE_ROOT="site"
export LEPTOS_SITE_PKG_DIR="pkg"
export LEPTOS_SITE_ADDR="127.0.0.1:3000"
export LEPTOS_RELOAD_PORT="3001"
```
Finally, run the server binary.
## Licensing
This template itself is released under the Unlicense. You should replace the LICENSE for your own application with an appropriate license if you plan to release it publicly.

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

58
sparse-server/src/app.rs Normal file
View File

@ -0,0 +1,58 @@
use leptos::prelude::*;
use leptos_meta::{provide_meta_context, MetaTags, Stylesheet, Title};
use leptos_router::{
components::{Route, Router, Routes},
StaticSegment,
};
pub fn shell(options: LeptosOptions) -> impl IntoView {
view! {
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<AutoReload options=options.clone() />
<HydrationScripts options/>
<MetaTags/>
</head>
<body>
<App/>
</body>
</html>
}
}
#[component]
pub fn App() -> impl IntoView {
provide_meta_context();
view! {
<Stylesheet id="leptos" href="/pkg/sparse-server.css"/>
// sets the document title
<Title text="Welcome to Leptos"/>
// content for this welcome page
<Router>
<main>
<Routes fallback=|| "Page not found.".into_view()>
<Route path=StaticSegment("") view=HomePage/>
</Routes>
</main>
</Router>
}
}
/// Renders the home page of your application.
#[component]
fn HomePage() -> impl IntoView {
// Creates a reactive value to update the button
let count = RwSignal::new(0);
let on_click = move |_| *count.write() += 1;
view! {
<h1>"Welcome to Leptos!"</h1>
<button on:click=on_click>"Click Me: " {count}</button>
}
}

9
sparse-server/src/lib.rs Normal file
View File

@ -0,0 +1,9 @@
pub mod app;
#[cfg(feature = "hydrate")]
#[wasm_bindgen::prelude::wasm_bindgen]
pub fn hydrate() {
use crate::app::*;
console_error_panic_hook::set_once();
leptos::mount::hydrate_body(App);
}

39
sparse-server/src/main.rs Normal file
View File

@ -0,0 +1,39 @@
#[cfg(feature = "ssr")]
#[tokio::main]
async fn main() {
use axum::Router;
use leptos::logging::log;
use leptos::prelude::*;
use leptos_axum::{generate_route_list, LeptosRoutes};
use sparse_server::app::*;
let conf = get_configuration(None).unwrap();
let addr = conf.leptos_options.site_addr;
let leptos_options = conf.leptos_options;
// Generate the list of routes in your Leptos App
let routes = generate_route_list(App);
let app = Router::new()
.leptos_routes(&leptos_options, routes, {
let leptos_options = leptos_options.clone();
move || shell(leptos_options.clone())
})
.fallback(leptos_axum::file_and_error_handler(shell))
.with_state(leptos_options);
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
log!("listening on http://{}", &addr);
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app.into_make_service())
.await
.unwrap();
}
#[cfg(not(feature = "ssr"))]
pub fn main() {
// no client-side main function
// unless we want this to work with e.g., Trunk for pure client-side testing
// see lib.rs for hydration function instead
}

View File

@ -0,0 +1,4 @@
body {
font-family: sans-serif;
text-align: center;
}