From 55c85ad7163a2a7f1b2d9329ded2fd1f3fe1aa99 Mon Sep 17 00:00:00 2001 From: Sebastian Moser Date: Thu, 14 May 2026 07:43:47 +0200 Subject: [PATCH] mize daemon service and some timetrack stuff as well --- flake.nix | 91 ++++++++++++++++++++++++++- md | 8 +-- packages/mize/src/platform/os/cli.rs | 8 ++- packages/mize/src/platform/os/main.rs | 8 +-- packages/ppc/Cargo.toml | 4 +- packages/ppc/auth/client.rs | 27 +++++++- packages/ppc/lib.rs | 5 ++ packages/ppc/platform/os/server.rs | 26 +++++++- packages/ppc/timetrack/mod.rs | 7 +++ 9 files changed, 167 insertions(+), 17 deletions(-) diff --git a/flake.nix b/flake.nix index 1134f48..ce5d31c 100644 --- a/flake.nix +++ b/flake.nix @@ -43,7 +43,7 @@ let }; -in { +in rec { ############################## PACKAGES ############################## packages = rec { @@ -109,6 +109,52 @@ in { libsoup_3 ]; }; + mize = osCrane.buildPackage { + src = fileSetForCrate ./packages/mize; + cargoExtraArgs = "-p mize"; + nativeBuildInputs = [ + pkgs.pkg-config + pkgs.gobject-introspection + pkgs.gobject-introspection.dev + ]; + + buildInputs = with pkgs; [ + git # needed to build spacetimedb as it needs to get it's git hash for setting it's version + at-spi2-atk + atkmm + cairo + gdk-pixbuf + glib + gtk3 + harfbuzz + librsvg + libsoup_3 + pango + webkitgtk_4_1 + openssl + wasm-bindgen-cli + lld_20 + xdotool + ]; + + LD_LIBRARY_PATH = with pkgs; pkgs.lib.makeLibraryPath [ + xdotool + webkitgtk_4_1 + pango + openssl + at-spi2-atk + atkmm + cairo + gdk-pixbuf + glib + gtk3 + harfbuzz + librsvg + libsoup_3 + ]; + }; + + }; ############################## DEV SHELLS ############################## @@ -264,6 +310,49 @@ in { }; }; + + ############################## NIXOS MODULES ############################## + nixosModules.default = { system, lib, config, ... }: { + options.mize = { + debuginary = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "/home/user/here/mize"; + description = "If set to NOT null, the mize daemon service will use this path instead of $${self.packages.system.mize}/bin/mize''"; + }; + debugConfigFile = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "/home/user/here/mize.toml"; + description = "If set to NOT null, the mize daemon service will use the config file at this path instead of one written to the nix store"; + }; + config = lib.mkOption { + type = lib.types.attrsOf lib.types.anything; + default = {}; + example = { + dat_dir = "home/user/my_mize_data"; + spacetime.url = "spacetime.example.com"; + }; + description = "mize config for the daemon"; + }; + + }; + systemd.user.services.mize = { + description = "the mize daemon"; + wantedBy = [ "default.target" ]; + After = [ "graphical-session.target" ]; + PartOf = [ "graphical-session.target" ]; # this should mean DISPLAY and WAYLAND_DISPLAY are set in the service env... + environment = { + MIZE_CONFIG_FILES = let fileInStore = (pkgs.formats.toml {}).generate "mize-daemon-config.toml" config.mize.config; in if config.mize.debugConfigFile then "${config.mize.debugConfigFile}" else "${fileInStore}"; + }; + serviceConfig = { + Restart = "on-failure"; + ExecStart = if config.mize.debuginary == null then "${self.packages.${system}.mize}/bin/mize daemon" else "${config.mize.debugBinary} daemon"; + }; + }; + }; + # for what we do the nixos and home-manager api is identical + homeModules.default = nixosModules.default; }) // { diff --git a/md b/md index 361e7f6..e3c7a80 100755 --- a/md +++ b/md @@ -30,12 +30,12 @@ function deploy_lush { if ! tmux has-session -t ppc-deploy 2>/dev/null; then echo "Created new tmux session...." tmux new-session -d -s ppc-deploy "nix develop git+file:///home/me/here/mize#buildShell" - tmux send-keys -t ppc-deploy "cargo build --featuers desktop --manifest-path /home/me/here/mize/packages/ppc/Cargo.toml" Enter - tmux send-keys -t ppc-deploy "systemctl --user restart ppc" Enter + tmux send-keys -t ppc-deploy "cargo build --featuers desktop --manifest-path /home/me/here/mize/packages/mize/Cargo.toml" Enter + tmux send-keys -t ppc-deploy "systemctl --user restart mize" Enter else echo "using existing session..." - tmux send-keys -t ppc-deploy "cargo build --features desktop --manifest-path /home/me/here/mize/packages/ppc/Cargo.toml" Enter - tmux send-keys -t ppc-deploy "systemctl --user restart ppc" Enter + tmux send-keys -t ppc-deploy "cargo build --features desktop --manifest-path /home/me/here/mize/packages/mize/Cargo.toml" Enter + tmux send-keys -t ppc-deploy "systemctl --user restart mize" Enter fi EOF diff --git a/packages/mize/src/platform/os/cli.rs b/packages/mize/src/platform/os/cli.rs index cccaff7..f81456e 100644 --- a/packages/mize/src/platform/os/cli.rs +++ b/packages/mize/src/platform/os/cli.rs @@ -66,9 +66,13 @@ pub fn mount(sub_matches: &ArgMatches) -> MizeResult<()> { Ok(()) } -pub fn run(sub_matches: &ArgMatches) -> MizeResult<()> { +pub fn daemon(sub_matches: &ArgMatches) -> MizeResult<()> { let instance = Mize::with_config(config_from_cli_args(sub_matches)?)?; - + + // load all parts we need for any mize application... making a fat daemon for now. + // in the future parts should be loaded on demand (from .so files and from parts.mize.works) + ppc + instance.wait(); return Ok(()); diff --git a/packages/mize/src/platform/os/main.rs b/packages/mize/src/platform/os/main.rs index 3b74d14..8f21b75 100644 --- a/packages/mize/src/platform/os/main.rs +++ b/packages/mize/src/platform/os/main.rs @@ -39,7 +39,7 @@ fn main() { // match command let result = match cli_matches.subcommand() { // mi daemon - Some(("run", sub_matches)) => cli::run(sub_matches), + Some(("daemon", sub_matches)) => cli::run(sub_matches), Some(("is-running", sub_matches)) => cli::is_running(sub_matches), @@ -130,11 +130,7 @@ fn cli_matches() -> clap::ArgMatches { .help("specify a config file") .global(true), ) - .subcommand( - Command::new("run") - .aliases(["r"]) - .about("Run a MiZe Instance"), - ) + .subcommand(Command::new("daemon").about("Run a MiZe Instance as a daemon")) .subcommand(Command::new("stop").about("Stop a MiZe Instance")) .subcommand(Command::new("mount").aliases(["m"])) .subcommand( diff --git a/packages/ppc/Cargo.toml b/packages/ppc/Cargo.toml index 277f770..0bd59d4 100644 --- a/packages/ppc/Cargo.toml +++ b/packages/ppc/Cargo.toml @@ -47,12 +47,12 @@ path = "lib.rs" name = "ppc" [features] -default = ["target-os", "server", "client", "desktop"] +default = ["target-os", "server", "client" ] target-os = [ "clap", "mize/target-os", "marts/target-os", "tracing", "webbrowser", "base64", "serde_json", "serde" ] target-obsidian = [ "js-sys", "wasm-bindgen", "mize/target-js", "marts/target-js", "base64", "serde_json", "serde", "openidconnect", "dioxus", "dioxus-web", "web-sys", "web-sys/Document", "dioxus/web" ] server = [ "axum", "axum-extra", "openidconnect", "serde", "serde_json", "reqwest", "rand", "url", "time", "tokio", "dioxus/ssr", "dioxus/server", "dioxus/fullstack", "dioxus/router", "dioxus-ssr", "html-escape", "axum-oidc", "tower", "tower-sessions", "marts/server", "target-os" ] desktop = ["dioxus/desktop", "marts/desktop", "target-os"] -client = [] +client = [ "tokio", "openidconnect" ] webbrowser = ["dep:webbrowser"] diff --git a/packages/ppc/auth/client.rs b/packages/ppc/auth/client.rs index 45b0e5b..87484a0 100644 --- a/packages/ppc/auth/client.rs +++ b/packages/ppc/auth/client.rs @@ -3,6 +3,7 @@ use base64::{ alphabet::STANDARD, engine::{DecodePaddingMode, GeneralPurpose, GeneralPurposeConfig}, }; +use chrono::{DateTime, Local, NaiveDateTime, TimeDelta, Utc}; use dioxus::{fullstack::ClientResponse, html::ol}; use mize::{Mize, MizeError, MizePart, MizeResult, item::ItemData, mize_err, mize_part}; use openidconnect::{ @@ -52,6 +53,7 @@ pub struct ClientSecrets { id_token: String, access_token: String, refresh_token: String, + expiry: DateTime, } impl MizePart for ClientAuth { @@ -97,7 +99,14 @@ impl ClientAuth { let mut mize_clone = self.mize.clone(); self.mize.spawn_background("auth.refresh", move || { loop { - thread::sleep(Duration::from_hours(23)); + let auth = mize_clone.get_part_native::("auth")?; + let to_sleep = Utc::now() + - auth.secrets.as_ref().unwrap().expiry.clone() + - TimeDelta::minutes(20); + drop(auth); + println!("refresh_thread: going to sleep for: {}", to_sleep); + thread::sleep(to_sleep.to_std()?); + println!("refresh_thread: sleeping done"); let mut auth = mize_clone.get_part_native::("auth")?; auth.refresh()?; drop(auth); @@ -118,6 +127,13 @@ pub fn client_auth(mize: &mut Mize) -> MizeResult<()> { } }; + // do a refresh if the tokens have expired + if (secrets.is_some() && secrets.unwrap().expiry < Utc::now()) { + secrets = Some( + mize.spawn_async_blocking("refresh_low", refresh_flow(mize.clone(), secrets.unwrap()))?, + ); + } + #[cfg(feature = "target-os")] { let mut cli = mize.get_part_native::("cli")?; @@ -260,11 +276,15 @@ async fn refresh_flow(mut mize: Mize, old_secrets: ClientSecrets) -> MizeResult< .exchange_refresh_token(&refresh_token)? .request_async(&http_client) .await?; + let expires_in = res.expires_in().ok_or(mize_err!( + "no expiry information was in token response of the refresh flow" + ))?; return Ok(ClientSecrets { id_token: res.id_token().unwrap().to_string(), access_token: res.access_token().secret().to_owned(), refresh_token: res.refresh_token().unwrap().secret().to_owned(), + expiry: Utc::now() + expires_in, }); } @@ -378,10 +398,15 @@ async fn auth_flow(mut mize: Mize) -> MizeResult { .refresh_token() .ok_or(mize_err!("no refresh token present"))?; + let expires_in = token_response.expires_in().ok_or(mize_err!( + "no expiry information was in token response of the refresh flow" + ))?; + Ok(ClientSecrets { id_token: id_token.to_string(), access_token: token_response.access_token().secret().to_string(), refresh_token: refresh.secret().to_owned(), + expiry: Utc::now() + expires_in, }) } diff --git a/packages/ppc/lib.rs b/packages/ppc/lib.rs index 8ceb410..398ce99 100644 --- a/packages/ppc/lib.rs +++ b/packages/ppc/lib.rs @@ -6,17 +6,22 @@ mod platform { #[cfg(feature = "target-os")] pub mod os { + #[cfg(feature = "server")] pub mod server; + #[cfg(feature = "desktop")] pub mod ui; } } #[cfg(feature = "target-os")] +#[cfg(feature = "website")] mod website; #[cfg(feature = "target-os")] +#[cfg(feature = "server")] pub use platform::os::server::server; #[cfg(feature = "target-os")] +#[cfg(feature = "desktop")] pub use platform::os::ui; pub mod auth { diff --git a/packages/ppc/platform/os/server.rs b/packages/ppc/platform/os/server.rs index 3ddba73..adf048c 100644 --- a/packages/ppc/platform/os/server.rs +++ b/packages/ppc/platform/os/server.rs @@ -1,3 +1,6 @@ +use axum::{Json, http::StatusCode}; +use serde_json::{Value, json}; +use std::net::SocketAddr; use std::str::FromStr; use axum::{ @@ -108,7 +111,10 @@ pub async fn start_server(mize: &mut Mize) -> MizeResult<()> { .layer(tower_http::trace::TraceLayer::new_for_http()) // not authenticated routes .route("/", get(ppc_main_page)) - .route("/oidc_display_code_and_state", get(display_code_and_state)); + .route("/oidc_display_code_and_state", get(display_code_and_state)) + // .well-known routes for matrix + .route("/.well-known/matrix/server", get(well_known_matrix_server)) + .route("/.well-known/matrix/client", get(well_known_matrix_client)); tracing::info!("Running on http://{listen_addr}:{port}"); @@ -199,3 +205,21 @@ async fn display_code_and_state(Query(params): Query) -> Html (StatusCode, Json) { + let response = json!({ + "m.server": "matrix.ppc.social:443" + }); + (StatusCode::OK, Json(response)) +} + +// Handler for /.well-known/matrix/client +async fn well_known_matrix_client() -> (StatusCode, Json) { + let response = json!({ + "m.homeserver": { + "base_url": "https://matrix.ppc.social:443" + } + }); + (StatusCode::OK, Json(response)) +} diff --git a/packages/ppc/timetrack/mod.rs b/packages/ppc/timetrack/mod.rs index 94f84cd..6c92ead 100644 --- a/packages/ppc/timetrack/mod.rs +++ b/packages/ppc/timetrack/mod.rs @@ -16,6 +16,13 @@ use crate::{ spacetime::SpacetimePart, }; +const MizeConfig = mconf!{ + hi "t" + rustBinary "hello" '' + println!("hello world"); + '' +}; + #[mize_part] #[derive(Default)] pub struct TimeTrack {