diff --git a/AGENTS.md b/AGENTS.md index 485fd02..a1d7bd5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,6 +17,9 @@ packages/ └── macros/ # Mize macros ``` +## Important +- usage of any git commands is strictly forbidden! + ## Key Components All code written for, with or as part as mize (except for the small core) is written as a Mize Part. see `docs/part-system.md` for how that works. diff --git a/marts/Cargo.toml b/marts/Cargo.toml deleted file mode 100644 index 05201cf..0000000 --- a/marts/Cargo.toml +++ /dev/null @@ -1,65 +0,0 @@ -[package] -name = "marts" -description = "marts = mize_parts - parts collection of the Mize framework" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib", "rlib"] - -[dependencies] -clap = { version = "4.5.59", optional = true, features = ["string"] } -flume = "0.12.0" -futures = "0.3.32" -mize = { path = "../", default-features = false, features = [] } -tokio = { version = "1.49.0", default-features = false, features = ["time"] } -# https://github.com/rscarson/rustyscript/pull/415 -#rustyscript = { git = 'https://github.com/rscarson/rustyscript', rev = 'e39529eac2c5d37cfcbb7d7d63da7264d7a5afdb', optional = true } -#deno_core = { version = "0.380.1", optional = true } -reqwest = { version = "0.13.2", features = ["blocking", "json"] } -serde = "1.0.228" -serde_json = "1.0.149" -rusqlite = { version = "0.37", features = ["bundled"], optional = true } -dioxus = { version = "0.7.1", optional = true } -spacetimedb-sdk = { version = "2.6.0", default-features = false } -generated = { path = "./generated" } -webbrowser = { version = "1.2.0", optional = true } -openidconnect = { version = "4", features = ["reqwest", "rustls-tls"], default-features = false } -tracing = "0.1.40" -wasm-bindgen = { version = "0.2.84", optional = true } -wasm-bindgen-futures = { version = "0.4.49", optional = true } -web-sys = { version = "0.3.70", optional = true, features = [ - "Window", - "Storage", - "console" -]} -js-sys = { version = "0.3.70", optional = true } -spacetimedb = { version = "2.6.0", features = ["unstable"] } -log = "0.4" -chrono = { version = "0.4.45", features = [], default-features = false } -chrono-tz = { version = "0.10.4", default-features = false } -url = "2.5.8" -serenity = { version = "0.12.5", optional = true } -matrix-sdk = "0.18.0" -axum = { version = "0.8.9", optional = true } -dioxus-ssr = { version = "0.7.10", optional = true } -axum-oidc = { version = "=1.0.0-dev-1", optional = true } -tower = { version = "0.5.3", optional = true } -tower-sessions = { version = "0.15.0", optional = true } -tower-http = { version = "0.7.1", optional = true, features = [ "cors", "trace" ] } -cmd_lib = "2.0.1" - - - -[features] -default = ["target-os", "desktop", "server", "client"] -#default = ["target-js", "target-obsidian"] # to get rust analyzer to analyzer js only parts -target-spacetime = [ "mize/target-js", "spacetimedb-sdk/browser" ] -target-os = [ "clap", "mize/target-os", "rusqlite", "dioxus", "dep:webbrowser" ] -target-js = [ "mize/target-js", "spacetimedb-sdk/browser", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", "js-sys", "generated/target-js", "web-sys/Storage", "web-sys/Window", "dioxus" ] -target-obsidian = [ "target-js" ] -desktop = ["dioxus/desktop"] -client = [] -server = [ "axum", "dioxus-ssr", "axum-oidc", "tower", "tower-sessions", "tower-http" ] -clap = ["dep:clap"] -serenity = ["dep:serenity"] diff --git a/marts/deno.json b/marts/deno.json deleted file mode 100644 index e3c3e2a..0000000 --- a/marts/deno.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@ppc/marts", - "imports": {}, - "exports": { - ".": "./src/index.ts" - }, - "tasks": {} -} diff --git a/marts/esbuild.config.mjs b/marts/esbuild.config.mjs deleted file mode 100644 index c3dc29e..0000000 --- a/marts/esbuild.config.mjs +++ /dev/null @@ -1,12 +0,0 @@ -import * as esbuild from "npm:esbuild"; - -import { denoPlugin } from "jsr:@deno/esbuild-plugin"; - -await esbuild.build({ - plugins: [denoPlugin()], - entryPoints: ["./habitica.ts"], - outfile: "./deno_dist/habitica.js", - bundle: true, - format: "iife", -}); -esbuild.stop(); diff --git a/marts/generated/Cargo.toml b/marts/generated/Cargo.toml deleted file mode 100644 index efa3be7..0000000 --- a/marts/generated/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "generated" -version = "0.1.0" -edition = "2021" - -[lib] -name = "generated" -path = "src/lib.rs" - -[dependencies] -spacetimedb-sdk = "2.6.0" - -[features] -target-js = [ "spacetimedb-sdk/browser" ] diff --git a/marts/generated/src/lib.rs b/marts/generated/src/lib.rs deleted file mode 100644 index d81c023..0000000 --- a/marts/generated/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod spacetime; diff --git a/marts/generated/src/spacetime/action_type.rs b/marts/generated/src/spacetime/action_type.rs deleted file mode 100644 index 33dfc43..0000000 --- a/marts/generated/src/spacetime/action_type.rs +++ /dev/null @@ -1,60 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct Action { - pub name: String, - pub activity: Option, - pub task: Option, - pub start: Option<__sdk::Timestamp>, - pub end: Option<__sdk::Timestamp>, - pub duration: Option, -} - -impl __sdk::InModule for Action { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `Action`. -/// -/// Provides typed access to columns for query building. -pub struct ActionCols { - pub name: __sdk::__query_builder::Col, - pub activity: __sdk::__query_builder::Col>, - pub task: __sdk::__query_builder::Col>, - pub start: __sdk::__query_builder::Col>, - pub end: __sdk::__query_builder::Col>, - pub duration: __sdk::__query_builder::Col>, -} - -impl __sdk::__query_builder::HasCols for Action { - type Cols = ActionCols; - fn cols(table_name: &'static str) -> Self::Cols { - ActionCols { - name: __sdk::__query_builder::Col::new(table_name, "name"), - activity: __sdk::__query_builder::Col::new(table_name, "activity"), - task: __sdk::__query_builder::Col::new(table_name, "task"), - start: __sdk::__query_builder::Col::new(table_name, "start"), - end: __sdk::__query_builder::Col::new(table_name, "end"), - duration: __sdk::__query_builder::Col::new(table_name, "duration"), - } - } -} - -/// Indexed column accessor struct for the table `Action`. -/// -/// Provides typed access to indexed columns for query building. -pub struct ActionIxCols {} - -impl __sdk::__query_builder::HasIxCols for Action { - type IxCols = ActionIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - ActionIxCols {} - } -} - -impl __sdk::__query_builder::CanBeLookupTable for Action {} diff --git a/marts/generated/src/spacetime/activities_table.rs b/marts/generated/src/spacetime/activities_table.rs deleted file mode 100644 index 82d823f..0000000 --- a/marts/generated/src/spacetime/activities_table.rs +++ /dev/null @@ -1,159 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::activity_type::Activity; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `activities`. -/// -/// Obtain a handle from the [`ActivitiesTableAccess::activities`] method on [`super::RemoteTables`], -/// like `ctx.db.activities()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.activities().on_insert(...)`. -pub struct ActivitiesTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `activities`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait ActivitiesTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`ActivitiesTableHandle`], which mediates access to the table `activities`. - fn activities(&self) -> ActivitiesTableHandle<'_>; -} - -impl ActivitiesTableAccess for super::RemoteTables { - fn activities(&self) -> ActivitiesTableHandle<'_> { - ActivitiesTableHandle { - imp: self.imp.get_table::("activities"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct ActivitiesInsertCallbackId(__sdk::CallbackId); -pub struct ActivitiesDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::Table for ActivitiesTableHandle<'ctx> { - type Row = Activity; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = ActivitiesInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> ActivitiesInsertCallbackId { - ActivitiesInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: ActivitiesInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = ActivitiesDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> ActivitiesDeleteCallbackId { - ActivitiesDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: ActivitiesDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct ActivitiesUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for ActivitiesTableHandle<'ctx> { - type UpdateCallbackId = ActivitiesUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> ActivitiesUpdateCallbackId { - ActivitiesUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: ActivitiesUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `id` unique index on the table `activities`, -/// which allows point queries on the field of the same name -/// via the [`ActivitiesIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.activities().id().find(...)`. -pub struct ActivitiesIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> ActivitiesTableHandle<'ctx> { - /// Get a handle on the `id` unique index on the table `activities`. - pub fn id(&self) -> ActivitiesIdUnique<'ctx> { - ActivitiesIdUnique { - imp: self.imp.get_unique_constraint::("id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> ActivitiesIdUnique<'ctx> { - /// Find the subscribed row whose `id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &u64) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("activities"); - _table.add_unique_constraint::("id", |row| &row.id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `Activity`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait activitiesQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `Activity`. - fn activities(&self) -> __sdk::__query_builder::Table; -} - -impl activitiesQueryTableAccess for __sdk::QueryTableAccessor { - fn activities(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("activities") - } -} diff --git a/marts/generated/src/spacetime/activity_type.rs b/marts/generated/src/spacetime/activity_type.rs deleted file mode 100644 index f9c162d..0000000 --- a/marts/generated/src/spacetime/activity_type.rs +++ /dev/null @@ -1,58 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct Activity { - pub id: u64, - pub name: String, - pub task: Option, - pub parents_ids: Vec, -} - -impl __sdk::InModule for Activity { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `Activity`. -/// -/// Provides typed access to columns for query building. -pub struct ActivityCols { - pub id: __sdk::__query_builder::Col, - pub name: __sdk::__query_builder::Col, - pub task: __sdk::__query_builder::Col>, - pub parents_ids: __sdk::__query_builder::Col>, -} - -impl __sdk::__query_builder::HasCols for Activity { - type Cols = ActivityCols; - fn cols(table_name: &'static str) -> Self::Cols { - ActivityCols { - id: __sdk::__query_builder::Col::new(table_name, "id"), - name: __sdk::__query_builder::Col::new(table_name, "name"), - task: __sdk::__query_builder::Col::new(table_name, "task"), - parents_ids: __sdk::__query_builder::Col::new(table_name, "parents_ids"), - } - } -} - -/// Indexed column accessor struct for the table `Activity`. -/// -/// Provides typed access to indexed columns for query building. -pub struct ActivityIxCols { - pub id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for Activity { - type IxCols = ActivityIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - ActivityIxCols { - id: __sdk::__query_builder::IxCol::new(table_name, "id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for Activity {} diff --git a/marts/generated/src/spacetime/add_activity_reducer.rs b/marts/generated/src/spacetime/add_activity_reducer.rs deleted file mode 100644 index d04a765..0000000 --- a/marts/generated/src/spacetime/add_activity_reducer.rs +++ /dev/null @@ -1,66 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub(super) struct AddActivityArgs { - pub name: String, -} - -impl From for super::Reducer { - fn from(args: AddActivityArgs) -> Self { - Self::AddActivity { name: args.name } - } -} - -impl __sdk::InModule for AddActivityArgs { - type Module = super::RemoteModule; -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the reducer `add_activity`. -/// -/// Implemented for [`super::RemoteReducers`]. -pub trait add_activity { - /// Request that the remote module invoke the reducer `add_activity` to run as soon as possible. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and this method provides no way to listen for its completion status. - /// /// Use [`add_activity:add_activity_then`] to run a callback after the reducer completes. - fn add_activity(&self, name: String) -> __sdk::Result<()> { - self.add_activity_then(name, |_, _| {}) - } - - /// Request that the remote module invoke the reducer `add_activity` to run as soon as possible, - /// registering `callback` to run when we are notified that the reducer completed. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and its status can be observed with the `callback`. - fn add_activity_then( - &self, - name: String, - - callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) - + Send - + 'static, - ) -> __sdk::Result<()>; -} - -impl add_activity for super::RemoteReducers { - fn add_activity_then( - &self, - name: String, - - callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) - + Send - + 'static, - ) -> __sdk::Result<()> { - self.imp - .invoke_reducer_with_callback(AddActivityArgs { name }, callback) - } -} diff --git a/marts/generated/src/spacetime/add_thought_reducer.rs b/marts/generated/src/spacetime/add_thought_reducer.rs deleted file mode 100644 index 040125e..0000000 --- a/marts/generated/src/spacetime/add_thought_reducer.rs +++ /dev/null @@ -1,68 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub(super) struct AddThoughtArgs { - pub thought: String, -} - -impl From for super::Reducer { - fn from(args: AddThoughtArgs) -> Self { - Self::AddThought { - thought: args.thought, - } - } -} - -impl __sdk::InModule for AddThoughtArgs { - type Module = super::RemoteModule; -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the reducer `add_thought`. -/// -/// Implemented for [`super::RemoteReducers`]. -pub trait add_thought { - /// Request that the remote module invoke the reducer `add_thought` to run as soon as possible. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and this method provides no way to listen for its completion status. - /// /// Use [`add_thought:add_thought_then`] to run a callback after the reducer completes. - fn add_thought(&self, thought: String) -> __sdk::Result<()> { - self.add_thought_then(thought, |_, _| {}) - } - - /// Request that the remote module invoke the reducer `add_thought` to run as soon as possible, - /// registering `callback` to run when we are notified that the reducer completed. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and its status can be observed with the `callback`. - fn add_thought_then( - &self, - thought: String, - - callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) - + Send - + 'static, - ) -> __sdk::Result<()>; -} - -impl add_thought for super::RemoteReducers { - fn add_thought_then( - &self, - thought: String, - - callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) - + Send - + 'static, - ) -> __sdk::Result<()> { - self.imp - .invoke_reducer_with_callback(AddThoughtArgs { thought }, callback) - } -} diff --git a/marts/generated/src/spacetime/daily_task_log_table.rs b/marts/generated/src/spacetime/daily_task_log_table.rs deleted file mode 100644 index 3c0f784..0000000 --- a/marts/generated/src/spacetime/daily_task_log_table.rs +++ /dev/null @@ -1,111 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::daily_task_log_type::DailyTaskLog; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `daily_task_log`. -/// -/// Obtain a handle from the [`DailyTaskLogTableAccess::daily_task_log`] method on [`super::RemoteTables`], -/// like `ctx.db.daily_task_log()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.daily_task_log().on_insert(...)`. -pub struct DailyTaskLogTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `daily_task_log`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait DailyTaskLogTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`DailyTaskLogTableHandle`], which mediates access to the table `daily_task_log`. - fn daily_task_log(&self) -> DailyTaskLogTableHandle<'_>; -} - -impl DailyTaskLogTableAccess for super::RemoteTables { - fn daily_task_log(&self) -> DailyTaskLogTableHandle<'_> { - DailyTaskLogTableHandle { - imp: self.imp.get_table::("daily_task_log"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct DailyTaskLogInsertCallbackId(__sdk::CallbackId); -pub struct DailyTaskLogDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::Table for DailyTaskLogTableHandle<'ctx> { - type Row = DailyTaskLog; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = DailyTaskLogInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> DailyTaskLogInsertCallbackId { - DailyTaskLogInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: DailyTaskLogInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = DailyTaskLogDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> DailyTaskLogDeleteCallbackId { - DailyTaskLogDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: DailyTaskLogDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("daily_task_log"); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `DailyTaskLog`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait daily_task_logQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `DailyTaskLog`. - fn daily_task_log(&self) -> __sdk::__query_builder::Table; -} - -impl daily_task_logQueryTableAccess for __sdk::QueryTableAccessor { - fn daily_task_log(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("daily_task_log") - } -} diff --git a/marts/generated/src/spacetime/daily_task_log_type.rs b/marts/generated/src/spacetime/daily_task_log_type.rs deleted file mode 100644 index 40bae60..0000000 --- a/marts/generated/src/spacetime/daily_task_log_type.rs +++ /dev/null @@ -1,48 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct DailyTaskLog { - pub daily_task_id: i64, - pub done: __sdk::Timestamp, -} - -impl __sdk::InModule for DailyTaskLog { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `DailyTaskLog`. -/// -/// Provides typed access to columns for query building. -pub struct DailyTaskLogCols { - pub daily_task_id: __sdk::__query_builder::Col, - pub done: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for DailyTaskLog { - type Cols = DailyTaskLogCols; - fn cols(table_name: &'static str) -> Self::Cols { - DailyTaskLogCols { - daily_task_id: __sdk::__query_builder::Col::new(table_name, "daily_task_id"), - done: __sdk::__query_builder::Col::new(table_name, "done"), - } - } -} - -/// Indexed column accessor struct for the table `DailyTaskLog`. -/// -/// Provides typed access to indexed columns for query building. -pub struct DailyTaskLogIxCols {} - -impl __sdk::__query_builder::HasIxCols for DailyTaskLog { - type IxCols = DailyTaskLogIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - DailyTaskLogIxCols {} - } -} - -impl __sdk::__query_builder::CanBeLookupTable for DailyTaskLog {} diff --git a/marts/generated/src/spacetime/daily_task_table.rs b/marts/generated/src/spacetime/daily_task_table.rs deleted file mode 100644 index 2e57907..0000000 --- a/marts/generated/src/spacetime/daily_task_table.rs +++ /dev/null @@ -1,111 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::daily_task_type::DailyTask; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `daily_task`. -/// -/// Obtain a handle from the [`DailyTaskTableAccess::daily_task`] method on [`super::RemoteTables`], -/// like `ctx.db.daily_task()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.daily_task().on_insert(...)`. -pub struct DailyTaskTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `daily_task`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait DailyTaskTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`DailyTaskTableHandle`], which mediates access to the table `daily_task`. - fn daily_task(&self) -> DailyTaskTableHandle<'_>; -} - -impl DailyTaskTableAccess for super::RemoteTables { - fn daily_task(&self) -> DailyTaskTableHandle<'_> { - DailyTaskTableHandle { - imp: self.imp.get_table::("daily_task"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct DailyTaskInsertCallbackId(__sdk::CallbackId); -pub struct DailyTaskDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::Table for DailyTaskTableHandle<'ctx> { - type Row = DailyTask; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = DailyTaskInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> DailyTaskInsertCallbackId { - DailyTaskInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: DailyTaskInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = DailyTaskDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> DailyTaskDeleteCallbackId { - DailyTaskDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: DailyTaskDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("daily_task"); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `DailyTask`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait daily_taskQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `DailyTask`. - fn daily_task(&self) -> __sdk::__query_builder::Table; -} - -impl daily_taskQueryTableAccess for __sdk::QueryTableAccessor { - fn daily_task(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("daily_task") - } -} diff --git a/marts/generated/src/spacetime/daily_task_type.rs b/marts/generated/src/spacetime/daily_task_type.rs deleted file mode 100644 index cead156..0000000 --- a/marts/generated/src/spacetime/daily_task_type.rs +++ /dev/null @@ -1,51 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct DailyTask { - pub id: i64, - pub name: String, - pub owner: __sdk::Identity, -} - -impl __sdk::InModule for DailyTask { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `DailyTask`. -/// -/// Provides typed access to columns for query building. -pub struct DailyTaskCols { - pub id: __sdk::__query_builder::Col, - pub name: __sdk::__query_builder::Col, - pub owner: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for DailyTask { - type Cols = DailyTaskCols; - fn cols(table_name: &'static str) -> Self::Cols { - DailyTaskCols { - id: __sdk::__query_builder::Col::new(table_name, "id"), - name: __sdk::__query_builder::Col::new(table_name, "name"), - owner: __sdk::__query_builder::Col::new(table_name, "owner"), - } - } -} - -/// Indexed column accessor struct for the table `DailyTask`. -/// -/// Provides typed access to indexed columns for query building. -pub struct DailyTaskIxCols {} - -impl __sdk::__query_builder::HasIxCols for DailyTask { - type IxCols = DailyTaskIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - DailyTaskIxCols {} - } -} - -impl __sdk::__query_builder::CanBeLookupTable for DailyTask {} diff --git a/marts/generated/src/spacetime/export_timetrack_procedure.rs b/marts/generated/src/spacetime/export_timetrack_procedure.rs deleted file mode 100644 index 73b6581..0000000 --- a/marts/generated/src/spacetime/export_timetrack_procedure.rs +++ /dev/null @@ -1,59 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -struct ExportTimetrackArgs { - pub username: String, - pub date: String, -} - -impl __sdk::InModule for ExportTimetrackArgs { - type Module = super::RemoteModule; -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the procedure `export_timetrack`. -/// -/// Implemented for [`super::RemoteProcedures`]. -pub trait export_timetrack { - fn export_timetrack(&self, username: String, date: String) { - self.export_timetrack_then(username, date, |_, _| {}); - } - - fn export_timetrack_then( - &self, - username: String, - date: String, - - __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, - ); -} - -impl export_timetrack for super::RemoteProcedures { - fn export_timetrack_then( - &self, - username: String, - date: String, - - __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, - ) { - self.imp - .invoke_procedure_with_callback::<_, Result>( - "export_timetrack", - ExportTimetrackArgs { username, date }, - __callback, - ); - } -} diff --git a/marts/generated/src/spacetime/first_timetrack_date_procedure.rs b/marts/generated/src/spacetime/first_timetrack_date_procedure.rs deleted file mode 100644 index 79b2f05..0000000 --- a/marts/generated/src/spacetime/first_timetrack_date_procedure.rs +++ /dev/null @@ -1,56 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -struct FirstTimetrackDateArgs { - pub username: String, -} - -impl __sdk::InModule for FirstTimetrackDateArgs { - type Module = super::RemoteModule; -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the procedure `first_timetrack_date`. -/// -/// Implemented for [`super::RemoteProcedures`]. -pub trait first_timetrack_date { - fn first_timetrack_date(&self, username: String) { - self.first_timetrack_date_then(username, |_, _| {}); - } - - fn first_timetrack_date_then( - &self, - username: String, - - __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, - ); -} - -impl first_timetrack_date for super::RemoteProcedures { - fn first_timetrack_date_then( - &self, - username: String, - - __callback: impl FnOnce( - &super::ProcedureEventContext, - Result, __sdk::InternalError>, - ) + Send - + 'static, - ) { - self.imp - .invoke_procedure_with_callback::<_, Result>( - "first_timetrack_date", - FirstTimetrackDateArgs { username }, - __callback, - ); - } -} diff --git a/marts/generated/src/spacetime/log_event_type.rs b/marts/generated/src/spacetime/log_event_type.rs deleted file mode 100644 index 366b6d0..0000000 --- a/marts/generated/src/spacetime/log_event_type.rs +++ /dev/null @@ -1,63 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::action_type::Action; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct LogEvent { - pub id: u64, - pub start: __sdk::Timestamp, - pub end: __sdk::Timestamp, - pub action: Action, - pub user: __sdk::Identity, -} - -impl __sdk::InModule for LogEvent { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `LogEvent`. -/// -/// Provides typed access to columns for query building. -pub struct LogEventCols { - pub id: __sdk::__query_builder::Col, - pub start: __sdk::__query_builder::Col, - pub end: __sdk::__query_builder::Col, - pub action: __sdk::__query_builder::Col, - pub user: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for LogEvent { - type Cols = LogEventCols; - fn cols(table_name: &'static str) -> Self::Cols { - LogEventCols { - id: __sdk::__query_builder::Col::new(table_name, "id"), - start: __sdk::__query_builder::Col::new(table_name, "start"), - end: __sdk::__query_builder::Col::new(table_name, "end"), - action: __sdk::__query_builder::Col::new(table_name, "action"), - user: __sdk::__query_builder::Col::new(table_name, "user"), - } - } -} - -/// Indexed column accessor struct for the table `LogEvent`. -/// -/// Provides typed access to indexed columns for query building. -pub struct LogEventIxCols { - pub id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for LogEvent { - type IxCols = LogEventIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - LogEventIxCols { - id: __sdk::__query_builder::IxCol::new(table_name, "id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for LogEvent {} diff --git a/marts/generated/src/spacetime/log_events_table.rs b/marts/generated/src/spacetime/log_events_table.rs deleted file mode 100644 index f855859..0000000 --- a/marts/generated/src/spacetime/log_events_table.rs +++ /dev/null @@ -1,160 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::action_type::Action; -use super::log_event_type::LogEvent; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `log_events`. -/// -/// Obtain a handle from the [`LogEventsTableAccess::log_events`] method on [`super::RemoteTables`], -/// like `ctx.db.log_events()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.log_events().on_insert(...)`. -pub struct LogEventsTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `log_events`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait LogEventsTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`LogEventsTableHandle`], which mediates access to the table `log_events`. - fn log_events(&self) -> LogEventsTableHandle<'_>; -} - -impl LogEventsTableAccess for super::RemoteTables { - fn log_events(&self) -> LogEventsTableHandle<'_> { - LogEventsTableHandle { - imp: self.imp.get_table::("log_events"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct LogEventsInsertCallbackId(__sdk::CallbackId); -pub struct LogEventsDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::Table for LogEventsTableHandle<'ctx> { - type Row = LogEvent; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = LogEventsInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> LogEventsInsertCallbackId { - LogEventsInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: LogEventsInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = LogEventsDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> LogEventsDeleteCallbackId { - LogEventsDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: LogEventsDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct LogEventsUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for LogEventsTableHandle<'ctx> { - type UpdateCallbackId = LogEventsUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> LogEventsUpdateCallbackId { - LogEventsUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: LogEventsUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `id` unique index on the table `log_events`, -/// which allows point queries on the field of the same name -/// via the [`LogEventsIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.log_events().id().find(...)`. -pub struct LogEventsIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> LogEventsTableHandle<'ctx> { - /// Get a handle on the `id` unique index on the table `log_events`. - pub fn id(&self) -> LogEventsIdUnique<'ctx> { - LogEventsIdUnique { - imp: self.imp.get_unique_constraint::("id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> LogEventsIdUnique<'ctx> { - /// Find the subscribed row whose `id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &u64) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("log_events"); - _table.add_unique_constraint::("id", |row| &row.id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `LogEvent`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait log_eventsQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `LogEvent`. - fn log_events(&self) -> __sdk::__query_builder::Table; -} - -impl log_eventsQueryTableAccess for __sdk::QueryTableAccessor { - fn log_events(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("log_events") - } -} diff --git a/marts/generated/src/spacetime/migrate_procedure.rs b/marts/generated/src/spacetime/migrate_procedure.rs deleted file mode 100644 index 5b3f9ea..0000000 --- a/marts/generated/src/spacetime/migrate_procedure.rs +++ /dev/null @@ -1,44 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -struct MigrateArgs {} - -impl __sdk::InModule for MigrateArgs { - type Module = super::RemoteModule; -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the procedure `migrate`. -/// -/// Implemented for [`super::RemoteProcedures`]. -pub trait migrate { - fn migrate(&self) { - self.migrate_then(|_, _| {}); - } - - fn migrate_then( - &self, - - __callback: impl FnOnce(&super::ProcedureEventContext, Result) - + Send - + 'static, - ); -} - -impl migrate for super::RemoteProcedures { - fn migrate_then( - &self, - - __callback: impl FnOnce(&super::ProcedureEventContext, Result) - + Send - + 'static, - ) { - self.imp - .invoke_procedure_with_callback::<_, String>("migrate", MigrateArgs {}, __callback); - } -} diff --git a/marts/generated/src/spacetime/mod.rs b/marts/generated/src/spacetime/mod.rs deleted file mode 100644 index 60c5f2c..0000000 --- a/marts/generated/src/spacetime/mod.rs +++ /dev/null @@ -1,1046 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -// This was generated using spacetimedb cli version 2.6.0 (commit refs/tags/v2.6.0). - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -pub mod action_type; -pub mod activities_table; -pub mod activity_type; -pub mod add_activity_reducer; -pub mod add_thought_reducer; -pub mod daily_task_log_table; -pub mod daily_task_log_type; -pub mod daily_task_table; -pub mod daily_task_type; -pub mod export_timetrack_procedure; -pub mod first_timetrack_date_procedure; -pub mod log_event_type; -pub mod log_events_table; -pub mod migrate_procedure; -pub mod next_action_reducer; -pub mod profile_type; -pub mod profiles_table; -pub mod remove_activity_reducer; -pub mod set_activity_name_reducer; -pub mod task_part_table; -pub mod task_part_type; -pub mod task_type; -pub mod tasks_table; -pub mod test_procedure; -pub mod thought_type; -pub mod thoughts_table; -pub mod update_activity_reducer; -pub mod update_upcoming_reducer; - -pub use action_type::Action; -pub use activities_table::*; -pub use activity_type::Activity; -pub use add_activity_reducer::add_activity; -pub use add_thought_reducer::add_thought; -pub use daily_task_log_table::*; -pub use daily_task_log_type::DailyTaskLog; -pub use daily_task_table::*; -pub use daily_task_type::DailyTask; -pub use export_timetrack_procedure::export_timetrack; -pub use first_timetrack_date_procedure::first_timetrack_date; -pub use log_event_type::LogEvent; -pub use log_events_table::*; -pub use migrate_procedure::migrate; -pub use next_action_reducer::next_action; -pub use profile_type::Profile; -pub use profiles_table::*; -pub use remove_activity_reducer::remove_activity; -pub use set_activity_name_reducer::set_activity_name; -pub use task_part_table::*; -pub use task_part_type::TaskPart; -pub use task_type::Task; -pub use tasks_table::*; -pub use test_procedure::test; -pub use thought_type::Thought; -pub use thoughts_table::*; -pub use update_activity_reducer::update_activity; -pub use update_upcoming_reducer::update_upcoming; - -#[derive(Clone, PartialEq, Debug)] - -/// One of the reducers defined by this module. -/// -/// Contained within a [`__sdk::ReducerEvent`] in [`EventContext`]s for reducer events -/// to indicate which reducer caused the event. - -pub enum Reducer { - AddActivity { - name: String, - }, - AddThought { - thought: String, - }, - NextAction { - break_flag: bool, - action: Option, - }, - RemoveActivity { - activity: Activity, - }, - SetActivityName { - id: u64, - name: String, - }, - UpdateActivity { - activity: Activity, - }, - UpdateUpcoming { - upcoming: Vec, - }, -} - -impl __sdk::InModule for Reducer { - type Module = RemoteModule; -} - -impl __sdk::Reducer for Reducer { - fn reducer_name(&self) -> &'static str { - match self { - Reducer::AddActivity { .. } => "add_activity", - Reducer::AddThought { .. } => "add_thought", - Reducer::NextAction { .. } => "next_action", - Reducer::RemoveActivity { .. } => "remove_activity", - Reducer::SetActivityName { .. } => "set_activity_name", - Reducer::UpdateActivity { .. } => "update_activity", - Reducer::UpdateUpcoming { .. } => "update_upcoming", - _ => unreachable!(), - } - } - #[allow(clippy::clone_on_copy)] - fn args_bsatn(&self) -> Result, __sats::bsatn::EncodeError> { - match self { - Reducer::AddActivity { name } => { - __sats::bsatn::to_vec(&add_activity_reducer::AddActivityArgs { name: name.clone() }) - } - Reducer::AddThought { thought } => { - __sats::bsatn::to_vec(&add_thought_reducer::AddThoughtArgs { - thought: thought.clone(), - }) - } - Reducer::NextAction { break_flag, action } => { - __sats::bsatn::to_vec(&next_action_reducer::NextActionArgs { - break_flag: break_flag.clone(), - action: action.clone(), - }) - } - Reducer::RemoveActivity { activity } => { - __sats::bsatn::to_vec(&remove_activity_reducer::RemoveActivityArgs { - activity: activity.clone(), - }) - } - Reducer::SetActivityName { id, name } => { - __sats::bsatn::to_vec(&set_activity_name_reducer::SetActivityNameArgs { - id: id.clone(), - name: name.clone(), - }) - } - Reducer::UpdateActivity { activity } => { - __sats::bsatn::to_vec(&update_activity_reducer::UpdateActivityArgs { - activity: activity.clone(), - }) - } - Reducer::UpdateUpcoming { upcoming } => { - __sats::bsatn::to_vec(&update_upcoming_reducer::UpdateUpcomingArgs { - upcoming: upcoming.clone(), - }) - } - _ => unreachable!(), - } - } -} - -#[derive(Default, Debug)] -#[allow(non_snake_case)] -#[doc(hidden)] -pub struct DbUpdate { - activities: __sdk::TableUpdate, - daily_task: __sdk::TableUpdate, - daily_task_log: __sdk::TableUpdate, - log_events: __sdk::TableUpdate, - profiles: __sdk::TableUpdate, - task_part: __sdk::TableUpdate, - tasks: __sdk::TableUpdate, - thoughts: __sdk::TableUpdate, -} - -impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate { - type Error = __sdk::Error; - fn try_from(raw: __ws::v2::TransactionUpdate) -> Result { - let mut db_update = DbUpdate::default(); - for table_update in __sdk::transaction_update_iter_table_updates(raw) { - match &table_update.table_name[..] { - "activities" => db_update - .activities - .append(activities_table::parse_table_update(table_update)?), - "daily_task" => db_update - .daily_task - .append(daily_task_table::parse_table_update(table_update)?), - "daily_task_log" => db_update - .daily_task_log - .append(daily_task_log_table::parse_table_update(table_update)?), - "log_events" => db_update - .log_events - .append(log_events_table::parse_table_update(table_update)?), - "profiles" => db_update - .profiles - .append(profiles_table::parse_table_update(table_update)?), - "task_part" => db_update - .task_part - .append(task_part_table::parse_table_update(table_update)?), - "tasks" => db_update - .tasks - .append(tasks_table::parse_table_update(table_update)?), - "thoughts" => db_update - .thoughts - .append(thoughts_table::parse_table_update(table_update)?), - - unknown => { - return Err(__sdk::InternalError::unknown_name( - "table", - unknown, - "DatabaseUpdate", - ) - .into()); - } - } - } - Ok(db_update) - } -} - -impl __sdk::InModule for DbUpdate { - type Module = RemoteModule; -} - -impl __sdk::DbUpdate for DbUpdate { - fn apply_to_client_cache( - &self, - cache: &mut __sdk::ClientCache, - ) -> AppliedDiff<'_> { - let mut diff = AppliedDiff::default(); - - diff.activities = cache - .apply_diff_to_table::("activities", &self.activities) - .with_updates_by_pk(|row| &row.id); - diff.daily_task = cache.apply_diff_to_table::("daily_task", &self.daily_task); - diff.daily_task_log = - cache.apply_diff_to_table::("daily_task_log", &self.daily_task_log); - diff.log_events = cache - .apply_diff_to_table::("log_events", &self.log_events) - .with_updates_by_pk(|row| &row.id); - diff.profiles = cache - .apply_diff_to_table::("profiles", &self.profiles) - .with_updates_by_pk(|row| &row.identity); - diff.task_part = cache - .apply_diff_to_table::("task_part", &self.task_part) - .with_updates_by_pk(|row| &row.identity); - diff.tasks = cache - .apply_diff_to_table::("tasks", &self.tasks) - .with_updates_by_pk(|row| &row.id); - diff.thoughts = cache - .apply_diff_to_table::("thoughts", &self.thoughts) - .with_updates_by_pk(|row| &row.id); - - diff - } - fn parse_initial_rows(raw: __ws::v2::QueryRows) -> __sdk::Result { - let mut db_update = DbUpdate::default(); - for table_rows in raw.tables { - match &table_rows.table[..] { - "activities" => db_update - .activities - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "daily_task" => db_update - .daily_task - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "daily_task_log" => db_update - .daily_task_log - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "log_events" => db_update - .log_events - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "profiles" => db_update - .profiles - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "task_part" => db_update - .task_part - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "tasks" => db_update - .tasks - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - "thoughts" => db_update - .thoughts - .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), - unknown => { - return Err( - __sdk::InternalError::unknown_name("table", unknown, "QueryRows").into(), - ); - } - } - } - Ok(db_update) - } - fn parse_unsubscribe_rows(raw: __ws::v2::QueryRows) -> __sdk::Result { - let mut db_update = DbUpdate::default(); - for table_rows in raw.tables { - match &table_rows.table[..] { - "activities" => db_update - .activities - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "daily_task" => db_update - .daily_task - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "daily_task_log" => db_update - .daily_task_log - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "log_events" => db_update - .log_events - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "profiles" => db_update - .profiles - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "task_part" => db_update - .task_part - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "tasks" => db_update - .tasks - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - "thoughts" => db_update - .thoughts - .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), - unknown => { - return Err( - __sdk::InternalError::unknown_name("table", unknown, "QueryRows").into(), - ); - } - } - } - Ok(db_update) - } -} - -#[derive(Default)] -#[allow(non_snake_case)] -#[doc(hidden)] -pub struct AppliedDiff<'r> { - activities: __sdk::TableAppliedDiff<'r, Activity>, - daily_task: __sdk::TableAppliedDiff<'r, DailyTask>, - daily_task_log: __sdk::TableAppliedDiff<'r, DailyTaskLog>, - log_events: __sdk::TableAppliedDiff<'r, LogEvent>, - profiles: __sdk::TableAppliedDiff<'r, Profile>, - task_part: __sdk::TableAppliedDiff<'r, TaskPart>, - tasks: __sdk::TableAppliedDiff<'r, Task>, - thoughts: __sdk::TableAppliedDiff<'r, Thought>, - __unused: std::marker::PhantomData<&'r ()>, -} - -impl __sdk::InModule for AppliedDiff<'_> { - type Module = RemoteModule; -} - -impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { - fn invoke_row_callbacks( - &self, - event: &EventContext, - callbacks: &mut __sdk::DbCallbacks, - ) { - callbacks.invoke_table_row_callbacks::("activities", &self.activities, event); - callbacks.invoke_table_row_callbacks::("daily_task", &self.daily_task, event); - callbacks.invoke_table_row_callbacks::( - "daily_task_log", - &self.daily_task_log, - event, - ); - callbacks.invoke_table_row_callbacks::("log_events", &self.log_events, event); - callbacks.invoke_table_row_callbacks::("profiles", &self.profiles, event); - callbacks.invoke_table_row_callbacks::("task_part", &self.task_part, event); - callbacks.invoke_table_row_callbacks::("tasks", &self.tasks, event); - callbacks.invoke_table_row_callbacks::("thoughts", &self.thoughts, event); - } -} - -#[doc(hidden)] -#[derive(Debug)] -pub struct RemoteModule; - -impl __sdk::InModule for RemoteModule { - type Module = Self; -} - -/// The `reducers` field of [`EventContext`] and [`DbConnection`], -/// with methods provided by extension traits for each reducer defined by the module. -pub struct RemoteReducers { - imp: __sdk::DbContextImpl, -} - -impl __sdk::InModule for RemoteReducers { - type Module = RemoteModule; -} - -/// The `procedures` field of [`DbConnection`] and other [`DbContext`] types, -/// with methods provided by extension traits for each procedure defined by the module. -pub struct RemoteProcedures { - imp: __sdk::DbContextImpl, -} - -impl __sdk::InModule for RemoteProcedures { - type Module = RemoteModule; -} - -/// The `db` field of [`EventContext`] and [`DbConnection`], -/// with methods provided by extension traits for each table defined by the module. -pub struct RemoteTables { - imp: __sdk::DbContextImpl, -} - -impl __sdk::InModule for RemoteTables { - type Module = RemoteModule; -} - -/// A connection to a remote module, including a materialized view of a subset of the database. -/// -/// Connect to a remote module by calling [`DbConnection::builder`] -/// and using the [`__sdk::DbConnectionBuilder`] builder-pattern constructor. -/// -/// You must explicitly advance the connection by calling any one of: -/// -/// - [`DbConnection::frame_tick`]. -#[cfg_attr(not(target_arch = "wasm32"), doc = "- [`DbConnection::run_threaded`].")] -#[cfg_attr( - target_arch = "wasm32", - doc = "- [`DbConnection::run_background_task`]." -)] -/// - [`DbConnection::run_async`]. -/// - [`DbConnection::advance_one_message`]. -#[cfg_attr( - not(target_arch = "wasm32"), - doc = "- [`DbConnection::advance_one_message_blocking`]." -)] -/// - [`DbConnection::advance_one_message_async`]. -/// -/// Which of these methods you should call depends on the specific needs of your application, -/// but you must call one of them, or else the connection will never progress. -pub struct DbConnection { - /// Access to tables defined by the module via extension traits implemented for [`RemoteTables`]. - pub db: RemoteTables, - /// Access to reducers defined by the module via extension traits implemented for [`RemoteReducers`]. - pub reducers: RemoteReducers, - #[doc(hidden)] - - /// Access to procedures defined by the module via extension traits implemented for [`RemoteProcedures`]. - pub procedures: RemoteProcedures, - - imp: __sdk::DbContextImpl, -} - -impl __sdk::InModule for DbConnection { - type Module = RemoteModule; -} - -impl __sdk::DbContext for DbConnection { - type DbView = RemoteTables; - type Reducers = RemoteReducers; - type Procedures = RemoteProcedures; - - fn db(&self) -> &Self::DbView { - &self.db - } - fn reducers(&self) -> &Self::Reducers { - &self.reducers - } - fn procedures(&self) -> &Self::Procedures { - &self.procedures - } - - fn is_active(&self) -> bool { - self.imp.is_active() - } - - fn disconnect(&self) -> __sdk::Result<()> { - self.imp.disconnect() - } - - type SubscriptionBuilder = __sdk::SubscriptionBuilder; - - fn subscription_builder(&self) -> Self::SubscriptionBuilder { - __sdk::SubscriptionBuilder::new(&self.imp) - } - - fn try_identity(&self) -> Option<__sdk::Identity> { - self.imp.try_identity() - } - fn connection_id(&self) -> __sdk::ConnectionId { - self.imp.connection_id() - } - fn try_connection_id(&self) -> Option<__sdk::ConnectionId> { - self.imp.try_connection_id() - } -} - -impl DbConnection { - /// Builder-pattern constructor for a connection to a remote module. - /// - /// See [`__sdk::DbConnectionBuilder`] for required and optional configuration for the new connection. - pub fn builder() -> __sdk::DbConnectionBuilder { - __sdk::DbConnectionBuilder::new() - } - - /// If any WebSocket messages are waiting, process one of them. - /// - /// Returns `true` if a message was processed, or `false` if the queue is empty. - /// Callers should invoke this message in a loop until it returns `false` - /// or for as much time is available to process messages. - /// - /// Returns an error if the connection is disconnected. - /// If the disconnection in question was normal, - /// i.e. the result of a call to [`__sdk::DbContext::disconnect`], - /// the returned error will be downcastable to [`__sdk::DisconnectedError`]. - /// - /// This is a low-level primitive exposed for power users who need significant control over scheduling. - /// Most applications should call [`Self::frame_tick`] each frame - /// to fully exhaust the queue whenever time is available. - pub fn advance_one_message(&self) -> __sdk::Result { - self.imp.advance_one_message() - } - - /// Process one WebSocket message, potentially blocking the current thread until one is received. - /// - /// Returns an error if the connection is disconnected. - /// If the disconnection in question was normal, - /// i.e. the result of a call to [`__sdk::DbContext::disconnect`], - /// the returned error will be downcastable to [`__sdk::DisconnectedError`]. - /// - /// This is a low-level primitive exposed for power users who need significant control over scheduling. - /// Most applications should call [`Self::run_threaded`] to spawn a thread - /// which advances the connection automatically. - #[cfg(not(target_arch = "wasm32"))] - pub fn advance_one_message_blocking(&self) -> __sdk::Result<()> { - self.imp.advance_one_message_blocking() - } - - /// Process one WebSocket message, `await`ing until one is received. - /// - /// Returns an error if the connection is disconnected. - /// If the disconnection in question was normal, - /// i.e. the result of a call to [`__sdk::DbContext::disconnect`], - /// the returned error will be downcastable to [`__sdk::DisconnectedError`]. - /// - /// This is a low-level primitive exposed for power users who need significant control over scheduling. - /// Most applications should call [`Self::run_async`] to run an `async` loop - /// which advances the connection when polled. - pub async fn advance_one_message_async(&self) -> __sdk::Result<()> { - self.imp.advance_one_message_async().await - } - - /// Process all WebSocket messages waiting in the queue, - /// then return without `await`ing or blocking the current thread. - pub fn frame_tick(&self) -> __sdk::Result<()> { - self.imp.frame_tick() - } - - /// Spawn a thread which processes WebSocket messages as they are received. - #[cfg(not(target_arch = "wasm32"))] - pub fn run_threaded(&self) -> std::thread::JoinHandle<()> { - self.imp.run_threaded() - } - - /// Spawn a background task which processes WebSocket messages as they are received. - #[cfg(target_arch = "wasm32")] - pub fn run_background_task(&self) { - self.imp.run_background_task() - } - - /// Run an `async` loop which processes WebSocket messages when polled. - pub async fn run_async(&self) -> __sdk::Result<()> { - self.imp.run_async().await - } -} - -impl __sdk::DbConnection for DbConnection { - fn new(imp: __sdk::DbContextImpl) -> Self { - Self { - db: RemoteTables { imp: imp.clone() }, - reducers: RemoteReducers { imp: imp.clone() }, - procedures: RemoteProcedures { imp: imp.clone() }, - imp, - } - } -} - -/// A handle on a subscribed query. -// TODO: Document this better after implementing the new subscription API. -#[derive(Clone)] -pub struct SubscriptionHandle { - imp: __sdk::SubscriptionHandleImpl, -} - -impl __sdk::InModule for SubscriptionHandle { - type Module = RemoteModule; -} - -impl __sdk::SubscriptionHandle for SubscriptionHandle { - fn new(imp: __sdk::SubscriptionHandleImpl) -> Self { - Self { imp } - } - - /// Returns true if this subscription has been terminated due to an unsubscribe call or an error. - fn is_ended(&self) -> bool { - self.imp.is_ended() - } - - /// Returns true if this subscription has been applied and has not yet been unsubscribed. - fn is_active(&self) -> bool { - self.imp.is_active() - } - - /// Unsubscribe from the query controlled by this `SubscriptionHandle`, - /// then run `on_end` when its rows are removed from the client cache. - fn unsubscribe_then(self, on_end: __sdk::OnEndedCallback) -> __sdk::Result<()> { - self.imp.unsubscribe_then(Some(on_end)) - } - - fn unsubscribe(self) -> __sdk::Result<()> { - self.imp.unsubscribe_then(None) - } -} - -/// Alias trait for a [`__sdk::DbContext`] connected to this module, -/// with that trait's associated types bounded to this module's concrete types. -/// -/// Users can use this trait as a boundary on definitions which should accept -/// either a [`DbConnection`] or an [`EventContext`] and operate on either. -pub trait RemoteDbContext: - __sdk::DbContext< - DbView = RemoteTables, - Reducers = RemoteReducers, - SubscriptionBuilder = __sdk::SubscriptionBuilder, -> -{ -} -impl< - Ctx: __sdk::DbContext< - DbView = RemoteTables, - Reducers = RemoteReducers, - SubscriptionBuilder = __sdk::SubscriptionBuilder, - >, - > RemoteDbContext for Ctx -{ -} - -/// An [`__sdk::DbContext`] augmented with a [`__sdk::Event`], -/// passed to [`__sdk::Table::on_insert`], [`__sdk::Table::on_delete`] and [`__sdk::TableWithPrimaryKey::on_update`] callbacks. -pub struct EventContext { - /// Access to tables defined by the module via extension traits implemented for [`RemoteTables`]. - pub db: RemoteTables, - /// Access to reducers defined by the module via extension traits implemented for [`RemoteReducers`]. - pub reducers: RemoteReducers, - /// Access to procedures defined by the module via extension traits implemented for [`RemoteProcedures`]. - pub procedures: RemoteProcedures, - /// The event which caused these callbacks to run. - pub event: __sdk::Event, - imp: __sdk::DbContextImpl, -} - -impl __sdk::AbstractEventContext for EventContext { - type Event = __sdk::Event; - fn event(&self) -> &Self::Event { - &self.event - } - fn new(imp: __sdk::DbContextImpl, event: Self::Event) -> Self { - Self { - db: RemoteTables { imp: imp.clone() }, - reducers: RemoteReducers { imp: imp.clone() }, - procedures: RemoteProcedures { imp: imp.clone() }, - event, - imp, - } - } -} - -impl __sdk::InModule for EventContext { - type Module = RemoteModule; -} - -impl __sdk::DbContext for EventContext { - type DbView = RemoteTables; - type Reducers = RemoteReducers; - type Procedures = RemoteProcedures; - - fn db(&self) -> &Self::DbView { - &self.db - } - fn reducers(&self) -> &Self::Reducers { - &self.reducers - } - fn procedures(&self) -> &Self::Procedures { - &self.procedures - } - - fn is_active(&self) -> bool { - self.imp.is_active() - } - - fn disconnect(&self) -> __sdk::Result<()> { - self.imp.disconnect() - } - - type SubscriptionBuilder = __sdk::SubscriptionBuilder; - - fn subscription_builder(&self) -> Self::SubscriptionBuilder { - __sdk::SubscriptionBuilder::new(&self.imp) - } - - fn try_identity(&self) -> Option<__sdk::Identity> { - self.imp.try_identity() - } - fn connection_id(&self) -> __sdk::ConnectionId { - self.imp.connection_id() - } - fn try_connection_id(&self) -> Option<__sdk::ConnectionId> { - self.imp.try_connection_id() - } -} - -impl __sdk::EventContext for EventContext {} - -/// An [`__sdk::DbContext`] augmented with a [`__sdk::ReducerEvent`], -/// passed to on-reducer callbacks. -pub struct ReducerEventContext { - /// Access to tables defined by the module via extension traits implemented for [`RemoteTables`]. - pub db: RemoteTables, - /// Access to reducers defined by the module via extension traits implemented for [`RemoteReducers`]. - pub reducers: RemoteReducers, - /// Access to procedures defined by the module via extension traits implemented for [`RemoteProcedures`]. - pub procedures: RemoteProcedures, - /// The event which caused these callbacks to run. - pub event: __sdk::ReducerEvent, - imp: __sdk::DbContextImpl, -} - -impl __sdk::AbstractEventContext for ReducerEventContext { - type Event = __sdk::ReducerEvent; - fn event(&self) -> &Self::Event { - &self.event - } - fn new(imp: __sdk::DbContextImpl, event: Self::Event) -> Self { - Self { - db: RemoteTables { imp: imp.clone() }, - reducers: RemoteReducers { imp: imp.clone() }, - procedures: RemoteProcedures { imp: imp.clone() }, - event, - imp, - } - } -} - -impl __sdk::InModule for ReducerEventContext { - type Module = RemoteModule; -} - -impl __sdk::DbContext for ReducerEventContext { - type DbView = RemoteTables; - type Reducers = RemoteReducers; - type Procedures = RemoteProcedures; - - fn db(&self) -> &Self::DbView { - &self.db - } - fn reducers(&self) -> &Self::Reducers { - &self.reducers - } - fn procedures(&self) -> &Self::Procedures { - &self.procedures - } - - fn is_active(&self) -> bool { - self.imp.is_active() - } - - fn disconnect(&self) -> __sdk::Result<()> { - self.imp.disconnect() - } - - type SubscriptionBuilder = __sdk::SubscriptionBuilder; - - fn subscription_builder(&self) -> Self::SubscriptionBuilder { - __sdk::SubscriptionBuilder::new(&self.imp) - } - - fn try_identity(&self) -> Option<__sdk::Identity> { - self.imp.try_identity() - } - fn connection_id(&self) -> __sdk::ConnectionId { - self.imp.connection_id() - } - fn try_connection_id(&self) -> Option<__sdk::ConnectionId> { - self.imp.try_connection_id() - } -} - -impl __sdk::ReducerEventContext for ReducerEventContext {} - -/// An [`__sdk::DbContext`] passed to procedure callbacks. -pub struct ProcedureEventContext { - /// Access to tables defined by the module via extension traits implemented for [`RemoteTables`]. - pub db: RemoteTables, - /// Access to reducers defined by the module via extension traits implemented for [`RemoteReducers`]. - pub reducers: RemoteReducers, - /// Access to procedures defined by the module via extension traits implemented for [`RemoteProcedures`]. - pub procedures: RemoteProcedures, - imp: __sdk::DbContextImpl, -} - -impl __sdk::AbstractEventContext for ProcedureEventContext { - type Event = (); - fn event(&self) -> &Self::Event { - &() - } - fn new(imp: __sdk::DbContextImpl, _event: Self::Event) -> Self { - Self { - db: RemoteTables { imp: imp.clone() }, - reducers: RemoteReducers { imp: imp.clone() }, - procedures: RemoteProcedures { imp: imp.clone() }, - imp, - } - } -} - -impl __sdk::InModule for ProcedureEventContext { - type Module = RemoteModule; -} - -impl __sdk::DbContext for ProcedureEventContext { - type DbView = RemoteTables; - type Reducers = RemoteReducers; - type Procedures = RemoteProcedures; - - fn db(&self) -> &Self::DbView { - &self.db - } - fn reducers(&self) -> &Self::Reducers { - &self.reducers - } - fn procedures(&self) -> &Self::Procedures { - &self.procedures - } - - fn is_active(&self) -> bool { - self.imp.is_active() - } - - fn disconnect(&self) -> __sdk::Result<()> { - self.imp.disconnect() - } - - type SubscriptionBuilder = __sdk::SubscriptionBuilder; - - fn subscription_builder(&self) -> Self::SubscriptionBuilder { - __sdk::SubscriptionBuilder::new(&self.imp) - } - - fn try_identity(&self) -> Option<__sdk::Identity> { - self.imp.try_identity() - } - fn connection_id(&self) -> __sdk::ConnectionId { - self.imp.connection_id() - } - fn try_connection_id(&self) -> Option<__sdk::ConnectionId> { - self.imp.try_connection_id() - } -} - -impl __sdk::ProcedureEventContext for ProcedureEventContext {} - -/// An [`__sdk::DbContext`] passed to [`__sdk::SubscriptionBuilder::on_applied`] and [`SubscriptionHandle::unsubscribe_then`] callbacks. -pub struct SubscriptionEventContext { - /// Access to tables defined by the module via extension traits implemented for [`RemoteTables`]. - pub db: RemoteTables, - /// Access to reducers defined by the module via extension traits implemented for [`RemoteReducers`]. - pub reducers: RemoteReducers, - /// Access to procedures defined by the module via extension traits implemented for [`RemoteProcedures`]. - pub procedures: RemoteProcedures, - imp: __sdk::DbContextImpl, -} - -impl __sdk::AbstractEventContext for SubscriptionEventContext { - type Event = (); - fn event(&self) -> &Self::Event { - &() - } - fn new(imp: __sdk::DbContextImpl, _event: Self::Event) -> Self { - Self { - db: RemoteTables { imp: imp.clone() }, - reducers: RemoteReducers { imp: imp.clone() }, - procedures: RemoteProcedures { imp: imp.clone() }, - imp, - } - } -} - -impl __sdk::InModule for SubscriptionEventContext { - type Module = RemoteModule; -} - -impl __sdk::DbContext for SubscriptionEventContext { - type DbView = RemoteTables; - type Reducers = RemoteReducers; - type Procedures = RemoteProcedures; - - fn db(&self) -> &Self::DbView { - &self.db - } - fn reducers(&self) -> &Self::Reducers { - &self.reducers - } - fn procedures(&self) -> &Self::Procedures { - &self.procedures - } - - fn is_active(&self) -> bool { - self.imp.is_active() - } - - fn disconnect(&self) -> __sdk::Result<()> { - self.imp.disconnect() - } - - type SubscriptionBuilder = __sdk::SubscriptionBuilder; - - fn subscription_builder(&self) -> Self::SubscriptionBuilder { - __sdk::SubscriptionBuilder::new(&self.imp) - } - - fn try_identity(&self) -> Option<__sdk::Identity> { - self.imp.try_identity() - } - fn connection_id(&self) -> __sdk::ConnectionId { - self.imp.connection_id() - } - fn try_connection_id(&self) -> Option<__sdk::ConnectionId> { - self.imp.try_connection_id() - } -} - -impl __sdk::SubscriptionEventContext for SubscriptionEventContext {} - -/// An [`__sdk::DbContext`] augmented with a [`__sdk::Error`], -/// passed to [`__sdk::DbConnectionBuilder::on_disconnect`], [`__sdk::DbConnectionBuilder::on_connect_error`] and [`__sdk::SubscriptionBuilder::on_error`] callbacks. -pub struct ErrorContext { - /// Access to tables defined by the module via extension traits implemented for [`RemoteTables`]. - pub db: RemoteTables, - /// Access to reducers defined by the module via extension traits implemented for [`RemoteReducers`]. - pub reducers: RemoteReducers, - /// Access to procedures defined by the module via extension traits implemented for [`RemoteProcedures`]. - pub procedures: RemoteProcedures, - /// The event which caused these callbacks to run. - pub event: Option<__sdk::Error>, - imp: __sdk::DbContextImpl, -} - -impl __sdk::AbstractEventContext for ErrorContext { - type Event = Option<__sdk::Error>; - fn event(&self) -> &Self::Event { - &self.event - } - fn new(imp: __sdk::DbContextImpl, event: Self::Event) -> Self { - Self { - db: RemoteTables { imp: imp.clone() }, - reducers: RemoteReducers { imp: imp.clone() }, - procedures: RemoteProcedures { imp: imp.clone() }, - event, - imp, - } - } -} - -impl __sdk::InModule for ErrorContext { - type Module = RemoteModule; -} - -impl __sdk::DbContext for ErrorContext { - type DbView = RemoteTables; - type Reducers = RemoteReducers; - type Procedures = RemoteProcedures; - - fn db(&self) -> &Self::DbView { - &self.db - } - fn reducers(&self) -> &Self::Reducers { - &self.reducers - } - fn procedures(&self) -> &Self::Procedures { - &self.procedures - } - - fn is_active(&self) -> bool { - self.imp.is_active() - } - - fn disconnect(&self) -> __sdk::Result<()> { - self.imp.disconnect() - } - - type SubscriptionBuilder = __sdk::SubscriptionBuilder; - - fn subscription_builder(&self) -> Self::SubscriptionBuilder { - __sdk::SubscriptionBuilder::new(&self.imp) - } - - fn try_identity(&self) -> Option<__sdk::Identity> { - self.imp.try_identity() - } - fn connection_id(&self) -> __sdk::ConnectionId { - self.imp.connection_id() - } - fn try_connection_id(&self) -> Option<__sdk::ConnectionId> { - self.imp.try_connection_id() - } -} - -impl __sdk::ErrorContext for ErrorContext {} - -impl __sdk::SpacetimeModule for RemoteModule { - type DbConnection = DbConnection; - type EventContext = EventContext; - type ReducerEventContext = ReducerEventContext; - type ProcedureEventContext = ProcedureEventContext; - type SubscriptionEventContext = SubscriptionEventContext; - type ErrorContext = ErrorContext; - type Reducer = Reducer; - type DbView = RemoteTables; - type Reducers = RemoteReducers; - type Procedures = RemoteProcedures; - type DbUpdate = DbUpdate; - type AppliedDiff<'r> = AppliedDiff<'r>; - type SubscriptionHandle = SubscriptionHandle; - type QueryBuilder = __sdk::QueryBuilder; - - fn register_tables(client_cache: &mut __sdk::ClientCache) { - activities_table::register_table(client_cache); - daily_task_table::register_table(client_cache); - daily_task_log_table::register_table(client_cache); - log_events_table::register_table(client_cache); - profiles_table::register_table(client_cache); - task_part_table::register_table(client_cache); - tasks_table::register_table(client_cache); - thoughts_table::register_table(client_cache); - } - const ALL_TABLE_NAMES: &'static [&'static str] = &[ - "activities", - "daily_task", - "daily_task_log", - "log_events", - "profiles", - "task_part", - "tasks", - "thoughts", - ]; -} diff --git a/marts/generated/src/spacetime/next_action_reducer.rs b/marts/generated/src/spacetime/next_action_reducer.rs deleted file mode 100644 index 6d0ea6f..0000000 --- a/marts/generated/src/spacetime/next_action_reducer.rs +++ /dev/null @@ -1,74 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::action_type::Action; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub(super) struct NextActionArgs { - pub break_flag: bool, - pub action: Option, -} - -impl From for super::Reducer { - fn from(args: NextActionArgs) -> Self { - Self::NextAction { - break_flag: args.break_flag, - action: args.action, - } - } -} - -impl __sdk::InModule for NextActionArgs { - type Module = super::RemoteModule; -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the reducer `next_action`. -/// -/// Implemented for [`super::RemoteReducers`]. -pub trait next_action { - /// Request that the remote module invoke the reducer `next_action` to run as soon as possible. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and this method provides no way to listen for its completion status. - /// /// Use [`next_action:next_action_then`] to run a callback after the reducer completes. - fn next_action(&self, break_flag: bool, action: Option) -> __sdk::Result<()> { - self.next_action_then(break_flag, action, |_, _| {}) - } - - /// Request that the remote module invoke the reducer `next_action` to run as soon as possible, - /// registering `callback` to run when we are notified that the reducer completed. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and its status can be observed with the `callback`. - fn next_action_then( - &self, - break_flag: bool, - action: Option, - - callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) - + Send - + 'static, - ) -> __sdk::Result<()>; -} - -impl next_action for super::RemoteReducers { - fn next_action_then( - &self, - break_flag: bool, - action: Option, - - callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) - + Send - + 'static, - ) -> __sdk::Result<()> { - self.imp - .invoke_reducer_with_callback(NextActionArgs { break_flag, action }, callback) - } -} diff --git a/marts/generated/src/spacetime/profile_type.rs b/marts/generated/src/spacetime/profile_type.rs deleted file mode 100644 index c6d2fba..0000000 --- a/marts/generated/src/spacetime/profile_type.rs +++ /dev/null @@ -1,54 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct Profile { - pub identity: __sdk::Identity, - pub username: String, -} - -impl __sdk::InModule for Profile { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `Profile`. -/// -/// Provides typed access to columns for query building. -pub struct ProfileCols { - pub identity: __sdk::__query_builder::Col, - pub username: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for Profile { - type Cols = ProfileCols; - fn cols(table_name: &'static str) -> Self::Cols { - ProfileCols { - identity: __sdk::__query_builder::Col::new(table_name, "identity"), - username: __sdk::__query_builder::Col::new(table_name, "username"), - } - } -} - -/// Indexed column accessor struct for the table `Profile`. -/// -/// Provides typed access to indexed columns for query building. -pub struct ProfileIxCols { - pub identity: __sdk::__query_builder::IxCol, - pub username: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for Profile { - type IxCols = ProfileIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - ProfileIxCols { - identity: __sdk::__query_builder::IxCol::new(table_name, "identity"), - username: __sdk::__query_builder::IxCol::new(table_name, "username"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for Profile {} diff --git a/marts/generated/src/spacetime/profiles_table.rs b/marts/generated/src/spacetime/profiles_table.rs deleted file mode 100644 index 1f46b98..0000000 --- a/marts/generated/src/spacetime/profiles_table.rs +++ /dev/null @@ -1,192 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::profile_type::Profile; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `profiles`. -/// -/// Obtain a handle from the [`ProfilesTableAccess::profiles`] method on [`super::RemoteTables`], -/// like `ctx.db.profiles()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.profiles().on_insert(...)`. -pub struct ProfilesTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `profiles`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait ProfilesTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`ProfilesTableHandle`], which mediates access to the table `profiles`. - fn profiles(&self) -> ProfilesTableHandle<'_>; -} - -impl ProfilesTableAccess for super::RemoteTables { - fn profiles(&self) -> ProfilesTableHandle<'_> { - ProfilesTableHandle { - imp: self.imp.get_table::("profiles"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct ProfilesInsertCallbackId(__sdk::CallbackId); -pub struct ProfilesDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::Table for ProfilesTableHandle<'ctx> { - type Row = Profile; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = ProfilesInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> ProfilesInsertCallbackId { - ProfilesInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: ProfilesInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = ProfilesDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> ProfilesDeleteCallbackId { - ProfilesDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: ProfilesDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct ProfilesUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for ProfilesTableHandle<'ctx> { - type UpdateCallbackId = ProfilesUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> ProfilesUpdateCallbackId { - ProfilesUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: ProfilesUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `identity` unique index on the table `profiles`, -/// which allows point queries on the field of the same name -/// via the [`ProfilesIdentityUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.profiles().identity().find(...)`. -pub struct ProfilesIdentityUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> ProfilesTableHandle<'ctx> { - /// Get a handle on the `identity` unique index on the table `profiles`. - pub fn identity(&self) -> ProfilesIdentityUnique<'ctx> { - ProfilesIdentityUnique { - imp: self - .imp - .get_unique_constraint::<__sdk::Identity>("identity"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> ProfilesIdentityUnique<'ctx> { - /// Find the subscribed row whose `identity` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &__sdk::Identity) -> Option { - self.imp.find(col_val) - } -} - -/// Access to the `username` unique index on the table `profiles`, -/// which allows point queries on the field of the same name -/// via the [`ProfilesUsernameUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.profiles().username().find(...)`. -pub struct ProfilesUsernameUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> ProfilesTableHandle<'ctx> { - /// Get a handle on the `username` unique index on the table `profiles`. - pub fn username(&self) -> ProfilesUsernameUnique<'ctx> { - ProfilesUsernameUnique { - imp: self.imp.get_unique_constraint::("username"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> ProfilesUsernameUnique<'ctx> { - /// Find the subscribed row whose `username` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &String) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("profiles"); - _table.add_unique_constraint::<__sdk::Identity>("identity", |row| &row.identity); - _table.add_unique_constraint::("username", |row| &row.username); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `Profile`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait profilesQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `Profile`. - fn profiles(&self) -> __sdk::__query_builder::Table; -} - -impl profilesQueryTableAccess for __sdk::QueryTableAccessor { - fn profiles(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("profiles") - } -} diff --git a/marts/generated/src/spacetime/remove_activity_reducer.rs b/marts/generated/src/spacetime/remove_activity_reducer.rs deleted file mode 100644 index ef22a7c..0000000 --- a/marts/generated/src/spacetime/remove_activity_reducer.rs +++ /dev/null @@ -1,70 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::activity_type::Activity; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub(super) struct RemoveActivityArgs { - pub activity: Activity, -} - -impl From for super::Reducer { - fn from(args: RemoveActivityArgs) -> Self { - Self::RemoveActivity { - activity: args.activity, - } - } -} - -impl __sdk::InModule for RemoveActivityArgs { - type Module = super::RemoteModule; -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the reducer `remove_activity`. -/// -/// Implemented for [`super::RemoteReducers`]. -pub trait remove_activity { - /// Request that the remote module invoke the reducer `remove_activity` to run as soon as possible. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and this method provides no way to listen for its completion status. - /// /// Use [`remove_activity:remove_activity_then`] to run a callback after the reducer completes. - fn remove_activity(&self, activity: Activity) -> __sdk::Result<()> { - self.remove_activity_then(activity, |_, _| {}) - } - - /// Request that the remote module invoke the reducer `remove_activity` to run as soon as possible, - /// registering `callback` to run when we are notified that the reducer completed. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and its status can be observed with the `callback`. - fn remove_activity_then( - &self, - activity: Activity, - - callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) - + Send - + 'static, - ) -> __sdk::Result<()>; -} - -impl remove_activity for super::RemoteReducers { - fn remove_activity_then( - &self, - activity: Activity, - - callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) - + Send - + 'static, - ) -> __sdk::Result<()> { - self.imp - .invoke_reducer_with_callback(RemoveActivityArgs { activity }, callback) - } -} diff --git a/marts/generated/src/spacetime/set_activity_name_reducer.rs b/marts/generated/src/spacetime/set_activity_name_reducer.rs deleted file mode 100644 index 784650d..0000000 --- a/marts/generated/src/spacetime/set_activity_name_reducer.rs +++ /dev/null @@ -1,72 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub(super) struct SetActivityNameArgs { - pub id: u64, - pub name: String, -} - -impl From for super::Reducer { - fn from(args: SetActivityNameArgs) -> Self { - Self::SetActivityName { - id: args.id, - name: args.name, - } - } -} - -impl __sdk::InModule for SetActivityNameArgs { - type Module = super::RemoteModule; -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the reducer `set_activity_name`. -/// -/// Implemented for [`super::RemoteReducers`]. -pub trait set_activity_name { - /// Request that the remote module invoke the reducer `set_activity_name` to run as soon as possible. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and this method provides no way to listen for its completion status. - /// /// Use [`set_activity_name:set_activity_name_then`] to run a callback after the reducer completes. - fn set_activity_name(&self, id: u64, name: String) -> __sdk::Result<()> { - self.set_activity_name_then(id, name, |_, _| {}) - } - - /// Request that the remote module invoke the reducer `set_activity_name` to run as soon as possible, - /// registering `callback` to run when we are notified that the reducer completed. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and its status can be observed with the `callback`. - fn set_activity_name_then( - &self, - id: u64, - name: String, - - callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) - + Send - + 'static, - ) -> __sdk::Result<()>; -} - -impl set_activity_name for super::RemoteReducers { - fn set_activity_name_then( - &self, - id: u64, - name: String, - - callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) - + Send - + 'static, - ) -> __sdk::Result<()> { - self.imp - .invoke_reducer_with_callback(SetActivityNameArgs { id, name }, callback) - } -} diff --git a/marts/generated/src/spacetime/task_part_table.rs b/marts/generated/src/spacetime/task_part_table.rs deleted file mode 100644 index a9ecce8..0000000 --- a/marts/generated/src/spacetime/task_part_table.rs +++ /dev/null @@ -1,162 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::action_type::Action; -use super::task_part_type::TaskPart; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `task_part`. -/// -/// Obtain a handle from the [`TaskPartTableAccess::task_part`] method on [`super::RemoteTables`], -/// like `ctx.db.task_part()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.task_part().on_insert(...)`. -pub struct TaskPartTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `task_part`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait TaskPartTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`TaskPartTableHandle`], which mediates access to the table `task_part`. - fn task_part(&self) -> TaskPartTableHandle<'_>; -} - -impl TaskPartTableAccess for super::RemoteTables { - fn task_part(&self) -> TaskPartTableHandle<'_> { - TaskPartTableHandle { - imp: self.imp.get_table::("task_part"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct TaskPartInsertCallbackId(__sdk::CallbackId); -pub struct TaskPartDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::Table for TaskPartTableHandle<'ctx> { - type Row = TaskPart; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = TaskPartInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> TaskPartInsertCallbackId { - TaskPartInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: TaskPartInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = TaskPartDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> TaskPartDeleteCallbackId { - TaskPartDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: TaskPartDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct TaskPartUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for TaskPartTableHandle<'ctx> { - type UpdateCallbackId = TaskPartUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> TaskPartUpdateCallbackId { - TaskPartUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: TaskPartUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `identity` unique index on the table `task_part`, -/// which allows point queries on the field of the same name -/// via the [`TaskPartIdentityUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.task_part().identity().find(...)`. -pub struct TaskPartIdentityUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> TaskPartTableHandle<'ctx> { - /// Get a handle on the `identity` unique index on the table `task_part`. - pub fn identity(&self) -> TaskPartIdentityUnique<'ctx> { - TaskPartIdentityUnique { - imp: self - .imp - .get_unique_constraint::<__sdk::Identity>("identity"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> TaskPartIdentityUnique<'ctx> { - /// Find the subscribed row whose `identity` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &__sdk::Identity) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("task_part"); - _table.add_unique_constraint::<__sdk::Identity>("identity", |row| &row.identity); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `TaskPart`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait task_partQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `TaskPart`. - fn task_part(&self) -> __sdk::__query_builder::Table; -} - -impl task_partQueryTableAccess for __sdk::QueryTableAccessor { - fn task_part(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("task_part") - } -} diff --git a/marts/generated/src/spacetime/task_part_type.rs b/marts/generated/src/spacetime/task_part_type.rs deleted file mode 100644 index 2111c1a..0000000 --- a/marts/generated/src/spacetime/task_part_type.rs +++ /dev/null @@ -1,60 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::action_type::Action; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct TaskPart { - pub identity: __sdk::Identity, - pub start_of_current: __sdk::Timestamp, - pub current: Action, - pub upcoming: Vec, -} - -impl __sdk::InModule for TaskPart { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `TaskPart`. -/// -/// Provides typed access to columns for query building. -pub struct TaskPartCols { - pub identity: __sdk::__query_builder::Col, - pub start_of_current: __sdk::__query_builder::Col, - pub current: __sdk::__query_builder::Col, - pub upcoming: __sdk::__query_builder::Col>, -} - -impl __sdk::__query_builder::HasCols for TaskPart { - type Cols = TaskPartCols; - fn cols(table_name: &'static str) -> Self::Cols { - TaskPartCols { - identity: __sdk::__query_builder::Col::new(table_name, "identity"), - start_of_current: __sdk::__query_builder::Col::new(table_name, "start_of_current"), - current: __sdk::__query_builder::Col::new(table_name, "current"), - upcoming: __sdk::__query_builder::Col::new(table_name, "upcoming"), - } - } -} - -/// Indexed column accessor struct for the table `TaskPart`. -/// -/// Provides typed access to indexed columns for query building. -pub struct TaskPartIxCols { - pub identity: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for TaskPart { - type IxCols = TaskPartIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - TaskPartIxCols { - identity: __sdk::__query_builder::IxCol::new(table_name, "identity"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for TaskPart {} diff --git a/marts/generated/src/spacetime/task_type.rs b/marts/generated/src/spacetime/task_type.rs deleted file mode 100644 index a6c9315..0000000 --- a/marts/generated/src/spacetime/task_type.rs +++ /dev/null @@ -1,58 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct Task { - pub id: u64, - pub done: bool, - pub name: String, - pub parent: Option, -} - -impl __sdk::InModule for Task { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `Task`. -/// -/// Provides typed access to columns for query building. -pub struct TaskCols { - pub id: __sdk::__query_builder::Col, - pub done: __sdk::__query_builder::Col, - pub name: __sdk::__query_builder::Col, - pub parent: __sdk::__query_builder::Col>, -} - -impl __sdk::__query_builder::HasCols for Task { - type Cols = TaskCols; - fn cols(table_name: &'static str) -> Self::Cols { - TaskCols { - id: __sdk::__query_builder::Col::new(table_name, "id"), - done: __sdk::__query_builder::Col::new(table_name, "done"), - name: __sdk::__query_builder::Col::new(table_name, "name"), - parent: __sdk::__query_builder::Col::new(table_name, "parent"), - } - } -} - -/// Indexed column accessor struct for the table `Task`. -/// -/// Provides typed access to indexed columns for query building. -pub struct TaskIxCols { - pub id: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for Task { - type IxCols = TaskIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - TaskIxCols { - id: __sdk::__query_builder::IxCol::new(table_name, "id"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for Task {} diff --git a/marts/generated/src/spacetime/tasks_table.rs b/marts/generated/src/spacetime/tasks_table.rs deleted file mode 100644 index 3d18b77..0000000 --- a/marts/generated/src/spacetime/tasks_table.rs +++ /dev/null @@ -1,159 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::task_type::Task; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `tasks`. -/// -/// Obtain a handle from the [`TasksTableAccess::tasks`] method on [`super::RemoteTables`], -/// like `ctx.db.tasks()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.tasks().on_insert(...)`. -pub struct TasksTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `tasks`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait TasksTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`TasksTableHandle`], which mediates access to the table `tasks`. - fn tasks(&self) -> TasksTableHandle<'_>; -} - -impl TasksTableAccess for super::RemoteTables { - fn tasks(&self) -> TasksTableHandle<'_> { - TasksTableHandle { - imp: self.imp.get_table::("tasks"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct TasksInsertCallbackId(__sdk::CallbackId); -pub struct TasksDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::Table for TasksTableHandle<'ctx> { - type Row = Task; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = TasksInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> TasksInsertCallbackId { - TasksInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: TasksInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = TasksDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> TasksDeleteCallbackId { - TasksDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: TasksDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct TasksUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for TasksTableHandle<'ctx> { - type UpdateCallbackId = TasksUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> TasksUpdateCallbackId { - TasksUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: TasksUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `id` unique index on the table `tasks`, -/// which allows point queries on the field of the same name -/// via the [`TasksIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.tasks().id().find(...)`. -pub struct TasksIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> TasksTableHandle<'ctx> { - /// Get a handle on the `id` unique index on the table `tasks`. - pub fn id(&self) -> TasksIdUnique<'ctx> { - TasksIdUnique { - imp: self.imp.get_unique_constraint::("id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> TasksIdUnique<'ctx> { - /// Find the subscribed row whose `id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &u64) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("tasks"); - _table.add_unique_constraint::("id", |row| &row.id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `Task`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait tasksQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `Task`. - fn tasks(&self) -> __sdk::__query_builder::Table; -} - -impl tasksQueryTableAccess for __sdk::QueryTableAccessor { - fn tasks(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("tasks") - } -} diff --git a/marts/generated/src/spacetime/test_procedure.rs b/marts/generated/src/spacetime/test_procedure.rs deleted file mode 100644 index adf8a32..0000000 --- a/marts/generated/src/spacetime/test_procedure.rs +++ /dev/null @@ -1,44 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -struct TestArgs {} - -impl __sdk::InModule for TestArgs { - type Module = super::RemoteModule; -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the procedure `test`. -/// -/// Implemented for [`super::RemoteProcedures`]. -pub trait test { - fn test(&self) { - self.test_then(|_, _| {}); - } - - fn test_then( - &self, - - __callback: impl FnOnce(&super::ProcedureEventContext, Result) - + Send - + 'static, - ); -} - -impl test for super::RemoteProcedures { - fn test_then( - &self, - - __callback: impl FnOnce(&super::ProcedureEventContext, Result) - + Send - + 'static, - ) { - self.imp - .invoke_procedure_with_callback::<_, String>("test", TestArgs {}, __callback); - } -} diff --git a/marts/generated/src/spacetime/thought_type.rs b/marts/generated/src/spacetime/thought_type.rs deleted file mode 100644 index 35e5997..0000000 --- a/marts/generated/src/spacetime/thought_type.rs +++ /dev/null @@ -1,60 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct Thought { - pub id: u64, - pub text: String, - pub user: __sdk::Identity, - pub time: __sdk::Timestamp, -} - -impl __sdk::InModule for Thought { - type Module = super::RemoteModule; -} - -/// Column accessor struct for the table `Thought`. -/// -/// Provides typed access to columns for query building. -pub struct ThoughtCols { - pub id: __sdk::__query_builder::Col, - pub text: __sdk::__query_builder::Col, - pub user: __sdk::__query_builder::Col, - pub time: __sdk::__query_builder::Col, -} - -impl __sdk::__query_builder::HasCols for Thought { - type Cols = ThoughtCols; - fn cols(table_name: &'static str) -> Self::Cols { - ThoughtCols { - id: __sdk::__query_builder::Col::new(table_name, "id"), - text: __sdk::__query_builder::Col::new(table_name, "text"), - user: __sdk::__query_builder::Col::new(table_name, "user"), - time: __sdk::__query_builder::Col::new(table_name, "time"), - } - } -} - -/// Indexed column accessor struct for the table `Thought`. -/// -/// Provides typed access to indexed columns for query building. -pub struct ThoughtIxCols { - pub id: __sdk::__query_builder::IxCol, - pub time: __sdk::__query_builder::IxCol, -} - -impl __sdk::__query_builder::HasIxCols for Thought { - type IxCols = ThoughtIxCols; - fn ix_cols(table_name: &'static str) -> Self::IxCols { - ThoughtIxCols { - id: __sdk::__query_builder::IxCol::new(table_name, "id"), - time: __sdk::__query_builder::IxCol::new(table_name, "time"), - } - } -} - -impl __sdk::__query_builder::CanBeLookupTable for Thought {} diff --git a/marts/generated/src/spacetime/thoughts_table.rs b/marts/generated/src/spacetime/thoughts_table.rs deleted file mode 100644 index 75c7868..0000000 --- a/marts/generated/src/spacetime/thoughts_table.rs +++ /dev/null @@ -1,159 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::thought_type::Thought; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `thoughts`. -/// -/// Obtain a handle from the [`ThoughtsTableAccess::thoughts`] method on [`super::RemoteTables`], -/// like `ctx.db.thoughts()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.thoughts().on_insert(...)`. -pub struct ThoughtsTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `thoughts`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait ThoughtsTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`ThoughtsTableHandle`], which mediates access to the table `thoughts`. - fn thoughts(&self) -> ThoughtsTableHandle<'_>; -} - -impl ThoughtsTableAccess for super::RemoteTables { - fn thoughts(&self) -> ThoughtsTableHandle<'_> { - ThoughtsTableHandle { - imp: self.imp.get_table::("thoughts"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct ThoughtsInsertCallbackId(__sdk::CallbackId); -pub struct ThoughtsDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::Table for ThoughtsTableHandle<'ctx> { - type Row = Thought; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = ThoughtsInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> ThoughtsInsertCallbackId { - ThoughtsInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: ThoughtsInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = ThoughtsDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> ThoughtsDeleteCallbackId { - ThoughtsDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: ThoughtsDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -pub struct ThoughtsUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for ThoughtsTableHandle<'ctx> { - type UpdateCallbackId = ThoughtsUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> ThoughtsUpdateCallbackId { - ThoughtsUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: ThoughtsUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -/// Access to the `id` unique index on the table `thoughts`, -/// which allows point queries on the field of the same name -/// via the [`ThoughtsIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.thoughts().id().find(...)`. -pub struct ThoughtsIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> ThoughtsTableHandle<'ctx> { - /// Get a handle on the `id` unique index on the table `thoughts`. - pub fn id(&self) -> ThoughtsIdUnique<'ctx> { - ThoughtsIdUnique { - imp: self.imp.get_unique_constraint::("id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> ThoughtsIdUnique<'ctx> { - /// Find the subscribed row whose `id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &u64) -> Option { - self.imp.find(col_val) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("thoughts"); - _table.add_unique_constraint::("id", |row| &row.id); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -#[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `Thought`. -/// -/// Implemented for [`__sdk::QueryTableAccessor`]. -pub trait thoughtsQueryTableAccess { - #[allow(non_snake_case)] - /// Get a query builder for the table `Thought`. - fn thoughts(&self) -> __sdk::__query_builder::Table; -} - -impl thoughtsQueryTableAccess for __sdk::QueryTableAccessor { - fn thoughts(&self) -> __sdk::__query_builder::Table { - __sdk::__query_builder::Table::new("thoughts") - } -} diff --git a/marts/generated/src/spacetime/update_activity_reducer.rs b/marts/generated/src/spacetime/update_activity_reducer.rs deleted file mode 100644 index 61624d7..0000000 --- a/marts/generated/src/spacetime/update_activity_reducer.rs +++ /dev/null @@ -1,70 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::activity_type::Activity; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub(super) struct UpdateActivityArgs { - pub activity: Activity, -} - -impl From for super::Reducer { - fn from(args: UpdateActivityArgs) -> Self { - Self::UpdateActivity { - activity: args.activity, - } - } -} - -impl __sdk::InModule for UpdateActivityArgs { - type Module = super::RemoteModule; -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the reducer `update_activity`. -/// -/// Implemented for [`super::RemoteReducers`]. -pub trait update_activity { - /// Request that the remote module invoke the reducer `update_activity` to run as soon as possible. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and this method provides no way to listen for its completion status. - /// /// Use [`update_activity:update_activity_then`] to run a callback after the reducer completes. - fn update_activity(&self, activity: Activity) -> __sdk::Result<()> { - self.update_activity_then(activity, |_, _| {}) - } - - /// Request that the remote module invoke the reducer `update_activity` to run as soon as possible, - /// registering `callback` to run when we are notified that the reducer completed. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and its status can be observed with the `callback`. - fn update_activity_then( - &self, - activity: Activity, - - callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) - + Send - + 'static, - ) -> __sdk::Result<()>; -} - -impl update_activity for super::RemoteReducers { - fn update_activity_then( - &self, - activity: Activity, - - callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) - + Send - + 'static, - ) -> __sdk::Result<()> { - self.imp - .invoke_reducer_with_callback(UpdateActivityArgs { activity }, callback) - } -} diff --git a/marts/generated/src/spacetime/update_upcoming_reducer.rs b/marts/generated/src/spacetime/update_upcoming_reducer.rs deleted file mode 100644 index 07b3122..0000000 --- a/marts/generated/src/spacetime/update_upcoming_reducer.rs +++ /dev/null @@ -1,70 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::action_type::Action; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub(super) struct UpdateUpcomingArgs { - pub upcoming: Vec, -} - -impl From for super::Reducer { - fn from(args: UpdateUpcomingArgs) -> Self { - Self::UpdateUpcoming { - upcoming: args.upcoming, - } - } -} - -impl __sdk::InModule for UpdateUpcomingArgs { - type Module = super::RemoteModule; -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the reducer `update_upcoming`. -/// -/// Implemented for [`super::RemoteReducers`]. -pub trait update_upcoming { - /// Request that the remote module invoke the reducer `update_upcoming` to run as soon as possible. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and this method provides no way to listen for its completion status. - /// /// Use [`update_upcoming:update_upcoming_then`] to run a callback after the reducer completes. - fn update_upcoming(&self, upcoming: Vec) -> __sdk::Result<()> { - self.update_upcoming_then(upcoming, |_, _| {}) - } - - /// Request that the remote module invoke the reducer `update_upcoming` to run as soon as possible, - /// registering `callback` to run when we are notified that the reducer completed. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and its status can be observed with the `callback`. - fn update_upcoming_then( - &self, - upcoming: Vec, - - callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) - + Send - + 'static, - ) -> __sdk::Result<()>; -} - -impl update_upcoming for super::RemoteReducers { - fn update_upcoming_then( - &self, - upcoming: Vec, - - callback: impl FnOnce(&super::ReducerEventContext, Result, __sdk::InternalError>) - + Send - + 'static, - ) -> __sdk::Result<()> { - self.imp - .invoke_reducer_with_callback(UpdateUpcomingArgs { upcoming }, callback) - } -} diff --git a/marts/package.json b/marts/package.json deleted file mode 100644 index b3e1fab..0000000 --- a/marts/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "@ppc/marts", - "version": "1.0.0", - "keywords": [], - "author": "", - "license": "ISC", - "dependencies": { - "@flowershow/remark-wiki-link": "^3.4.0", - "builtin-modules": "^5.0.0", - "esbuild": "^0.27.3", - "mdast": "^3.0.0", - "obsidian": "^1.12.3", - "remark-frontmatter": "^5.0.0", - "remark-gfm": "^4.0.1", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "typescript": "^5.9.3", - "unified": "^11.0.5", - "unist-util-visit": "^5.1.0" - } -} diff --git a/marts/spacetime/Cargo.toml b/marts/spacetime/Cargo.toml deleted file mode 100644 index 588d170..0000000 --- a/marts/spacetime/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "mize-spacetime" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -crate-type = ["cdylib"] - -[dependencies] -spacetimedb = { version = "2.4.0", features = ["unstable"] } -log = "0.4" -chrono = { version = "0.4.45", features = [], default-features = false } -chrono-tz = { version = "0.10.4", default-features = false } -url = "2.5.8" diff --git a/marts/spacetime/src/lib.rs b/marts/spacetime/src/lib.rs deleted file mode 100644 index 2f128f1..0000000 --- a/marts/spacetime/src/lib.rs +++ /dev/null @@ -1,394 +0,0 @@ -use std::collections::HashMap; -use std::time::Duration; - -use chrono::{DateTime, TimeZone}; -use chrono_tz::Europe; -use log::*; -use spacetimedb::SpacetimeType; -use spacetimedb::sys::raw::index_id_from_name; -use spacetimedb::{Identity, ReducerContext, ProcedureContext, Table, Timestamp, reducer, table, procedure}; -use spacetimedb::http::*; - -#[table(accessor = profiles, public)] -pub struct Profile { - #[primary_key] - identity: Identity, - #[unique] - username: String, -} - -#[table(accessor = task_part, public)] -pub struct TaskPart { - #[primary_key] - identity: Identity, - start_of_current: Timestamp, - current: Action, - upcoming: Vec, -} - -#[table(accessor = activities, public)] -pub struct Activity { - #[primary_key] - #[auto_inc] - id: u64, - name: String, - task: Option, - parents_ids: Vec, -} - -#[table(accessor = tasks, public)] -pub struct Task { - #[primary_key] - #[auto_inc] - id: u64, - done: bool, - name: String, - parent: Option, -} - -#[table(accessor = thoughts, public)] -pub struct Thought { - #[primary_key] - #[auto_inc] - id: u64, - text: String, - user: Identity, - #[index(btree)] - time: Timestamp, -} - -#[table(accessor = action)] -#[derive(Clone)] -pub struct Action { - name: String, - activity: Option, - task: Option, - start: Option, - end: Option, - duration: Option, -} - -impl Action { - pub fn name_only(name: String) -> Self { - Action { - name, - activity: None, - task: None, - start: None, - end: None, - duration: None, - } - } -} - -#[reducer] -pub fn add_thought(ctx: &ReducerContext, thought: String) -> Result<(), String> { - ctx.db.thoughts().try_insert(Thought { - id: 0, - text: thought, - user: ctx.sender(), - time: ctx.timestamp, - })?; - Ok(()) -} - -#[table(accessor = log_events, public, index(accessor = log_events_index, btree(columns = [user, end])))] -pub struct LogEvent { - #[primary_key] - #[auto_inc] - id: u64, - start: Timestamp, - end: Timestamp, - action: Action, - user: Identity, -} - -#[reducer(init)] -pub fn init(_ctx: &ReducerContext) { - // Called when the module is initially published - info!("hiiiiiii from ppc module"); -} - -// the one from ppc, hardcoded rn, as we for now only support config at run time. -// this needs to be loaded at build time. (this code runs as a wasm module on the spacetimedb server) -const PPC_AUTH_CLIENT_ID: &str = "363331597203734531"; - -#[reducer(client_connected)] -pub fn connect(ctx: &ReducerContext) -> Result<(), String> { - check_auth(ctx)?; - info!("hooooo"); - - // add user - let _ = ctx.db.profiles().try_insert(Profile { - identity: ctx.sender(), - username: ctx.sender().to_string(), - }); - Ok(()) -} - -fn check_auth(ctx: &ReducerContext) -> Result<(), String> { - let jwt = ctx - .sender_auth() - .jwt() - .ok_or("Authentication required".to_string())?; - if jwt.issuer() != "https://auth.ppc.social" { - return Err("Invalid issuer".to_string()); - } - - if !jwt.audience().iter().any(|a| a == PPC_AUTH_CLIENT_ID) { - return Err("Invalid audience".to_string()); - } - Ok(()) -} - -#[reducer(client_disconnected)] -pub fn identity_disconnected(_ctx: &ReducerContext) { - // Called everytime a client disconnects -} - -#[reducer] -pub fn add_activity(ctx: &ReducerContext, name: String) { - ctx.db.activities().insert(Activity { - name, - task: None, - id: 0, // auto-increments - parents_ids: Vec::new(), - }); -} - -#[reducer] -pub fn set_activity_name(ctx: &ReducerContext, id: u64, name: String) { - if let Some(old_ac) = ctx.db.activities().id().find(id) { - ctx.db.activities().id().update(Activity { name, ..old_ac }); - } else { - return (); - } -} - -#[reducer] -pub fn update_upcoming(ctx: &ReducerContext, upcoming: Vec) { - if ctx.db.task_part().identity().find(ctx.sender()).is_none() { - ctx.db.task_part().insert(TaskPart { - upcoming, - identity: ctx.sender(), - current: Action { - name: "filler".to_string(), - activity: None, - task: None, - start: None, - end: None, - duration: None, - }, - start_of_current: ctx.timestamp, - }); - } else { - ctx.db.task_part().identity().update(TaskPart { - upcoming, - ..ctx.db.task_part().identity().find(&ctx.sender()).unwrap() - }); - } -} - -#[reducer] -pub fn next_action(ctx: &ReducerContext, break_flag: bool, action: Option) -> Result<(), String> { - if let Some(mut task_part) = ctx.db.task_part().identity().find(&ctx.sender()) { - if task_part.upcoming.is_empty() { - return Err("No upcoming actions".to_string()); - } - let new_action = match action { - Some(action) => action, - // when we do "ppc nextAction -b" ... we want to do a generic break "b" action. - None => if break_flag { Action::name_only("idk".to_string()) } else { task_part.upcoming.remove(0) }, - }; - // when break flag, push current_action again to the front of upcoming - if break_flag { - // insert generic "b" action when no one is specified - task_part.upcoming.insert(0, task_part.current.clone()); - } - let start_of_old_action = task_part.start_of_current; - ctx.db.task_part().identity().update(TaskPart { - upcoming: task_part.upcoming, - identity: task_part.identity, - current: new_action.clone(), - start_of_current: ctx.timestamp, - }); - - // create log event - ctx.db.log_events().insert(LogEvent { - start: start_of_old_action, - end: ctx.timestamp, - action: task_part.current, - id: 0, - user: ctx.sender(), - }); - Ok(()) - } else { - Err("Task part data not found for this user".to_string()) - } -} - -#[reducer] -pub fn update_activity(ctx: &ReducerContext, activity: Activity) { - if activity.id == 0 { - ctx.db.activities().insert(activity); - } else { - ctx.db.activities().id().update(activity); - } -} - -#[reducer] -pub fn remove_activity(ctx: &ReducerContext, activity: Activity) { - ctx.db.activities().delete(activity); -} - - -//////////////////// daily metric /////////////////// - -#[table(accessor = daily_task, public)] -pub struct DailyTask { - id: i64, - name: String, - owner: Identity, -} - -#[table(accessor = daily_task_log, public)] -pub struct DailyTaskLog { - daily_task_id: i64, - done: Timestamp, -} - -#[procedure] -fn first_timetrack_date(ctx: &mut ProcedureContext, username: String) -> Result { - let timestamp = ctx.try_with_tx(|tx| { - let profile = tx.db.profiles().username().find(username.clone()).ok_or("No such Profile".to_string())?; - let event = tx.db.log_events() - .log_events_index() - .filter(&profile.identity) - .nth(0) - .ok_or("Profile has no row in log_events")?; - let time = event.start - .to_chrono_date_time().map_err(|e| format!("chrono error: {e}"))? - .with_timezone(&chrono_tz::Europe::Vienna); - Ok::(time.format("%Y-%m-%d").to_string()) - })?; - Ok(timestamp) -} - -#[procedure] -fn export_timetrack(ctx: &mut ProcedureContext, username: String, date: String) -> Result { - // CEST only rn - let start = chrono::NaiveDate::parse_from_str(&date, "%Y-%m-%d").unwrap().and_hms(5, 0, 0); - let start_local = chrono_tz::Europe::Vienna.from_local_datetime(&start).unwrap(); - let start_utc = start_local.with_timezone(&chrono::Utc); - let start_timestamp = Timestamp::from_micros_since_unix_epoch(start_utc.timestamp_micros()); - - let end = chrono::NaiveDate::parse_from_str(&date, "%Y-%m-%d").unwrap().and_hms(4, 0, 0) + Duration::from_hours(24); - let end_local = chrono_tz::Europe::Vienna.from_local_datetime(&end).unwrap(); - let end_utc = end_local.with_timezone(&chrono::Utc); - let end_timestamp = Timestamp::from_micros_since_unix_epoch(end_utc.timestamp_micros()); - - info!("start_of_day: {}", start_timestamp); - info!("end_of_day: {}", end_timestamp); - - let mut export = String::new(); - //export.push_str(&format!("### actions\n")); - - let profile = ctx.with_tx(|tx| tx.db.profiles().username().find(&username)).ok_or(format!("Profile with username {} not found", username))?; - - let events = ctx.with_tx(|tx| - tx.db.log_events() - .log_events_index() - .filter((profile.identity, start_timestamp..end_timestamp)) - ); - for event in events { - let start = event.start - .to_chrono_date_time() - .map_err(|err| err.to_string())? - .with_timezone(&Europe::Vienna) - .format("%H:%M"); - let end = event.end - .to_chrono_date_time() - .map_err(|err| err.to_string())? - .with_timezone(&Europe::Vienna) - .format("%H:%M"); - - let line = format!("{} to {} ... {}\n", start, end, event.action.name); - export.push_str(line.as_str()); - } - - return Ok(export); // don't do thoughts right now - - export.push_str("\n"); - export.push_str("## thoughts\n"); - let thoughts = ctx.with_tx(|tx| { - tx.db.thoughts().time().filter(start_timestamp..end_timestamp) - }); - for thought in thoughts { - let line = format!("- {}\n\n", thought.text); - export.push_str(line.as_str()); - } - - Ok(export) -} - - - #[procedure] -pub fn migrate(ctx: &mut ProcedureContext) -> String { - info!("migrate procedure called"); - //let msg = "Nothing to migrate".to_string(); - - let msg: Result = ctx.try_with_tx(|tx| { - let mut out = String::new(); - let mut count = 0; - //for event in tx.db.log_events_tmp().iter() { - //count += 1; - //} - out.push_str(format!("Migrated {} rows................", count).as_str()); - Ok(out) - }); - - return match msg { - Ok(msg) => msg, - Err(err) => err, - }; -} - -#[procedure] -pub fn test(ctx: &mut ProcedureContext) -> String { - let mut s = String::from("hoooooooooooooooooooooo\n"); - let a: String = ctx.with_tx(|_tx| { - let s = String::new(); - - - - - return s; - }); - s.push_str(&format!("{}\n\n", a)); - s.push_str("\n"); - s.push_str(&format!("sender: {}", ctx.sender())); - - s -} - -#[handler] -pub fn test_handler(ctx: &mut HandlerContext, _req: Request) -> Response { - let res = ctx.try_with_tx(|tx| { - let mut s = String::new(); - for a in tx.db.profiles().iter() { - s.push_str(&format!("{} ... {}\n", a.identity, a.username)); - } - s.push_str(&format!("sender: {}", tx.sender())); - return Ok(s); - }); - return Response::new(Body::from_bytes(match res { - Ok(body) => body, - Err(e) => e, - })); -} - -#[spacetimedb::http::router] -fn router() -> Router { - Router::new() - .get("/test", test_handler) -} diff --git a/marts/src/auth/client.rs b/marts/src/auth/client.rs deleted file mode 100644 index c85f810..0000000 --- a/marts/src/auth/client.rs +++ /dev/null @@ -1,677 +0,0 @@ -use chrono::{DateTime, TimeDelta, Utc}; -use mize::out; -use mize::{ - item::ItemData, mize_err, mize_part, Mize, MizeError, MizePart, MizePartCreate, MizeResult, -}; -use openidconnect::{ - ClientId, DeviceAuthorizationResponse, EmptyExtraDeviceAuthorizationFields, IssuerUrl, - OAuth2TokenResponse, RefreshToken, Scope, TokenResponse, -}; -use serde::{Deserialize, Serialize}; -use std::fs::OpenOptions; -use std::io::Write; -use std::{path::PathBuf, thread}; -use tracing::{info, warn}; - -// console_log macro -// that can be copied into other files for debugging purposes -#[cfg(feature = "target-obsidian")] -use wasm_bindgen::prelude::*; - -#[cfg(feature = "target-obsidian")] -#[wasm_bindgen] -extern "C" { - #[wasm_bindgen(js_namespace = console)] - fn log(s: &str); -} - -#[cfg(feature = "target-obsidian")] -macro_rules! console_log { - // Note that this is using the `log` function imported above during - // `bare_bones` - ($($t:tt)*) => (unsafe { log(&format_args!($($t)*).to_string())}) -} - -#[cfg(feature = "target-os")] -use clap::Command; - -#[derive(Default)] -#[mize_part] -pub struct ClientAuth { - mize: Mize, - secrets: Option, -} - -#[derive(Default, Serialize, Deserialize, Clone, Debug)] -pub struct ClientSecrets { - id_token: String, - access_token: String, - refresh_token: String, - expiry: DateTime, -} - -impl MizePartCreate for ClientAuth {} - -impl MizePart for ClientAuth { - fn name(&self) -> &'static str { - "client_auth" - } -} - -#[cfg(feature = "target-js")] -pub fn store_secrets_js(mize: &Mize, secrets: &ClientSecrets) -> MizeResult<()> { - use web_sys::window; - - // Serialize struct to JSON string - let serialized = serde_json::to_string(&secrets)?; - - // Get browser window object - let window = window().ok_or_else(|| mize_err!("No global window found"))?; - - // Access local storage - let storage = window - .local_storage().map_err(|_| mize_err!("couldn't get local_storage"))? - .ok_or_else(|| mize_err!("LocalStorage is not available"))?; - - // Store the JSON string - storage.set_item("mize_client_secrets", &serialized).map_err(|_| mize_err!("couldn't set item in local_storage"))?; - - Ok(()) -} - - -impl ClientAuth { - pub fn secrets(&self) -> Option<&ClientSecrets> { - self.secrets.as_ref() - } - - pub fn id_token(&self) -> MizeResult<&str> { - if self.secrets.is_none() { - return Err(mize_err!("Client not logged in")); - } - Ok(&self.secrets.as_ref().unwrap().id_token) - } - - pub fn access_token(&self) -> MizeResult<&str> { - if self.secrets.is_none() { - return Err(mize_err!("Client not logged in")); - } - Ok(&self.secrets.as_ref().unwrap().access_token) - } - - pub fn refresh_token(&self) -> MizeResult<&str> { - if self.secrets.is_none() { - return Err(mize_err!("Client not logged in")); - } - Ok(&self.secrets.as_ref().unwrap().refresh_token) - } - - pub fn refresh(&mut self) -> MizeResult<()> { - #[cfg(feature = "target-js")] { - console_log!("refresh is not implemented yet on wasm"); - } - - #[cfg(feature = "target-os")] { - let secrets = self.secrets.clone().ok_or(mize_err!( - "no client secrets, meaning client_auth.refresh() thread can't use the refresh token" - ))?; - let new_secrets = self.mize.spawn_async_blocking( - "auth.refresh_flow", - refresh_flow(self.mize.clone(), secrets), - )?; - store_secrets(&mut self.mize, &new_secrets)?; - self.secrets = Some(new_secrets); - } - - Ok(()) - } - - pub fn login(&mut self) -> MizeResult<()> { - #[cfg(feature = "target-os")] { - if self.secrets().is_none() { - let secrets = self - .mize - .spawn_async_blocking("auth.login_flow", auth_flow(self.mize.clone()))?; - store_secrets(&mut self.mize, &secrets)?; - self.secrets = Some(secrets); - } - } - #[cfg(feature = "target-js")] { - if self.secrets().is_none() { - let mut mize_clone = self.mize.clone(); - wasm_bindgen_futures::spawn_local(async move { - console_log!("before auth_flow"); - let secrets = match auth_flow(mize_clone.clone()).await { - Ok(secrets) => secrets, - Err(e) => { - mize_clone.report_err(e); - return (); - } - }; - console_log!("after auth_flow"); - if let Err(e) = store_secrets_js(&mut mize_clone, &secrets) { - mize_clone.report_err(e); - return (); - } - let mut auth = match mize_clone.get_part_native::("client_auth") { - Ok(auth) => auth, - Err(e) => { - mize_clone.report_err(e); - return (); - } - }; - auth.secrets = Some(secrets); - }); - } - } - Ok(()) - } - - pub fn start_refresh_thread(&mut self) -> MizeResult<()> { - - // background thread for os targets - #[cfg(not(feature = "target-js"))] - { - let mut mize_clone = self.mize.clone(); - self.mize.spawn_background("auth.refresh", move || loop { - info!("hi from auth.refresh thread..."); - thread::sleep(Duration::from_secs(33)); // TERRIBLE hack - let auth = mize_clone.get_part_native::("client_auth")?; - let expiry = auth.secrets.as_ref().unwrap().expiry.clone(); - info!("auth.refresh thread: now: {}", Utc::now()); - info!("auth.refresh thread: expiry: {}", expiry); - let to_sleep = expiry - Utc::now() - TimeDelta::minutes(20); - /* - if to_sleep < TimeDelta::from_std(Duration::from_secs(0))? { - if let Err(e) = auth.refresh() { - e.log(); - } - } - */ - drop(auth); - - info!("auth.refresh: thread going to sleep for: {}", to_sleep); - thread::sleep(to_sleep.to_std()?); - - info!("refresh_thread: sleeping done"); - let mut auth = mize_clone.get_part_native::("auth")?; - auth.refresh()?; - drop(auth); - })?; - Ok(()) - } - - // spawn an async background task doing the refresh - #[cfg(feature = "target-js")] { - use wasm_bindgen::prelude::*; - use wasm_bindgen_futures::JsFuture; - - // Get the window object - let window = web_sys::window().expect("no global `window` exists"); - - // Clone mize for the closure - let mize_clone = self.mize.clone(); - - // Create a closure that will be called periodically - let refresh_closure = Closure::wrap(Box::new(move || { - let mut mize_clone = mize_clone.clone(); - wasm_bindgen_futures::spawn_local(async move { - let mut auth = mize_clone.get_part_native::("client_auth"); - match auth { - Ok(mut auth_part) => { - if let Some(secrets) = auth_part.secrets() { - let now = Utc::now(); - let expiry = secrets.expiry; - let time_until_expiry = expiry - now; - - // Refresh if token will expire in less than 20 minutes - if time_until_expiry < TimeDelta::minutes(20) { - if let Err(e) = auth_part.refresh() { - console_log!("Error refreshing token: {:?}", e); - } else { - console_log!("Token refreshed successfully"); - } - } - } - } - Err(e) => { - console_log!("Error getting auth part: {:?}", e); - } - } - }); - }) as Box); - - // Set up interval to run every 50 minutes (300000 ms) - let interval_ms = 3000000; - let _ = window.set_interval_with_callback_and_timeout_and_arguments_0( - refresh_closure.as_ref().unchecked_ref(), - interval_ms, - ); - - // Leak the closure to prevent it from being dropped - refresh_closure.forget(); - - Ok(()) - } - } - -} - -pub fn part_client_auth(mize: &mut Mize) -> MizeResult<()> { - let mize_clone = mize.clone(); - - let mut auth_part = ClientAuth { - secrets: None, - mize: mize.clone(), - }; - - let secrets = match load_secrets(mize) { - Ok(secrets) => Some(secrets), - Err(err) => { - tracing::warn!("err reading secrets: {:?}", err); - None - } - }; - auth_part.secrets = secrets.clone(); - - // do a refresh if the tokens have expired - if secrets.is_some() && secrets.clone().unwrap().expiry < Utc::now() { - auth_part.refresh()?; - } - - - // start refresh tread if configured - if mize - .get_config("auth.client.refresh_thread") - .unwrap_or(ItemData::new()) - .value_bool() - .unwrap_or(false) - { - auth_part.start_refresh_thread()?; - } - - - // cli command for os - #[cfg(feature = "target-os")] { - let mut cli = mize.get_part_native::("cli")?; - cli.set_command("ppc"); - cli.subcommand(Command::new("login"), move |_, mut mize| { - let mut auth = mize.get_part_native::("client_auth")?; - let secrets = if auth.secrets.is_some() { - match mize.spawn_async_blocking( - "client_auth", - refresh_flow(mize.clone(), auth.secrets.clone().unwrap()), - ) { - Ok(secrets) => secrets, - Err(err) => { - out!("err refreshing secrets: {:?}", err); - mize.spawn_async_blocking("client_auth", auth_flow(mize_clone.clone()))? - } - } - } else { - mize.spawn_async_blocking("client_auth", auth_flow(mize_clone.clone()))? - }; - store_secrets(&mut mize, &secrets)?; - auth.secrets = Some(secrets); - Ok(()) - })?; - } - - - // register command for obsidian - #[cfg(feature = "target-obsidian")] { - use crate::MartsCommand; - console_log!("register obsidian command..."); - - let obsidian = mize.get_part_native::("obsidian")?; - obsidian.add_command(MartsCommand { - id: "mize-login".to_string(), - name: "Mize Login".to_string(), - callback: Box::new(|mut mize| { - let mut auth = mize.get_part_native::("client_auth")?; - let res = auth.login(); - console_log!("auth.login done: {:?}", res); - res - }), - })?; - } - - - auth_part.secrets = secrets; - - mize.register_part(Box::new(auth_part))?; - - Ok(()) -} - -fn load_secrets(mize: &mut Mize) -> MizeResult { - #[cfg(feature = "target-os")] { - let mize_dir = mize.get_config("data_dir")?.value_string()?; - let secrets_file_path = PathBuf::from(mize_dir).join("client_secrets.json"); - - let secrets_string = std::fs::read_to_string(secrets_file_path)?; - let secrets: ClientSecrets = serde_json::from_str(&secrets_string)?; - return Ok(secrets); - } - - #[cfg(feature = "target-js")] { - use web_sys::window; - - // Get browser window object - let window = window().ok_or_else(|| mize_err!("No global window found"))?; - - // Access local storage - let storage = window - .local_storage().map_err(|_| mize_err!("couldn't get local_storage"))? - .ok_or_else(|| mize_err!("LocalStorage is not available"))?; - - // Retrieve the string item - return match storage.get_item("mize_client_secrets").map_err(|_| mize_err!("couldn't get item from local_storage"))? { - Some(json_str) => { - // Deserialize JSON string back into Client struct - let secrets: ClientSecrets = serde_json::from_str(json_str.as_str())?; - Ok(secrets) - } - None => Err(mize_err!("no secrets")), // Key does not exist - } - } - -} - -fn store_secrets(mize: &mut Mize, secrets: &ClientSecrets) -> MizeResult<()> { - - #[cfg(feature = "target-os")] { - let mize_dir = mize.get_config("store")?.value_string()?; - let secrets_file_path = PathBuf::from(mize_dir.clone()) - .join("misc") - .join("client_secrets.json"); - std::fs::create_dir_all(PathBuf::from(mize_dir).join("misc"))?; - - let secrets_string = serde_json::to_string(secrets)?; - log::info!("secrets_file_path: {}", secrets_file_path.display()); - //std::fs::write(secrets_file_path, secrets_string)?; - OpenOptions::new() - .write(true) - .create(true) - .open(secrets_file_path)? - .write_all(&secrets_string.as_bytes())?; - - // update the spacetimedb_token in XDG_CONFIG_HOME/spacetime/cli.toml config file if configured to do so - if mize - .get_config("auth.client.update_spacetime_token") - .unwrap_or(ItemData::empty()) - .as_bool() - .unwrap_or(false) - { - update_spacetimedb_token(&secrets.id_token.as_str())?; - } - } - - - - Ok(()) -} - -use openidconnect::reqwest::Client as HttpClient; -use openidconnect::DeviceAuthorizationUrl; -use std::time::Duration; -//use wasm_bindgen::JsCast; - - -async fn refresh_flow(mut mize: Mize, old_secrets: ClientSecrets) -> MizeResult { - out!("Refresh flow..."); - let issuer = mize.get_config("auth.client.issuer")?.value_string()?; - let client_id = mize.get_config("auth.client.client_id")?.value_string()?; - - let issuer = IssuerUrl::new(issuer)?; - let client_id = ClientId::new(client_id); - - let http_client = HttpClient::new(); - - // Teach openidconnect-rs about the device authorization url. - #[derive(Clone, Debug, Deserialize, Serialize)] - struct MyExtraProviderMetadata { - device_authorization_endpoint: String, - } - use openidconnect::core::{ - CoreAuthDisplay, CoreClaimName, CoreClaimType, CoreClient, CoreClientAuthMethod, - CoreGrantType, CoreJsonWebKey, CoreJweContentEncryptionAlgorithm, - CoreJweKeyManagementAlgorithm, CoreResponseMode, CoreResponseType, - CoreSubjectIdentifierType, - }; - use openidconnect::AdditionalProviderMetadata; - use openidconnect::ProviderMetadata; - impl AdditionalProviderMetadata for MyExtraProviderMetadata {} - type MyProviderMetadata = ProviderMetadata< - MyExtraProviderMetadata, - CoreAuthDisplay, - CoreClientAuthMethod, - CoreClaimName, - CoreClaimType, - CoreGrantType, - CoreJweContentEncryptionAlgorithm, - CoreJweKeyManagementAlgorithm, - CoreJsonWebKey, - CoreResponseMode, - CoreResponseType, - CoreSubjectIdentifierType, - >; - - // Discover provider metadata - let provider_metadata: MyProviderMetadata = - MyProviderMetadata::discover_async(issuer, &http_client).await?; - - let device_auth_url = provider_metadata - .additional_metadata() - .device_authorization_endpoint - .clone(); - - let client = CoreClient::from_provider_metadata( - provider_metadata, - client_id, - None, // public client - ) - .set_device_authorization_url(DeviceAuthorizationUrl::new(device_auth_url)?); - - let refresh_token = RefreshToken::new(old_secrets.refresh_token); - let res = client - .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, - }); -} - -async fn auth_flow(mut mize: Mize) -> MizeResult { - let issuer = mize.get_config("auth.client.issuer")?.value_string()?; - let client_id = mize.get_config("auth.client.client_id")?.value_string()?; - - let issuer = IssuerUrl::new(issuer)?; - let client_id = ClientId::new(client_id); - - let http_client = HttpClient::new(); - - // Teach openidconnect-rs about the device authorization url. - #[derive(Clone, Debug, Deserialize, Serialize)] - struct MyExtraProviderMetadata { - device_authorization_endpoint: String, - } - use openidconnect::core::{ - CoreAuthDisplay, CoreClaimName, CoreClaimType, CoreClient, CoreClientAuthMethod, - CoreGrantType, CoreJsonWebKey, CoreJweContentEncryptionAlgorithm, - CoreJweKeyManagementAlgorithm, CoreResponseMode, CoreResponseType, - CoreSubjectIdentifierType, - }; - use openidconnect::AdditionalProviderMetadata; - use openidconnect::ProviderMetadata; - impl AdditionalProviderMetadata for MyExtraProviderMetadata {} - type MyProviderMetadata = ProviderMetadata< - MyExtraProviderMetadata, - CoreAuthDisplay, - CoreClientAuthMethod, - CoreClaimName, - CoreClaimType, - CoreGrantType, - CoreJweContentEncryptionAlgorithm, - CoreJweKeyManagementAlgorithm, - CoreJsonWebKey, - CoreResponseMode, - CoreResponseType, - CoreSubjectIdentifierType, - >; - - // Discover provider metadata - let provider_metadata: MyProviderMetadata = - MyProviderMetadata::discover_async(issuer, &http_client).await?; - - let device_auth_url = provider_metadata - .additional_metadata() - .device_authorization_endpoint - .clone(); - - let client = CoreClient::from_provider_metadata( - provider_metadata, - client_id, - None, // public client - ) - .set_device_authorization_url(DeviceAuthorizationUrl::new(device_auth_url)?); - - // ===== DEVICE AUTH REQUEST ===== - let details: Result, _> = - client - .exchange_device_code() - .add_scope(Scope::new("openid".into())) - .add_scope(Scope::new("profile".into())) - .add_scope(Scope::new("offline_access".into())) - .request_async(&http_client) - .await; - - let details = match details { - Ok(val) => val, - Err(err) => { - out!("err: {:?}", err); - out!("err: {}", err); - panic!(); - } - }; - - #[cfg(feature = "target-obsidian")] { - console_log!("details: {:?}", details); - use std::str::FromStr; - - use js_sys::{Array, Function, JsString, Reflect}; - use mize::error::IntoMizeResultJsValue; - use wasm_bindgen::convert::TryFromJsValue; - - let obsidian = mize.get_part_native::("obsidian")?; - let show_device_code = Reflect::get(&obsidian.plugin(), &JsValue::from_str("showDeviceCode")).mres()?; - let args = Array::new(); - args.push(&JsValue::from_str(details.user_code().secret().as_str())); - args.push(&JsValue::from_str(details.verification_uri_complete().unwrap().secret().as_str())); - - Reflect::apply(&show_device_code.dyn_into::().mres()?, obsidian.plugin(), &args).mres()?; - } - - #[cfg(feature = "target-os")] { - out!( - "If your browser does not open automatically, open this URL in it:\n{}\n", - details.verification_uri_complete().unwrap().secret() - ); - out!( - "Or enter this PPC login code:\n{}\n", - details.user_code().secret() - ); - - if let Some(_) = details.verification_uri_complete() { - let _ = webbrowser::open(details.verification_uri_complete().unwrap().secret()); - } - } - - let token_response = client - .exchange_device_access_token(&details)? - .request_async( - &http_client, - async |dur: Duration| { - #[cfg(feature = "target-os")] { - tokio::time::sleep(dur).await; - } - #[cfg(feature = "target-js")] { - console_log!("sleeping"); - use wasm_bindgen::prelude::*; - use wasm_bindgen_futures::JsFuture; - let promise = js_sys::Promise::new(&mut |resolve, _| { - web_sys::window() - .unwrap() - .set_timeout_with_callback_and_timeout_and_arguments_0(&resolve, dur.as_millis() as i32) - .unwrap(); - }); - - // Await the JS Promise like a Rust Future - let _ = JsFuture::from(promise).await; - - } - }, - None, - ) - .await?; - - - // ===== TOKENS ===== - let id_token = token_response - .extra_fields() - .id_token() - .ok_or(mize_err!("no id_token"))?; - - let refresh = token_response - .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, - }) -} - -fn update_spacetimedb_token(new_token: &str) -> MizeResult<()> { - // Resolve config directory - let config_dir = match std::env::var("XDG_CONFIG_HOME") { - Ok(val) => PathBuf::from(val), - Err(_) => { - let home = std::env::var("HOME")?; - std::path::PathBuf::from(home).join(".config") - } - }; - - let file_path = config_dir.join("spacetime").join("cli.toml"); - - if !file_path.exists() { - warn!("spacetime config file does not exist, not updating token there"); - return Ok(()); - }; - - // Read existing file (or create empty document if it doesn't exist) - let content = std::fs::read_to_string(&file_path).unwrap_or_default(); - let mut data = ItemData::from_toml(content.as_str())?; - - // Update the field - data.set_path("spacetimedb_token", new_token)?; - - // Write back - std::fs::write(&file_path, data.to_toml()?)?; - - Ok(()) -} diff --git a/marts/src/c2vi/dashboard.rs b/marts/src/c2vi/dashboard.rs deleted file mode 100644 index 2275afc..0000000 --- a/marts/src/c2vi/dashboard.rs +++ /dev/null @@ -1,9 +0,0 @@ -use dioxus::prelude::*; - -pub fn main() -> Element { - rsx! { - div { - h1 { "my dashbaord" } - } - } -} diff --git a/marts/src/c2vi/deno.ts b/marts/src/c2vi/deno.ts deleted file mode 100644 index a9412bb..0000000 --- a/marts/src/c2vi/deno.ts +++ /dev/null @@ -1,431 +0,0 @@ -import { createClient } from "@libsql/client"; -import { drizzle } from "drizzle-orm/libsql"; -import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core"; -import { eq } from "drizzle-orm"; -import fs from "node:fs"; -import path from "node:path"; -import os from "node:os"; -import { spawnSync } from "node:child_process"; - -export async function init(ppc: PPC) { - ppc.c2vi = new C2vi(ppc); - - ppc.cli - .command("bed", "command to run when c2vi goes to bed") - .action(async () => { - await save_habitica_dailies(ppc); - await save_habitica_logs(ppc); - }); - - ppc.cli - .command("clearTodos", "command to run when c2vi goes to bed") - .alias("clt") - .action(async () => { - const todos = await ppc.habitica.get_tasks(); - for (const todo of todos) { - await ppc.habitica.delete_task(todo.id); - } - }); - - ppc.cli - .command("listTodos", "command to run when c2vi goes to bed") - .alias("dut") - .action(async () => { - const todos = await ppc.habitica.get_tasks(); - for (const todo of todos) { - console.log(todo.text); - } - }); - - ppc.cli - .command("buyHealthPotion", "command to run when c2vi goes to bed") - .alias("buyh") - .action(async () => { - await ppc.habitica.api_request("POST", "/user/buy-health-potion"); - }); - - ppc.cli - .command("addActionItems", "command to run when c2vi goes to bed") - .alias("aal") - .action(async () => { - await add_action_items(ppc); - }); - - ppc.cli - .command("test", "a command to run some test code") - .alias("t") - .action(async () => {}); - - ppc.cli - .command("skip [num]", "command to skip a habitica todo") - .alias("sk") - .action((num = 1) => { - skip_habitica_todo(ppc, parseInt(num)); - }); - - ppc.cli.command("dumpLog", "dump the complete habitica log").action(() => { - dump_habitica_logs(ppc); - }); - - ppc.cli - .command("listDailies", "list all dailies") - .action(async (folder, options) => { - const allDailies = await ppc.c2vi.db.select().from(dailiesTable).all(); - for (const task of allDailies) { - console.log(task.id + ": " + task.text); - } - }); - - ppc.cli - .command("printTask ", "print a specific todo") - .action(async (id) => { - const data = await ppc.habitica.api_request("GET", `/tasks/${id}`, {}); - console.log(data.history); - }); -} - -class C2vi { - [key: string]: any; - - constructor(ppc: PPC) { - this.ppc = ppc; - this.db = drizzle( - createClient({ - url: "file://" + ppc.config.local_storage_path + "/data.db", - }), - ); - } -} - -function formatDate(d) { - const pad = (n) => n.toString().padStart(2, "0"); - - // Custom YYYY-MM-DD format - const formatted = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`; - return formatted; -} - -// ============= SCHEMA DEFINITION ============= -const dailiesTable = sqliteTable("habitica_dailies", { - id: text("id").primaryKey(), - text: text("text").notNull(), - notes: text("notes"), - priority: text("priority"), // 0.1, 1, 1.5, 2 - frequency: text("frequency"), // 'daily', 'weekly', etc. -}); -const habiticaLogTable = sqliteTable("habitica_log", { - date: text("date").primaryKey(), - data: text("data").notNull(), -}); - -async function save_habitica_dailies(ppc) { - console.log("######### cli bed cmd #########"); - await ppc.c2vi.db.run( - "CREATE TABLE IF NOT EXISTS habitica_dailies (id TEXT PRIMARY KEY, text TEXT NOT NULL, notes TEXT, priority TEXT, frequency TEXT)", - ); - await ppc.c2vi.db.run( - "CREATE TABLE IF NOT EXISTS habitica_log (date TEXT PRIMARY KEY, data TEXT NOT NULL)", - ); - - // ============= DATABASE INITIALIZATION ============= - if (!ppc.config.habitica.user_id || !ppc.config.habitica.api_token) { - console.error( - "Error: HABITICA_USER_ID and HABITICA_API_TOKEN env vars required", - ); - console.error( - "Get these from Habitica Settings > API and configure them in the ppc.config", - ); - process.exit(1); - } - - const dailies = await ppc.habitica.get_tasks("dailys"); - - await writeDailiesToDatabase(dailies, ppc); -} - -async function dump_habitica_logs(ppc) { - const entries = await ppc.c2vi.db.select().from(habiticaLogTable).all(); - for (const entry of entries) { - console.log(entry.date + ": ", JSON.parse(entry.data)); - } -} - -async function skip_habitica_todo(ppc, num) { - await ppc.c2vi.db.run( - "CREATE TABLE IF NOT EXISTS habitica_dailies (id TEXT PRIMARY KEY, text TEXT NOT NULL, notes TEXT, priority TEXT, frequency TEXT)", - ); - await ppc.c2vi.db.run( - "CREATE TABLE IF NOT EXISTS habitica_log (date TEXT PRIMARY KEY, data TEXT NOT NULL)", - ); - - const todos = await ppc.habitica.get_tasks("todos"); - - const date = new Date(); - const save_for_yesterday = date.getHours() < 12; - if (save_for_yesterday) { - console.log( - "Saving logs for yesterday!!!! because it is " + - date.getHours() + - "hours of the day", - ); - date.setDate(date.getDate() - 1); - } - - const result = await ppc.c2vi.db - .select() - .from(habiticaLogTable) - .where(eq(habiticaLogTable.date, formatDate(date))); - - const data = result[0] - ? JSON.parse(result[0].data) - : { - dailies_done: [], - dailies_skipped: [], - todos_done: [], - todos_skipped: [], - }; - - for (let i = 0; i < num; i++) { - const todo = todos[i]; - if (!todo) continue; - await ppc.habitica.delete_task(todo.id); - await incrementHabit(ppc); - - data.todos_skipped.push({ - id: todo.id, - text: todo.text, - notes: todo.notes || "", - checklist: todo.checklist || [], - tags: todo.tags || [], - }); - } - - // saving to db - await ppc.c2vi.db - .insert(habiticaLogTable) - .values({ date: formatDate(date), data: JSON.stringify(data) }) - .onConflictDoUpdate({ - target: habiticaLogTable.date, - set: { - data: JSON.stringify(data), - }, - }); -} - -async function save_habitica_logs(ppc) { - const date = new Date(); - const save_for_yesterday = date.getHours() < 12; - if (save_for_yesterday) { - console.log( - "Saving logs for yesterday!!!! because it is " + - date.getHours() + - "hours of the day", - ); - date.setDate(date.getDate() - 1); - } - - const result = await ppc.c2vi.db - .select() - .from(habiticaLogTable) - .where(eq(habiticaLogTable.date, formatDate(date))); - - const data = result[0] - ? JSON.parse(result[0].data) - : { - dailies_done: [], - dailies_skipped: [], - todos_done: [], - todos_skipped: [], - }; - - // dailies - const dailies = await ppc.habitica.get_tasks("dailys"); - for (const daily of dailies) { - let completed = daily.completed; - let isDue = daily.isDue; - if (save_for_yesterday) { - const yesterday = daily.history.reduce((prev, current) => { - return prev.date > current.date ? prev : current; - }); - completed = yesterday.completed; - isDue = yesterday.isDue; - } - if (!isDue) { - continue; - } - if (completed) { - data.dailies_done.push(daily.id); - console.log("daily-done: " + daily.text); - } else { - data.dailies_skipped.push(daily.id); - console.log("daily-skipped: " + daily.text); - } - } - - // todos done - const todos = await ppc.habitica.get_tasks("completedTodos"); - for (const todo of todos) { - const dateCompleted = new Date(todo.dateCompleted); - - // check if this todo is already saved in yesterday's log entry - if (save_for_yesterday) { - // get yesterday log entry - const result = await ppc.c2vi.db - .select() - .from(habiticaLogTable) - .where(eq(habiticaLogTable.date, formatDate(date))); - - const data = result[0] - ? JSON.parse(result[0].data) - : { - dailies_done: [], - dailies_skipped: [], - todos_done: [], - todos_skipped: [], - }; - - // check if this todo is already saved in yesterday's log entry - const todoIndex = data.todos_done.findIndex((t) => t.id === todo.id); - if (todoIndex !== -1) { - continue; // skipp saving this todo - } - } - - if (dateCompleted.toDateString() == date.toDateString()) { - console.log("todo-done:", todo.text); - data.todos_done.push({ - id: todo.id, - text: todo.text, - notes: todo.notes || "", - checklist: todo.checklist || [], - tags: todo.tags || [], - }); - } - - // we save_for_yesterday but the todo was completed today... also save that for this day - if ( - save_for_yesterday && - dateCompleted.toDateString() == new Date().toDateString() - ) { - console.log("todo-done:", todo.text); - data.todos_done.push({ - id: todo.id, - text: todo.text, - notes: todo.notes || "", - checklist: todo.checklist || [], - tags: todo.tags || [], - }); - } - } - - // saving to db - await ppc.c2vi.db - .insert(habiticaLogTable) - .values({ date: formatDate(date), data: JSON.stringify(data) }) - .onConflictDoUpdate({ - target: habiticaLogTable.date, - set: { - data: JSON.stringify(data), - }, - }); -} - -async function writeDailiesToDatabase(dailies, ppc) { - console.log(`Syncing ${dailies.length} dailies to database...`); - - const records = dailies.map((daily) => ({ - id: daily.id, - text: daily.text, - notes: daily.notes || "", - priority: daily.priority?.toString() || null, - frequency: daily.frequency || "daily", - })); - - async function upsertMany(records) { - for (const record of records) { - await ppc.c2vi.db - .insert(dailiesTable) - .values(record) - .onConflictDoUpdate({ - target: dailiesTable.id, - set: { - text: record.text, - notes: record.notes, - priority: record.priority, - frequency: record.frequency, - }, - }); - } - } - - await upsertMany(records); -} - -async function incrementHabit(ppc) { - const habits = await ppc.habitica.get_tasks("habits"); - let id = ""; - for (const habit of habits) { - if ((habit.text = "skipped a planned task")) { - id = habit.id; - } - } - await ppc.habitica.api_request("POST", `tasks/${id}/score/down`); -} - -async function add_action_items(ppc: PPC) { - let task_ids = []; - - const tmpFile = path.join(os.tmpdir(), `habitica-tasks-${Date.now()}.md`); - const initialContent = ` -gu 10min TIMER -uw 15min FROG -b coffee/tee/kakau -uw FROG -b breakfast, brush teeth, lüften -uw FROG - -lunch - -uw 15min TIMER of next days FROG -fw -dt 30min TIMER - -fun 20:00 (smth that can be stopped easily) -se 21:40 -read -bed 22:10 -`; - - fs.writeFileSync(tmpFile, initialContent.trim()); - - spawnSync("nvim", [tmpFile], { stdio: "inherit" }); - - // read file - const listStr = fs.readFileSync(tmpFile, "utf8"); - - // delete file - fs.unlinkSync(tmpFile); - - // Simple parser: filter out empty lines - const tasks = listStr - .split("\n") - .map((t) => t.trim()) - .filter((t) => t.length > 0); - - // 5. Add tasks to Habitica - for (const todoText of tasks) { - const data = await ppc.habitica.api_request( - "POST", - "tasks/user", - {}, - { text: todoText, type: "todo" }, - ); - task_ids.push(data.id); - console.log(`Added to-do: '${todoText}' with id '${data.id}'`); - } - - // 6. Move tasks to bottom - for (const taskId of task_ids) { - await ppc.habitica.api_request("POST", `tasks/${taskId}/move/to/-1`); - } -} diff --git a/marts/src/c2vi/obsidian-canvas-patch.ts b/marts/src/c2vi/obsidian-canvas-patch.ts deleted file mode 100644 index 98e51fd..0000000 --- a/marts/src/c2vi/obsidian-canvas-patch.ts +++ /dev/null @@ -1,170 +0,0 @@ -export function c2vi_obsidian_canvas_patch(mize: any) { - const plugin = mize.get_part_native("obsidian"); - - window.pc = patchCanvas; - window.upc = () => { - unpatchCanvas(plugin, plugin.app.workspace.activeLeaf); - }; - - console.log("hereeeeeeeeeeeeeeeee"); - // canvas patching - plugin.registerEvent( - plugin.app.workspace.on("file-open", (file: any) => { - if (file?.extension === "canvas") { - maybePathCanvas(plugin, plugin.app.workspace.activeLeaf); - } - }), - ); - plugin.registerEvent( - plugin.app.workspace.on("active-leaf-change", (file: any) => { - if (file?.extension === "canvas") { - maybePathCanvas(plugin, plugin.app.workspace.activeLeaf); - } - }), - ); -} - -const maybePathCanvas = (plugin: PPCObsidianPlugin, leaf: any | null) => { - console.log("maybePathCanvas called"); - const file = plugin.app.workspace.getActiveFile(); - - if (file?.extension !== "canvas") return; - console.log("patching canvas....."); - - const canvas = plugin.app.workspace.activeLeaf.view.canvas; - if ("isPatched" in canvas) return; - - patchCanvas(plugin, leaf, canvas); -}; - -function patchCanvas(plugin: PPCObsidianPlugin, leaf: any, canvas: any) { - canvas.isPatched = true; - const canvasEl = canvas.canvasEl; - const canvasWrapperEl = canvasEl.parentElement; - const overlay = createDiv(); - overlay.setAttr("class", "c2vi-canvas-overlay"); - const canvas_card_menue = canvasWrapperEl.childNodes[1]; - canvasWrapperEl.insertBefore(overlay, canvas_card_menue); - Object.assign(overlay.style, { - position: "absolute", - inset: "0", - //zIndex: "1337", - }); - overlay.addEventListener("contextmenu", (e) => { - if (e.button === 2) { - e.preventDefault(); - e.stopPropagation(); - e.stopImmediatePropagation(); - } - }); - overlay.addEventListener("mouseout", (e) => { - const menu = document.getElementsByClassName("menu")[0]; - if (!menu) return; - menu.addEventListener("pointerup", (e) => { - console.log("pointerup on menu", e); - e.target.click(); - /* - menu.dispatchEvent( - new MouseEvent("mousedown", { - bubbles: true, - cancelable: true, - composed: true, - clientX: e.clientX, - clientY: e.clientY, - button: e.button, - buttons: e.buttons, - view: window, - }), - ); - */ - }); - }); - - setupEventPropagation("pointerdown", PointerEvent, overlay, canvasWrapperEl); - setupEventPropagation("pointerup", PointerEvent, overlay, canvasWrapperEl); - setupEventPropagation("mousedown", MouseEvent, overlay, canvasWrapperEl); - setupEventPropagation("mouseup", MouseEvent, overlay, canvasWrapperEl); - setupEventPropagation("click", MouseEvent, overlay, canvasWrapperEl); - setupEventPropagation("dragstart", DragEvent, overlay, canvasWrapperEl); - setupEventPropagation("dragstop", DragEvent, overlay, canvasWrapperEl); - - window.a = canvasWrapperEl; - window.b = overlay; - - const mouseEvents = [ - "mousedown", - "mouseup", - "click", - "dblclick", - //"mousemove", - "mouseover", - "mouseout", - "wheel", - ]; - - mouseEvents.forEach((eventType) => { - canvasWrapperEl.addEventListener( - eventType, - (event) => { - console.log(`Mouse Event Triggered: ${event.type}`, event); - }, - { passive: true }, - ); - }); -} - -function unpatchCanvas(plugin: PPCObsidianPlugin, leaf: any) { - const canvas = plugin.app.workspace.activeLeaf.view.canvas; - if (!canvas.isPatched) return; - canvas.isPatched = false; - const canvasEl = canvas.canvasEl; - const canvasWrapperEl = canvasEl.parentElement; - - const targets = canvasEl.querySelectorAll(":scope > .c2vi-canvas-overlay"); - - targets.forEach((child) => child.remove()); -} - -function setupEventPropagation(type: string, evClass, overlay: any, target) { - overlay.addEventListener(type, (originalEvent) => { - originalEvent.stopPropagation(); - originalEvent.stopImmediatePropagation(); - originalEvent.preventDefault(); - const newEvent = new evClass(type, originalEvent); - if (type == "pointerdown" && originalEvent.ctrlKey == true) { - dispatchContextMenue( - target, - originalEvent.clientX, - originalEvent.clientY, - ); - return; - } - if (type === "pointerdown") { - window.downEv = newEvent; - } - if (type === "pointerup") { - window.upEv = newEvent; - } - newEvent.isTrusted = true; - console.log("original Event of", type, originalEvent); - console.log("new Event of", type, newEvent); - target.dispatchEvent(newEvent); - }); -} - -function dispatchContextMenue(target, x, y) { - const newEvent = new PointerEvent("contextmenu", { - bubbles: true, - cancelable: true, - composed: true, - view: window, - clientX: x, - clientY: y, - pointerType: "mouse", - button: 2, - buttons: 2, - pointerId: 1, - isPrimary: true, - }); - target.dispatchEvent(newEvent); -} diff --git a/marts/src/c2vi/part.rs b/marts/src/c2vi/part.rs deleted file mode 100644 index e42c069..0000000 --- a/marts/src/c2vi/part.rs +++ /dev/null @@ -1,995 +0,0 @@ -use std::sync::Mutex; - -use chrono::{Timelike, Utc}; -use clap::{Arg, Command}; -#[cfg(feature = "desktop")] -use mize::item::ItemData; -use rusqlite::{params, Connection}; -use serde_json::{json, Value}; -use clap::ArgMatches; -use cmd_lib::run_cmd as sh; - -use dioxus::prelude::*; -use mize::{mize_err, mize_part, Mize, MizeError, MizePart, MizePartCreate, MizeResult}; -use tracing::instrument::WithSubscriber; - -use crate::cli::CliPart; -use crate::habitica::Habitica; -use crate::SpacetimePart; -use generated::spacetime::{ - Action, ActivitiesTableAccess, Activity, DbConnection, LogEventsTableAccess, TaskPart, TaskPartTableAccess, activitiesQueryTableAccess, next_action, remove_activity, task_partQueryTableAccess, update_activity, update_upcoming -}; -use spacetimedb_sdk::{ - credentials, DbContext, Error, Event, Identity, Status, - TableWithPrimaryKey, -}; - -static MIZE_SRC: &str = "/home/me/work/config/mize"; -static SRC: &str = "/home/me/work/config"; -static RSYNC_EXCLUDES: &str = "--exclude=node_modules --exclude=target --exclude=mize_config.toml --exclude=rust_dist --exclude=deno_dist --exclude=dist --exclude=result --exclude=pkg --exclude /src --exclude obsidian-brat --exclude forked-zed"; - -#[mize_part] -#[derive(Default)] -pub struct C2vi { - mize: Mize, - db: Mutex>, -} - -impl MizePart for C2vi { - fn opts(&self, mize: &mut Mize) { - mize.new_opt("c2vi.local_storage_path"); - } -} -impl MizePartCreate for C2vi {} - -impl C2vi { - fn with_db(&self, f: F) -> MizeResult - where - F: FnOnce(&Connection) -> MizeResult, - { - let guard = self - .db - .lock() - .map_err(|e| mize_err!("DB lock poisoned: {}", e))?; - let conn = guard - .as_ref() - .ok_or_else(|| mize_err!("DB not initialized"))?; - f(conn) - } -} - -pub fn part_c2vi(mize: &mut Mize) -> MizeResult<()> { - c2vi_deploy_things(mize)?; - - #[cfg(feature = "desktop")] - if mize - .get_config("c2vi.dash.enable") - .unwrap_or(ItemData::empty()) - .as_bool() - .unwrap_or(false) - { - launch_c2vi_dashboard(mize); - } - - #[cfg(feature = "target-obsidian")] { - use crate::MartsCommand; - - let obsidian = mize.get_part_native::("obsidian").unwrap(); - obsidian.add_command(MartsCommand { - id: "sc2-publish-daily-journal".to_string(), - name: "SC2 Publish Daily Journal".to_string(), - callback: Box::new(|mut mize| { - let matrix = mize.get_part_native::("matrix")?; - //matrix.send_message(room_id); - - Ok(()) - }), - })?; - } - - Ok(()) -} - -pub fn new_deploy(mize: Mize, matches: &ArgMatches, hostname: &str) -> MizeResult<()> { - let path = match hostname { - "mac" => "/home/me/here/mize", - _ => "/home/me/here/mize", - }; - let is_release = match hostname { - "mac" => true, - _ => false, - }; - let ld_lib_path = std::env::var("LD_LIBRARY_PATH")?; - if is_release { - sh!(echo cmd: cargo build --manifest-path $SRC/mize/Cargo.toml --bin mize --release)?; - sh!(cargo build --manifest-path $SRC/mize/Cargo.toml --bin mize --release)?; - sh!(echo cmd: patchelf --set-rpath $ld_lib_path $SRC/mize/target/release/mize)?; - let _ = sh!(patchelf --set-rpath $ld_lib_path $SRC/mize/target/release/mize); - sh!(echo cmd: scp $SRC/mize/target/release/mize $hostname:$path)?; - sh!(scp $SRC/mize/target/release/mize $hostname:$path)?; - } else { - sh!(echo cmd: cargo build --manifest-path $SRC/mize/Cargo.toml --bin mize)?; - sh!(cargo build --manifest-path $SRC/mize/Cargo.toml --bin mize)?; - sh!(echo cmd: patchelf --set-rpath $ld_lib_path $SRC/mize/target/debug/mize)?; - let _ = sh!(patchelf --set-rpath $ld_lib_path $SRC/mize/target/debug/mize); - sh!(echo cmd: scp $SRC/mize/target/debug/mize $hostname:$path)?; - sh!(scp $SRC/mize/target/debug/mize $hostname:$path)?; - } - - Ok(()) -} - -fn c2vi_deploy_things(mize: &mut Mize) -> MizeResult<()> { - let mut cli = mize.get_part_native::("cli")?; - cli.set_command("dev"); - - let bin_arg = Arg::new("bin").short('b'); - - cli.subcommand( - Command::new("deploy-lush").alias("dlu").arg(&bin_arg), - Box::new(move |matches: &ArgMatches, mize| remote_deploy(matches, mize, "te")), - )?; - cli.subcommand( - Command::new("deploy-mac").alias("dmc").arg(&bin_arg), - Box::new(move |matches: &ArgMatches, mize| new_deploy(mize, matches, "mac")), - )?; - cli.subcommand( - Command::new("deploy-files").alias("dfi").arg(&bin_arg), - Box::new(move |matches: &ArgMatches, mize| remote_deploy(matches, mize, "files")), - )?; - cli.subcommand( - Command::new("deploy-ppc").alias("dpp").arg(&bin_arg), - Box::new(move |matches: &ArgMatches, mize| remote_deploy(matches, mize, "ppc-hosting")), - )?; - cli.subcommand( - Command::new("deploy-nico").alias("dni").arg(&bin_arg), - Box::new(move |matches: &ArgMatches, mize| remote_deploy(matches, mize, "nico")), - )?; - cli.subcommand( - Command::new("deploy-main").alias("dma").arg(&bin_arg), - Box::new(main_deploy), - )?; - cli.subcommand( - Command::new("deploy-obsidian").alias("do").arg(&bin_arg), - Box::new(obsidian_deploy), - )?; - cli.subcommand( - Command::new("deploy-spacetime").alias("dsp").arg(&bin_arg), - Box::new(deploy_spacetime), - )?; - Ok(()) -} - -#[cfg(feature = "desktop")] -pub fn launch_c2vi_dashboard(mize: &mut Mize) { - std::env::remove_var("WAYLAND_DISPLAY"); - std::env::set_var("DISPLAY", ":0"); - use dioxus::desktop::{muda::Menu, Config, WindowBuilder}; - let mize_clone = mize.clone(); - LaunchBuilder::new() - .with_context_provider(move || Box::new(mize_clone.clone())) - .with_cfg(desktop! { - Config::new().with_window(WindowBuilder::new().with_decorations(false).with_title("SCI display")) - }) - .launch(c2vi_dash_main); -} - -//use spacetimedb_sdk::spacetime_module::QueryBuilder; - -/* -pub fn use_spacetime(query: T) { - let mut mize = use_context::(); - let mut spacetime = mize.get_part_native::("spacetime").unwrap(); - let con = spacetime.con(); - con.subscription_builder() - .on_applied(move |ctx| { - let data = ctx.db.task_part().identity().find(&ctx.identity()).unwrap(); - current.set(data.current.name.clone()); - }) - .add_query(query) - .subscribe(); - con.db - .task_part() - .on_update(move |_, old: &TaskPart, new: &TaskPart| { - current.set(new.current.name.clone()); - }); -} - */ - -//pub fn use_by_pk(identity: Identity) -//pub fn use_one - - -pub fn c2vi_dash_main() -> Element { - let mut current = use_signal_sync(|| "".to_string()); - let mut next = use_signal_sync(|| "".to_string()); - //TaskPart:: - //use_one() - use_effect(move || { - let mut mize = use_context::(); - let spacetime = match mize.get_part_native::("spacetime") { - Ok(val) => val, - Err(e) => { - e.log(); - return; - }, - }; - let con = spacetime.con(); - con.subscription_builder() - .on_applied(move |ctx| { - let data = match ctx.db.task_part().identity().find(&ctx.identity()) { - Some(val) => val, - None => { - debug!("can't find task part for user"); - return; - }, - }; - current.set(data.current.name.clone()); - if let Some(first_upcoming) = data.upcoming.first() { - next.set(first_upcoming.name.clone()); - } else { - next.set("".to_string()); - } - }) - .add_query(|q| q.from.task_part().r#where(|t| t.identity.eq(con.identity()))) - .subscribe(); - con.db - .task_part() - .on_update(move |_, _old: &TaskPart, new: &TaskPart| { - current.set(new.current.name.clone()); - if let Some(first_upcoming) = new.upcoming.first() { - next.set(first_upcoming.name.clone()); - } else { - next.set("".to_string()); - } - }); - }); - rsx! { - div { - style: "text-align: center; padding: 2rem; font-size: 120px;", - p { - "{current}" - } - p { - style: "font-size: 50px; color: grey; opacity: 0.7;", - "{next}" - } - } - } -} - -pub fn c2vi_client(mize: &mut Mize) -> MizeResult<()> { - //let storage_path = mize.get_config("c2vi.local_storage_path")?.as_ - let storage_path = "/home/me/work/app-data/ppc"; - //println!("storage_path: {}", storage_path); - let db_path = std::path::PathBuf::from(&storage_path).join("data.db"); - let conn = Connection::open(&db_path) - .map_err(|e| mize_err!("Failed to open C2vi database at {:?}: {}", db_path, e))?; - - setup_tables(&conn)?; - - let c2vi_part = C2vi { - mize: mize.clone(), - db: Mutex::new(Some(conn)), - }; - mize.register_part(Box::new(c2vi_part))?; - - // Register CLI subcommands - let mut cli = mize.get_part_native::("cli")?; - register_subcommands(&mut cli); - - Ok(()) -} - -fn setup_tables(conn: &Connection) -> MizeResult<()> { - conn.execute( - "CREATE TABLE IF NOT EXISTS habitica_dailies ( - id TEXT PRIMARY KEY, - text TEXT NOT NULL, - notes TEXT, - priority TEXT, - frequency TEXT - )", - [], - ) - .map_err(|e| mize_err!("DB error creating habitica_dailies: {}", e))?; - conn.execute( - "CREATE TABLE IF NOT EXISTS habitica_log ( - date TEXT PRIMARY KEY, - data TEXT NOT NULL - )", - [], - ) - .map_err(|e| mize_err!("DB error creating habitica_log: {}", e))?; - Ok(()) -} - -fn register_subcommands(cli: &mut CliPart) { - cli.subcommand( - Command::new("c2vi-dash").about("Run the c2vi dashboard gui"), - |_matches, mut _mize| Ok(dioxus::launch(super::dashboard::main)), - ); - cli.subcommand( - Command::new("bed").about("Command to run when c2vi goes to bed"), - |_matches, mut mize| { - save_habitica_dailies(&mut mize)?; - save_habitica_logs(&mut mize)?; - Ok(()) - }, - ); - - cli.subcommand( - Command::new("clearTodos") - .about("Clear all Habitica todos") - .alias("clt"), - |_matches, mut mize| { - let todos = { - let mut hab = mize.get_part_native::("habitica")?; - hab.get_tasks("todos")? - }; - let mut hab = mize.get_part_native::("habitica")?; - if let Some(arr) = todos.as_array() { - for todo in arr { - if let Some(id) = todo["id"].as_str() { - hab.delete_task(id)?; - } - } - } - Ok(()) - }, - ); - - cli.subcommand( - Command::new("listTodos") - .about("List all Habitica todos") - .alias("dut"), - |_matches, mut mize| { - let mut hab = mize.get_part_native::("habitica")?; - let todos = hab.get_tasks("todos")?; - if let Some(arr) = todos.as_array() { - for todo in arr { - if let Some(text) = todo["text"].as_str() { - println!("{}", text); - } - } - } - Ok(()) - }, - ); - - cli.subcommand( - Command::new("buyHealthPotion") - .about("Buy a health potion") - .alias("buyh"), - |_matches, mut mize| { - let mut hab = mize.get_part_native::("habitica")?; - hab.api_request( - reqwest::Method::POST, - "user/buy-health-potion".to_string(), - json!({}), - )?; - Ok(()) - }, - ); - - cli.subcommand( - Command::new("addActionItems") - .about("Add action items from temp file") - .alias("aal"), - |_matches, mut mize| add_action_items(&mut mize), - ); - - cli.subcommand( - Command::new("skip") - .about("Skip a Habitica todo") - .alias("sk") - .arg(Arg::new("num").default_value("1")), - |matches, mut mize| { - let num: usize = matches - .get_one::("num") - .unwrap() - .parse() - .unwrap_or(1); - skip_habitica_todo(&mut mize, num) - }, - ); - - cli.subcommand( - Command::new("dumpLog").about("Dump the complete Habitica log"), - |_matches, mut mize| dump_habitica_logs(&mut mize), - ); - - cli.subcommand( - Command::new("listDailies").about("List all dailies from local DB"), - |_matches, mut mize| { - let c2vi = mize.get_part_native::("c2vi")?; - c2vi.with_db(|conn| { - let mut stmt = conn - .prepare("SELECT id, text FROM habitica_dailies") - .map_err(|e| mize_err!("DB error: {}", e))?; - let rows = stmt - .query_map([], |row| { - Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?)) - }) - .map_err(|e| mize_err!("DB error: {}", e))?; - for row in rows { - let (id, text) = row.map_err(|e| mize_err!("DB error: {}", e))?; - println!("{}: {}", id, text); - } - Ok(()) - }) - }, - ); - - cli.subcommand( - Command::new("printTask") - .about("Print a specific task from Habitica") - .arg(Arg::new("id").required(true)), - |matches, mut mize| { - let id = matches.get_one::("id").unwrap(); - let mut hab = mize.get_part_native::("habitica")?; - let data = hab.api_request(reqwest::Method::GET, format!("tasks/{}", id), json!({}))?; - if let Some(history) = data.get("history") { - println!( - "{}", - serde_json::to_string_pretty(history).unwrap_or_default() - ); - } else { - println!( - "{}", - serde_json::to_string_pretty(&data).unwrap_or_default() - ); - } - Ok(()) - }, - ); -} - -// ============= Business Logic ============= - -fn format_date(dt: chrono::DateTime) -> String { - dt.format("%Y-%m-%d").to_string() -} - -/// Get the target date, adjusted for "save for yesterday" logic (before noon = yesterday) -fn get_target_date() -> (String, bool) { - let now = Utc::now(); - let save_for_yesterday = now.hour() < 12; - let date = if save_for_yesterday { - now - chrono::Duration::days(1) - } else { - now - }; - if save_for_yesterday { - println!( - "Saving logs for yesterday because it is {} hours of the day", - now.hour() - ); - } - (format_date(date), save_for_yesterday) -} - -/// Load existing log entry from DB, or return a default empty one -fn get_or_create_log(conn: &Connection, date: &str) -> MizeResult { - let mut stmt = conn - .prepare("SELECT data FROM habitica_log WHERE date = ?1") - .map_err(|e| mize_err!("DB error: {}", e))?; - let result: Option = stmt.query_row(params![date], |row| row.get(0)).ok(); - match result { - Some(data_str) => { - serde_json::from_str(&data_str).map_err(|e| mize_err!("JSON parse error: {}", e)) - } - None => Ok(json!({ - "dailies_done": [], - "dailies_skipped": [], - "todos_done": [], - "todos_skipped": [] - })), - } -} - -/// Upsert a log entry into the database -fn upsert_log(conn: &Connection, date: &str, data: &Value) -> MizeResult<()> { - let data_str = - serde_json::to_string(data).map_err(|e| mize_err!("JSON serialize error: {}", e))?; - conn.execute( - "INSERT INTO habitica_log (date, data) VALUES (?1, ?2) - ON CONFLICT(date) DO UPDATE SET data=excluded.data", - params![date, data_str], - ) - .map_err(|e| mize_err!("DB error upserting log: {}", e))?; - Ok(()) -} - -fn save_habitica_dailies(mize: &mut Mize) -> MizeResult<()> { - println!("######### cli bed cmd #########"); - - // Fetch dailies from Habitica - let dailies = { - let mut hab = mize.get_part_native::("habitica")?; - hab.get_tasks("dailys")? - }; - - // Write to database - let c2vi = mize.get_part_native::("c2vi")?; - c2vi.with_db(|conn| { - if let Some(arr) = dailies.as_array() { - println!("Syncing {} dailies to database...", arr.len()); - for daily in arr { - let id = daily["id"].as_str().unwrap_or(""); - let text = daily["text"].as_str().unwrap_or(""); - let notes = daily["notes"].as_str().unwrap_or(""); - let priority = daily["priority"].to_string(); - let frequency = daily["frequency"].as_str().unwrap_or("daily"); - - conn.execute( - "INSERT INTO habitica_dailies (id, text, notes, priority, frequency) - VALUES (?1, ?2, ?3, ?4, ?5) - ON CONFLICT(id) DO UPDATE SET - text=excluded.text, - notes=excluded.notes, - priority=excluded.priority, - frequency=excluded.frequency", - params![id, text, notes, priority, frequency], - ) - .map_err(|e| mize_err!("DB error writing daily: {}", e))?; - } - } - Ok(()) - }) -} - -fn save_habitica_logs(mize: &mut Mize) -> MizeResult<()> { - let (date_str, save_for_yesterday) = get_target_date(); - - // Fetch dailies and completed todos from Habitica - let (dailies, completed_todos) = { - let mut hab = mize.get_part_native::("habitica")?; - let dailies = hab.get_tasks("dailys")?; - let completed_todos = hab.get_tasks("completedTodos")?; - (dailies, completed_todos) - }; - - let c2vi = mize.get_part_native::("c2vi")?; - c2vi.with_db(|conn| { - let mut data = get_or_create_log(conn, &date_str)?; - - // Process dailies - if let Some(arr) = dailies.as_array() { - for daily in arr { - let is_due = if save_for_yesterday { - // Look at history for yesterday's status - daily["history"] - .as_array() - .and_then(|h| h.iter().max_by_key(|e| e["date"].as_i64().unwrap_or(0))) - .map(|e| e["isDue"].as_bool().unwrap_or(false)) - .unwrap_or(false) - } else { - daily["isDue"].as_bool().unwrap_or(false) - }; - - if !is_due { - continue; - } - - let completed = if save_for_yesterday { - daily["history"] - .as_array() - .and_then(|h| h.iter().max_by_key(|e| e["date"].as_i64().unwrap_or(0))) - .map(|e| e["completed"].as_bool().unwrap_or(false)) - .unwrap_or(false) - } else { - daily["completed"].as_bool().unwrap_or(false) - }; - - let daily_id = daily["id"].as_str().unwrap_or(""); - let daily_text = daily["text"].as_str().unwrap_or(""); - - if completed { - data["dailies_done"] - .as_array_mut() - .unwrap() - .push(json!(daily_id)); - println!("daily-done: {}", daily_text); - } else { - data["dailies_skipped"] - .as_array_mut() - .unwrap() - .push(json!(daily_id)); - println!("daily-skipped: {}", daily_text); - } - } - } - - // Process completed todos - if let Some(arr) = completed_todos.as_array() { - let today_str = format_date(Utc::now()); - for todo in arr { - let date_completed_str = todo["dateCompleted"].as_str().unwrap_or(""); - - // Parse the completion date (ISO 8601 format from Habitica) - let date_completed = chrono::DateTime::parse_from_rfc3339(date_completed_str) - .map(|d| format_date(d.with_timezone(&Utc))) - .unwrap_or_default(); - - // Check if already in the log for this date - if save_for_yesterday { - let existing_todos = data["todos_done"].as_array().unwrap(); - let todo_id = todo["id"].as_str().unwrap_or(""); - if existing_todos - .iter() - .any(|t| t["id"].as_str() == Some(todo_id)) - { - continue; - } - } - - let todo_entry = json!({ - "id": todo["id"], - "text": todo["text"], - "notes": todo.get("notes").unwrap_or(&json!("")), - "checklist": todo.get("checklist").unwrap_or(&json!([])), - "tags": todo.get("tags").unwrap_or(&json!([])), - }); - - // Save if completed on the target date - if date_completed == date_str { - println!("todo-done: {}", todo["text"].as_str().unwrap_or("")); - data["todos_done"] - .as_array_mut() - .unwrap() - .push(todo_entry.clone()); - } - - // If saving for yesterday but todo was completed today, also record it - if save_for_yesterday && date_completed == today_str { - println!("todo-done: {}", todo["text"].as_str().unwrap_or("")); - data["todos_done"].as_array_mut().unwrap().push(todo_entry); - } - } - } - - upsert_log(conn, &date_str, &data)?; - Ok(()) - }) -} - -fn skip_habitica_todo(mize: &mut Mize, num: usize) -> MizeResult<()> { - let (date_str, _) = get_target_date(); - - // Fetch todos from Habitica - let todos = { - let mut hab = mize.get_part_native::("habitica")?; - hab.get_tasks("todos")? - }; - - let arr = todos - .as_array() - .ok_or_else(|| mize_err!("Expected array of todos"))?; - - // Delete and log each skipped todo - for i in 0..num { - let todo = match arr.get(i) { - Some(t) => t, - None => continue, - }; - - let todo_id = todo["id"].as_str().unwrap_or(""); - - // Delete the todo and score the skip habit - { - let mut hab = mize.get_part_native::("habitica")?; - hab.delete_task(todo_id)?; - } - increment_habit(mize)?; - - // Record in log - let c2vi = mize.get_part_native::("c2vi")?; - c2vi.with_db(|conn| { - let mut data = get_or_create_log(conn, &date_str)?; - data["todos_skipped"].as_array_mut().unwrap().push(json!({ - "id": todo["id"], - "text": todo["text"], - "notes": todo.get("notes").unwrap_or(&json!("")), - "checklist": todo.get("checklist").unwrap_or(&json!([])), - "tags": todo.get("tags").unwrap_or(&json!([])), - })); - upsert_log(conn, &date_str, &data)?; - Ok(()) - })?; - } - - Ok(()) -} - -fn increment_habit(mize: &mut Mize) -> MizeResult<()> { - let mut hab = mize.get_part_native::("habitica")?; - let habits = hab.get_tasks("habits")?; - if let Some(arr) = habits.as_array() { - for habit in arr { - if habit["text"].as_str() == Some("skipped a planned task") { - let id = habit["id"].as_str().unwrap_or(""); - hab.api_request( - reqwest::Method::POST, - format!("tasks/{}/score/down", id), - json!({}), - )?; - return Ok(()); - } - } - } - Ok(()) -} - -fn add_action_items(mize: &mut Mize) -> MizeResult<()> { - let initial_content = "\ -gu 10min TIMER -uw 15min FROG -b coffee/tee/kakau -uw FROG -b breakfast, brush teeth, lüften -uw FROG - -lunch - -uw 15min TIMER of next days FROG -fw -dt 30min TIMER - -fun 20:00 (smth that can be stopped easily) -se 21:40 -read -bed 22:10"; - - let tmp_file = - std::env::temp_dir().join(format!("habitica-tasks-{}.md", Utc::now().timestamp())); - std::fs::write(&tmp_file, initial_content) - .map_err(|e| mize_err!("Failed to write temp file: {}", e))?; - - // Open in nvim for editing - std::process::Command::new("nvim") - .arg(&tmp_file) - .status() - .map_err(|e| mize_err!("Failed to run nvim: {}", e))?; - - // Read back and parse - let list_str = std::fs::read_to_string(&tmp_file) - .map_err(|e| mize_err!("Failed to read temp file: {}", e))?; - let _ = std::fs::remove_file(&tmp_file); - - let tasks: Vec<&str> = list_str - .lines() - .map(|l| l.trim()) - .filter(|l| !l.is_empty()) - .collect(); - - // Add tasks to Habitica - let mut task_ids = Vec::new(); - { - let mut hab = mize.get_part_native::("habitica")?; - for todo_text in &tasks { - let data = hab.api_request( - reqwest::Method::POST, - "tasks/user".to_string(), - json!({ "text": todo_text, "type": "todo" }), - )?; - let id = data["id"].as_str().unwrap_or("").to_string(); - println!("Added to-do: '{}' with id '{}'", todo_text, id); - task_ids.push(id); - } - - // Move all tasks to bottom - for task_id in &task_ids { - hab.api_request( - reqwest::Method::POST, - format!("tasks/{}/move/to/-1", task_id), - json!({}), - )?; - } - } - - Ok(()) -} - -fn dump_habitica_logs(mize: &mut Mize) -> MizeResult<()> { - let c2vi = mize.get_part_native::("c2vi")?; - c2vi.with_db(|conn| { - let mut stmt = conn - .prepare("SELECT date, data FROM habitica_log ORDER BY date") - .map_err(|e| mize_err!("DB error: {}", e))?; - let rows = stmt - .query_map([], |row| { - Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?)) - }) - .map_err(|e| mize_err!("DB error: {}", e))?; - for row in rows { - let (date, data_str) = row.map_err(|e| mize_err!("DB error: {}", e))?; - let data: Value = - serde_json::from_str(&data_str).unwrap_or(json!({"parse_error": data_str})); - println!( - "{}: {}", - date, - serde_json::to_string_pretty(&data).unwrap_or_default() - ); - } - Ok(()) - }) -} - -pub fn remote_deploy(matches: &ArgMatches, _: Mize, hostname: &str) -> MizeResult<()> { - unsafe { - /* - std::env::set_var( - "PATH", - "/home/me/work/path-extra/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/home/me/.local/state/nix/profile/bin:/home/me/.nix-profile/bin", - ); - */ - std::env::set_var("SRC", SRC); - std::env::set_var("HOSTNAME", hostname); - } - - let mut do_mize_restart = false; - - let bin = match matches.get_one::("bin") { - Some(val) => val.to_owned(), - None => { - "mize".to_owned() - } - }; - - let remote_src_dir = match hostname { - "lush" => "/home/me/here/config", - "mac" => "/data/external/config", - "files" => "/home/files/here/config", - "nico" => "/root/work/config-c2vi", - "ppc-hosting" => "/root/host/c2vi-config", - _ => "/home/me/here/config", - }; - let mize_store_dir = match hostname { - "lush" => "/home/me/host/mize", - "mac" => "/home/me/host/mize", - "files" => "/home/files/storage/files/mize", - "nico" => "/root/work/app-data/mize", - "ppc-hosting" => "/root/host/mize", - _ => "/home/me/host/mize", - }; - let rclone_flag = match hostname { - "nico" => "--chown=root:root", - "ppc-hosting" => "--chown=root:root", - _ => "", - }; - - sh!(echo cmd: rsync -r -u -v -a --delete --perms $rclone_flag --include=".git/" --include=".git/**" --exclude="target" --mkpath $RSYNC_EXCLUDES $SRC/ $hostname:$remote_src_dir)?; - sh!(rsync -r -u -v -a --delete --perms $rclone_flag --include=".git/" --include=".git/**" --exclude="target" --mkpath $RSYNC_EXCLUDES $SRC/ $hostname:$remote_src_dir)?; - - let ssh_cmd = format!( - r#" - if ! tmux has-session -t mize-deploy 2>/dev/null; then - echo "Created new tmux session...." - tmux new-session -d -s mize-deploy "nix develop git+file://{remote_src_dir}/mize#buildShell --max-jobs 1" - else - echo "using existing session..." - fi - - tmux send-keys -t mize-deploy "DO_MIZE_RESTART={do_mize_restart}" Enter - tmux send-keys -t mize-deploy "cargo build --manifest-path {remote_src_dir}/mize/Cargo.toml --bin {bin}" Enter - tmux send-keys -t mize-deploy 'BUILD_SUCCESS=$?' Enter - tmux send-keys -t mize-deploy '[[ "$BUILD_SUCCESS" == "0" ]] && echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" > {mize_store_dir}/daemon.env' Enter - tmux send-keys -t mize-deploy '[[ "$BUILD_SUCCESS" == "0" ]] && echo "MIZE_CONFIG_FILES={mize_store_dir}/config.toml" >> {mize_store_dir}/daemon.env' Enter - tmux send-keys -t mize-deploy '[[ "$BUILD_SUCCESS" == "0" ]] && [[ "$HOSTNAME" == "nico" ]] && echo "PATH=/root/work/path-extra:$PATH" >> {mize_store_dir}/daemon.env' Enter - tmux send-keys -t mize-deploy '[[ "$BUILD_SUCCESS" == "0" ]] && [[ "$DO_MIZE_RESTART" == "true" ]] && systemctl --user restart mize' Enter - "# - ); - - sh!(ssh $hostname $ssh_cmd)?; - - Ok(()) -} - -pub fn deploy_spacetime(_: &ArgMatches, _: Mize) -> MizeResult<()> { - unsafe { - /* - std::env::set_var( - "PATH", - "/home/me/work/path-extra/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/home/me/.local/state/nix/profile/bin:/home/me/.nix-profile/bin", - ); - */ - std::env::set_var("SRC", SRC); - } - - let cmd = format!( - r#" - if ! tmux has-session -t mize-deploy 2>/dev/null; then - echo "Created new tmux session...." - systemd-run --user --scope --description="mize deploy tmux session" tmux new-session -d -s mize-deploy "nix develop git+file://$SRC/mize --impure" - else - echo "using existing session..." - tmux send-keys -t mize-deploy "echo hoooooooooooooo" Enter - fi - - tmux send-keys -t mize-deploy "spacetime publish -p $SRC/mize/marts/spacetime/ --yes mize" Enter -"# - ); - sh!(/bin/sh -c "$cmd")?; - Ok(()) - -} - -pub fn obsidian_deploy(_: &ArgMatches, _: Mize) -> MizeResult<()> { - unsafe { - std::env::set_var( - "PATH", - "/home/me/work/path-extra/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/home/me/.local/state/nix/profile/bin:/home/me/.nix-profile/bin", - ); - std::env::set_var("SRC", SRC); - } - let cmd = format!( - r#" - if ! tmux has-session -t mize-deploy 2>/dev/null; then - echo "Created new tmux session...." - systemd-run --user --scope --description="mize deploy tmux session" tmux new-session -d -s mize-deploy "nix develop git+file://$SRC/mize --impure" - else - echo "using existing session..." - fi - tmux send-keys -t mize-deploy "deno run --config {SRC}/mize/apps/obsidian-plugin/deno.json build" Enter - tmux send-keys -t mize-deploy "cp -r {SRC}/mize/apps/obsidian-plugin/dist/* ~/work/things/.obsidian/plugins/mize/" Enter -"# - ); - sh!(/bin/sh -c "$cmd")?; - Ok(()) - -} - -pub fn main_deploy(_: &ArgMatches, _: Mize) -> MizeResult<()> { - unsafe { - std::env::set_var( - "PATH", - "/home/me/work/path-extra/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/home/me/.local/state/nix/profile/bin:/home/me/.nix-profile/bin", - ); - std::env::set_var("SRC", SRC); - } - let cmd = - r#" - if ! tmux has-session -t mize-deploy 2>/dev/null; then - systemd-run --user --scope --description="mize deploy tmux session" tmux new-session -d -s mize-deploy "nix develop git+file://$SRC/mize#buildShell" - else - echo "using existing session..." - fi - tmux send-keys -t mize-deploy "cargo build --manifest-path $SRC/mize/Cargo.toml --bin mize" Enter - tmux send-keys -t mize-deploy 'echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" > /home/me/work/app-data/mize/daemon.env' Enter - tmux send-keys -t mize-deploy "systemctl --user restart mize" Enter - "#; - sh!(/bin/sh -c "$cmd")?; - Ok(()) -} - - - -pub fn nico_notes_sync_thread(mize: Mize) -> MizeResult<()> { - tracing::info!("starting nico_notes_sync_thread"); - loop { - let res = sh!(/bin/bash -c r#" - cd /root/work/nico/notes/c2vi - git add . - git commit -m "nico notes sync" - git pull --rebase - git push - - cd /root/work/nico/notes/nexus - git add . - git commit -m "nico nexus notes sync" - git pull --rebase - git push - - cd /root/work/nico/notes/ppc-wiki - git add . - git commit -m "nico ppc-wiki notes sync" - git pull --rebase - git push - "#); - if let Err(e) = res { - tracing::error!("error in nico_notes_sync_thread: {}", e); - }; - std::thread::sleep(std::time::Duration::from_mins(2)); - } -} diff --git a/marts/src/cli/mod.rs b/marts/src/cli/mod.rs deleted file mode 100644 index a7286bc..0000000 --- a/marts/src/cli/mod.rs +++ /dev/null @@ -1,357 +0,0 @@ -use clap::{ArgMatches, Command}; -use dioxus::core::SpawnIfAsync; -use std::{cell::RefCell, collections::HashMap}; - -use mize::{ - item::ItemData, mize_err, mize_part, proto::MizeMessage, Mize, MizeError, MizePart, - MizePartCreate, MizeResult, -}; - -thread_local! { - pub static MIZE_CLI_SPAWN: RefCell> = const { RefCell::new(None) }; -} - -struct CliSpawn { - wait_rx: flume::Receiver<()>, - conn_id: Option, - mize: Mize, -} - -pub fn cli_spawn_setup(mize: Mize, conn_id: u64, wait_rx: flume::Receiver<()>) -> MizeResult<()> { - MIZE_CLI_SPAWN.with(|cell| { - *cell.borrow_mut() = Some(CliSpawn { - wait_rx, - conn_id: Some(conn_id), - mize, - }); - Ok(()) - }) -} - -pub fn cli_spawn(mize: &mut Mize, cmd: String) -> MizeResult<()> { - // spawn locally - if !mize.get_config("cli.daemonMode").unwrap_or(ItemData::new()).as_bool().unwrap_or(false) { - std::process::Command::new("/bin/sh") - .arg("-c") - .arg(&cmd) - .status()?; - return Ok(()); - } - - // for spawning in the client if we are running in the daemon (which is eg attached to the users tty) - MIZE_CLI_SPAWN.with(|cell| { - if let Some(spawn) = cell.borrow().as_ref() { - let conn_id = spawn.conn_id.ok_or(mize_err!("no conn_id set"))?; - let conn = spawn.mize.get_connection(conn_id)?; - conn.send(MizeMessage::new_custom("cli.spawn", cmd, conn_id))?; - - log::info!("before wait_rx.recv()"); - spawn.wait_rx.recv()?; - log::info!("after wait_rx.recv()"); - Ok(()) - } else { - Err(mize_err!("no cli spawn thread_local available")) - } - }) -} - -#[mize_part("cli")] -#[derive(Default)] -pub struct CliPart { - mize: Mize, - cmds: HashMap, - current_cmd_name: String, - actions: - HashMap MizeResult<()> + Send + Sync + 'static>>, - parsers: Option) -> MizeResult<()> + Send + Sync + 'static>>>, -} - -pub fn cli(mize: &mut Mize) -> MizeResult<()> { - let command = Command::new("marts-cli").allow_external_subcommands(true); - let (spawn_wait_tx, spawn_wait_rx) = flume::unbounded::<()>(); - let mut cli_part = CliPart { - mize: mize.clone(), - cmds: HashMap::new(), - current_cmd_name: "marts-cli".to_string(), - actions: HashMap::new(), - parsers: Some(Vec::new()), - }; - cli_part.cmds.insert("marts-cli".to_string(), command); - - mize.add_listener( - "cli", - Box::new(move |msg, mize| cli_msg_handler(msg, mize, spawn_wait_rx.clone())), - )?; - mize.add_listener( - "cli.spawn_done", - Box::new(move |_msg, _mize| { - log::info!("before send"); - spawn_wait_tx.send(()); - log::info!("after send"); - Ok(()) - }), - )?; - mize.add_part(Box::new(cli_part)) -} - -impl MizePartCreate for CliPart {} - -impl MizePart for CliPart { - fn init(&mut self, _mize: &mut Mize) -> MizeResult<()> { - Ok(()) - } - fn run(&mut self, mize: &mut Mize) -> MizeResult<()> { - if mize - .get_config("cli.daemonMode") - .unwrap_or(ItemData::new()) - .as_bool() - .unwrap_or(false) - { - return Ok(()); - } - let matches = self - .cmds - .remove(&self.current_cmd_name) - .unwrap() - .get_matches(); - let sub_cmd = match matches.subcommand_name() { - Some(sub_cmd) => sub_cmd, - None => { - log::info!("No subcommand provided"); - return Ok(()); - } - }; - let action = match self.actions.remove(sub_cmd) { - Some(action) => action, - None => { - // external parsers - for parser in self.parsers.take().unwrap() { - parser( - mize.clone(), - matches - .subcommand_matches(sub_cmd) - .unwrap() - .get_many::("") - .unwrap() - .map(|s| s.to_string()) - .collect::>(), - )?; - } - return Ok(()); - } - }; - action(matches.subcommand_matches(sub_cmd).unwrap(), mize.clone())?; - Ok(()) - } - fn opts(&self, mize: &mut Mize) { - mize.new_opt("cli.name"); - } -} - -fn cli_msg_handler( - mut msg: MizeMessage, - mize: &mut Mize, - spawn_wait_rx: flume::Receiver<()>, -) -> MizeResult<()> { - let tmp = msg.data()?; - let data = tmp - .cbor() - .as_array() - .ok_or(mize_err!("cli message data was not an array"))?; - let full_cmd = data - .iter() - .nth(0) - .cloned() - .ok_or(mize_err!("cli message data was empty"))?; - let full_cmd_text = full_cmd - .as_text() - .ok_or(mize_err!("cli cmd was not text"))?; - let cmd = full_cmd_text - .split("/") - .last() - .ok_or(mize_err!("failed to get cmd"))?; - let mut cli = mize.get_part_native::("cli").unwrap(); - let command = cli - .cmds - .get(cmd) - .ok_or(mize_err!("no command {cmd} in cli part"))?; - let matches = command - .clone() - .get_matches_from(data.iter().map(|v| v.as_text().unwrap())); - let sub_cmd_name = match matches.subcommand_name() { - Some(sub_cmd) => sub_cmd, - None => { - cli.send_stderr(&msg, "No subcommand provided".to_string())?; - return Ok(()); - } - }; - let action = match cli.actions.get_mut(sub_cmd_name) { - Some(action) => action, - None => { - return Ok(()); - } - }; - - let original_msg = msg.clone(); - let mize_clone = mize.clone(); - mize::MIZE_STDOUT.with(move |stdout| { - *stdout.borrow_mut() = Some(Box::new(move |string| { - let conn_id = original_msg.conn_id; - let msg = MizeMessage::new_custom("cli.stdout", string, conn_id); - let conn = mize_clone.get_connection(conn_id)?; - conn.send(msg)?; - Ok(()) - })) - }); - - cli_spawn_setup(mize.clone(), msg.conn_id, spawn_wait_rx)?; - - action( - matches.subcommand_matches(sub_cmd_name).unwrap(), - mize.clone(), - )?; - cli.send_done(&msg)?; - Ok(()) -} - -impl CliPart { - pub fn set_command(&mut self, cmd: &str) { - self.current_cmd_name = cmd.to_owned(); - if !self.cmds.contains_key(cmd) { - self.cmds - .insert(cmd.to_owned(), Command::new(cmd.to_owned())); - } - } - pub fn send_stderr(&mut self, original_msg: &MizeMessage, msg: String) -> MizeResult<()> { - let conn_id = original_msg.conn_id; - let msg = MizeMessage::new_custom("cli.stderr", msg, conn_id); - let conn = self.mize.get_connection(conn_id)?; - conn.send(msg)?; - Ok(()) - } - pub fn send_stdout(&mut self, original_msg: &MizeMessage, msg: String) -> MizeResult<()> { - let conn_id = original_msg.conn_id; - let msg = MizeMessage::new_custom("cli.stdout", msg, conn_id); - let conn = self.mize.get_connection(conn_id)?; - conn.send(msg)?; - Ok(()) - } - pub fn send_spawn(&mut self, original_msg: &MizeMessage, msg: String) -> MizeResult<()> { - let conn_id = original_msg.conn_id; - let msg = MizeMessage::new_custom("cli.spawn", msg, conn_id); - let conn = self.mize.get_connection(conn_id)?; - conn.send(msg)?; - Ok(()) - } - pub fn send_done(&mut self, original_msg: &MizeMessage) -> MizeResult<()> { - let conn_id = original_msg.conn_id; - let msg = MizeMessage::new_custom("cli.done", ItemData::new(), conn_id); - let conn = self.mize.get_connection(conn_id)?; - conn.send(msg)?; - Ok(()) - } - pub fn subcommand MizeResult<()> + Send + Sync + 'static>( - &mut self, - subcmd: Command, - action: T, - ) -> MizeResult<()> { - let name = subcmd.get_name().to_string(); - let cmd = self - .cmds - .remove(&self.current_cmd_name) - .unwrap() - .subcommand(subcmd); - self.cmds.insert(self.current_cmd_name.clone(), cmd); - self.actions.insert(name, Box::new(action)); - Ok(()) - } - pub fn add_sub_parser) -> MizeResult<()> + Send + Sync + 'static>( - &mut self, - parser: T, - ) -> MizeResult<()> { - self.parsers.as_mut().unwrap().push(Box::new(parser)); - Ok(()) - } - pub fn with_cmd( - &mut self, - func: fn(mize: Mize, cmd: Command) -> MizeResult, - ) -> MizeResult<()> { - let cmd = self.cmds.remove(&self.current_cmd_name).ok_or(mize_err!( - "current command {} not found", - self.current_cmd_name - ))?; - let cmd = func(self.mize.clone(), cmd)?; - self.cmds.insert(self.current_cmd_name.clone(), cmd); - Ok(()) - } - pub fn run(&mut self, cmdline: Vec) -> MizeResult<()> { - let cmd_name = cmdline.iter().nth(0).ok_or(mize_err!("empty cmdline"))?; - let cmd = self.cmds.remove(cmd_name).ok_or(mize_err!("cmd {} not found in CliPart", cmd_name))?; - - let matches = cmd.get_matches_from(cmdline); - let sub_name = matches.subcommand_name().ok_or(mize_err!("subcommand not found"))?; - let sub_matches = matches.subcommand_matches(sub_name).ok_or(mize_err!("subcommand matches not found"))?; - let action = self.actions.remove(sub_name).ok_or(mize_err!("action for subcommand not found"))?; - action(sub_matches, self.mize.clone())?; - - Ok(()) - } -} - -// impl smth like this to run cli commands in the daemon. -/* -pub fn mize_thin_cli_client(bin_name: Option<&str>) -> MizeResult<()> { - use std::io::Write; - use std::os::unix::net::UnixStream; - - let store_path = - std::env::var("MIZE_STORE").map_err(|_| mize_err!("MIZE_STORE not set in environment"))?; - let sock_path = store_path + "/sock"; - println!("sock_path: {}", sock_path); - let mut cmd_line = std::env::args().collect::>(); - if let Some(bin_name) = bin_name { - cmd_line[0] = bin_name.to_owned(); - } - let msg = MizeMessage::new_custom("cli", cmd_line, 0); - - let mut stream = UnixStream::connect(sock_path)?; - - stream.write_all(&msg.bytes())?; - - // Optional: Ensure all buffered data is pushed to the socket - stream.flush()?; - let mut reader = BufReader::new(stream.try_clone()?); - - loop { - let msg: Value = ciborium::from_reader(&mut reader)?; - let mut msg = MizeMessage::new(msg, 0); - match msg.cmd()? { - MessageCmd::Custom(kind) => { - if kind == "cli.done".into_item_data() { - break; - } - if kind == "cli.stdout".into_item_data() { - println!("{}", msg.data()?.value_string()?); - } - if kind == "cli.stderr".into_item_data() { - eprintln!("{}", msg.data()?.value_string()?); - } - if kind == "cli.spawn".into_item_data() { - let cmd = msg.data()?.value_string()?; - std::process::Command::new("/bin/sh") - .arg("-c") - .arg(&cmd) - .status()?; - let done_msg = MizeMessage::new_custom("cli.spawn_done", ItemData::new(), 0); - stream.write_all(&done_msg.bytes())?; - } - } - _ => { - continue; - } - } - } - - Ok(()) -} - */ diff --git a/marts/src/dev/mod.rs b/marts/src/dev/mod.rs deleted file mode 100644 index 55c049f..0000000 --- a/marts/src/dev/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ - -use mize::{Mize, MizeResult, MizeError, mize_err}; - -use crate::CliPart; -use clap::Arg; - -// spacetime gen command: sh!(RUST_LOG=error RUST_BACKTRACE=0 spacetime generate --build-options="--lint-dir=" -p $SRC/mize/marts/spacetime -o $SRC/mize/marts/generated/src/spacetime --lang rust)?; -pub fn part_dev(mize: &mut Mize) -> MizeResult<()> { - let mut cli = mize.get_part_native::("cli")?; - cli.set_command("dev"); - - - - - mize.add_name_only_part("dev"); - Ok(()) -} diff --git a/marts/src/discord/mod.rs b/marts/src/discord/mod.rs deleted file mode 100644 index 7231e39..0000000 --- a/marts/src/discord/mod.rs +++ /dev/null @@ -1,167 +0,0 @@ -pub use mize::*; - -// ========== WASM-specific imports (Obsidian plugin) ========== -#[cfg(feature = "target-obsidian")] -use wasm_bindgen::prelude::*; -#[cfg(feature = "target-obsidian")] -use js_sys; -#[cfg(feature = "target-obsidian")] -use web_sys; -#[cfg(feature = "target-obsidian")] -use crate::obsidian::{ObsidianPart, MartsCommand}; - -// ========== Native-specific imports (OS daemon) ========== -#[cfg(feature = "target-os")] -use serenity::{ - async_trait as serenity_async_trait, - client::{Client, Context, EventHandler}, - model::{ - channel::Message, - gateway::Ready, - id::ChannelId, - }, - prelude::GatewayIntents, -}; -#[cfg(feature = "target-os")] -use mize::async_trait; - -#[derive(Clone)] -#[mize_part] -pub struct DiscordPart { - pub mize: Mize, - // Native: serenity client - #[cfg(feature = "target-os")] - pub client: Option, -} - -impl DiscordPart { - // ========== WASM (Obsidian plugin) methods ========== - - /// Read a file from the Obsidian vault using the Obsidian API - #[cfg(feature = "target-obsidian")] - pub fn read_obsidian_file(&self, path: &str) -> MizeResult { - // TODO: Implement using js_sys to call Obsidian's vault.read() or similar - // Example approach: - use wasm_bindgen::JsCast; - use js_sys::Reflect; - let obsidian_part = self.mize.get_part_native::("obsidian")?; - let plugin = &obsidian_part.plugin(); - let app = Reflect::get(plugin, &"app".into())?; - let vault = Reflect::get(&app, &"vault".into())?; - let content = Reflect::call(&vault, &"read".into(), &path.into())?; - content.as_string().ok_or_else(|| mize_err!("Failed to read file")) - } - - /// Send content to Discord channel using Discord REST API - #[cfg(feature = "target-obsidian")] - pub fn send_to_discord_rest(&self, content: String, channel_id: u64) -> MizeResult<()> { - // TODO: Implement using web_sys to call Discord REST API - // 1. Get token: mize.get_config("discord.token") - // 2. POST to https://discord.com/api/v10/channels/{channel_id}/messages - // 3. Headers: Authorization: Bot , Content-Type: application/json - // 4. Body: {"content": content} - Ok(()) - } - - // ========== Native (OS daemon) methods ========== - - /// Start the serenity Discord bot - #[cfg(feature = "target-os")] - pub async fn start_serenity_bot(&mut self, mize: &mut Mize) -> MizeResult<()> { - let token = mize.get_config("discord.token")?.value_string()?; - - // Define event handler - struct Handler; - - #[serenity_async_trait] - impl EventHandler for Handler { - async fn ready(&self, _: Context, ready: Ready) { - println!("Discord bot logged in as {}", ready.user.name); - } - - // TODO: Add message handler for receiving commands from plugin - // This is where you'll implement communication with the Obsidian plugin - // Example: - // async fn message(&self, ctx: Context, msg: Message) { - // if msg.content.starts_with("!send") { - // // Parse command and send file to channel - // } - // } - } - - let mut client = Client::builder(&token, GatewayIntents::non_privileged()) - .event_handler(Handler) - .await?; - - // Spawn the client in a tokio task - tokio::spawn({ - let client_clone = client.clone(); - async move { - if let Err(why) = client_clone.start().await { - eprintln!("Discord client error: {:?}", why); - } - } - }); - - self.client = Some(client); - Ok(()) - } -} - -impl MizePart for DiscordPart { - fn init(&mut self, mize: &mut Mize) -> MizeResult<()> { - // WASM: Add command to Obsidian - #[cfg(feature = "target-obsidian")] - { - let obsidian_part = mize.get_part_native::("obsidian")?; - - let callback = { - let mize_clone = mize.clone(); - move |mize_inner: Mize| -> MizeResult<()> { - // Get configuration values - let file_path = mize_inner.get_config("sc2.shared_daily_journal_file")? - .value_string()?; - let channel_id_str = mize_inner.get_config("sc2.shared_daily_journal_channel")? - .value_string()?; - let channel_id = channel_id_str.parse::()?; - - // Get DiscordPart and send the file - let mut mize_mut = mize_inner; - let discord_part = mize_mut.get_part_native::("discord")?; - let content = discord_part.read_obsidian_file(&file_path)?; - - // TODO: COMMUNICATION WITH DAEMON GOES HERE - // For now, we send directly using REST API. - // Replace this with your plugin-to-daemon messaging logic. - discord_part.send_to_discord_rest(content, channel_id)?; - - Ok(()) - } - }; - - obsidian_part.add_command(MartsCommand { - id: "send_to_discord".to_string(), - name: "Send to Discord".to_string(), - callback: Box::new(callback), - })?; - } - - Ok(()) - } - - // Native: Override async_init to start serenity bot - #[cfg(feature = "target-os")] - async fn async_init(&mut self, mize: &mut Mize) -> MizeResult<()> { - self.start_serenity_bot(mize).await - } -} - -impl MizePartCreate for DiscordPart {} - -pub fn part_discord(mize: &mut Mize) -> MizeResult<()> { - mize.register_part(Box::new(DiscordPart { - mize: mize.clone(), - #[cfg(feature = "target-os")] - client: None, - })) -} diff --git a/marts/src/habitica.rs b/marts/src/habitica.rs deleted file mode 100644 index abace1e..0000000 --- a/marts/src/habitica.rs +++ /dev/null @@ -1,128 +0,0 @@ -use chrono::{DateTime, Utc}; -use mize::{mize_err, mize_part, Mize, MizeError, MizePart, MizePartCreate, MizeResult}; -use reqwest::{blocking::Client, blocking::Response, header, Method}; -use serde_json::{json, Value}; -use std::thread::sleep; -use std::time::Duration; - -#[mize_part] -#[derive(Default)] -pub struct Habitica { - mize: Mize, - client: Client, -} - -pub fn habitica(mize: &mut Mize) -> MizeResult<()> { - let client = Client::new(); - mize.register_part(Box::new(Habitica { - mize: mize.clone(), - client, - })) -} - -impl MizePartCreate for Habitica {} -impl MizePart for Habitica { - fn opts(&self, mize: &mut Mize) { - mize.new_opt("habitica.api_url"); - mize.new_opt("habitica.user_id"); - mize.new_opt("habitica.api_token"); - mize.new_opt("habitica.client_name"); - } -} - -impl Habitica { - pub fn api_request(&mut self, method: Method, path: String, data: Value) -> MizeResult { - let api_url = self.mize.get_config("habitica.api_url")?.to_string(); - let user_id = self.mize.get_config("habitica.user_id")?.to_string(); - let api_token = self.mize.get_config("habitica.api_token")?.to_string(); - let client_name = self.mize.get_config("habitica.client_name")?.to_string(); - - let mut headers = header::HeaderMap::new(); - headers.insert( - "Content-Type", - header::HeaderValue::from_static("application/json"), - ); - headers.insert("x-api-user", header::HeaderValue::from_str(&user_id)?); - headers.insert("x-api-key", header::HeaderValue::from_str(&api_token)?); - headers.insert("x-client", header::HeaderValue::from_str(&client_name)?); - - let url = format!("{}/{}", api_url, path.trim_start_matches('/')); - - let mut request_builder = self.client.request(method, &url).headers(headers); - - if data != json!({}) { - request_builder = request_builder.json(&data); - } - - let response = request_builder.send()?; - - handle_rate_limit(&response); - - if !response.status().is_success() { - let status = response.status(); - let text = response.text().unwrap_or_default(); - log::info!("request_url: {}", url); - return Err(mize_err!( - "Habitica API error: {} {} - {}", - status.as_u16(), - status.canonical_reason().unwrap_or(""), - text - )); - } - - let json_response: Value = response.json()?; - Ok(json_response.get("data").cloned().unwrap_or(Value::Null)) - } - - pub fn get_tasks(&mut self, task_type: &str) -> MizeResult { - self.api_request( - Method::GET, - format!("tasks/user?type={}", task_type), - json!({}), - ) - } - - pub fn delete_task(&mut self, id: &str) -> MizeResult { - self.api_request(Method::DELETE, format!("tasks/{}", id), json!({})) - } -} - -fn handle_rate_limit(response: &Response) { - let headers = response.headers(); - let limit = headers - .get("X-RateLimit-Limit") - .and_then(|v| v.to_str().ok()) - .unwrap_or("NONE"); - let remaining = headers - .get("X-RateLimit-Remaining") - .and_then(|v| v.to_str().ok()) - .and_then(|s| s.parse::().ok()) - .unwrap_or(10); - let reset = headers - .get("X-RateLimit-Reset") - .and_then(|v| v.to_str().ok()); - - log::info!( - "RateLimit: {} | Remaining: {} | Reset: {}", - limit, - remaining, - reset.unwrap_or("N/A") - ); - - if remaining < 2 { - if let Some(reset_str) = reset { - if let Ok(reset_date) = DateTime::parse_from_rfc2822(reset_str) { - let now = Utc::now(); - let wait_duration = reset_date.signed_duration_since(now).to_std(); - if let Ok(wait_duration) = wait_duration { - let wait_ms = wait_duration.as_millis() as u64 + 1000; - log::info!( - "Waiting {} secs for next rate limit window...", - (wait_ms / 1000) - ); - sleep(Duration::from_millis(wait_ms)); - } - } - } - } -} diff --git a/marts/src/index.ts b/marts/src/index.ts deleted file mode 100644 index d5c1e84..0000000 --- a/marts/src/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./task/obsidian-otask-parse"; -export * from "./c2vi/obsidian-canvas-patch"; - -export * from "./js/stub_deno"; diff --git a/marts/src/js/glue_deno.rs b/marts/src/js/glue_deno.rs deleted file mode 100644 index 4fd563f..0000000 --- a/marts/src/js/glue_deno.rs +++ /dev/null @@ -1,53 +0,0 @@ -use deno_core::extension; -use deno_core::op2; -use deno_core::OpState; -use mize::{Mize, MizeError}; -use std::sync::Arc; - -use crate::CliPart; -use crate::JsPart; - -#[op2(fast)] -fn op_mize_get_part(#[string] name: &str) { - log::info!("js wants the part {}", name); -} - -#[op2] -#[string] -fn op_mize_get_config(state: &mut OpState, #[string] key: &str) -> String { - let mize: Mize = state.borrow::().clone(); - format!("config_value_for_{}", key) -} - -#[op2(fast)] -fn op_mize_add_part(state: &mut OpState, #[string] key: &str) { - let mize: Mize = state.borrow::().clone(); - log::info!("adding part {}", key); -} - -#[op2(fast)] -fn op_cli_subcommand(state: &mut OpState, #[string] name: String) { - let mut mize: Mize = state.borrow::().clone(); - let mut cli = mize.get_part_native::("cli").unwrap(); - cli.subcommand( - clap::Command::new(name.clone()), - move |_sub_matches, mut mize| { - let mut js = mize.get_part_native::("js").unwrap(); - js.eval("log(\"cli command being called\")".to_string())?; - js.eval(format!("mize.vars.cli.subcommand({name})"))?; - Ok(()) - }, - ); -} - -// Create an extension with your custom ops -extension!( - my_extension, - ops = [op_mize_get_part, op_mize_get_config], - options = { - mize: Mize, - }, - state = |state: &mut OpState, config: Config| { - state.put::(config.mize); - }, -); diff --git a/marts/src/js/glue_deno.ts b/marts/src/js/glue_deno.ts deleted file mode 100644 index d3d48cc..0000000 --- a/marts/src/js/glue_deno.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Mize } from "./stub_deno.ts"; - -function argsToMessage(...args) { - return args.map((arg) => JSON.stringify(arg)).join(" "); -} - -globalThis.log = (...args) => { - Deno.core.print(`[out]: ${argsToMessage(...args)}\n`, false); -}; - -globalThis.mize = new Mize(); diff --git a/marts/src/js/mod.rs b/marts/src/js/mod.rs deleted file mode 100644 index 378f5bd..0000000 --- a/marts/src/js/mod.rs +++ /dev/null @@ -1,136 +0,0 @@ -use deno_core::error::AnyError; -use deno_core::url::Url; -use deno_core::v8::OneByteConst; -use deno_core::{ - ascii_str_include, extension, op2, JsRuntime, ModuleSpecifier, PollEventLoopOptions, - RuntimeOptions, -}; -use deno_core::{FastStaticString, FsModuleLoader}; -use mize::async_trait; -use mize::instance::MizePartCreate; -use mize::{mize_part, Mize, MizePart, MizeResult}; -use std::future::Future; -use std::path::Path; -use std::pin::Pin; -use std::rc::Rc; -use std::str::FromStr; -use tokio::runtime::Builder; -use tokio::task::{spawn_local, LocalSet}; - -mod glue_deno; - -#[mize_part("js")] -#[derive(Default)] -pub struct JsPart { - mize: Mize, - sender: Option>, -} - -pub type BoxFuture<'a> = Pin> + 'a>>; -pub type BoxClosure = Box FnOnce(&'a mut JsRuntime) -> BoxFuture<'a> + Send + 'static>; - -impl MizePart for JsPart { - fn run(&mut self, mize: &mut Mize) -> MizeResult<()> { - log::info!("js part run"); - self.sender - .as_ref() - .unwrap() - .send(JsRuntimeThreadMessage::DoRunPhase) - .unwrap(); - Ok(()) - } -} - -pub fn js(mize: &mut Mize) -> MizeResult<()> { - let (sender, receiver) = flume::unbounded::(); - let mize_clone = mize.clone(); - - // the thread which will run any js - mize.spawn_and_wait("js_runtime_thread", || { - js_runtime_thread(mize_clone, receiver) - })?; - - mize.add_part(Box::new(JsPart { - mize: mize.clone(), - sender: Some(sender), - })) -} - -pub fn part_from_file( - mize: &mut Mize, - name: &'static str, - code: FastStaticString, -) -> MizeResult<()> { - let mut js = mize.get_part_native::("js")?; - js.execute_init_js(code)?; - Ok(()) -} - -impl JsPart { - pub fn execute_init_js(&mut self, code: FastStaticString) -> MizeResult<()> { - self.sender - .as_ref() - .unwrap() - .send(JsRuntimeThreadMessage::RunInitJs(code)) - .unwrap(); - Ok(()) - } - pub fn eval(&mut self, code: String) -> MizeResult<()> { - self.sender - .as_ref() - .unwrap() - .send(JsRuntimeThreadMessage::RunJs(code)) - .unwrap(); - Ok(()) - } -} - -fn js_runtime_thread( - mize: Mize, - receiver: flume::Receiver, -) -> MizeResult<()> { - let mut js_runtime = JsRuntime::new(RuntimeOptions { - //module_loader: Some(Rc::new(FsModuleLoader)), - //extensions: vec![glue_deno::my_extension::init(mize.clone())], - ..Default::default() - }); - - js_runtime - .execute_script("[stub]", ascii_str_include!("../deno_dist/glue_deno.js")) - .unwrap(); - - loop { - log::info!("js thread waiting for smth"); - let msg = receiver.recv().unwrap(); - log::info!("js thread got smth"); - match msg { - JsRuntimeThreadMessage::RunInitJs(js_code) => { - if let Err(err) = js_runtime.execute_script("[init]", js_code) { - log::info!("err: {}", err); - } - log::info!("done running js"); - } - JsRuntimeThreadMessage::RunJs(js_code) => { - if let Err(err) = js_runtime.execute_script("[idk]", js_code) { - log::info!("err: {}", err); - } - log::info!("done running js"); - } - JsRuntimeThreadMessage::DoRunPhase => { - if let Err(err) = js_runtime.execute_script("[runPhase]", "mize.runPhase()") { - log::info!("err: {}", err); - } - log::info!("done with runPhase"); - return Ok(()); - } - } - } -} - -enum JsRuntimeThreadMessage { - //Closure(Box MizeResult<()> + Send>), - //AsyncClosure(BoxClosure), - RunInitJs(FastStaticString), - RunJs(String), - DoRunPhase, -} diff --git a/marts/src/js/stub_deno.ts b/marts/src/js/stub_deno.ts deleted file mode 100644 index 6c4d3e8..0000000 --- a/marts/src/js/stub_deno.ts +++ /dev/null @@ -1,18 +0,0 @@ -export class Mize { - async get_config(key: string): Promise { - return "hiiiiiii"; - } - async add_opts(opts: any): Promise {} - async add_part(part: any): Promise {} - async report_err(err: MizeError) {} - runPhase() { - Deno.core.print("runPhase in js \n"); - } -} - -type MizeError = string; - -export class Cli { - constructor(mize: Mize) {} - async sub_command(name: string, cmd: any): Promise {} -} diff --git a/marts/src/lib.rs b/marts/src/lib.rs deleted file mode 100644 index a42c944..0000000 --- a/marts/src/lib.rs +++ /dev/null @@ -1,54 +0,0 @@ -#![feature(oneshot_channel)] - -#[cfg(feature = "target-os")] -pub mod cli; -#[cfg(feature = "target-os")] -pub use cli::*; - -#[cfg(feature = "target-os")] -pub mod habitica; -#[cfg(feature = "target-os")] -pub use habitica::*; - -#[cfg(feature = "target-os")] -pub mod c2vi { - pub mod part; - pub mod dashboard; -} -pub use c2vi::part::*; - -#[cfg(feature = "target-os")] -pub mod dev; -#[cfg(feature = "target-os")] -pub use dev::part_dev; - -#[cfg(feature = "target-obsidian")] -pub mod obsidian; -#[cfg(feature = "target-obsidian")] -pub use obsidian::*; - -pub mod spacetime; -pub use spacetime::*; - -pub mod auth { - pub mod client; - pub use client::*; -} -pub use auth::*; - -pub mod ppc; - - -#[cfg(feature = "target-obsidian")] -pub mod matrix; -#[cfg(feature = "target-obsidian")] -pub use matrix::part_matrix; - -pub mod sci; - -//#[cfg(feature = "target-os")] -//pub mod js; -//#[cfg(feature = "target-os")] -//pub use js::*; - -pub use generated; diff --git a/marts/src/matrix/mod.rs b/marts/src/matrix/mod.rs deleted file mode 100644 index 3d79084..0000000 --- a/marts/src/matrix/mod.rs +++ /dev/null @@ -1,247 +0,0 @@ -use mize::{Mize, MizeResult, MizePart, MizePartCreate, mize_part}; -use wasm_bindgen::prelude::*; -use wasm_bindgen_futures::spawn_local; -use js_sys::Function; -use web_sys::HtmlElement; - -use matrix_sdk::{ - Client, ClientConfig, SyncState, - ruma::{ - user_id::UserId, - events::room::message::RoomMessageEventContent, - }, -}; - -#[cfg(feature = "target-js")] -mod ui; -use ui::mount_chat_app; - -const ROOM_ID: &str = "!XwqdXGPlmaLatdGUiN:ppc.social"; -const ACCOUNT_NAME: &str = "default"; -const INITIAL_LOAD_LIMIT: usize = 50; - -/// Matrix part that manages Matrix client and UI -#[mize_part("matrix")] -#[derive(Clone)] -pub struct MatrixPart { - mize: Mize, - pub client: Option, - pub timeline: Vec, - pub message_draft: String, - pub edit_event_id: Option, -} - -impl MizePart for MatrixPart {} -impl MizePartCreate for MatrixPart {} - -impl MatrixPart { - /// Create a new MatrixPart - pub fn new(mize: Mize) -> Self { - Self { - mize, - client: None, - timeline: Vec::new(), - message_draft: String::new(), - edit_event_id: None, - } - } - - /// Initialize the Matrix client from config - pub async fn init_client(&mut self) -> Result<(), String> { - let homeserver = self.mize - .get_config(&format!("matrix.accounts.{}.homeserver", ACCOUNT_NAME)) - .map_err(|e| format!("Failed to get homeserver config: {:?}", e))?; - - let access_token = self.mize - .get_config(&format!("matrix.accounts.{}.access_token", ACCOUNT_NAME)) - .map_err(|e| format!("Failed to get access_token config: {:?}", e))?; - - let user_id_str = self.mize - .get_config(&format!("matrix.accounts.{}.user_id", ACCOUNT_NAME)) - .map_err(|e| format!("Failed to get user_id config: {:?}", e))?; - - let device_id = self.mize - .get_config(&format!("matrix.accounts.{}.device_id", ACCOUNT_NAME)) - .map_err(|e| format!("Failed to get device_id config: {:?}", e))?; - - let user_id = UserId::parse(&user_id_str) - .map_err(|e| format!("Invalid user_id: {:?}", e))?; - - let config = ClientConfig::new() - .homeserver_url(homeserver) - .device_id(device_id); - - let client = Client::new_with_config(user_id, Some(access_token), config) - .await - .map_err(|e| format!("Failed to create client: {:?}", e))?; - - self.client = Some(client.clone()); - - // Start sync in background - self.start_sync(client).await?; - - Ok(()) - } - - /// Start sync and set up event listeners - async fn start_sync(&mut self, client: Client) -> Result<(), String> { - let room_id = ROOM_ID.to_string(); - let mize = self.mize.clone(); - - // Start sync - let sync_token = client.sync_token().await; - let mut sync_state = SyncState::new(sync_token); - - let client_clone = client.clone(); - - spawn_local(async move { - loop { - match client_clone.sync(&mut sync_state).await { - Ok(response) => { - // Process sync response - update MatrixPart via mize - if let Some(rooms) = response.rooms { - if let Some(join) = rooms.join { - if let Some(room_events) = join.get(&room_id) { - // Get MatrixPart and update timeline - if let Ok(mut matrix_part) = mize.get_part_native::("matrix") { - for event in &room_events.timeline.events { - if event.room_id() == room_id { - matrix_part.timeline.push(event.clone()); - // Keep only last INITIAL_LOAD_LIMIT events - if matrix_part.timeline.len() > INITIAL_LOAD_LIMIT { - matrix_part.timeline.remove(0); - } - } - } - } - } - } - } - - // Check if we should stop syncing - if sync_state.should_stop() { - break; - } - } - Err(e) => { - console_log!("Sync error: {:?}", e); - break; - } - } - } - }); - - Ok(()) - } - - /// Send a message to the room - pub async fn send_message(&mut self, room_id: &str, content: Option<>) -> MizeResult<()> { - let client = self.client.as_ref() - .ok_or_else(|| mize::error::Error::new("Client not initialized"))?; - - if self.message_draft.is_empty() { - return Ok(()); - } - - let content = RoomMessageEventContent::text_plain(&self.message_draft); - - if let Some(_event_id) = &self.edit_event_id { - // Editing existing message - placeholder for now - console_log!("Editing message (not yet implemented)"); - } - - // Send message - client.send_room_message(room_id, content).await?; - - // Clear draft after sending - self.message_draft.clear(); - self.edit_event_id = None; - - Ok(()) - } -} - -/// Entry point for the Matrix part -pub fn part_matrix(mize: &mut Mize) -> MizeResult<()> { - #[cfg(feature = "target-obsidian")] { - use crate::ObsidianPart; - - // Get the Obsidian part - let obsidian = mize.get_part_native::("obsidian")?; - - // Create and register MatrixPart - let matrix_part = MatrixPart::new(mize.clone()); - mize.register_part(Box::new(matrix_part)); - - // Get the registered MatrixPart to initialize it - let mize_clone = mize.clone(); - spawn_local(async move { - if let Ok(mut matrix_part) = mize_clone.get_part_native::("matrix") { - if let Err(e) = matrix_part.init_client().await { - console_log!("Failed to initialize Matrix client: {}", e); - } - } - }); - - // Create a JS function that will be called when the view is opened - let mize_for_view = mize.clone(); - let view_creator = Closure::::wrap(Box::new(move |leaf: JsValue| { - if let Some(element) = extract_dom_element(leaf) { - // Get MatrixPart state for the UI - if let Ok(matrix_part) = mize_for_view.get_part_native::("matrix") { - let timeline = matrix_part.timeline.clone(); - let message_draft = matrix_part.message_draft.clone(); - let edit_event_id = matrix_part.edit_event_id.clone(); - - mount_chat_app(element, timeline, message_draft, edit_event_id, mize_for_view.clone()); - } - } else { - console_log!("Failed to extract DOM element from leaf"); - } - })); - - // Convert closure to JS Function - let view_creator_fn: &Function = view_creator.as_ref().unchecked_ref(); - - // Register the view with Obsidian - ObsidianPart::register_view(&obsidian.plugin(), "matrix-chat-view", view_creator_fn)?; - - // Prevent the closure from being dropped - view_creator.forget(); - } - - Ok(()) -} - -/// Extract DOM element from Obsidian leaf JSValue -fn extract_dom_element(leaf: JsValue) -> Option { - use wasm_bindgen::JsCast; - use js_sys::Reflect; - - // Try to get the containerEl from the leaf - let container_value = Reflect::get(&leaf, &"containerEl".into()).ok()?; - let container = container_value.dyn_into::().ok()?; - - // Create a div to mount into - let doc = web_sys::window()?.document()?; - let mount_point = doc.create_element("div").ok()?; - mount_point.set_attribute("style", "height: 100%; width: 100%;").ok()?; - - container.append_child(&mount_point).ok()?; - mount_point.dyn_into::().ok() -} - -// Console log macros -#[macro_export] -macro_rules! console_log { - ($($t:tt)*) => { - web_sys::console::log_1(&format!($($t)*).into()); - }; -} - -#[macro_export] -macro_rules! console_error { - ($($t:tt)*) => { - web_sys::console::error_1(&format!($($t)*).into()); - }; -} diff --git a/marts/src/matrix/ui.rs b/marts/src/matrix/ui.rs deleted file mode 100644 index 3ebf160..0000000 --- a/marts/src/matrix/ui.rs +++ /dev/null @@ -1,269 +0,0 @@ -use dioxus::prelude::*; -use dioxus_web::events::FormEvent; -use mize::Mize; -use matrix_sdk::SyncRoomEvent; - -const ROOM_ID: &str = "!XwqdXGPlmaLatdGUiN:ppc.social"; - -/// Props for the chat component -#[derive(Props, Clone)] -pub struct ChatProps { - pub mize: Mize, - pub initial_timeline: Vec, - pub initial_draft: String, - pub initial_edit_id: Option, -} - -/// Message component - renders a single message -#[component] -pub fn Message(cx: Scope, event: SyncRoomEvent) -> Element { - let sender = event.sender().to_string(); - let timestamp = event.origin_server_ts(); - - // Extract display name from MXID (basic version) - let display_name = if let Some(at_pos) = sender.find('@') { - if let Some(colon_pos) = sender.rfind(':') { - &sender[at_pos + 1..colon_pos] - } else { - &sender[at_pos + 1..] - } - } else { - &sender - }; - - // Format timestamp - let time_str = { - let dt = js_sys::Date::new(&(timestamp as f64)); - dt.to_locale_string() - }; - - // Extract message content - let content = event - .as_original() - .and_then(|e| e.content().deserialize().ok()) - .and_then(|c: matrix_sdk::ruma::events::room::message::RoomMessageEventContent| { - c.body().map(|s| s.to_string()) - }) - .unwrap_or_default(); - - // Check if this is an edit - let is_edit = event - .as_original() - .map(|e| { - e.content() - .get("m.relates_to") - .and_then(|v| v.as_object()) - .and_then(|o| o.get("rel_type")) - .and_then(|v| v.as_str()) - == Some("m.replace") - }) - .unwrap_or(false); - - cx.render(rsx! { - div { - class: "matrix-chat-event", - style: "margin: 14px 16px; padding-bottom: 10px; border-bottom: 1px solid var(--background-modifier-border);", - - div { - class: "matrix-chat-msghead", - style: "font-size: 1em; font-weight: 500; color: var(--interactive-accent); display: flex; align-items: center; gap: 10px;", - - span { display_name } - span { - style: "font-size: 0.85em; color: var(--text-muted); margin-left: auto;", - {time_str.clone()} - if is_edit { " · edited" } - } - } - - div { - class: "matrix-chat-msgbody", - style: "margin: 6px 0 0 0; font-size: 1em;", - {content} - } - } - }) -} - -/// Editor component - message input area -#[component] -pub fn Editor(cx: Scope, mize: Mize, draft: UseSignal, edit_id: UseSignal>) -> Element { - let on_input = move |evt: FormEvent| { - draft.set(evt.value.clone()); - }; - - let on_send = move |_| { - let mize_clone = mize.clone(); - let draft_val = draft.read().clone(); - let edit_id_val = edit_id.read().clone(); - - cx.spawn(async move { - if let Ok(mut matrix_part) = mize_clone.get_part_native::("matrix") { - matrix_part.message_draft = draft_val; - matrix_part.edit_event_id = edit_id_val; - if let Err(e) = matrix_part.send_message().await { - console_log!("Failed to send message: {:?}", e); - } - // Clear local draft - draft.set(String::new()); - edit_id.set(None); - } - }); - }; - - let on_keydown = move |evt: dioxus_web::events::KeyboardEvent| { - if (evt.ctrl_key() || evt.meta_key()) && evt.key() == "Enter" { - on_send(evt); - } - }; - - let on_cancel = move |_| { - draft.set(String::new()); - edit_id.set(None); - }; - - cx.render(rsx! { - div { - class: "matrix-chat-editor", - style: "border-top: 1px solid var(--background-modifier-border); background: var(--background-primary); padding: 8px 12px;", - - div { - class: "matrix-chat-editor-inner", - style: "border: 1px solid var(--background-modifier-border); border-radius: 6px; overflow: hidden; background: var(--background-secondary);", - - textarea { - r#type: "text", - rows: "3", - style: "width: 99%; min-height: 40px; resize: vertical; background: transparent; border: none; outline: none; padding: 8px; font-family: inherit; font-size: inherit; color: var(--text-normal);", - value: "{draft}", - oninput: on_input, - onkeydown: on_keydown, - } - } - - button { - r#type: "button", - style: "margin-top: 3px; float: right; padding: 6px 14px; font-size: 0.97em; border-radius: 5px; border: none; background: var(--interactive-accent); color: white; cursor: pointer;", - onclick: on_send, - if edit_id.read().is_some() { "Save" } else { "Send" } - } - - if edit_id.read().is_some() { - button { - r#type: "button", - style: "margin-right: 12px; padding: 6px 12px; font-size: 0.93em; border-radius: 5px; border: none; color: var(--text-normal); background: var(--background-secondary); cursor: pointer;", - onclick: on_cancel, - "Cancel" - } - } - } - }) -} - -/// Timeline component - list of messages -#[component] -pub fn Timeline(cx: Scope, mize: Mize, timeline: UseSignal>) -> Element { - // Periodically refresh timeline from MatrixPart - cx.use_effect((), move |_| { - let mize_clone = mize.clone(); - let timeline_clone = timeline.clone(); - - // Set up interval to poll for updates - let interval = js_sys::set_interval( - &Closure::::wrap(Box::new(move || { - if let Ok(matrix_part) = mize_clone.get_part_native::("matrix") { - *timeline_clone.write() = matrix_part.timeline.clone(); - } - })), - 1000, // 1 second - ); - - // Cleanup on unmount - move || { - js_sys::clear_interval(interval); - } - }); - - cx.render(rsx! { - div { - class: "matrix-chat-scroll", - style: "flex-grow: 1; overflow-y: auto; padding: 8px 0; background: var(--background-secondary);", - - // Room name header - div { - class: "matrix-chat-roomname", - style: "font-weight: 600; text-align: center; font-size: 1.1em; margin: 2px 0 12px 0; border-bottom: 1px solid var(--background-modifier-border); color: var(--text-accent); background: var(--background-primary);", - "Matrix Chat - {ROOM_ID}" - } - - // Messages - for event in timeline.read().iter() { - rsx! { Message { event: event.clone() } } - } - } - }) -} - -/// Root chat component -#[component] -pub fn Chat(cx: Scope, props: ChatProps) -> Element { - let timeline = use_signal(&cx, || props.initial_timeline); - let draft = use_signal(&cx, || props.initial_draft); - let edit_id = use_signal(&cx, || props.initial_edit_id); - - cx.render(rsx! { - div { - class: "matrix-chat-root", - style: "height: 100%; display: flex; flex-direction: column; background: var(--background-primary); color: var(--text-normal);", - - // Title - div { - class: "matrix-chat-title", - style: "padding: 12px; font-weight: bold; font-size: 1.2em; text-align: center; border-bottom: 1px solid var(--background-modifier-border);", - "Matrix Chat" - } - - // Info - div { - class: "matrix-chat-info", - style: "font-size: 0.85em; color: var(--text-muted); text-align: center; margin-bottom: 5px;", - "Room: {ROOM_ID}" - } - - // Timeline - Timeline { mize: props.mize.clone(), timeline } - - // Editor - Editor { mize: props.mize.clone(), draft, edit_id } - } - }) -} - -/// Mount the Dioxus app into a DOM element -pub fn mount_chat_app( - element: web_sys::HtmlElement, - initial_timeline: Vec, - initial_draft: String, - initial_edit_id: Option, - mize: Mize, -) { - dioxus_web::launch( - dioxus::prelude::App::new(move || rsx! { - Chat { - mize: mize.clone(), - initial_timeline: initial_timeline.clone(), - initial_draft: initial_draft.clone(), - initial_edit_id: initial_edit_id.clone(), - } - }), - element, - ); -} - -// Console log macro -#[macro_export] -macro_rules! console_log { - ($($t:tt)*) => { - web_sys::console::log_1(&format!($($t)*).into()); - }; -} diff --git a/marts/src/obsidian.rs b/marts/src/obsidian.rs deleted file mode 100644 index b95ab4e..0000000 --- a/marts/src/obsidian.rs +++ /dev/null @@ -1,133 +0,0 @@ -use mize::{Mize, MizeResult, MizePart, MizePartCreate, mize_part}; -use wasm_bindgen::JsValue; -use mize::error::IntoMizeResultJsValue; -use wasm_bindgen::prelude::*; -use dioxus::prelude::*; -use crate::ClientAuth; -use wasm_bindgen::prelude::*; -use serde::{Serialize, Deserialize}; -use mize::platform::js::JsMize; - - -// console_log macro - -#[wasm_bindgen] -extern "C" { - #[wasm_bindgen(js_namespace = console)] - fn log(s: &str); -} - -macro_rules! console_log { - // Note that this is using the `log` function imported above during - // `bare_bones` - ($($t:tt)*) => ({ log(&format_args!($($t)*).to_string())}) -} - -pub fn part_obsidian(mize: &mut Mize, plugin: JsValue, app: JsValue) -> MizeResult<()> { - - mize.register_part(Box::new(ObsidianPart { - mize: mize.clone(), - plugin, - app, - })); - - Ok(()) -} - - -#[mize_part("obsidian")] -#[derive(Default)] -pub struct ObsidianPart { - mize: Mize, - plugin: JsValue, // the jsValue of the obsidian plugin - app: JsValue, // the jsValue of the obsidian instance -} - -pub struct MartsCommand { - pub id: String, - pub name: String, - pub callback: Box MizeResult<()>>, -} - -impl MizePart for ObsidianPart {} -impl MizePartCreate for ObsidianPart {} - -impl ObsidianPart { - pub fn plugin(&self) -> &JsValue { - &self.plugin - } - pub fn add_command(&self, mut cmd: MartsCommand) -> MizeResult<()> { - use wasm_bindgen::prelude::*; - use wasm_bindgen::JsCast; - use js_sys::{Function, Reflect, Object}; - let obsidian_cmd = Object::new(); - - Reflect::set(&obsidian_cmd, &"id".into(), &"login".into()).mres()?; - Reflect::set(&obsidian_cmd, &"name".into(), &"Login".into()).mres()?; - - // callback - let mize_clone = self.mize.clone(); - let cb = Closure::::wrap(Box::new(move || { - if let Err(e) = (cmd.callback)(mize_clone.clone()) { - mize_clone.report_err(e); - } - })); - - Reflect::set(&obsidian_cmd, &"callback".into(), cb.as_ref()).mres()?; - - // plugin.addCommand(cmd) - let add_command_fn = Reflect::get(&self.plugin, &"addCommand".into()).mres()? - .dyn_into::().mres()?; - - add_command_fn - .call1(&self.plugin, &obsidian_cmd).mres()?; - - - // IMPORTANT: prevent callback from being dropped - cb.forget(); - - Ok(()) - } -} - - -#[wasm_bindgen] -pub fn test_fn(mize: &mut JsMize) { - let mize = mize.inner(); - console_log!("test fn..."); - - if let Err(e) = try_test_fn(mize) { - console_log!("err: {:?}", e); - } - -} - -fn try_test_fn(mize: &mut Mize) -> MizeResult<()> { - //let auth = mize.get_part_native::("client_auth")?; - //console_log!("secrets: {:?}", auth.secrets()); - - let parts = mize.parts.lock().unwrap(); - for part in parts.keys() { - console_log!("part: {}", part) - } - - Ok(()) -} - -#[wasm_bindgen] -pub fn part_obsidian_init(mize: &mut JsMize, plugin: JsValue, app: JsValue) { - let mut mize = mize.inner(); - if let Err(e) = obsidian_mize_main(&mut mize, plugin, app) { - console_log!("Failed to start the obsidian mize part: {:?}", e); - } -} - -fn obsidian_mize_main(mize: &mut Mize, plugin: JsValue, app: JsValue) -> MizeResult<()> { - - crate::part_obsidian(mize, plugin, app)?; - crate::part_client_auth(mize)?; - crate::spacetime(mize)?; - crate::part_matrix(mize)?; - - Ok(()) -} diff --git a/marts/src/ppc/mod.rs b/marts/src/ppc/mod.rs deleted file mode 100644 index acad6ab..0000000 --- a/marts/src/ppc/mod.rs +++ /dev/null @@ -1,199 +0,0 @@ - -use std::str::FromStr; -use axum::response::Html; -use clap::Command; -use dioxus::prelude::*; -use mize::Mize; -use mize::MizeResult; - -pub mod server; - -pub fn mc_page() -> Html { - Html(r#" - - - - - - - - PPC Minecraft Server - - - - - - -
-
-
Welcome to the
-
PPC
-
Minecraft Cluster
-
-
-
- Address - first.ppc.social - Java 1.21.11 and Bedrock (bedrock not working rn) -
-
- Discord - https://discord.gg/cMKQNJMkRe - come and say hi! -
-
- See you ingame and invite all your friends to play as well!! -
-
-
- SimpleVoicechat - - This is not required, but makes playing soooo much more fun, so it's - highly encouraged. -

- Instructions can be found here:
- Fabric -
- SimpleVoiceChat -

-
-
-
- - - "#.to_owned()) -} - -pub fn main_page() -> Html { - Html(r#" - - - - - - People Corner - - - - - - - -
-

"Cool People doing Cool things together"

-

Read what this is all about: About

- -
-

There is a Discord Server: https://discord.gg/cMKQNJMkRe

- -

There is a Minecraft server.

- -

There is The PPC Wiki Projekt.

- -

There is an Instagram and a Youtube Channel

- -

and that's about all for now...

- - - - "#.to_owned()) -} diff --git a/marts/src/ppc/server.rs b/marts/src/ppc/server.rs deleted file mode 100644 index 218572d..0000000 --- a/marts/src/ppc/server.rs +++ /dev/null @@ -1,146 +0,0 @@ -use std::str::FromStr; - -use mize::{Mize, MizeError, MizeResult, mize_err}; - -use axum::response::Html; -use serde_json::json; -use serde_json::Value; -use axum::{ - Json, - Router, - error_handling::HandleErrorLayer, - http::Uri, - response::IntoResponse, - routing::{any, get}, -}; -use axum_oidc::handle_oidc_redirect; -use axum_oidc::{ - EmptyAdditionalClaims, OidcAuthLayer, OidcClaims, OidcClient, OidcLoginLayer, - OidcRpInitiatedLogout, error::MiddlewareError, -}; -use openidconnect::Scope; -use openidconnect::{ClientId, ClientSecret, IssuerUrl}; -use tower::ServiceBuilder; -use tower_sessions::{ - Expiry, MemoryStore, SessionManagerLayer, - cookie::{SameSite, time::Duration}, -}; - -pub fn part_ppc_server(mize: &mut Mize) -> MizeResult<()> { - mize.add_name_only_part("ppc.server"); - - let mize_clone = mize.clone(); - mize.spawn_async("ppc.server_runner", start_server(mize_clone)); - - Ok(()) -} - -pub async fn start_server(mut mize: Mize) -> MizeResult<()> { - dioxus::logger::initialize_default(); - - let issuer = mize.get_config("auth.server.issuer")?.value_string()?; - let client_id = mize.get_config("auth.server.client_id")?.value_string()?; - let client_secret = mize.get_config("auth.server.client_secret")?.value_string()?; - let url = mize.get_config("web.url")?.value_string()?; - let redirect_url = format!("{url}/oidc"); - - let session_store = MemoryStore::default(); - let session_layer = SessionManagerLayer::new(session_store) - .with_secure(false) - .with_same_site(SameSite::Lax) - .with_expiry(Expiry::OnInactivity(Duration::seconds(120))); - - let oidc_login_service = ServiceBuilder::new() - .layer(HandleErrorLayer::new(|e: MiddlewareError| async { - dbg!(&e); - e.into_response() - })) - .layer(OidcLoginLayer::::new()); - - let oidc_client = OidcClient::::builder() - .with_default_http_client() - .with_redirect_url(Uri::from_str(redirect_url.as_str())?) - .with_client_id(ClientId::new(client_id)) - .add_scope(Scope::new("profile".into())) - .add_scope(Scope::new("email".into())) - // Optional: add untrusted audiences. If the `aud` claim contains any of these audiences, the token is rejected. - //.add_untrusted_audience(Audience::new("123456789".to_string())) - .with_client_secret(ClientSecret::new(client_secret)) - .discover(IssuerUrl::new(issuer.into()).expect("Invalid IssuerUrl")) - .await - .unwrap() - .build(); - - let oidc_auth_service = ServiceBuilder::new() - .layer(HandleErrorLayer::new(|e: MiddlewareError| async { - dbg!(&e); - e.into_response() - })) - .layer(OidcAuthLayer::new(oidc_client)); - - let app = Router::new() - .route("/foo", get(authenticated)) - .route("/logout", get(logout)) - .layer(oidc_login_service) - .route("/bar", get(maybe_authenticated)) - .route("/oidc", any(handle_oidc_redirect::)) - .layer(oidc_auth_service) - .layer(session_layer) - .layer(tower_http::trace::TraceLayer::new_for_http()) - // not authenticated routes - .route("/", get(crate::ppc::main_page())) - .route("/mc", get(crate::ppc::mc_page())) - // matrix .well-known - .route( - "/.well-known/matrix/client", - get(handle_matrix_client).layer(tower_http::cors::CorsLayer::permissive()), - ) - .route( - "/.well-known/matrix/server", - get(handle_matrix_server), - ); - - tracing::info!("Running on http://localhost:3000"); - - let listener = tokio::net::TcpListener::bind("0.0.0.0:8010").await.unwrap(); - axum::serve(listener, app.into_make_service()) - .await - .unwrap(); - - Ok(()) -} - -async fn authenticated(claims: OidcClaims) -> impl IntoResponse { - format!("Hello {}", claims.subject().as_str()) -} - -async fn maybe_authenticated( - claims: Result, axum_oidc::error::ExtractorError>, -) -> impl IntoResponse { - if let Ok(claims) = claims { - format!( - "Hello {}! You are already logged in from another Handler.", - claims.subject().as_str() - ) - } else { - "Hello anon!".to_string() - } -} - -async fn logout(logout: OidcRpInitiatedLogout) -> impl IntoResponse { - logout.with_post_logout_redirect(Uri::from_static("https://localhost:3000")) -} - -async fn handle_matrix_client() -> Json { - Json(json!({ - "m.homeserver": { - "base_url": "https://matrix.ppc.social" - } - })) -} - -async fn handle_matrix_server() -> Json { - Json(json!({ - "m.server": "matrix.ppc.social:443" - })) -} diff --git a/marts/src/sci/inbox/mod.rs b/marts/src/sci/inbox/mod.rs deleted file mode 100644 index 9014bf3..0000000 --- a/marts/src/sci/inbox/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ - -pub use mize::{Mize, MizeResult, MizeError}; - -pub fn part_sci_inbox(mize: &mut Mize) -> MizeResult<()> { - - mize.add_name_only_part("sci.inbox"); - Ok(()) -} diff --git a/marts/src/sci/mod.rs b/marts/src/sci/mod.rs deleted file mode 100644 index ef018ce..0000000 --- a/marts/src/sci/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ - -use mize::*; -pub mod timetrack; -use clap::Command; - -pub fn part_sci(mize: &mut Mize) -> MizeResult<()> { - part_add_thought(mize)?; - - Ok(()) -} - -pub fn part_add_thought(mize: &mut Mize) -> MizeResult<()> { - use crate::generated::spacetime::add_thought; - let mut cli = mize.get_part_native::("cli")?; - cli.set_command("sci"); - cli.subcommand(Command::new("inputThought").alias("ti"), |_matches, mut mize| { - - let tmp_file = std::env::temp_dir().join(format!( - "sc2-input-thought-{}.txt", - chrono::Utc::now().timestamp() - )); - crate::cli_spawn(&mut mize, format!("nvim {}", tmp_file.display()))?; - let new_file_content = std::fs::read_to_string(&tmp_file) - .map_err(|e| mize_err!("Failed to read temp file: {}", e))?; - let _ = std::fs::remove_file(&tmp_file); - let spacetime = mize.get_part_native::("spacetime")?; - spacetime.con().reducers.add_thought(new_file_content)?; - Ok(()) - })?; - Ok(()) -} diff --git a/marts/src/sci/timetrack/mod.rs b/marts/src/sci/timetrack/mod.rs deleted file mode 100644 index bafbfa5..0000000 --- a/marts/src/sci/timetrack/mod.rs +++ /dev/null @@ -1,640 +0,0 @@ -use std::sync::oneshot; - -#[cfg(feature = "target-os")] -use clap::{Arg, ArgAction, ArgMatches, Command}; -use generated::spacetime::{Profile, TaskPart}; -use mize::out; -use mize::proto::MizeMessage; -use mize::{Mize, MizeError, MizePart, MizePartCreate, MizeResult, mize_err, mize_part}; -use spacetimedb_sdk::{DbContext, Table}; -use generated::spacetime::export_timetrack; -use generated::spacetime::first_timetrack_date; -use std::fs::OpenOptions; -use chrono::Local; -use chrono::TimeDelta; -use std::io::Write; -use std::path::Path; -use std::fs; -use std::io; - -use generated::spacetime::{ - Action, ActivitiesTableAccess, Activity, DbConnection, TaskPartTableAccess, - activitiesQueryTableAccess, next_action, remove_activity, task_partQueryTableAccess, - update_activity, update_upcoming, -}; -use crate::spacetime::SpacetimePart; -use spacetimedb_sdk::TableWithPrimaryKey; - -#[mize_part] -#[derive(Default)] -pub struct TimeTrack { - mize: Mize, -} - -pub fn part_timetrack(mize: &mut Mize) -> MizeResult<()> { - part_timetrack_export(mize)?; - - #[cfg(feature = "target-os")] { - let mut cli = mize.get_part_native::("cli")?; - cli.set_command("sci"); - - cli.subcommand( - Command::new("editActionList").alias("aal").arg( - Arg::new("defaultTemplate") - .short('d') - .action(ArgAction::SetTrue), - ), - command_edit_action_list, - )?; - cli.subcommand(Command::new("nextAction").alias("ne").arg( - Arg::new("break") - .short('b') - .action(ArgAction::SetTrue), - ).arg( - Arg::new("action") - .trailing_var_arg(true) - .allow_hyphen_values(true) - .num_args(0..), // Accepts 0 or more arguments - ), command_next_action)?; - cli.subcommand( - Command::new("printCurrentAction").alias("cu"), - command_current_action, - )?; - cli.subcommand( - Command::new("listActions").alias("la"), - command_list_actions, - )?; - cli.subcommand( - Command::new("listActivities").alias("lac"), - command_list_activities, - )?; - cli.subcommand( - Command::new("editActivities").alias("eac"), - command_edit_activities, - )?; - mize.add_listener( - "timetrack.sub_current", - Box::new(timetrack_sub_current_listener), - )?; - - - } - mize.register_part(Box::new(TimeTrack { mize: mize.clone() }))?; - Ok(()) -} - -fn send_current_update_msg(conn_id: u64, data: TaskPart, mize: &mut Mize) -> MizeResult<()> { - let now = fixed_len(data.current.name.clone(), 48); - let next = fixed_len( - data.upcoming - .iter() - .nth(0) - .unwrap_or(&Action { - name: "".to_string(), - activity: None, - task: None, - start: None, - end: None, - duration: None, - }) - .name - .clone(), - 48, - ); - let msg = MizeMessage::new_custom( - "timetrack.current", - format!(" {} NEXT: {} ", now, next), - conn_id, - ); - let con = mize.get_connection(conn_id)?; - con.send(msg)?; - - Ok(()) -} - -fn fixed_len(mut buf: String, len: usize) -> String { - if buf.len() > len { - buf.truncate(len - 4); // Cut off extra characters - buf.push_str(" ..."); - } else { - while buf.len() < len { - buf.push(' '); // Fill with whitespace - } - } - buf -} - -pub fn timetrack_sub_current_listener(msg: MizeMessage, mize: &mut Mize) -> MizeResult<()> { - let spacetime = mize.get_part_native::("spacetime").unwrap(); - let con = spacetime.con(); - let mut mize_clone = mize.clone(); - let mut mize_clone_two = mize.clone(); - con.subscription_builder() - .on_applied(move |ctx| { - let data = ctx.db.task_part().identity().find(&ctx.identity()).unwrap(); - if let Err(e) = send_current_update_msg(msg.conn_id, data, &mut mize_clone) { - e.log(); - } - }) - .add_query(|q| q.from.task_part()) - .subscribe(); - con.db - .task_part() - .on_update(move |_, _old: &TaskPart, new: &TaskPart| { - if let Err(e) = send_current_update_msg(msg.conn_id, new.clone(), &mut mize_clone_two) { - e.log(); - } - }); - Ok(()) -} - -impl MizePartCreate for TimeTrack {} - -impl MizePart for TimeTrack { - fn name(&self) -> &'static str { - "timetrack" - } -} - -#[cfg(feature = "target-os")] -fn command_next_action(matches: &ArgMatches, mut mize: Mize) -> MizeResult<()> { - let spacetime = mize.get_part_native::("spacetime")?; - let con = spacetime.con(); - - let break_flag = matches.get_flag("break"); - let action = matches.get_many::("action") - .map(|vals| vals.map(|s| s.as_str()).collect::>().join(" ")); - let action = match action { - Some(action) => Some(Action { - name: action.clone(), - activity: None, - task: None, - start: None, - end: None, - duration: None, - }), - None => None, - }; - - let old_action = get_current_action(&mut mize, con)?; - out!("before action: {}", old_action.name); - let (wait_tx, waiter_rx) = std::sync::oneshot::channel::<()>(); - con.reducers.next_action_then(break_flag, action, |_, _| { - wait_tx.send(()).unwrap(); - })?; - waiter_rx.recv()?; - - let new_action = get_current_action(&mut mize, con)?; - out!("new action: {}", new_action.name); - - Ok(()) -} - -#[cfg(feature = "target-os")] -fn command_current_action(_: &ArgMatches, mut mize: Mize) -> MizeResult<()> { - let spacetime = mize.get_part_native::("spacetime")?; - let action = get_current_action(&mut mize, spacetime.con())?; - out!("{}", action.name); - Ok(()) -} - -fn get_current_action(_mize: &mut Mize, con: &DbConnection) -> MizeResult { - let (wait_tx, wait_rx) = std::sync::oneshot::channel::(); - con.subscription_builder() - .on_applied(|ctx| { - let task_part_data = ctx.db.task_part().identity().find(&ctx.identity()); - if task_part_data.is_none() { - wait_tx - .send(Action { - name: "fillier".to_string(), - activity: None, - task: None, - start: None, - end: None, - duration: None, - }) - .unwrap(); - } else { - wait_tx.send(task_part_data.unwrap().current).unwrap(); - } - }) - .add_query(|q| { - q.from.task_part() - //.r#where(|row| row.identity.eq(con.identity())) - }) - .subscribe(); - let action = wait_rx.recv().unwrap(); - Ok(action) -} - -#[cfg(feature = "target-os")] -fn command_list_activities(_: &ArgMatches, mut mize: Mize) -> MizeResult<()> { - let spacetime = mize.get_part_native::("spacetime")?; - let activities = get_activities(&mut mize, spacetime.con())?; - - for ac in activities.clone() { - print!("ac {}: {}", ac.id, ac.name); - if !ac.parents_ids.is_empty() { - print!(" -"); - } - for child_id in ac.parents_ids { - let child_ac = activities.iter().find(|ac| ac.id == child_id).unwrap(); - print!(" {}", child_ac.name); - } - print!("\n") - } - Ok(()) -} - -#[cfg(feature = "target-os")] -fn command_list_actions(_: &ArgMatches, mut mize: Mize) -> MizeResult<()> { - let spacetime = mize.get_part_native::("spacetime")?; - - let actions = get_actions(spacetime.con())?; - - for action in actions { - out!("{}", action.name) - } - - Ok(()) -} - -#[cfg(feature = "target-os")] -fn command_edit_action_list(matches: &ArgMatches, mut mize: Mize) -> MizeResult<()> { - let spacetime = mize.get_part_native::("spacetime")?; - - // maybe append a template to the action list - if matches.get_flag("defaultTemplate") { - out!("Appending template..."); - return Ok(()); - } - - // get list of actions - let mut actions = get_actions(spacetime.con())?; - - // write to tmp file - let tmp_file_content = actions_to_string(&actions)?; - let tmp_file = std::env::temp_dir().join(format!( - "ppc-edit-actions-{}.txt", - chrono::Utc::now().timestamp() - )); - std::fs::write(&tmp_file, tmp_file_content) - .map_err(|e| mize_err!("Failed to write temp file: {}", e))?; - - // open $EDITOR blocking - crate::cli_spawn(&mut mize, format!("nvim {}", tmp_file.display()))?; - - // read file and update db - let new_file_content = std::fs::read_to_string(&tmp_file) - .map_err(|e| mize_err!("Failed to read temp file: {}", e))?; - - actions = actions_from_string(new_file_content)?; - set_actions(actions, spacetime.con())?; - - // delete tmpfile - let _ = std::fs::remove_file(&tmp_file); - - Ok(()) -} - -fn get_actions(con: &DbConnection) -> MizeResult> { - let (exit_tx, exit_rx) = std::sync::oneshot::channel::>(); - con.subscription_builder() - .on_applied(|ctx| { - let task_part_data = ctx.db.task_part().identity().find(&ctx.identity()); - if task_part_data.is_none() { - exit_tx.send(Vec::new()).unwrap(); - } else { - exit_tx.send(task_part_data.unwrap().upcoming).unwrap(); - } - }) - .add_query(|q| { - q.from.task_part() - //.r#where(|row| row.identity.eq(con.identity())) - }) - .subscribe(); - let activities = exit_rx.recv().unwrap(); - Ok(activities) -} - -fn set_actions(actions: Vec, con: &DbConnection) -> MizeResult<()> { - let (wait_tx, waiter_rx) = std::sync::oneshot::channel::<()>(); - con.reducers - .update_upcoming_then(actions, |_, _| wait_tx.send(()).unwrap())?; - waiter_rx.recv().unwrap(); - Ok(()) -} - -fn actions_to_string(actions: &Vec) -> MizeResult { - let mut string = String::new(); - - for action in actions.iter() { - string.push_str(format!("{}\n", action.name).as_str()); - } - - Ok(string) -} - -fn actions_from_string(string: String) -> MizeResult> { - let mut new_actions = Vec::new(); - for line in string.lines() { - if line.trim().is_empty() { - continue; - } - - let mut action = Action { - name: line.to_owned(), - activity: None, - task: None, - start: None, - end: None, - duration: None, - }; - parse_action(&mut action); - new_actions.push(action); - } - Ok(new_actions) -} - -fn parse_action(action: &mut Action) { - let _parts: Vec<&str> = action.name.split_whitespace().collect(); -} - -#[cfg(feature = "target-os")] -fn command_edit_activities(_: &ArgMatches, mut mize: Mize) -> MizeResult<()> { - let spacetime = mize.get_part_native::("spacetime")?; - - // get list of activities - let activities = get_activities(&mut mize, spacetime.con())?; - - let con = spacetime.con(); - - // write to tmp file - let mut tmp_file_content = String::new(); - for ac in activities.iter() { - tmp_file_content.push_str(format!("{} {}", ac.id, ac.name).as_str()); - if !ac.parents_ids.is_empty() { - tmp_file_content.push_str(" -"); - for parent_id in ac.parents_ids.iter() { - let parent_ac = activities.iter().find(|ac| ac.id == *parent_id).unwrap(); - tmp_file_content.push_str(" "); - tmp_file_content.push_str(&parent_ac.name); - } - } - tmp_file_content.push_str("\n"); - } - let tmp_file = std::env::temp_dir().join(format!( - "ppc-edit-activities-{}.txt", - chrono::Utc::now().timestamp() - )); - std::fs::write(&tmp_file, tmp_file_content) - .map_err(|e| mize_err!("Failed to write temp file: {}", e))?; - - loop { - // open $EDITOR blocking - crate::cli_spawn(&mut mize, format!("nvim {}", tmp_file.display()))?; - - let new_file_content = std::fs::read_to_string(&tmp_file) - .map_err(|e| mize_err!("Failed to read temp file: {}", e))?; - - let mut input = String::new(); - - let old_activities = get_activities(&mut mize, con)?; - if let Err(err) = - parse_activities_from_text(&mut mize, con, new_file_content, old_activities) - { - out!("error parsing the activities from the file: {:?}", err); - out!("press ENTER to open the file again"); - - // wait for user input - // so that they can se the err msg, before running nvim again - std::io::stdin().read_line(&mut input)?; - } else { - break; - } - } - - // delete tmpfile - let _ = std::fs::remove_file(&tmp_file); - - Ok(()) -} - -fn get_activities(_mize: &mut Mize, con: &DbConnection) -> MizeResult> { - let (exit_tx, exit_rx) = std::sync::oneshot::channel::>(); - con.subscription_builder() - .on_applied(|ctx| { - exit_tx.send(ctx.db.activities().iter().collect()).unwrap(); - }) - .add_query(|q| q.from.activities()) - .subscribe(); - let activities = exit_rx.recv().unwrap(); - Ok(activities) -} - -fn parse_activities_from_text( - mize: &mut Mize, - con: &DbConnection, - text: String, - old_activities: Vec, -) -> MizeResult<()> { - let mut activities_to_delete = old_activities.clone(); - let mut wait_revievers = Vec::new(); - for line in text.lines() { - if line == "" { - continue; - } - - // split - let mut parts = line.split(" "); - let id: u64 = parts.next().ok_or(mize_err!(".."))?.parse()?; - let name = parts.next().ok_or(mize_err!(".."))?.to_string(); - - // remove from to-delete list - if let Some(pos) = activities_to_delete.iter().position(|ac| ac.id == id) { - activities_to_delete.remove(pos); - } - - // wait rx - let (wait_tx, wait_rx) = oneshot::channel::<()>(); - wait_revievers.push(wait_rx); - - // update or create activity - if let Some(old_activity) = old_activities.iter().find(|ac| ac.id == id) { - con.reducers.update_activity_then( - Activity { - id, - name, - task: old_activity.task, - parents_ids: old_activity.parents_ids.clone(), - }, - move |_, _| { - let _ = wait_tx.send(()); - }, - )?; - } else { - con.reducers.update_activity_then( - Activity { - id: 0, - name, - task: None, - parents_ids: Vec::new(), - }, - move |_, _| { - let _ = wait_tx.send(()); - }, - )?; - } - } - - // remove deleted activities - for activity in activities_to_delete { - let (wait_tx, wait_rx) = oneshot::channel::<()>(); - wait_revievers.push(wait_rx); - con.reducers.remove_activity_then(activity, move |_, _| { - let _ = wait_tx.send(()); - })?; - } - - // wait for db stuff to finish - for wait_rx in wait_revievers { - wait_rx.recv().unwrap(); - } - let mut wait_revievers = Vec::new(); - - // check for declared parents - let new_activities = get_activities(mize, con)?; - out!("new_activities: {:?}", new_activities); - for line in text.lines() { - if line == "" { - continue; - } - - // split - let mut parts = line.split(" "); - let _id: u64 = parts.next().ok_or(mize_err!(".."))?.parse()?; - let name = parts.next().ok_or(mize_err!(".."))?.to_string(); - - // parse parents - let seperator = parts.next(); - if seperator.is_some() && seperator.unwrap() == "-" { - let mut parents_ids = Vec::new(); - for parent_name in parts { - // find id from old_parts by this name - let res_from_old = old_activities.iter().find(|ac| ac.name == parent_name); - let res_from_new = new_activities.iter().find(|ac| ac.name == parent_name); - let parent_activity = res_from_old.or(res_from_new).ok_or(mize_err!( - "activity '{name}' declares parent '{parent_name}'" - ))?; - parents_ids.push(parent_activity.id); - } - let child_activity = new_activities - .iter() - .find(|ac| ac.name == name) - .ok_or(mize_err!(".."))?; - let (wait_tx, wait_rx) = oneshot::channel::<()>(); - wait_revievers.push(wait_rx); - con.reducers.update_activity_then( - Activity { - parents_ids, - ..child_activity.to_owned() - }, - move |_, _| { - let _ = wait_tx.send(()); - }, - )?; - } - } - - // wait for db stuff to finish - for wait_rx in wait_revievers { - wait_rx.recv().unwrap(); - } - - Ok(()) -} - -pub fn part_timetrack_export(mize: &mut Mize) -> MizeResult<()> { - let mut cli = mize.get_part_native::("cli")?; - - cli.set_command("sci"); - cli.subcommand(Command::new("timetrackExport").alias("te").arg(Arg::new("date").short('d')).arg(Arg::new("all").short('a').action(ArgAction::SetTrue)), |matches , mut mize| { - let spacetime = mize.get_part_native::("spacetime")?; - let today = Local::now().format("%Y-%m-%d").to_string(); - let mut date = matches.get_one::("date").unwrap_or(&today); - let all = matches.get_flag("all"); - if all { - out!("exporting all not implemented rn"); - let (tx, rx) = oneshot::channel(); - spacetime.con().procedures.first_timetrack_date_then("c2vi".to_string(), |_, res| {tx.send(res);}); - let res = rx.recv()???; - let dates = dates_until_today(&res)?; - for date in dates { - out!("date: {}", date); - let (tx, rx) = oneshot::channel(); - spacetime.con().procedures.export_timetrack_then("c2vi".to_string(), date.to_owned(), |_, res| {tx.send(res);}); - let res = rx.recv()???; - //let mut file = OpenOptions::new().create(true).write(true).open(Path::new(¬es_dir).join("timetrack_exports").join(format!("timetrack_export_{}.md", date)))?; - //file.write_all(res.as_bytes())?; - } - return Ok(()); - } - out!("date: {}", date); - let (tx, rx) = oneshot::channel(); - spacetime.con().procedures.export_timetrack_then("c2vi".to_string(), date.to_owned(), |_, res| {let _ = tx.send(res);}); - let res = rx.recv()???; - let daily_notes_path = mize.get_config("timetrack.dailyNotesPath")?.value_string()?; - let note_path = format!("{}/{}.md", daily_notes_path, date); - out!("writing to file: {}", note_path); - write_under_heading(note_path, "## timetrack export", res.as_ref())?; - - Ok(()) - })?; - Ok(()) -} - -fn write_under_heading( - file_path: impl AsRef, - heading: &str, - content: &str, -) -> io::Result<()> { - - let file_path = file_path.as_ref(); - let markdown = fs::read_to_string(file_path)?; - - let heading_line = format!("{}", heading); - let mut lines: Vec<&str> = markdown.lines().collect(); - - let index = lines - .iter() - .position(|line: &&str| line.trim() == heading_line) - .ok_or_else(|| { - io::Error::new( - io::ErrorKind::NotFound, - format!("Heading '{}' not found", heading), - ) - })?; - - lines.insert(index + 1, content); - - let mut updated = lines.join("\n"); - updated.push('\n'); - - fs::write(file_path, updated) -} - - -fn dates_until_today(start: &str) -> Result, chrono::ParseError> { - use chrono::NaiveDate; - let mut current = NaiveDate::parse_from_str(start, "%Y-%m-%d")?; - let today = Local::now().date_naive(); - - let mut dates = Vec::new(); - - while current <= today { - dates.push(current.format("%Y-%m-%d").to_string()); - current += TimeDelta::days(1); - } - - Ok(dates) -} diff --git a/marts/src/spacetime.rs b/marts/src/spacetime.rs deleted file mode 100644 index 658d824..0000000 --- a/marts/src/spacetime.rs +++ /dev/null @@ -1,107 +0,0 @@ -use std::sync::oneshot::Sender; - -use mize::{mize_part, Mize, MizePart, MizePartCreate, MizeResult}; - -use crate::auth::client::ClientAuth; -use generated::spacetime::DbConnection; - -#[mize_part] -#[derive(Default)] -pub struct SpacetimePart { - mize: Mize, - con: Option, -} - -impl MizePartCreate for SpacetimePart {} -impl MizePart for SpacetimePart { - fn name(&self) -> &'static str { - "spacetime" - } -} - -impl SpacetimePart { - pub fn con_mut(&mut self) -> &mut DbConnection { - self.con.as_mut().unwrap() - } - pub fn con(&self) -> &DbConnection { - self.con.as_ref().unwrap() - } - // does not work, because i can't use the QueryBuilder type in my code.... it's private - /* - pub fn get( - &self, - on_applied: impl FnOnce(&generated::spacetime::SubscriptionEventContext, Sender)+ Send + 'static, - query: impl FnOnce(QueryBuilder)+ Send + 'static - ) -> MizeResult { - let (done_tx, done_rx) = std::sync::oneshot::channel::(); - use spacetimedb_sdk::DbContext; - self.con().subscription_builder().on_applied(move |ctx| { - on_applied(ctx, done_tx); - }).add_query(build); - } - */ -} - -pub fn spacetime(mize: &mut Mize) -> MizeResult<()> { - let auth = mize.get_part_native::("client_auth")?; - let db_url = mize.get_config("spacetime.url")?.value_string()?; - - let con: Option; - - #[cfg(feature = "target-os")] { - con = Some(DbConnection::builder() - .with_token(Some(auth.id_token()?)) - .with_database_name("mize") - .with_uri(db_url) - //.on_connect(callback) - //.on_disconnect(callback) - //.on_connect_error(callback) - //.with_compression(...) - .build()?); - con.as_ref().unwrap().run_threaded(); - } - - #[cfg(feature = "target-js")] { - let mut mize = mize.clone(); - con = None; - wasm_bindgen_futures::spawn_local(async move { - let id_token = match auth.id_token() { - Ok(val) => val, - Err(e) => { - mize.report_err(e.into()); - return; - } - }; - let con = match DbConnection::builder() - .with_token(Some(id_token)) - .with_database_name("mize") - .with_uri(db_url) - //.on_connect(callback) - //.on_disconnect(callback) - //.on_connect_error(callback) - //.with_compression(...) - .build().await { - Ok(val) => val, - Err(e) => { - mize.report_err(e.into()); - return; - } - }; - let mut spacetime = match mize.get_part_native::("spacetime") { - Ok(val) => val, - Err(e) => { - mize.report_err(e.into()); - return; - } - }; - con.run_async(); - spacetime.con = Some(con); - }); - } - - - mize.register_part(Box::new(SpacetimePart { - mize: mize.clone(), - con: con, - })) -} diff --git a/marts/src/task/mod.rs b/marts/src/task/mod.rs deleted file mode 100644 index e69de29..0000000 diff --git a/marts/src/task/obsidian-otask-parse.ts b/marts/src/task/obsidian-otask-parse.ts deleted file mode 100644 index ffe6547..0000000 --- a/marts/src/task/obsidian-otask-parse.ts +++ /dev/null @@ -1,538 +0,0 @@ -import remarkParse from "remark-parse"; -import remarkStringify from "remark-stringify"; -import { unified } from "unified"; -import { visit } from "unist-util-visit"; -import { Root, Content, Heading, List, ListItem, Text } from "mdast"; -import remarkFrontmatter from "remark-frontmatter"; -import remarkGfm from "remark-gfm"; -import wikiLinkPlugin from "@flowershow/remark-wiki-link"; -import { TFile } from "obsidian"; - -const OTASK_PROP_NAMES = ["short", "outcome", "priority"]; -const ACTION_PROP_NAMES = []; - -const REMARK = unified() - .use(remarkParse) - .use(remarkFrontmatter) - .use(remarkGfm) - .use(remarkStringify, { bullet: "-" }); - -export function task_obsidian_otask_parse(mize: any) { - const obsidian_plugin = mize.get_part_native("obsidian"); - - obsidian_plugin.addCommand({ - id: "full-parse", - name: "Parse all otask files into the db", - callback: async () => { - await full_parse(); - }, - }); -} - -async function full_parse() { - console.log("full parse.......................... yay"); - let otasks = []; - OTASK_PARSE_QUEUE = []; - OTASK_LIST = []; - - const root_file = app.vault.getAbstractFileByPath("task/my-projects.md"); - - const content = await app.vault.read(root_file); - const list = await getListUnderHeading(content, "root"); - - for (const entry of list) { - queue_otasks_from_list_item(entry, []); - } - - // go through the queue of otaskParseTasks - // using a queue instead of recursive calls, to make it more debuggable... - do { - const task = OTASK_PARSE_QUEUE.shift(); - dbg("task", task); - if (task.file) { - const otask = await otasks_from_file( - task.file, - task.otask_path, - task.priority, - ); - dbg("otask", otask); - if (otask) { - OTASK_LIST.push(otask); - } - } else { - const otask = await otasks_from_list_item( - task.listItem, - task.otask_path, - task.priority, - ); - dbg("otask", otask); - if (otask) { - OTASK_LIST.push(otask); - } - } - } while (OTASK_PARSE_QUEUE.length > 0); - - console.log("otasks::", OTASK_LIST); - - render_sub0_file(OTASK_LIST); -} - -let OTASK_PARSE_QUEUE: any = []; -let OTASK_LIST = []; -let DBG = false; - -function dbg() { - if (DBG) { - console.log(arguments); - } -} - -function queue_otasks_from_list_item(listItem, otask_path, priority = 0) { - OTASK_PARSE_QUEUE.push({ - listItem, - otask_path, - priority, - }); -} - -function queue_otasks_from_file(file, otask_path, priority = 0) { - OTASK_PARSE_QUEUE.push({ - file, - otask_path, - priority, - }); -} - -// parsing helper functions - -async function render_sub0_file(otasks) { - const sub0_file = app.vault.getAbstractFileByPath("private/sub0-tasks.md"); - if (!(sub0_file instanceof TFile)) { - console.error( - "SystemC2: sub0_file not found:", - "private/sub0-tasks.md", - sub0_file, - ); - return; - } - - //render sub0 - const sub0_otasks = otasks.filter( - (otask) => otask.priority == 0 && !otask.is_file, - ); - console.log("sub0 otasks...", sub0_otasks); - - let rendered_otasks_string = ""; - - for (const otask of sub0_otasks) { - const path_part = otask.path.length > 0 ? otask.path.join(": ") + ": " : ""; - - let content_part = otask.content ? otask.content + "\n" : ""; - content_part = content_part - .split("\n") - .map((line) => "\t" + line) - .join("\n"); // add a \t in front of every otask.content line - - rendered_otasks_string += `- ${path_part}${otask.longName}\n${content_part}\n`; - } - //console.log("newContent...", rendered_otasks_string) - - await replaceHeading(sub0_file, "sub0", rendered_otasks_string); - - //render sub-1 -} - -async function replaceHeading( - file: TFile, - heading: string, - newContent: string, -) { - const data = await this.app.vault.read(file); - - // Parse the Markdown into an AST - const tree = REMARK.parse(data) as Root; - - // Split new content into AST nodes - const newContentAst = REMARK.parse(newContent) as Root; - - const children = tree.children; - const newChildren: Content[] = []; - let insideTarget = false; - let targetLevel = 0; - - for (let i = 0; i < children.length; i++) { - const node = children[i]; - - if (node.type === "heading") { - const headingNode = node as Heading; - const text = headingNode.children - .filter((c) => c.type === "text") - .map((c: any) => c.value) - .join(""); - - // If we encounter our target heading - if (text.trim() === heading) { - insideTarget = true; - targetLevel = headingNode.depth; - newChildren.push(node); // Keep the heading itself - // Insert new content right after - newChildren.push(...newContentAst.children); - continue; - } - - // If we’re currently inside target section and see a heading of same or higher level - if (insideTarget && headingNode.depth <= targetLevel) { - insideTarget = false; - } - } - - // If we’re not inside the target section, keep the node - if (!insideTarget) { - newChildren.push(node); - } - } - - const newTree: Root = { ...tree, children: newChildren }; - - // Convert AST back to Markdown - const newMarkdown = await REMARK.stringify(newTree); - - await this.app.vault.modify(file, newMarkdown); -} - -async function otasks_from_list_item(listItem, otask_path, priority = 0) { - try { - // the main otask this listItem is about - let otask = { - description: [], - actions: [], - path: [], - priority, - }; - dbg("SystemC2: otasks_from_list_item", listItem, otask_path); - - if (!listItem.children[0].type === "paragraph") { - dbg( - "listItem[0] of a otask item is not a paragraph... the otask:", - listItem, - ); - return null; - } - let longName = nodeToString(listItem.children[0]); - - dbg("longName:", longName); - - // check for [[anotherotask]], call otasks_from_file, return those - const match = longName.match(/\[\[([^\]]+)\]\]/); - if (match) { - const file = app.metadataCache.getFirstLinkpathDest(match[1], ""); - if (file) { - const metadata = app.metadataCache.getFileCache(file); - - if (metadata?.frontmatter?.tags?.includes("t/otask")) { - queue_otasks_from_file(file, otask_path); - return null; - } else { - dbg( - "SystemC2: listItem with Link to '", - match[1], - "', which is not an otask", - longName, - ); - } - } - } - - //check for [x] and remove from name - if (longName.startsWith("[ ") || longName.startsWith("[x")) { - longName = longName.slice(4); - } - - //check for "ot:" and remove from name - if (longName.startsWith("ot:")) { - longName = longName.slice(4); - } - - otask.longName = longName; - otask.short = longName; - otask.path = otask_path; - let new_otask_path = [...otask_path, otask.short]; - - // go through sub list items - // - if it's a prop for the otask... handle that - // - if it's an "ac:" handle that - // - if it's "ot: " handle as another otask -> recursive call - // - if it's "[ ]" handle as another otask -> recursive call - // - if it's a link to a otask file... handle as another otask -> call otasks_from_file() - // - else add it as description item list to otask - if (!listItem.children || listItem.children.length < 2) { - return otask; - } - - // add content as text to otask - if (otask.longName == "hosting updates") { - console.log("listItem... ", listItem.children[1]); - let hii = REMARK.stringify(listItem.children[1]); - console.log("text...", hii); - } - let content_text = REMARK.stringify(listItem.children[1]); - otask.content = content_text; - - for (const subListItem of listItem.children[1].children) { - let text = nodeToString(subListItem.children[0]); - - // check prop - if (check_otask_prop_from_list_item(subListItem, otask)) { - new_otask_path = [...otask_path, otask.short]; // have to redo it here, in case short changed from aprop - continue; // don't do any other processing on this sub-listItem - } - - // remove "[ ]" - if (text.startsWith("[ ") || text.startsWith("[x")) { - text = text.slice(4); - } - - // check ac - if (text.startsWith("ac:")) { - otask.actions = [ - ...otask.actions, - action_from_list_item(subListItem, new_otask_path, otask.priority), - ]; - - continue; // don't do any other processing on this sub-listItem - } - - // check ot - if (text.startsWith("ot:")) { - queue_otasks_from_list_item( - subListItem, - new_otask_path, - otask.priority, - ); - - continue; // don't do any other processing on this sub-listItem - } - - // check [ ] - if (text.startsWith("[ ] ") || text.startsWith("[x] ")) { - queue_otasks_from_list_item( - subListItem, - new_otask_path, - otask.priority, - ); - - continue; // don't do any other processing on this sub-listItem - } - - // check link to otask file - const match = text.match(/\[\[([^\]]+)\]\]/); - if (match) { - const file = app.metadataCache.getFirstLinkpathDest(match[1], ""); - if (file) { - const metadata = app.metadataCache.getFileCache(file); - - if (metadata?.frontmatter?.tags?.includes("t/otask")) { - queue_otasks_from_file(file, new_otask_path, otask.priority); - continue; - } else { - dbg( - "SystemC2: listItem with Link to '", - match[1], - "', which is not an otask", - longName, - ); - } - - continue; // don't do any other processing on this sub-listItem - } - } - - // add as description - const desc = REMARK.stringify(subListItem); - otask.description.push(desc); - } - - return otask; - } catch (error) { - console.log("failed to parse list item:", listItem); - } -} - -async function otasks_from_file(file: TFile, otask_path, priority = 0) { - try { - dbg("SystemC2: otasks_from_file", file, otask_path); - - // the main otask this file is about - let otask = { - description: [], - actions: [], - path: [], - priority, - is_file: true, - }; - - otask.longName = file.basename; - otask.short = otask.longName; - otask.path = otask_path; - let new_otask_path = [...otask_path, otask.short]; - - const content = await app.vault.read(file); - - // parse listItems at the top... for props - const topListItems = getListItemsBeforeFirstHeading(content); - for (const topListItem of topListItems) { - const text = nodeToString(topListItem); - - // check for prop - if (check_otask_prop_from_list_item(topListItem, otask)) { - new_otask_path = [...otask_path, otask.short]; - continue; // don't do any other processing on this sub-listItem - } - } - - // parse all the sub sections - const SUB_COUNT = 10; - for (let sub_number = 0; sub_number < SUB_COUNT; sub_number++) { - let listItems = await getListUnderHeading(content, "sub" + sub_number); - - // "sub" without a number should have priority 5 - if (sub_number == 5) { - listItems = listItems.concat(await getListUnderHeading(content, "sub")); - } - - //dbg(`sub section ${sub_number} has items:`, listItems) - - for (const listItem of listItems) { - // check if listItem is an action... - let text = nodeToString(listItem.children[0]); - if ( - text.startsWith("ac:") || - text.startsWith("[ ] ac:") || - text.startsWith("[x] ac:") - ) { - const action = action_from_list_item(listItem, otask_path); - otask.actions.push(action); - } - - queue_otasks_from_list_item( - listItem, - new_otask_path, - otask.priority + sub_number, - ); - } - } - - return otask; - } catch (error) { - console.log("failed to parse file: ", file.path); - } -} - -function action_from_list_item(listItem, otask_path) { - dbg("SystemC2: action_from_list_item", listItem, otask_path); - let action = {}; - let text = nodeToString(listItem.children[0]).slice(4); - - if (text.startsWith("[")) { - text = text.slice(4); - } - - action.name = text; - - return action; -} - -function check_otask_prop_from_list_item(listItem, otask) { - let text = nodeToString(listItem.children[0]); - - for (const prop_name of OTASK_PROP_NAMES) { - if (text.startsWith(prop_name + ":")) { - const value = text.slice(prop_name.length + 2); - - if (prop_name == "priority") { - // parse priority as int - otask[prop_name] = parseInt(value); - } else if (prop_name == "outcome") { - // add sub items to it - let fullText = REMARK.stringify(listItem).slice(prop_name.length + 4); - otask[prop_name] = fullText; - } else { - otask[prop_name] = value; - } - - return true; - } - } - return false; -} - -// Extract plain text from a node -function nodeToString(node: any): string { - let result = ""; - visit(node, "text", (textNode: Text) => { - result += textNode.value; - }); - return result.trim(); -} - -async function getListUnderHeading( - markdown: string, - headingText: string, -): string[] { - const tree = REMARK.parse(markdown); - //dbg("tree", tree) - - let capture = false; - let items: string[] = []; - - for (let i = 0; i < tree.children.length; i++) { - const node: Content = tree.children[i]; - - // Detect the target heading - if ( - node.type === "heading" && - nodeToString(node).toLowerCase() === headingText.toLowerCase() - ) { - capture = true; - continue; - } - - // Stop if another heading of the same or higher level comes - if (capture && node.type === "heading") { - break; - } - - // Collect list items if capturing - if (capture && node.type === "list") { - for (const li of (node as List).children) { - if (li.type === "listItem") { - items.push(li); - } - } - } - } - - return items; -} - -function getListItemsBeforeFirstHeading(markdown: string) { - const tree = REMARK.parse(markdown); - - let items = []; - - for (const node of tree.children) { - if (node.type === "heading") { - // stop at first heading - break; - } - if (node.type === "list") { - for (const li of (node as List).children) { - if (li.type === "listItem") { - items.push(li); - } - } - } - } - - return items; -}