diff --git a/Cargo.toml b/Cargo.toml index c3c548d..60d1ac4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,13 +8,15 @@ repository.workspace = true [features] default = ["macros"] +bevy = ["dep:caretta-sync-bevy"] mobile = ["dep:caretta-sync-mobile"] cli = ["dep:caretta-sync-cli"] -desktop = ["cli"] +desktop = ["cli", "bevy"] macros = ["dep:caretta-sync-macros"] test = ["caretta-sync-core/test"] [dependencies] +caretta-sync-bevy = { path = "bevy", optional = true } caretta-sync-core.workspace = true caretta-sync-cli = { path="cli", optional = true } caretta-sync-mobile = { path = "mobile", optional = true } @@ -24,7 +26,7 @@ caretta-sync-macros = { path="macros", optional = true} caretta-sync-core = {workspace = true, features = ["test"]} [workspace] -members = [ ".", "core", "macros", "cli", "mobile", "examples/demo/*" ] +members = [ ".", "core", "macros", "cli", "mobile", "examples/demo/*" , "bevy"] resolver = "3" [workspace.package] @@ -35,11 +37,12 @@ license = "MIT OR Apache-2.0" repository = "https://forgejo.fireturlte.net/lazy-supplements" [workspace.dependencies] +bevy = "0.16.1" chrono = "0.4.41" ciborium = "0.2.2" clap = { version = "4.5.38", features = ["derive"] } -dioxus = { version = "0.6.0", features = [] } caretta-sync-core.path = "core" +futures = { version = "0.3.31", features = ["executor"] } libp2p = { version = "0.55.0", features = ["macros", "mdns", "noise", "ping", "tcp", "tokio", "yamux" ] } sea-orm = { version = "1.1.11", features = ["sqlx-sqlite", "runtime-tokio-native-tls", "macros", "with-chrono", "with-uuid"] } sea-orm-migration = { version = "1.1.0", features = ["runtime-tokio-rustls", "sqlx-postgres"] } @@ -49,3 +52,12 @@ tokio = { version = "1.45.0", features = ["macros", "rt", "rt-multi-thread"] } tonic = "0.14.0" uuid = { version = "1.17.0", features = ["v7"] } +[profile.dev] +opt-level = 1 + +[profile.dev.package."*"] +opt-level = 3 + +[profile.release] +codegen-units = 1 +lto = "thin" diff --git a/bevy/Cargo.toml b/bevy/Cargo.toml new file mode 100644 index 0000000..a6f8fe4 --- /dev/null +++ b/bevy/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "caretta-sync-bevy" +edition.workspace = true +version.workspace = true +description.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +bevy.workspace = true +caretta-sync-core.workspace = true +futures.workspace = true +sea-orm.workspace = true +tokio.workspace = true +tonic.workspace = true \ No newline at end of file diff --git a/bevy/src/global.rs b/bevy/src/global.rs new file mode 100644 index 0000000..41df6fc --- /dev/null +++ b/bevy/src/global.rs @@ -0,0 +1,4 @@ +use bevy::{asset::uuid::Uuid, ecs::component::Component}; + +#[derive(Component)] +struct Id(Uuid); diff --git a/bevy/src/lib.rs b/bevy/src/lib.rs new file mode 100644 index 0000000..c30187d --- /dev/null +++ b/bevy/src/lib.rs @@ -0,0 +1,2 @@ +pub mod global; +pub mod peer; diff --git a/bevy/src/peer.rs b/bevy/src/peer.rs new file mode 100644 index 0000000..5e1157c --- /dev/null +++ b/bevy/src/peer.rs @@ -0,0 +1,47 @@ +use bevy::{app::{App, Plugin, Startup, Update}, ecs::{component::Component, query::With, system::{Commands, Query}}, tasks::TaskPool}; +use caretta_sync_core::{cache::entity::{CachedPeerEntity, CachedPeerModel}, global::{CONFIG, DATABASE_CONNECTIONS}}; +use caretta_sync_core::{ + proto::*, +}; +use sea_orm::EntityTrait; + +#[derive(Component)] +pub struct Peer; + +#[derive(Component)] +pub struct PeerId(String); + +#[derive(Component)] +pub struct PeerAddress(String); + +#[tokio::main] +async fn add_cached_peers(mut commands: Commands) { + let config = CONFIG.get_unchecked(); + let path = String::from("unix://") + config.rpc.socket_path.as_os_str().to_str().expect("Invalid string"); + let mut client = caretta_sync_core::proto::cached_peer_service_client::CachedPeerServiceClient::connect(path).await.expect("Unix socket should be accessible"); + let request = tonic::Request::new(CachedPeerListRequest {}); + let response = client.list(request).await.expect("Faild to request/response"); + let peers = response.into_inner().peers; + for model in peers.into_iter() { + commands.spawn((Peer, PeerId(model.peer_id.to_string()))); + } +} + +fn print_peer(query: Query<&PeerId, With>) { + for peer_id in &query { + println!("Hello {}!", peer_id.0); + } +} + +fn hello_world() { + println!("hello world!"); +} + +pub struct PeerPlugin; + +impl Plugin for PeerPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, add_cached_peers); + app.add_systems(Update, (hello_world, print_peer)); + } +} \ No newline at end of file diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 17007f8..306b9a3 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -26,4 +26,3 @@ uuid.workspace = true [dev-dependencies] caretta-sync-core = {workspace = true, features = ["test"]} - diff --git a/cli/src/cli/config/check.rs b/cli/src/cli/config/check.rs index 302f20e..8917145 100644 --- a/cli/src/cli/config/check.rs +++ b/cli/src/cli/config/check.rs @@ -9,6 +9,7 @@ pub struct ConfigCheckCommandArgs{ } impl Runnable for ConfigCheckCommandArgs { + #[tokio::main] async fn run(self, app_name: &'static str) { let _ = self.config.into_config(app_name).await; println!("Ok"); diff --git a/cli/src/cli/config/list.rs b/cli/src/cli/config/list.rs index e80bbac..daf1da4 100644 --- a/cli/src/cli/config/list.rs +++ b/cli/src/cli/config/list.rs @@ -11,6 +11,7 @@ pub struct ConfigListCommandArgs{ } impl Runnable for ConfigListCommandArgs { + #[tokio::main] async fn run(self, app_name: &'static str) { let config: PartialConfig = if self.all { self.config.into_config(app_name).await.into() diff --git a/cli/src/cli/config/mod.rs b/cli/src/cli/config/mod.rs index 09abbd0..60bf143 100644 --- a/cli/src/cli/config/mod.rs +++ b/cli/src/cli/config/mod.rs @@ -15,8 +15,8 @@ pub struct ConfigCommandArgs { } impl Runnable for ConfigCommandArgs { - async fn run(self, app_name: &'static str) { - self.command.run(app_name).await + fn run(self, app_name: &'static str) { + self.command.run(app_name) } } @@ -27,10 +27,10 @@ pub enum ConfigSubcommand { } impl Runnable for ConfigSubcommand { - async fn run(self, app_name: &'static str) { + fn run(self, app_name: &'static str) { match self { - Self::Check(x) => x.run(app_name).await, - Self::List(x) => x.run(app_name).await, + Self::Check(x) => x.run(app_name), + Self::List(x) => x.run(app_name), } } } diff --git a/cli/src/cli/device/add.rs b/cli/src/cli/device/add.rs index 5663d65..58d5f45 100644 --- a/cli/src/cli/device/add.rs +++ b/cli/src/cli/device/add.rs @@ -16,7 +16,7 @@ pub struct DeviceAddCommandArgs { } impl Runnable for DeviceAddCommandArgs { - async fn run(self, app_name: &'static str) { + fn run(self, app_name: &'static str) { todo!() } } diff --git a/cli/src/cli/device/list.rs b/cli/src/cli/device/list.rs index 36f92ea..eda652b 100644 --- a/cli/src/cli/device/list.rs +++ b/cli/src/cli/device/list.rs @@ -9,7 +9,7 @@ pub struct DeviceListCommandArgs{ } impl Runnable for DeviceListCommandArgs { - async fn run(self, app_name: &'static str) { + fn run(self, app_name: &'static str) { todo!() } } \ No newline at end of file diff --git a/cli/src/cli/device/mod.rs b/cli/src/cli/device/mod.rs index a8237b3..9ce0624 100644 --- a/cli/src/cli/device/mod.rs +++ b/cli/src/cli/device/mod.rs @@ -22,8 +22,8 @@ pub struct DeviceCommandArgs { } impl Runnable for DeviceCommandArgs { - async fn run(self, app_name: &'static str) { - self.command.run(app_name).await + fn run(self, app_name: &'static str) { + self.command.run(app_name) } } @@ -37,13 +37,13 @@ pub enum DeviceSubcommand { } impl Runnable for DeviceSubcommand { - async fn run(self, app_name: &'static str) { + fn run(self, app_name: &'static str) { match self { - Self::Add(x) => x.run(app_name).await, - Self::List(x) => x.run(app_name).await, - Self::Ping(x) => x.run(app_name).await, - Self::Remove(x) => x.run(app_name).await, - Self::Scan(x) => x.run(app_name).await, + Self::Add(x) => x.run(app_name), + Self::List(x) => x.run(app_name), + Self::Ping(x) => x.run(app_name), + Self::Remove(x) => x.run(app_name), + Self::Scan(x) => x.run(app_name), } } } diff --git a/cli/src/cli/device/ping.rs b/cli/src/cli/device/ping.rs index 3efe588..4c518e2 100644 --- a/cli/src/cli/device/ping.rs +++ b/cli/src/cli/device/ping.rs @@ -11,7 +11,7 @@ pub struct DevicePingCommandArgs{ } impl Runnable for DevicePingCommandArgs { - async fn run(self, app_name: &'static str) { + fn run(self, app_name: &'static str) { todo!() } } \ No newline at end of file diff --git a/cli/src/cli/device/remove.rs b/cli/src/cli/device/remove.rs index cebb145..84e65fc 100644 --- a/cli/src/cli/device/remove.rs +++ b/cli/src/cli/device/remove.rs @@ -11,7 +11,7 @@ pub struct DeviceRemoveCommandArgs{ } impl Runnable for DeviceRemoveCommandArgs { - async fn run(self, app_name: &'static str) { + fn run(self, app_name: &'static str) { todo!() } } \ No newline at end of file diff --git a/cli/src/cli/device/scan.rs b/cli/src/cli/device/scan.rs index adcd173..e5896bd 100644 --- a/cli/src/cli/device/scan.rs +++ b/cli/src/cli/device/scan.rs @@ -9,7 +9,7 @@ pub struct DeviceScanCommandArgs{ } impl Runnable for DeviceScanCommandArgs { - async fn run(self, app_name: &'static str) { + fn run(self, app_name: &'static str) { todo!() } } \ No newline at end of file diff --git a/cli/src/cli/logs.rs b/cli/src/cli/logs.rs deleted file mode 100644 index c0bfff0..0000000 --- a/cli/src/cli/logs.rs +++ /dev/null @@ -1,14 +0,0 @@ -use caretta_sync_core::utils::runnable::Runnable; -use clap::Args; - -#[derive(Args, Debug)] -pub struct LogsCommandArgs { - #[arg(short='n', long)] - lines: Option, -} - -impl Runnable for LogsCommandArgs { - async fn run(self, app_name: &'static str) { - todo!() - } -} \ No newline at end of file diff --git a/cli/src/cli/mod.rs b/cli/src/cli/mod.rs index b85cb40..2b1ee6b 100644 --- a/cli/src/cli/mod.rs +++ b/cli/src/cli/mod.rs @@ -3,13 +3,11 @@ use std::path::PathBuf; mod args; mod config; mod device; -mod logs; mod peer; mod serve; pub use args::*; pub use config::*; pub use device::*; -pub use logs::*; pub use peer::*; pub use serve::*; \ No newline at end of file diff --git a/cli/src/cli/peer/info.rs b/cli/src/cli/peer/info.rs index 5ca2858..8be302b 100644 --- a/cli/src/cli/peer/info.rs +++ b/cli/src/cli/peer/info.rs @@ -11,7 +11,7 @@ pub struct PeerInfoCommandArgs{ } impl Runnable for PeerInfoCommandArgs { - async fn run(self, app_name: &'static str) { + fn run(self, app_name: &'static str) { todo!() } } \ No newline at end of file diff --git a/cli/src/cli/peer/list.rs b/cli/src/cli/peer/list.rs index 73fd7ae..4b551f5 100644 --- a/cli/src/cli/peer/list.rs +++ b/cli/src/cli/peer/list.rs @@ -12,6 +12,7 @@ pub struct PeerListCommandArgs{ } impl Runnable for PeerListCommandArgs { + #[tokio::main] async fn run(self, app_name: &'static str) { let config = self.config.into_config(app_name).await; let path = String::from("unix://") + config.rpc.socket_path.as_os_str().to_str().expect("Invalid string"); diff --git a/cli/src/cli/peer/mod.rs b/cli/src/cli/peer/mod.rs index b2421dc..ceedc05 100644 --- a/cli/src/cli/peer/mod.rs +++ b/cli/src/cli/peer/mod.rs @@ -17,8 +17,8 @@ pub struct PeerCommandArgs { } impl Runnable for PeerCommandArgs { - async fn run(self, app_name: &'static str) { - self.command.run(app_name).await + fn run(self, app_name: &'static str) { + self.command.run(app_name) } } @@ -30,11 +30,11 @@ pub enum PeerSubcommand { } impl Runnable for PeerSubcommand { - async fn run(self, app_name: &'static str) { + fn run(self, app_name: &'static str) { match self { - Self::Info(x) => x.run(app_name).await, - Self::List(x) => x.run(app_name).await, - Self::Ping(x) => x.run(app_name).await, + Self::Info(x) => x.run(app_name), + Self::List(x) => x.run(app_name), + Self::Ping(x) => x.run(app_name), } } } diff --git a/cli/src/cli/peer/ping.rs b/cli/src/cli/peer/ping.rs index 7f85ad0..ac2f3bd 100644 --- a/cli/src/cli/peer/ping.rs +++ b/cli/src/cli/peer/ping.rs @@ -11,6 +11,7 @@ pub struct PeerPingCommandArgs{ } impl Runnable for PeerPingCommandArgs { + #[tokio::main] async fn run(self, app_name: &'static str) { todo!() } diff --git a/cli/src/cli/serve.rs b/cli/src/cli/serve.rs index 77d6e61..3d6ac25 100644 --- a/cli/src/cli/serve.rs +++ b/cli/src/cli/serve.rs @@ -20,6 +20,7 @@ impl Runnable for ServeCommandArgs where T: ServerTrait { + #[tokio::main] async fn run(self, app_name: &'static str) { let config = CONFIG.get_or_init::(self.config.into_config(app_name).await).await; let _ = DATABASE_CONNECTIONS.get_or_init_unchecked(&config, DataMigrator).await; diff --git a/core/Cargo.toml b/core/Cargo.toml index 3a4e839..c195326 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -18,7 +18,7 @@ chrono-tz = "0.10.3" ciborium.workspace = true clap = {workspace = true, optional = true} dirs = "6.0.0" -futures = "0.3.31" +futures.workspace = true libp2p.workspace = true libp2p-core = { version = "0.43.0", features = ["serde"] } libp2p-identity = { version = "0.2.11", features = ["ed25519", "peerid", "rand", "serde"] } diff --git a/core/src/global/config.rs b/core/src/global/config.rs index 0ef961d..4181eff 100644 --- a/core/src/global/config.rs +++ b/core/src/global/config.rs @@ -32,4 +32,7 @@ impl GlobalConfig { pub fn get(&'static self) -> Option<&'static Config> { self.inner.get() } + pub fn get_unchecked(&'static self) -> &'static Config { + self.get().expect("Config must be initialized before use!") + } } \ No newline at end of file diff --git a/core/src/utils/runnable.rs b/core/src/utils/runnable.rs index 92486f5..786be8f 100644 --- a/core/src/utils/runnable.rs +++ b/core/src/utils/runnable.rs @@ -1,6 +1,3 @@ -#[cfg(feature="macros")] -pub use caretta_sync_macros::Runnable; - pub trait Runnable { - async fn run(self, app_name: &'static str); + fn run(self, app_name: &'static str); } \ No newline at end of file diff --git a/examples/demo/core/Cargo.toml b/examples/demo/core/Cargo.toml index 86b5e96..af7d124 100644 --- a/examples/demo/core/Cargo.toml +++ b/examples/demo/core/Cargo.toml @@ -7,7 +7,8 @@ license.workspace = true repository.workspace = true [dependencies] -caretta-sync.path = "../../.." +bevy.workspace = true +caretta-sync = { path = "../../..", features = ["bevy"] } libp2p.workspace = true tokio.workspace = true tokio-stream = { version = "0.1.17", features = ["net"] } diff --git a/examples/demo/core/src/gui.rs b/examples/demo/core/src/gui.rs new file mode 100644 index 0000000..930f023 --- /dev/null +++ b/examples/demo/core/src/gui.rs @@ -0,0 +1,13 @@ +use caretta_sync::{bevy::peer::PeerPlugin, utils::Runnable}; +use bevy::prelude::*; + +pub struct Gui {} + +impl Runnable for Gui { + fn run(self, app_name: &'static str) { + App::new() + //.add_plugins(DefaultPlugins) + .add_plugins(PeerPlugin) + .run(); + } +} \ No newline at end of file diff --git a/examples/demo/core/src/lib.rs b/examples/demo/core/src/lib.rs index 1eaa7fe..831b31d 100644 --- a/examples/demo/core/src/lib.rs +++ b/examples/demo/core/src/lib.rs @@ -1,3 +1,4 @@ pub mod global; +pub mod gui; pub mod rpc; pub mod server; diff --git a/examples/demo/desktop/Cargo.toml b/examples/demo/desktop/Cargo.toml index 7e0f6c1..a845263 100644 --- a/examples/demo/desktop/Cargo.toml +++ b/examples/demo/desktop/Cargo.toml @@ -10,8 +10,7 @@ repository.workspace = true [dependencies] clap.workspace = true -caretta-sync = { path = "../../..", features = ["desktop", "test"] } +caretta-sync = { path = "../../..", features = ["cli", "bevy", "test"] } caretta-sync-demo-core.path = "../core" libp2p.workspace = true tokio.workspace = true - diff --git a/examples/demo/desktop/src/cli/mod.rs b/examples/demo/desktop/src/cli/mod.rs index 8d59841..fe70c32 100644 --- a/examples/demo/desktop/src/cli/mod.rs +++ b/examples/demo/desktop/src/cli/mod.rs @@ -1,20 +1,39 @@ -use caretta_sync_demo_core::server::Server; +use caretta_sync_demo_core::{gui::Gui, server::Server}; use clap::{Parser, Subcommand}; -use caretta_sync::{cli::*, utils::runnable::Runnable}; +use caretta_sync::{cli::*, config::Config, data::migration::DataMigrator, global::{CONFIG, DATABASE_CONNECTIONS}, utils::Runnable}; -#[derive(Debug, Parser, Runnable)] +#[derive(Debug, Parser)] pub struct Cli { #[command(subcommand)] - #[runnable] - command: CliCommand + command: Option, + #[command(flatten)] + config: ConfigArgs, +} + +impl Runnable for Cli { + fn run(self, app_name: &'static str) { + if let Some(x) = self.command { + x.run(app_name) + } else { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { + let config: caretta_sync::config::Config = self.config.into_config(app_name).await; + let _ = CONFIG.get_or_init::(config).await; + }); + //let _ = DATABASE_CONNECTIONS.get_or_init_unchecked(&config, DataMigrator).await; + Gui{}.run(app_name) + } + } } #[derive(Debug, Subcommand, Runnable)] pub enum CliCommand { Config(ConfigCommandArgs), Device(DeviceCommandArgs), - Logs(LogsCommandArgs), Peer(PeerCommandArgs), Serve(ServeCommandArgs), } \ No newline at end of file diff --git a/examples/demo/desktop/src/main.rs b/examples/demo/desktop/src/main.rs index 2733b6a..4b697f4 100644 --- a/examples/demo/desktop/src/main.rs +++ b/examples/demo/desktop/src/main.rs @@ -1,4 +1,4 @@ -use caretta_sync::utils::runnable::Runnable; +use caretta_sync::utils::Runnable; use caretta_sync_demo_core::global::APP_NAME; use clap::Parser; @@ -7,8 +7,7 @@ use crate::cli::Cli; mod cli; mod ipc; -#[tokio::main] -async fn main() { +fn main() { let args = Cli::parse(); - args.run(APP_NAME).await; + args.run(APP_NAME); } diff --git a/macros/Cargo.toml b/macros/Cargo.toml index 56d0435..ae30dcc 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -20,4 +20,4 @@ chrono.workspace = true caretta-sync-core.workspace = true sea-orm.workspace = true tokio.workspace = true -uuid.workspace = true \ No newline at end of file +uuid.workspace = true diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 6726e79..75ac0e9 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -206,8 +206,8 @@ pub fn runnable(input: TokenStream) -> TokenStream { quote!{ impl Runnable for #type_ident { - async fn run(self, app_name: &'static str) { - <#field_type as Runnable>::run(self.#field_ident, app_name).await + fn run(self, app_name: &'static str) { + <#field_type as Runnable>::run(self.#field_ident, app_name) } } }.into() @@ -216,12 +216,12 @@ pub fn runnable(input: TokenStream) -> TokenStream { let quote_vec = extract_idents_and_types_from_enum_struct(&variants); let quote_iter = quote_vec.iter().map(|(variant_ident, variant_type)|{ quote!{ - Self::#variant_ident(x) => <#variant_type as Runnable>::run(x, app_name).await, + Self::#variant_ident(x) => <#variant_type as Runnable>::run(x, app_name), } }); quote!{ impl Runnable for #type_ident { - async fn run(self, app_name: &'static str) { + fn run(self, app_name: &'static str) { match self { #(#quote_iter)* } diff --git a/mobile/Cargo.toml b/mobile/Cargo.toml index eeb443e..a3e69d7 100644 --- a/mobile/Cargo.toml +++ b/mobile/Cargo.toml @@ -11,4 +11,4 @@ default = [] test = ["caretta-sync-core/test"] [dependencies] -caretta-sync-core.workspace = true \ No newline at end of file +caretta-sync-core.workspace = true diff --git a/src/lib.rs b/src/lib.rs index 99c4899..eeb4910 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,7 @@ pub use caretta_sync_core::*; + +#[cfg(feature = "bevy")] +pub use caretta_sync_bevy as bevy; #[cfg(feature = "cli")] pub use caretta_sync_cli::*; #[cfg(feature = "mobile")] @@ -6,8 +9,14 @@ pub use caretta_sync_mobile::*; #[cfg(feature = "macros")] pub mod utils { - pub mod runnable { - pub use caretta_sync_core::utils::runnable::Runnable; - pub use caretta_sync_macros::Runnable; - } + pub use caretta_sync_core::utils::{ + runnable::Runnable, + emptiable::Emptiable, + mergeable::Mergeable, + }; + pub use caretta_sync_macros::{ + Runnable, + Emptiable, + Mergeable, + }; } \ No newline at end of file