Split lazy-supplements to core and desktop
This commit is contained in:
parent
d94a927461
commit
f8422d98fa
48 changed files with 219 additions and 524 deletions
|
@ -1,5 +1,5 @@
|
|||
[workspace]
|
||||
members = [ "examples/*", "lazy-supplements", "lazy-supplements-*" ]
|
||||
members = [ "lazy-supplements-*" ]
|
||||
|
||||
[workspace.package]
|
||||
edition = "2024"
|
||||
|
@ -9,8 +9,11 @@ license = "MIT OR Apache-2.0"
|
|||
repository = "https://forgejo.fireturlte.net"
|
||||
|
||||
[workspace.dependencies]
|
||||
lazy-supplements.path = "lazy-supplements"
|
||||
lazy-supplements-core.path = "lazy-supplements-core"
|
||||
libp2p = { version = "0.55.0", features = ["macros", "mdns", "noise", "ping", "tcp", "tokio", "yamux" ] }
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
thiserror = "2.0.12"
|
||||
tokio = { version = "1.45.0", features = ["macros", "rt", "rt-multi-thread"] }
|
||||
|
||||
[workspace.dependencies.sea-orm-migration]
|
||||
version = "1.1.0"
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
[package]
|
||||
name = "simple-list"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
description.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.41"
|
||||
clap = { version = "4.5.38", features = ["derive"] }
|
||||
lazy-supplements.workspace = true
|
||||
sea-orm = "1.1.11"
|
||||
sea-orm-migration.workspace = true
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
tokio = "1.45.1"
|
||||
|
||||
[dev-dependencies]
|
||||
lazy-supplements = { workspace = true, features = [ "test" ] }
|
|
@ -1,16 +0,0 @@
|
|||
use clap::{Parser, Subcommand};
|
||||
use lazy_supplements::{cli::ServerArgs, config::PartialServerConfig};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Cli {
|
||||
#[command(subcommand)]
|
||||
command: CliCommand
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum CliCommand {
|
||||
Add,
|
||||
Delete,
|
||||
List,
|
||||
Server(ServerArgs)
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
use chrono::Local;
|
||||
use sea_orm::entity::{
|
||||
*,
|
||||
prelude::*
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "list_item")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
#[sea_orm(indexed)]
|
||||
pub created_at: DateTimeUtc,
|
||||
#[sea_orm(indexed)]
|
||||
pub updated_at: DateTimeUtc,
|
||||
#[sea_orm(indexed)]
|
||||
pub is_trashed: bool,
|
||||
#[sea_orm(indexed)]
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl ActiveModel {
|
||||
pub fn new() -> Self {
|
||||
let timestamp: DateTimeUtc = Local::now().to_utc();
|
||||
Self{
|
||||
id: Set(Uuid::new_v4()),
|
||||
created_at: Set(timestamp),
|
||||
updated_at: Set(timestamp),
|
||||
is_trashed: Set(false),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::global::GLOBAL;
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_insert_node() {
|
||||
let db = crate::tests::get_or_init_temporary_database().await;
|
||||
|
||||
ActiveModel{
|
||||
content: Set("test note".to_owned()),
|
||||
..ActiveModel::new()
|
||||
}.insert(db).await.unwrap();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
mod list_item;
|
||||
pub use lazy_supplements::entity::*;
|
||||
|
||||
pub use list_item::{
|
||||
ActiveModel as ListItemActiveModel,
|
||||
Column as ListItemColumn,
|
||||
Entity as ListItemEntity,
|
||||
Model as ListItemModel,
|
||||
};
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
use clap::Parser;
|
||||
|
||||
mod migration;
|
||||
mod cli;
|
||||
mod entity;
|
||||
|
||||
pub use lazy_supplements::error;
|
||||
pub use lazy_supplements::global;
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use sea_orm::DatabaseConnection;
|
||||
use sea_orm_migration::MigratorTrait;
|
||||
|
||||
use super::*;
|
||||
pub async fn get_or_init_temporary_database() -> &'static DatabaseConnection {
|
||||
global::GLOBAL.get_or_try_init_temporary_database(migration::Migrator).await.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let args = cli::Cli::parse();
|
||||
println!("{:?}", args);
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
use sea_orm_migration::{prelude::*, schema::*};
|
||||
|
||||
use lazy_supplements_migration::TableMigration;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
ListItem::up(manager).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
ListItem::down(manager).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum ListItem {
|
||||
Table,
|
||||
Id,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
IsTrashed,
|
||||
Content,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl TableMigration for ListItem {
|
||||
async fn up<'a>(manager: &'a SchemaManager<'a>) -> Result<(), DbErr> {
|
||||
manager.create_table(
|
||||
Table::create()
|
||||
.table(Self::Table)
|
||||
.if_not_exists()
|
||||
.col(pk_uuid(Self::Id))
|
||||
.col(timestamp(Self::CreatedAt))
|
||||
.col(timestamp(Self::UpdatedAt))
|
||||
.col(boolean(Self::IsTrashed))
|
||||
.col(string_len(Self::Content, 255))
|
||||
.to_owned()
|
||||
).await?;
|
||||
Ok(())
|
||||
}
|
||||
async fn down<'a>(manager: &'a SchemaManager<'a>) -> Result<(), DbErr>{
|
||||
manager.drop_table(Table::drop().table(Self::Table).to_owned()).await
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
use sea_orm_migration::{prelude::*, schema::*};
|
||||
use lazy_supplements_migration::m20220101_000001_create_lazy_supplements_tables;
|
||||
mod m20220101_000002_create_simple_list_tables;
|
||||
|
||||
pub struct Migrator;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigratorTrait for Migrator {
|
||||
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||
vec![
|
||||
Box::new(m20220101_000002_create_simple_list_tables::Migration),
|
||||
Box::new(m20220101_000001_create_lazy_supplements_tables::Migration)
|
||||
]
|
||||
}
|
||||
}
|
|
@ -6,4 +6,26 @@ description.workspace = true
|
|||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
test = ["dep:tempfile"]
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.22.1"
|
||||
chrono = "0.4.41"
|
||||
chrono-tz = "0.10.3"
|
||||
futures = "0.3.31"
|
||||
libp2p.workspace = true
|
||||
sea-orm = { version = "1.1.11", features = ["sqlx-sqlite", "runtime-tokio-native-tls", "macros", "with-chrono", "with-uuid"] }
|
||||
sea-orm-migration.workspace = true
|
||||
serde.workspace = true
|
||||
tempfile = { version = "3.20.0", optional = true }
|
||||
thiserror.workspace = true
|
||||
tokio.workspace = true
|
||||
toml = "0.8.22"
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
|
||||
uuid = { version = "1.17.0", features = ["v7"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.20.0"
|
||||
|
|
2
lazy-supplements-core/src/cache/mod.rs
vendored
Normal file
2
lazy-supplements-core/src/cache/mod.rs
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod entity;
|
||||
pub mod migration;
|
|
@ -4,10 +4,7 @@ use std::path::Path;
|
|||
use crate::error::Error;
|
||||
pub use node::{ NodeConfig, RawNodeConfig };
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use crate::global::{
|
||||
DEFAULT_LISTEN_IPS,
|
||||
DEFAULT_PORT,
|
||||
};
|
||||
|
||||
use tokio::{fs::File, io::{AsyncReadExt, AsyncWriteExt}};
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct PartialConfig {
|
|
@ -1,16 +1,15 @@
|
|||
use std::{net::IpAddr, ops, path::{Path, PathBuf}};
|
||||
|
||||
use base64::{prelude::BASE64_STANDARD, Engine};
|
||||
use clap::Args;
|
||||
use libp2p::{identity::{self, DecodingError, Keypair}, noise, ping, tcp, yamux, Swarm};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::{fs::File, io::{AsyncReadExt, AsyncWriteExt}};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
|
||||
use crate::{cli::ConfigArgs, error::Error, global::DEFAULT_DATABASE_FILE_PATH, p2p};
|
||||
use crate::{error::Error, p2p};
|
||||
|
||||
use super::{PartialConfig, DEFAULT_LISTEN_IPS, DEFAULT_PORT};
|
||||
use super::{PartialConfig};
|
||||
|
||||
fn keypair_to_base64(keypair: &Keypair) -> Result<String, Error> {
|
||||
let vec = keypair.to_protobuf_encoding()?;
|
||||
|
@ -83,15 +82,11 @@ mod keypair_parser {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Args, Clone, Debug, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct RawNodeConfig {
|
||||
#[arg(skip)]
|
||||
pub secret: Option<String>,
|
||||
#[arg(long)]
|
||||
pub database_path: Option<PathBuf>,
|
||||
#[arg(long)]
|
||||
pub listen_ips: Option<Vec<IpAddr>>,
|
||||
#[arg(long)]
|
||||
pub port: Option<u16>,
|
||||
}
|
||||
impl RawNodeConfig {
|
|
@ -14,3 +14,8 @@ pub use record_deletion::{
|
|||
Entity as RecordDeletionEntity,
|
||||
Model as RecordDeletionModel,
|
||||
};
|
||||
use uuid::{ContextV7, Timestamp, Uuid};
|
||||
|
||||
pub fn generate_uuid() -> Uuid {
|
||||
Uuid::new_v7(Timestamp::now(ContextV7::new()))
|
||||
}
|
|
@ -32,7 +32,7 @@ impl ActiveModel {
|
|||
pub fn new() -> Self {
|
||||
let timestamp: DateTimeUtc = Local::now().to_utc();
|
||||
Self{
|
||||
id: Set(Uuid::new_v4()),
|
||||
id: Set(super::generate_uuid()),
|
||||
created_at: Set(timestamp),
|
||||
updated_at: Set(timestamp),
|
||||
..Default::default()
|
|
@ -26,7 +26,7 @@ impl ActiveModel {
|
|||
pub fn new() -> Self {
|
||||
let timestamp: DateTimeUtc = Local::now().to_utc();
|
||||
Self{
|
||||
id: Set(Uuid::new_v4()),
|
||||
id: Set(super::generate_uuid()),
|
||||
created_at: Set(timestamp),
|
||||
..Default::default()
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ impl ActiveModel {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use uuid::Uuid;
|
||||
use uuid::{Timestamp, Uuid};
|
||||
use crate::global::get_or_init_temporary_main_database;
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -46,7 +46,7 @@ mod tests {
|
|||
|
||||
assert!(ActiveModel{
|
||||
table_name: Set("test_table".to_string()),
|
||||
record_id: Set(Uuid::new_v4()),
|
||||
record_id: Set(super::super::generate_uuid()),
|
||||
..ActiveModel::new()
|
||||
}.insert(db).await.is_ok());
|
||||
}
|
2
lazy-supplements-core/src/data/mod.rs
Normal file
2
lazy-supplements-core/src/data/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod entity;
|
||||
pub mod migration;
|
|
@ -18,12 +18,6 @@ pub enum Error {
|
|||
Multiaddr(#[from] libp2p::multiaddr::Error),
|
||||
#[error("Noise error: {0}")]
|
||||
Noise(#[from] libp2p::noise::Error),
|
||||
#[error("Parse args error: {0}")]
|
||||
ParseCommand(#[from] clap::Error),
|
||||
#[error("Readline error: {0}")]
|
||||
Readline(#[from] rustyline::error::ReadlineError),
|
||||
#[error("Shell word split error: {0}")]
|
||||
ShellWord(#[from] shell_words::ParseError),
|
||||
#[error("toml deserialization error: {0}")]
|
||||
TomlDe(#[from] toml::de::Error),
|
||||
#[error("toml serialization error: {0}")]
|
|
@ -16,43 +16,16 @@ pub static PRODUCT_NAME: LazyLock<String> = LazyLock::new(|| {
|
|||
|
||||
pub static DEFAULT_LISTEN_IPS: &[IpAddr] = &[IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))];
|
||||
|
||||
pub static DEFAULT_PORT: u16 = 8080;
|
||||
|
||||
pub static DEFAULT_CONFIG_DIR_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
let dir = if let Some(x) = dirs::config_local_dir() {
|
||||
x
|
||||
} else {
|
||||
todo!()
|
||||
};
|
||||
|
||||
dir.join(&*PRODUCT_NAME)
|
||||
});
|
||||
|
||||
pub static DEFAULT_CONFIG_FILE_NAME: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
PathBuf::from(String::new() + env!("CARGO_PKG_NAME") + ".toml")
|
||||
});
|
||||
|
||||
pub static DEFAULT_CONFIG_FILE_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
DEFAULT_CONFIG_DIR_PATH.join(&*DEFAULT_CONFIG_FILE_NAME)
|
||||
});
|
||||
|
||||
pub static DEFAULT_DATA_DIR_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
let dir = if let Some(x) = dirs::data_local_dir() {
|
||||
x
|
||||
} else {
|
||||
todo!()
|
||||
};
|
||||
|
||||
dir.join(&*PRODUCT_NAME)
|
||||
});
|
||||
|
||||
pub static DEFAULT_DATABASE_FILE_NAME: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
PathBuf::from(String::new() + env!("CARGO_PKG_NAME") + ".sqlite")
|
||||
});
|
||||
|
||||
pub static DEFAULT_DATABASE_FILE_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
DEFAULT_DATA_DIR_PATH.join(&*DEFAULT_DATABASE_FILE_NAME)
|
||||
});
|
||||
|
||||
|
||||
pub static GLOBAL: Global = Global{
|
||||
node_config: OnceCell::const_new(),
|
||||
|
@ -140,14 +113,7 @@ impl GlobalDatabase for Global {
|
|||
|
||||
}
|
||||
|
||||
pub static DEFAULT_RAW_NODE_CONFIG: LazyLock<RawNodeConfig> = LazyLock::new(|| {
|
||||
RawNodeConfig {
|
||||
secret: None,
|
||||
database_path: Some(DEFAULT_DATABASE_FILE_PATH.to_path_buf()),
|
||||
listen_ips: Some(DEFAULT_LISTEN_IPS.to_vec()),
|
||||
port: Some(DEFAULT_PORT),
|
||||
}
|
||||
});
|
||||
|
||||
#[cfg(test)]
|
||||
pub use tests::{get_or_init_temporary_main_database, get_or_init_temporary_cache_database};
|
||||
#[cfg(test)]
|
||||
|
@ -156,7 +122,7 @@ pub mod tests {
|
|||
|
||||
use sea_orm_migration::MigratorTrait;
|
||||
|
||||
use crate::{global::GLOBAL, migration::{cache::CacheMigrator, main::MainMigrator}};
|
||||
use crate::{global::GLOBAL, cache::migration::CacheMigrator, data::migration::MainMigrator};
|
||||
|
||||
use super::*;
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
pub mod cache;
|
||||
pub mod config;
|
||||
pub mod data;
|
||||
pub mod error;
|
||||
pub mod global;
|
||||
pub mod migration;
|
||||
pub mod p2p;
|
||||
#[cfg(any(test, feature="test"))]
|
||||
pub mod tests;
|
|
@ -1,6 +1,3 @@
|
|||
pub mod cache;
|
||||
pub mod main;
|
||||
|
||||
use sea_orm_migration::{prelude::*, schema::*};
|
||||
|
||||
#[async_trait::async_trait]
|
19
lazy-supplements-desktop/Cargo.toml
Normal file
19
lazy-supplements-desktop/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "lazy-supplements-desktop"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
description.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.38", features = ["derive"] }
|
||||
dirs = "6.0.0"
|
||||
lazy-supplements-core.workspace = true
|
||||
libp2p.workspace = true
|
||||
serde.workspace = true
|
||||
thiserror.workspace = true
|
||||
tokio.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
lazy-supplements-core = {workspace = true, features = ["test"]}
|
54
lazy-supplements-desktop/src/cli/config.rs
Normal file
54
lazy-supplements-desktop/src/cli/config.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use std::{net::IpAddr, path::PathBuf};
|
||||
|
||||
use clap::Args;
|
||||
use lazy_supplements_core::config::RawNodeConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{config::NodeConfig, error::Error, global::{DEFAULT_CONFIG_FILE_PATH, DEFAULT_RAW_NODE_CONFIG}};
|
||||
|
||||
#[derive(Args, Clone, Debug)]
|
||||
pub struct ConfigArgs {
|
||||
#[arg(long)]
|
||||
pub config: Option<PathBuf>,
|
||||
#[command(flatten)]
|
||||
pub config_values: ConfigValueArgs,
|
||||
}
|
||||
|
||||
impl ConfigArgs {
|
||||
pub fn get_config_path_or_default(&self) -> PathBuf {
|
||||
if let Some(x) = self.config.as_ref() {
|
||||
x.clone()
|
||||
} else {
|
||||
DEFAULT_CONFIG_FILE_PATH.to_path_buf()
|
||||
}
|
||||
}
|
||||
pub async fn try_into_raw_node_config(self) -> Result<RawNodeConfig, Error> {
|
||||
Ok(RawNodeConfig::read_from(self.get_config_path_or_default()).await? + self.config_values.into())
|
||||
}
|
||||
pub async fn try_into_node_config(self) -> Result<NodeConfig, Error> {
|
||||
Ok((DEFAULT_RAW_NODE_CONFIG.clone() + self.try_into_raw_node_config().await?).try_into()?)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Args, Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct ConfigValueArgs {
|
||||
#[arg(skip)]
|
||||
pub secret: Option<String>,
|
||||
#[arg(long)]
|
||||
pub database_path: Option<PathBuf>,
|
||||
#[arg(long)]
|
||||
pub listen_ips: Option<Vec<IpAddr>>,
|
||||
#[arg(long)]
|
||||
pub port: Option<u16>,
|
||||
}
|
||||
|
||||
impl Into<RawNodeConfig> for ConfigValueArgs {
|
||||
fn into(self) -> RawNodeConfig {
|
||||
RawNodeConfig {
|
||||
secret : self.secret,
|
||||
database_path: self.database_path,
|
||||
listen_ips: self.listen_ips,
|
||||
port: self.port
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,9 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
mod config;
|
||||
mod console;
|
||||
mod init;
|
||||
mod node;
|
||||
mod server;
|
||||
|
||||
pub use config::ConfigArgs;
|
||||
pub use console::{ConsoleArgs, ConsoleCommands};
|
||||
pub use init::InitArgs;
|
||||
pub use node::{ NodeArgs, NodeCommand, PeerArgs , ConsoleNodeArgs};
|
||||
pub use server::ServerArgs;
|
|
@ -1,13 +1,11 @@
|
|||
use std::{net::IpAddr, ops::Mul, path::PathBuf, str::FromStr};
|
||||
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use futures::StreamExt;
|
||||
use libp2p::{
|
||||
multiaddr::Protocol, noise, ping, swarm::SwarmEvent, tcp, yamux, Multiaddr, PeerId
|
||||
};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
use crate::{cli::ServerArgs, error::Error};
|
||||
use crate::{cli::ServerArgs, error::{CoreError, DesktopError, Error}};
|
||||
|
||||
use super::ConfigArgs;
|
||||
|
||||
|
@ -30,10 +28,6 @@ impl NodeArgs {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn parse_and_run_console_node_command(s:Vec<String>) -> Result<(), Error> {
|
||||
ConsoleNodeArgs::try_parse_from(s)?.args.run().await
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct PeerArgs {
|
||||
#[arg(value_parser = clap::value_parser!(PeerArg))]
|
|
@ -1,9 +1,7 @@
|
|||
use clap::Args;
|
||||
use futures::StreamExt;
|
||||
use libp2p::{noise, ping, swarm::{NetworkBehaviour, SwarmEvent}, tcp, yamux, Swarm};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
use crate::{error::Error, global::GLOBAL};
|
||||
use crate::{error::Error, global::GLOBAL, error::CoreError};
|
||||
|
||||
use super::ConfigArgs;
|
||||
|
||||
|
@ -15,6 +13,6 @@ pub struct ServerArgs {
|
|||
impl ServerArgs {
|
||||
pub async fn start_server(self) -> Result<(), Error>{
|
||||
let _ = crate::global::GLOBAL.get_or_init_node_config(self.config.try_into_node_config().await?).await;
|
||||
GLOBAL.launch_swarm().await
|
||||
GLOBAL.launch_swarm().await.or_else(|e| {Err(Error::from(CoreError::from(e)))})
|
||||
}
|
||||
}
|
16
lazy-supplements-desktop/src/error.rs
Normal file
16
lazy-supplements-desktop/src/error.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
pub use lazy_supplements_core::error::Error as CoreError;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum DesktopError {
|
||||
#[error("Parse args error: {0}")]
|
||||
ParseCommand(#[from] clap::Error),
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("{0}")]
|
||||
Core(#[from] CoreError),
|
||||
#[error("{0}")]
|
||||
Desktop(#[from] DesktopError),
|
||||
}
|
||||
|
39
lazy-supplements-desktop/src/global.rs
Normal file
39
lazy-supplements-desktop/src/global.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use std::{path::PathBuf, sync::LazyLock};
|
||||
|
||||
use lazy_supplements_core::config::RawNodeConfig;
|
||||
pub use lazy_supplements_core::global::*;
|
||||
|
||||
pub static DEFAULT_DATA_DIR_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
let dir = if let Some(x) = dirs::data_local_dir() {
|
||||
x
|
||||
} else {
|
||||
todo!()
|
||||
};
|
||||
|
||||
dir.join(&*PRODUCT_NAME)
|
||||
});
|
||||
pub static DEFAULT_CONFIG_DIR_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
let dir = if let Some(x) = dirs::config_local_dir() {
|
||||
x
|
||||
} else {
|
||||
todo!()
|
||||
};
|
||||
|
||||
dir.join(&*PRODUCT_NAME)
|
||||
});
|
||||
|
||||
pub static DEFAULT_CONFIG_FILE_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
DEFAULT_CONFIG_DIR_PATH.join(&*DEFAULT_CONFIG_FILE_NAME)
|
||||
});
|
||||
pub static DEFAULT_DATABASE_FILE_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
DEFAULT_DATA_DIR_PATH.join(&*DEFAULT_DATABASE_FILE_NAME)
|
||||
});
|
||||
|
||||
pub static DEFAULT_RAW_NODE_CONFIG: LazyLock<RawNodeConfig> = LazyLock::new(|| {
|
||||
RawNodeConfig {
|
||||
secret: None,
|
||||
database_path: Some(DEFAULT_DATABASE_FILE_PATH.to_path_buf()),
|
||||
listen_ips: Some(DEFAULT_LISTEN_IPS.to_vec()),
|
||||
port: Some(0),
|
||||
}
|
||||
});
|
8
lazy-supplements-desktop/src/lib.rs
Normal file
8
lazy-supplements-desktop/src/lib.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
pub mod cli;
|
||||
pub mod error;
|
||||
pub mod global;
|
||||
pub use lazy_supplements_core::{
|
||||
cache,
|
||||
config,
|
||||
data,
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
use clap::{Parser, Subcommand};
|
||||
use lazy_supplements::{cli::{ConfigArgs, ConsoleArgs, ConsoleCommands, InitArgs, NodeArgs, NodeCommand, ServerArgs}, global::{Global, GLOBAL}, *};
|
||||
use lazy_supplements_desktop::{cli::{ConfigArgs, NodeArgs, NodeCommand, ServerArgs}, global::{Global, GLOBAL}, *};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct Cli {
|
||||
|
@ -11,9 +11,7 @@ struct Cli {
|
|||
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum Command {
|
||||
Console(ConsoleArgs),
|
||||
Node(NodeArgs),
|
||||
Init(InitArgs),
|
||||
Server(ServerArgs),
|
||||
}
|
||||
|
||||
|
@ -24,8 +22,6 @@ async fn main() {
|
|||
let _ = GLOBAL.get_or_init_node_config(cli.config.try_into_node_config().await.unwrap()).await;
|
||||
match cli.command {
|
||||
Command::Node(x) => x.run().await.unwrap(),
|
||||
Command::Init(x) => x.init_config().await,
|
||||
Command::Server(x) => x.start_server().await.unwrap(),
|
||||
Command::Console(x) => x.start_console(ConsoleCommands::default()).await.unwrap(),
|
||||
}
|
||||
}
|
9
lazy-supplements-mobile/Cargo.toml
Normal file
9
lazy-supplements-mobile/Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "lazy-supplements-mobile"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
description.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
14
lazy-supplements-mobile/src/lib.rs
Normal file
14
lazy-supplements-mobile/src/lib.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
pub fn add(left: u64, right: u64) -> u64 {
|
||||
left + right
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
[package]
|
||||
name = "lazy-supplements"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
description.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
test = ["dep:tempfile"]
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.22.1"
|
||||
chrono = "0.4.41"
|
||||
chrono-tz = "0.10.3"
|
||||
clap = { version = "4.5.38", features = ["derive"] }
|
||||
dirs = "6.0.0"
|
||||
futures = "0.3.31"
|
||||
libp2p.workspace = true
|
||||
rustyline = "16.0.0"
|
||||
sea-orm = { version = "1.1.11", features = ["sqlx-sqlite", "runtime-tokio-native-tls", "macros", "with-chrono", "with-uuid"] }
|
||||
sea-orm-migration.workspace = true
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
shell-words = "1.1.0"
|
||||
tempfile = { version = "3.20.0", optional = true }
|
||||
thiserror = "2.0.12"
|
||||
tokio = { version = "1.45.0", features = ["macros", "rt", "rt-multi-thread"] }
|
||||
toml = "0.8.22"
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
|
||||
uuid = { version = "1.17.0", features = ["v4"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.20.0"
|
|
@ -1,30 +0,0 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use clap::Args;
|
||||
use libp2p::identity;
|
||||
|
||||
use crate::{config::{NodeConfig, RawNodeConfig}, error::Error, global::{DEFAULT_CONFIG_FILE_PATH, DEFAULT_RAW_NODE_CONFIG}};
|
||||
|
||||
#[derive(Args, Clone, Debug)]
|
||||
pub struct ConfigArgs {
|
||||
#[arg(long)]
|
||||
pub config: Option<PathBuf>,
|
||||
#[command(flatten)]
|
||||
pub node_config: RawNodeConfig,
|
||||
}
|
||||
|
||||
impl ConfigArgs {
|
||||
pub fn get_config_path_or_default(&self) -> PathBuf {
|
||||
if let Some(x) = self.config.as_ref() {
|
||||
x.clone()
|
||||
} else {
|
||||
DEFAULT_CONFIG_FILE_PATH.to_path_buf()
|
||||
}
|
||||
}
|
||||
pub async fn try_into_raw_node_config(self) -> Result<RawNodeConfig, Error> {
|
||||
Ok(RawNodeConfig::read_from(self.get_config_path_or_default()).await? + self.node_config)
|
||||
}
|
||||
pub async fn try_into_node_config(self) -> Result<NodeConfig, Error> {
|
||||
Ok((DEFAULT_RAW_NODE_CONFIG.clone() + self.try_into_raw_node_config().await?).try_into()?)
|
||||
}
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
mod writer;
|
||||
|
||||
use std::{collections::HashMap, ffi::OsString, hash::Hash, time::Duration};
|
||||
|
||||
use clap::{Args, Parser};
|
||||
use futures::{future::BoxFuture, StreamExt};
|
||||
use libp2p::{core::transport::dummy::DummyTransport, noise, ping, swarm::{NetworkBehaviour, SwarmEvent}, tcp, yamux, Swarm};
|
||||
use rustyline::ExternalPrinter;
|
||||
use tokio::{sync::Mutex, time::sleep};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use writer::ConsoleWriter;
|
||||
|
||||
use crate::{error::Error, global::GLOBAL};
|
||||
|
||||
use super::{node::parse_and_run_console_node_command, ConfigArgs};
|
||||
|
||||
pub trait Executable {
|
||||
fn execute(self) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
pub trait ConsoleCommand {
|
||||
fn execute_line(&self, line: String) -> Result<(), Error>;
|
||||
}
|
||||
pub struct ConsoleCommands {
|
||||
content: HashMap<&'static str, Box<dyn Fn(Vec<String>) -> BoxFuture<'static, Result<(), Error>>>>,
|
||||
}
|
||||
impl ConsoleCommands {
|
||||
pub fn new() -> Self {
|
||||
Self{content: HashMap::new()}
|
||||
}
|
||||
pub fn insert<F, Fut>(&mut self,name: &'static str, f: F)
|
||||
where
|
||||
F: Fn(Vec<String>) -> Fut + 'static,
|
||||
Fut: Future<Output = Result<(), Error>> + Send + 'static,
|
||||
{
|
||||
if let Some(_) = self.content.insert(name, Box::new(move |v| {
|
||||
Box::pin(f(v))
|
||||
})){
|
||||
unreachable!();
|
||||
};
|
||||
}
|
||||
pub async fn parse_and_run(&self, line: String) -> Result<(), Error>{
|
||||
let args = shell_words::split(&line)?;
|
||||
if let Some(command_name) = args.first().map(|s| {s.clone()}) {
|
||||
if let Some(command) = self.content.get(command_name.as_str()) {
|
||||
command(args).await
|
||||
} else {
|
||||
println!("Invalid command: {command_name}");
|
||||
self.print_commands();
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
pub fn print_commands(&self) {
|
||||
for key in self.content.keys(){
|
||||
println!("{key}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ConsoleCommands {
|
||||
fn default() -> Self {
|
||||
let mut commands = Self::new();
|
||||
commands.insert("node", parse_and_run_console_node_command);
|
||||
commands
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ConsoleArgs {
|
||||
#[command(flatten)]
|
||||
config: ConfigArgs,
|
||||
}
|
||||
|
||||
impl ConsoleArgs {
|
||||
pub async fn start_console(self, commands: ConsoleCommands) -> Result<(), Error>
|
||||
{
|
||||
let _ = crate::global::GLOBAL.get_or_init_node_config(self.config.try_into_node_config().await?).await;
|
||||
tokio::spawn( async {
|
||||
GLOBAL.launch_swarm().await
|
||||
});
|
||||
let mut rl = rustyline::DefaultEditor::new()?;
|
||||
let mut printer = rl.create_external_printer()?;
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(EnvFilter::from_default_env())
|
||||
.with_writer(std::sync::Mutex::new(ConsoleWriter::try_from(&mut rl)?)
|
||||
).init();
|
||||
tokio::spawn(async move {
|
||||
loop{
|
||||
tracing::event!(tracing::Level::ERROR, "test");
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
});
|
||||
loop {
|
||||
match rl.readline(">> ") {
|
||||
Ok(line) => {
|
||||
if let Err(e) = commands.parse_and_run(line).await {
|
||||
println!("{e}");
|
||||
}
|
||||
},
|
||||
Err(x) => Err(x)?,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
use std::io::Read;
|
||||
|
||||
use rustyline::{DefaultEditor, ExternalPrinter};
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
pub struct ConsoleWriter {
|
||||
printer: Box<dyn ExternalPrinter + 'static + Send>
|
||||
}
|
||||
|
||||
impl TryFrom<&mut DefaultEditor> for ConsoleWriter {
|
||||
type Error = Error;
|
||||
fn try_from(e: &mut DefaultEditor) -> Result<Self, Error> {
|
||||
Ok(ConsoleWriter {
|
||||
printer: Box::new(e.create_external_printer()?)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl std::io::Write for ConsoleWriter {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
let msg = String::from_utf8_lossy(buf).into_owned();
|
||||
let size = msg.as_bytes().len();
|
||||
self.printer.as_mut().print(msg);
|
||||
Ok(size)
|
||||
}
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use clap::Args;
|
||||
use libp2p::identity;
|
||||
|
||||
use crate::{config::RawNodeConfig, global::DEFAULT_CONFIG_FILE_PATH};
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct InitArgs {
|
||||
#[arg(long)]
|
||||
config: Option<PathBuf>,
|
||||
#[arg(short, long)]
|
||||
force: bool,
|
||||
#[command(flatten)]
|
||||
node_config: RawNodeConfig,
|
||||
}
|
||||
|
||||
impl InitArgs {
|
||||
pub async fn init_config(self) {
|
||||
let config_path = if let Some(x) = self.config {
|
||||
x
|
||||
} else {
|
||||
DEFAULT_CONFIG_FILE_PATH.to_path_buf()
|
||||
};
|
||||
if config_path.exists() && !self.force {
|
||||
println!("Config file already exists!");
|
||||
return;
|
||||
} else {
|
||||
let config = self.node_config.with_new_secret();
|
||||
config.write_to(config_path).await.unwrap()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
pub mod cli;
|
||||
pub mod config;
|
||||
pub mod entity;
|
||||
pub mod error;
|
||||
pub mod global;
|
||||
pub mod migration;
|
||||
pub mod p2p;
|
||||
#[cfg(any(test, feature="test"))]
|
||||
pub mod tests;
|
Loading…
Add table
Reference in a new issue