Merge server config to node config
This commit is contained in:
parent
a3a8295880
commit
8aa96d091a
8 changed files with 132 additions and 66 deletions
|
@ -11,7 +11,7 @@ repository = "https://forgejo.fireturlte.net"
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
lazy-supplements.path = "lazy-supplements"
|
lazy-supplements.path = "lazy-supplements"
|
||||||
lazy-supplements-migration.path = "lazy-supplements-migration"
|
lazy-supplements-migration.path = "lazy-supplements-migration"
|
||||||
libp2p = "0.55.0"
|
libp2p = { version = "0.55.0", features = ["noise", "ping", "tcp", "tokio", "yamux" ] }
|
||||||
|
|
||||||
[workspace.dependencies.sea-orm-migration]
|
[workspace.dependencies.sea-orm-migration]
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
|
@ -2,9 +2,6 @@ use std::path::PathBuf;
|
||||||
|
|
||||||
mod init;
|
mod init;
|
||||||
mod node;
|
mod node;
|
||||||
mod server;
|
|
||||||
|
|
||||||
pub use server::ServerArgs;
|
|
||||||
|
|
||||||
pub fn default_config_path() -> PathBuf {
|
pub fn default_config_path() -> PathBuf {
|
||||||
todo!()
|
todo!()
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
use std::{net::IpAddr, path::PathBuf};
|
use std::{net::IpAddr, path::PathBuf};
|
||||||
|
|
||||||
use clap::{Args, Subcommand};
|
use clap::{Args, Subcommand};
|
||||||
use libp2p::PeerId;
|
use futures::StreamExt;
|
||||||
|
use libp2p::{
|
||||||
|
multiaddr::Protocol, noise, ping, swarm::SwarmEvent, tcp, yamux, Multiaddr
|
||||||
|
};
|
||||||
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
pub struct NodeArgs {
|
pub struct NodeArgs {
|
||||||
|
@ -14,7 +20,7 @@ pub struct JoinNodeArgs {
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
endpoint: IpAddr,
|
endpoint: IpAddr,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
port: i32,
|
port: u16,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
peer_id: String,
|
peer_id: String,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
|
@ -28,3 +34,40 @@ pub enum NodeCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl JoinNodeArgs {
|
||||||
|
pub async fn ping(self) -> Result<(), Error> {
|
||||||
|
let _ = tracing_subscriber::fmt()
|
||||||
|
.with_env_filter(EnvFilter::from_default_env())
|
||||||
|
.try_init();
|
||||||
|
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
|
||||||
|
.with_tokio()
|
||||||
|
.with_tcp(
|
||||||
|
tcp::Config::default(),
|
||||||
|
noise::Config::new,
|
||||||
|
yamux::Config::default,
|
||||||
|
)?
|
||||||
|
.with_behaviour(|_| ping::Behaviour::default())?
|
||||||
|
.build();
|
||||||
|
|
||||||
|
swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?;
|
||||||
|
|
||||||
|
|
||||||
|
let mut remote: Multiaddr = Multiaddr::empty();
|
||||||
|
remote.push(match self.endpoint {
|
||||||
|
IpAddr::V4(x) => Protocol::Ip4(x),
|
||||||
|
IpAddr::V6(x) => Protocol::Ip6(x),
|
||||||
|
});
|
||||||
|
remote.push(Protocol::Tcp(self.port));
|
||||||
|
let addr = remote.to_string();
|
||||||
|
swarm.dial(remote)?;
|
||||||
|
println!("Dialed {addr}");
|
||||||
|
|
||||||
|
loop{
|
||||||
|
match swarm.select_next_some().await {
|
||||||
|
SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {address:?}"),
|
||||||
|
SwarmEvent::Behaviour(event) => println!("{event:?}"),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +0,0 @@
|
||||||
use std::{net::IpAddr, path::PathBuf};
|
|
||||||
|
|
||||||
use clap::Args;
|
|
||||||
|
|
||||||
use crate::config::PartialServerConfig;
|
|
||||||
|
|
||||||
#[derive(Args, Debug)]
|
|
||||||
pub struct ServerArgs {
|
|
||||||
#[command(flatten)]
|
|
||||||
server_config: PartialServerConfig,
|
|
||||||
#[arg(long)]
|
|
||||||
config: PathBuf,
|
|
||||||
}
|
|
|
@ -1,30 +1,23 @@
|
||||||
mod node;
|
mod node;
|
||||||
mod server;
|
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
pub use node::NodeConfig;
|
pub use node::NodeConfig;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
pub use server::{
|
pub use crate::global::{
|
||||||
PartialServerConfig,
|
|
||||||
ServerConfig,
|
|
||||||
DEFAULT_LISTEN_IPS,
|
DEFAULT_LISTEN_IPS,
|
||||||
DEFAULT_PORT,
|
DEFAULT_PORT,
|
||||||
DEFAULT_PARTIAL_SERVER_CONFIG,
|
|
||||||
DEFAULT_SERVER_CONFIG
|
|
||||||
};
|
};
|
||||||
use tokio::{fs::File, io::{AsyncReadExt, AsyncWriteExt}};
|
use tokio::{fs::File, io::{AsyncReadExt, AsyncWriteExt}};
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct PartialConfig {
|
pub struct PartialConfig {
|
||||||
node: Option<NodeConfig>,
|
node: Option<NodeConfig>,
|
||||||
server: Option<ServerConfig>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialConfig {
|
impl PartialConfig {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
PartialConfig {
|
PartialConfig {
|
||||||
node: Some(NodeConfig::new()),
|
node: Some(NodeConfig::default()),
|
||||||
server: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn read_or_create<T>(path: T) -> Result<Self, Error>
|
pub async fn read_or_create<T>(path: T) -> Result<Self, Error>
|
||||||
|
|
|
@ -1,52 +1,87 @@
|
||||||
use std::path::PathBuf;
|
use std::{net::IpAddr, path::PathBuf};
|
||||||
|
|
||||||
use libp2p::identity::{self, Keypair};
|
use base64::{prelude::BASE64_STANDARD, Engine};
|
||||||
|
use libp2p::identity::{self, DecodingError, Keypair};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::global::DEFAULT_DATABASE_FILE_PATH;
|
|
||||||
|
use crate::{error::Error, global::DEFAULT_DATABASE_FILE_PATH};
|
||||||
|
|
||||||
|
use super::{DEFAULT_LISTEN_IPS, DEFAULT_PORT};
|
||||||
|
|
||||||
|
fn keypair_to_base64(keypair: &Keypair) -> Result<String, Error> {
|
||||||
|
let vec = keypair.to_protobuf_encoding()?;
|
||||||
|
let base64 = BASE64_STANDARD.encode(vec);
|
||||||
|
Ok(base64)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn base64_to_keypair(base64: &str) -> Result<Keypair, Error> {
|
||||||
|
let vec = BASE64_STANDARD.decode(base64)?;
|
||||||
|
Ok(Keypair::from_protobuf_encoding(&vec)?)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct NodeConfig {
|
pub struct NodeConfig {
|
||||||
#[serde(with = "keypair")]
|
#[serde(with = "keypair_parser")]
|
||||||
secret: Keypair,
|
secret: Keypair,
|
||||||
database_path: Option<PathBuf>
|
database_path: PathBuf,
|
||||||
|
listen_ips: Vec<IpAddr>,
|
||||||
|
port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeConfig {
|
impl Default for NodeConfig {
|
||||||
pub fn new() -> Self {
|
fn default() -> NodeConfig{
|
||||||
Self {
|
NodeConfig {
|
||||||
secret: identity::Keypair::generate_ed25519(),
|
secret: identity::Keypair::generate_ed25519(),
|
||||||
database_path: None,
|
database_path: DEFAULT_DATABASE_FILE_PATH.to_path_buf(),
|
||||||
}
|
listen_ips: DEFAULT_LISTEN_IPS.to_vec(),
|
||||||
}
|
port: DEFAULT_PORT,
|
||||||
pub fn get_database_path(&self) -> PathBuf {
|
|
||||||
if let Some(x) = self.database_path.clone() {
|
|
||||||
x
|
|
||||||
} else {
|
|
||||||
DEFAULT_DATABASE_FILE_PATH.clone()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod keypair {
|
impl TryFrom<RawNodeConfig> for NodeConfig {
|
||||||
use base64::{prelude::BASE64_STANDARD, Engine};
|
type Error = Error;
|
||||||
|
fn try_from(raw: RawNodeConfig) -> Result<NodeConfig, Self::Error> {
|
||||||
|
Ok(NodeConfig {
|
||||||
|
secret: base64_to_keypair(&raw.secret.ok_or(Error::MissingConfig("secret"))?)?,
|
||||||
|
database_path: raw.database_path.ok_or(Error::MissingConfig("database_path"))?,
|
||||||
|
listen_ips: raw.listen_ips.ok_or(Error::MissingConfig("listen_ips"))?,
|
||||||
|
port: raw.port.ok_or(Error::MissingConfig("port"))?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod keypair_parser {
|
||||||
use libp2p::identity::Keypair;
|
use libp2p::identity::Keypair;
|
||||||
use serde::{Deserialize, Deserializer, Serializer};
|
use serde::{Deserialize, Deserializer, Serializer};
|
||||||
|
|
||||||
pub fn serialize<S>(keypair: &Keypair, serializer: S) -> Result<S::Ok, S::Error>
|
pub fn serialize<S>(keypair: &Keypair, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where S: Serializer
|
where S: Serializer
|
||||||
{
|
{
|
||||||
let vec = keypair.to_protobuf_encoding().unwrap();
|
match super::keypair_to_base64(keypair) {
|
||||||
let base64 = BASE64_STANDARD.encode(vec);
|
Ok(x) => serializer.serialize_str(&x),
|
||||||
serializer.serialize_str(&base64)
|
Err(_) => Err(serde::ser::Error::custom("Decoding keypair error"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Keypair, D::Error>
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<Keypair, D::Error>
|
||||||
where D: Deserializer<'de>
|
where D: Deserializer<'de>
|
||||||
{
|
{
|
||||||
let base64 = String::deserialize(deserializer)?;
|
match super::base64_to_keypair(&String::deserialize(deserializer)?) {
|
||||||
let vec = BASE64_STANDARD.decode(base64).unwrap();
|
Ok(x) => Ok(x),
|
||||||
Ok(Keypair::from_protobuf_encoding(&vec).unwrap())
|
Err(crate::error::Error::Base64Decode(_)) => Err(serde::de::Error::custom("Decoding base64 error")),
|
||||||
|
Err(_) => unreachable!()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub struct RawNodeConfig {
|
||||||
|
secret: Option<String>,
|
||||||
|
database_path: Option<PathBuf>,
|
||||||
|
listen_ips: Option<Vec<IpAddr>>,
|
||||||
|
port: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -56,15 +91,10 @@ mod tests {
|
||||||
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn serialize_deserialize() {
|
async fn parse_keypair() {
|
||||||
let keypair = identity::Keypair::generate_ed25519();
|
let keypair = identity::Keypair::generate_ed25519();
|
||||||
let config = NodeConfig {
|
let keypair2 = base64_to_keypair(&keypair_to_base64(&keypair).unwrap()).unwrap();
|
||||||
secret: keypair.clone(),
|
|
||||||
database_path: None,
|
assert_eq!(keypair.public(), keypair2.public());
|
||||||
};
|
|
||||||
let string = toml::to_string(&config).unwrap();
|
|
||||||
println!("Parsed config: {}", &string);
|
|
||||||
let parsed_config: NodeConfig = toml::from_str(&string).unwrap();
|
|
||||||
assert_eq!(keypair.public(), parsed_config.secret.public());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,27 @@
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
#[error("Base64 decode error: {0}")]
|
||||||
|
Base64Decode(#[from] base64::DecodeError),
|
||||||
#[error("DB Error: {0}")]
|
#[error("DB Error: {0}")]
|
||||||
Db(#[from]sea_orm::DbErr),
|
Db(#[from]sea_orm::DbErr),
|
||||||
|
#[error("Dial Error: {0}")]
|
||||||
|
Dial(#[from] libp2p::swarm::DialError),
|
||||||
|
#[error("Decoding identity error: {0}")]
|
||||||
|
IdentityDecoding(#[from] libp2p::identity::DecodingError),
|
||||||
|
#[error("Infallible: {0}")]
|
||||||
|
Infallible(#[from] std::convert::Infallible),
|
||||||
#[error("IO Error: {0}")]
|
#[error("IO Error: {0}")]
|
||||||
Io(#[from]std::io::Error),
|
Io(#[from]std::io::Error),
|
||||||
#[error("mandatory config `{0}` is missing")]
|
#[error("mandatory config `{0}` is missing")]
|
||||||
MissingConfig(String),
|
MissingConfig(&'static str),
|
||||||
|
#[error("Multiaddr error: {0}")]
|
||||||
|
Multiaddr(#[from] libp2p::multiaddr::Error),
|
||||||
|
#[error("Noise error: {0}")]
|
||||||
|
Noise(#[from] libp2p::noise::Error),
|
||||||
#[error("toml deserialization error: {0}")]
|
#[error("toml deserialization error: {0}")]
|
||||||
TomlDe(#[from] toml::de::Error),
|
TomlDe(#[from] toml::de::Error),
|
||||||
#[error("toml serialization error: {0}")]
|
#[error("toml serialization error: {0}")]
|
||||||
TomlSer(#[from] toml::ser::Error),
|
TomlSer(#[from] toml::ser::Error),
|
||||||
|
#[error("Transport error: {0}")]
|
||||||
|
Transport(#[from]libp2p::TransportError<std::io::Error>)
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{path::PathBuf, sync::LazyLock};
|
use std::{net::{IpAddr, Ipv4Addr}, path::PathBuf, sync::LazyLock};
|
||||||
|
|
||||||
use crate::config::{NodeConfig, ServerConfig};
|
use crate::config::NodeConfig;
|
||||||
use sea_orm::DatabaseConnection;
|
use sea_orm::DatabaseConnection;
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
|
|
||||||
|
@ -10,6 +10,10 @@ pub static PRODUCT_NAME: LazyLock<String> = LazyLock::new(|| {
|
||||||
env!("CARGO_PKG_NAME").to_string()
|
env!("CARGO_PKG_NAME").to_string()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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(|| {
|
pub static DEFAULT_CONFIG_DIR_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||||
let dir = if let Some(x) = dirs::config_local_dir() {
|
let dir = if let Some(x) = dirs::config_local_dir() {
|
||||||
x
|
x
|
||||||
|
@ -48,11 +52,9 @@ pub static DEFAULT_DATABASE_FILE_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||||
|
|
||||||
pub static GLOBAL: Global = Global{
|
pub static GLOBAL: Global = Global{
|
||||||
node_config: OnceCell::const_new(),
|
node_config: OnceCell::const_new(),
|
||||||
server_config: OnceCell::const_new(),
|
|
||||||
database: OnceCell::const_new(),
|
database: OnceCell::const_new(),
|
||||||
};
|
};
|
||||||
pub struct Global {
|
pub struct Global {
|
||||||
pub server_config: OnceCell<ServerConfig>,
|
|
||||||
pub node_config: OnceCell<NodeConfig>,
|
pub node_config: OnceCell<NodeConfig>,
|
||||||
pub database: OnceCell<DatabaseConnection>,
|
pub database: OnceCell<DatabaseConnection>,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue