Add node command and default path
This commit is contained in:
parent
d2b63140fd
commit
a3a8295880
10 changed files with 189 additions and 19 deletions
|
@ -15,6 +15,8 @@ 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
|
||||
sea-orm = { version = "1.1.11", features = ["sqlx-sqlite", "runtime-tokio-native-tls", "macros", "with-chrono", "with-uuid"] }
|
||||
sea-orm-migration.workspace = true
|
||||
|
@ -23,9 +25,10 @@ tempfile = { version = "3.20.0", optional = true }
|
|||
thiserror = "2.0.12"
|
||||
tokio = { version = "1.45.0", features = ["macros", "rt"] }
|
||||
toml = "0.8.22"
|
||||
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
|
||||
uuid = { version = "1.17.0", features = ["v4"] }
|
||||
|
||||
[dev-dependencies]
|
||||
lazy-supplements-migration.workspace = true
|
||||
sea-orm-migration.workspace = true
|
||||
tempfile = "3.20.0"
|
||||
tempfile = "3.20.0"
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
use std::{net::IpAddr, path::PathBuf};
|
||||
|
||||
use clap::Args;
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ConnectArgs {
|
||||
#[arg(long)]
|
||||
endpoint: IpAddr,
|
||||
#[arg(long)]
|
||||
port: i32,
|
||||
#[arg(long)]
|
||||
config: PathBuf,
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
mod connect;
|
||||
mod init;
|
||||
mod node;
|
||||
mod server;
|
||||
|
||||
pub use server::ServerArgs;
|
||||
|
|
30
lazy-supplements/src/cli/node.rs
Normal file
30
lazy-supplements/src/cli/node.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use std::{net::IpAddr, path::PathBuf};
|
||||
|
||||
use clap::{Args, Subcommand};
|
||||
use libp2p::PeerId;
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct NodeArgs {
|
||||
#[command(subcommand)]
|
||||
command: NodeCommand
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct JoinNodeArgs {
|
||||
#[arg(long)]
|
||||
endpoint: IpAddr,
|
||||
#[arg(long)]
|
||||
port: i32,
|
||||
#[arg(long)]
|
||||
peer_id: String,
|
||||
#[arg(long)]
|
||||
config: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum NodeCommand {
|
||||
Ping(JoinNodeArgs),
|
||||
Join(JoinNodeArgs),
|
||||
}
|
||||
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
mod node;
|
||||
mod server;
|
||||
|
||||
use std::path::Path;
|
||||
use crate::error::Error;
|
||||
pub use node::NodeConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use server::{
|
||||
PartialServerConfig,
|
||||
ServerConfig,
|
||||
|
@ -10,4 +13,51 @@ pub use server::{
|
|||
DEFAULT_PARTIAL_SERVER_CONFIG,
|
||||
DEFAULT_SERVER_CONFIG
|
||||
};
|
||||
use tokio::{fs::File, io::{AsyncReadExt, AsyncWriteExt}};
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct PartialConfig {
|
||||
node: Option<NodeConfig>,
|
||||
server: Option<ServerConfig>,
|
||||
}
|
||||
|
||||
impl PartialConfig {
|
||||
pub fn new() -> Self {
|
||||
PartialConfig {
|
||||
node: Some(NodeConfig::new()),
|
||||
server: None,
|
||||
}
|
||||
}
|
||||
pub async fn read_or_create<T>(path: T) -> Result<Self, Error>
|
||||
where
|
||||
T: AsRef<Path>
|
||||
{
|
||||
if !path.as_ref().exists() {
|
||||
Self::new().write_to(&path).await?;
|
||||
}
|
||||
Self::read_from(&path).await
|
||||
}
|
||||
pub async fn read_from<T>(path:T) -> Result<Self, Error>
|
||||
where
|
||||
T: AsRef<Path>
|
||||
{
|
||||
let mut file = File::open(path.as_ref()).await?;
|
||||
let mut content = String::new();
|
||||
file.read_to_string(&mut content).await?;
|
||||
let config: PartialConfig = toml::from_str(&content)?;
|
||||
Ok(config)
|
||||
}
|
||||
pub async fn write_to<T>(&self, path:T) -> Result<(), Error>
|
||||
where
|
||||
T: AsRef<Path>
|
||||
{
|
||||
if !path.as_ref().exists() {
|
||||
let _ = File::create(&path).await?;
|
||||
}
|
||||
let mut file = File::open(&path).await?;
|
||||
file.write_all(toml::to_string(self)?.as_bytes()).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,31 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use libp2p::identity::{self, Keypair};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::global::DEFAULT_DATABASE_FILE_PATH;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct NodeConfig {
|
||||
#[serde(with = "keypair")]
|
||||
secret: Keypair,
|
||||
database_path: Option<PathBuf>
|
||||
}
|
||||
|
||||
impl NodeConfig {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
secret: identity::Keypair::generate_ed25519(),
|
||||
database_path: None,
|
||||
}
|
||||
}
|
||||
pub fn get_database_path(&self) -> PathBuf {
|
||||
if let Some(x) = self.database_path.clone() {
|
||||
x
|
||||
} else {
|
||||
DEFAULT_DATABASE_FILE_PATH.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod keypair {
|
||||
|
@ -39,6 +60,7 @@ mod tests {
|
|||
let keypair = identity::Keypair::generate_ed25519();
|
||||
let config = NodeConfig {
|
||||
secret: keypair.clone(),
|
||||
database_path: None,
|
||||
};
|
||||
let string = toml::to_string(&config).unwrap();
|
||||
println!("Parsed config: {}", &string);
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
pub enum Error {
|
||||
#[error("DB Error: {0}")]
|
||||
Db(#[from]sea_orm::DbErr),
|
||||
#[error("IO Error: {0}")]
|
||||
Io(#[from]std::io::Error),
|
||||
#[error("mandatory config `{0}` is missing")]
|
||||
MissingConfig(String),
|
||||
#[error("toml deserialization error: {0}")]
|
||||
TomlDe(#[from] toml::de::Error),
|
||||
#[error("toml serialization error: {0}")]
|
||||
TomlSer(#[from] toml::ser::Error),
|
||||
}
|
|
@ -1,17 +1,70 @@
|
|||
use crate::config::{ServerConfig};
|
||||
use std::{path::PathBuf, sync::LazyLock};
|
||||
|
||||
use crate::config::{NodeConfig, ServerConfig};
|
||||
use sea_orm::DatabaseConnection;
|
||||
use tokio::sync::OnceCell;
|
||||
|
||||
mod database;
|
||||
|
||||
pub static PRODUCT_NAME: LazyLock<String> = LazyLock::new(|| {
|
||||
env!("CARGO_PKG_NAME").to_string()
|
||||
});
|
||||
|
||||
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(),
|
||||
server_config: OnceCell::const_new(),
|
||||
database: OnceCell::const_new(),
|
||||
};
|
||||
pub struct Global {
|
||||
server_config: OnceCell<ServerConfig>,
|
||||
database: OnceCell<DatabaseConnection>,
|
||||
pub server_config: OnceCell<ServerConfig>,
|
||||
pub node_config: OnceCell<NodeConfig>,
|
||||
pub database: OnceCell<DatabaseConnection>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub use database::tests::get_or_init_temporary_database;
|
||||
pub use database::tests::get_or_init_temporary_database;
|
||||
|
||||
impl Global {
|
||||
pub fn get_node_config(&self) -> Option<&NodeConfig> {
|
||||
self.node_config.get()
|
||||
}
|
||||
pub async fn get_or_try_init_node_config(&self, config: NodeConfig) -> &NodeConfig {
|
||||
self.node_config.get_or_init(|| async {config}).await
|
||||
}
|
||||
}
|
|
@ -3,3 +3,5 @@ pub mod config;
|
|||
pub mod entity;
|
||||
pub mod error;
|
||||
pub mod global;
|
||||
#[cfg(any(test, feature="test"))]
|
||||
pub mod tests;
|
||||
|
|
17
lazy-supplements/src/tests.rs
Normal file
17
lazy-supplements/src/tests.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use std::{path::PathBuf, sync::LazyLock};
|
||||
|
||||
use tempfile::TempDir;
|
||||
|
||||
pub static TEST_DIR_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
let pkg_name = env!("CARGO_PKG_NAME");
|
||||
let timestamp = chrono::Local::now().to_rfc3339_opts(chrono::SecondsFormat::Nanos, false);
|
||||
std::env::temp_dir().join(pkg_name).join( ×tamp)
|
||||
});
|
||||
|
||||
pub static TEST_DIR: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
TempDir::new().unwrap().keep()
|
||||
});
|
||||
|
||||
pub static TEST_DATABASE_PATH: std::sync::LazyLock<PathBuf> = std::sync::LazyLock::new(|| {
|
||||
TEST_DIR_PATH.join("lazy-supplements.sqlite")
|
||||
});
|
Loading…
Add table
Reference in a new issue