Add command and update config
This commit is contained in:
parent
2cb1f50f57
commit
5120005128
29 changed files with 332 additions and 220 deletions
|
@ -23,6 +23,24 @@ pub struct Config {
|
|||
pub rpc: RpcConfig,
|
||||
}
|
||||
|
||||
impl AsRef<StorageConfig> for Config {
|
||||
fn as_ref(&self) -> &StorageConfig {
|
||||
&self.storage
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<P2pConfig> for Config {
|
||||
fn as_ref(&self) -> &P2pConfig {
|
||||
&self.p2p
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<RpcConfig> for Config {
|
||||
fn as_ref(&self) -> &RpcConfig {
|
||||
&self.rpc
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature="desktop", derive(Args))]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
pub struct PartialConfig {
|
||||
|
@ -96,16 +114,3 @@ impl Emptiable for PartialConfig {
|
|||
self.p2p.is_empty() && self.rpc.is_empty() && self.storage.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use libp2p::identity;
|
||||
use super::*;
|
||||
use crate::{tests::test_toml_serialize_deserialize};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_p2p_config_serialize_deserialize() {
|
||||
test_toml_serialize_deserialize(PartialConfig::empty());
|
||||
}
|
||||
}
|
|
@ -151,7 +151,6 @@ impl Mergeable for PartialP2pConfig {
|
|||
mod tests {
|
||||
use libp2p::identity;
|
||||
use super::*;
|
||||
use crate::{tests::test_toml_serialize_deserialize};
|
||||
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -161,9 +160,5 @@ mod tests {
|
|||
|
||||
assert_eq!(keypair.public(), keypair2.public());
|
||||
}
|
||||
#[tokio::test]
|
||||
async fn test_p2p_config_serialize_deserialize() {
|
||||
test_toml_serialize_deserialize(PartialP2pConfig::empty());
|
||||
test_toml_serialize_deserialize(PartialP2pConfig::default());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,9 +12,6 @@ use serde::{Deserialize, Serialize};
|
|||
static DATA_DATABASE_NAME: &str = "data.sqlite";
|
||||
static CACHE_DATABASE_NAME: &str = "cache.sqlite";
|
||||
|
||||
#[cfg(any(test, feature="test"))]
|
||||
use crate::tests::{GlobalTestDefault, TestDefault};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StorageConfig {
|
||||
pub data_directory: PathBuf,
|
||||
|
@ -30,14 +27,6 @@ impl StorageConfig {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature="test"))]
|
||||
impl TestDefault for StorageConfig {
|
||||
fn test_default() -> Self {
|
||||
|
||||
let temp_dir = tempdir().unwrap().keep();
|
||||
Self { data_directory: temp_dir.clone(), cache_directory: temp_dir }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<PartialStorageConfig> for StorageConfig {
|
||||
type Error = ConfigError;
|
||||
|
|
|
@ -99,22 +99,3 @@ impl sea_orm::sea_query::Nullable for PeerIdValue {
|
|||
<String as sea_orm::sea_query::Nullable>::null()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tests::{test_cbor_serialize_deserialize, test_toml_serialize_deserialize};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
|
||||
struct PeerIdValueWrapper {
|
||||
content: PeerIdValue
|
||||
|
||||
}
|
||||
#[test]
|
||||
fn test_serialize_deserialize() {
|
||||
let peer_id= PeerIdValueWrapper{content: PeerIdValue::from(PeerId::random())};
|
||||
let x = toml::to_string(&peer_id).unwrap();
|
||||
assert_eq!(peer_id.content, toml::from_str::<PeerIdValueWrapper>(&x).unwrap().content)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::ffi::OsString;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Base64 decode error: {0}")]
|
||||
|
@ -22,6 +24,8 @@ pub enum Error {
|
|||
Multiaddr(#[from] libp2p::multiaddr::Error),
|
||||
#[error("Noise error: {0}")]
|
||||
Noise(#[from] libp2p::noise::Error),
|
||||
#[error("Parse OsString error: {0:?}")]
|
||||
OsStringConvert(std::ffi::OsString),
|
||||
#[cfg(feature="desktop")]
|
||||
#[error("Parse args error: {0}")]
|
||||
ParseCommand(#[from] clap::Error),
|
||||
|
@ -32,3 +36,9 @@ pub enum Error {
|
|||
#[error("Transport error: {0}")]
|
||||
Transport(#[from]libp2p::TransportError<std::io::Error>)
|
||||
}
|
||||
|
||||
impl From<std::ffi::OsString> for Error {
|
||||
fn from(s: OsString) -> Error {
|
||||
Self::OsStringConvert(s)
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
#[cfg(any(test,feature="test"))]
|
||||
use tempfile::TempDir;
|
||||
use tokio::sync::OnceCell;
|
||||
|
||||
use crate::{config::{Config, PartialP2pConfig, PartialRpcConfig, PartialStorageConfig, StorageConfig}, error::Error, global::GlobalConstant};
|
||||
use crate::{config::{Config, ConfigError, PartialP2pConfig, PartialRpcConfig, PartialStorageConfig, StorageConfig}, error::Error};
|
||||
|
||||
pub static CONFIG: GlobalConfig = GlobalConfig::const_new();
|
||||
pub struct GlobalConfig {
|
||||
|
@ -14,33 +15,21 @@ impl GlobalConfig {
|
|||
inner: OnceCell::const_new()
|
||||
}
|
||||
}
|
||||
pub async fn get_or_init(&'static self, source: Config) -> &'static Config {
|
||||
pub async fn get_or_init<T>(&'static self, config: T) -> &'static Config where
|
||||
T: AsRef<Config>{
|
||||
self.inner.get_or_init(|| async {
|
||||
source
|
||||
config.as_ref().clone()
|
||||
}).await
|
||||
}
|
||||
pub async fn get_or_try_init<T, E>(&'static self, config: T) -> Result<&'static Config, <T as TryInto<Config>>::Error> where
|
||||
T: TryInto<Config>,
|
||||
{
|
||||
self.inner.get_or_try_init(|| async {
|
||||
config.try_into()
|
||||
}).await
|
||||
|
||||
}
|
||||
pub fn get(&'static self) -> Option<&'static Config> {
|
||||
self.inner.get()
|
||||
}
|
||||
pub fn get_and_unwrap(&'static self) -> &'static Config {
|
||||
self.get().expect(&format!("Config is uninitialized!"))
|
||||
}
|
||||
#[cfg(any(test, feature=test))]
|
||||
pub async fn get_or_init_test(&'static self) -> &'static Config {
|
||||
let temp_dir = TempDir::new().unwrap().keep();
|
||||
let mut data_dir = temp_dir.clone();
|
||||
data_dir.push("data");
|
||||
let mut cache_dir = temp_dir;
|
||||
cache_dir.push("cache");
|
||||
|
||||
|
||||
self.get_or_init(Config {
|
||||
p2p: PartialP2pConfig::default().with_new_secret().try_into().unwrap(),
|
||||
storage: StorageConfig {
|
||||
data_directory: data_dir,
|
||||
cache_directory: cache_dir,
|
||||
},
|
||||
rpc: PartialRpcConfig::default().try_into().unwrap(),
|
||||
}).await
|
||||
}
|
||||
}
|
|
@ -1,39 +1,67 @@
|
|||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use sea_orm::{ConnectOptions, Database, DbErr, DatabaseConnection};
|
||||
use sea_orm_migration::MigratorTrait;
|
||||
use crate::error::Error;
|
||||
use crate::{config::StorageConfig, error::Error};
|
||||
use tokio::sync::OnceCell;
|
||||
|
||||
pub static DATA_DATABASE_CONNECTION: GlobalDatabaseConnection = GlobalDatabaseConnection::const_new(stringify!(DATA_DATABASE_CONNECTION));
|
||||
pub static CACHE_DATABASE_CONNECTION: GlobalDatabaseConnection = GlobalDatabaseConnection::const_new(stringify!(CACHE_DATABASE_CONNECTION));
|
||||
enum StorageType {
|
||||
Data,
|
||||
Cache,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for StorageType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f,"{}", match self {
|
||||
StorageType::Data => "data",
|
||||
StorageType::Cache => "cache",
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub static DATA_DATABASE_CONNECTION: GlobalDatabaseConnection = GlobalDatabaseConnection::const_new(StorageType::Data);
|
||||
pub static CACHE_DATABASE_CONNECTION: GlobalDatabaseConnection = GlobalDatabaseConnection::const_new(StorageType::Cache);
|
||||
|
||||
pub struct GlobalDatabaseConnection {
|
||||
name: &'static str,
|
||||
storage: StorageType,
|
||||
inner: OnceCell<DatabaseConnection>
|
||||
}
|
||||
|
||||
impl GlobalDatabaseConnection {
|
||||
pub const fn const_new(name: &'static str) -> Self {
|
||||
pub const fn const_new(storage: StorageType) -> Self {
|
||||
Self {
|
||||
name: name,
|
||||
storage: storage,
|
||||
inner: OnceCell::const_new()
|
||||
}
|
||||
}
|
||||
pub fn get(&'static self) -> &'static DatabaseConnection {
|
||||
self.inner.get().expect(&format!("{} is uninitialized!", self.name))
|
||||
pub fn get(&'static self) -> Option<&'static DatabaseConnection> {
|
||||
self.inner.get()
|
||||
}
|
||||
pub async fn get_or_init<T, U>(&'static self, path: T, _: U) -> &'static DatabaseConnection
|
||||
fn get_file_path<T>(&self, config: T) -> PathBuf
|
||||
where
|
||||
T: AsRef<Path>,
|
||||
T: AsRef<StorageConfig>
|
||||
{
|
||||
match self.storage {
|
||||
StorageType::Cache => config.as_ref().cache_directory.join("cache.db"),
|
||||
StorageType::Data => config.as_ref().data_directory.join("data.db"),
|
||||
}
|
||||
}
|
||||
pub fn get_unchecked(&'static self) -> &'static DatabaseConnection {
|
||||
self.get().expect("Global database connection should initialized beforehand!")
|
||||
}
|
||||
pub async fn get_or_try_init<T, U>(&'static self, config: T, _: U) -> Result<&'static DatabaseConnection, Error>
|
||||
where
|
||||
T: AsRef<StorageConfig>,
|
||||
U: MigratorTrait
|
||||
{
|
||||
let url = "sqlite://".to_string() + path.as_ref().to_str().unwrap() + "?mode=rwc";
|
||||
self.inner.get_or_try_init(|| async {
|
||||
let url = "sqlite://".to_string() + &self.get_file_path(config).into_os_string().into_string()? + "?mode=rwc";
|
||||
Ok(self.inner.get_or_try_init(|| async {
|
||||
let db = Database::connect(&url).await?;
|
||||
U::up(&db, None).await?;
|
||||
Ok::<DatabaseConnection, DbErr>(db)
|
||||
}).await.expect(&format!("Fail to initialize {}!", self.name))
|
||||
}).await?)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,12 +72,12 @@ pub use tests::*;
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{cache::migration::CacheMigrator, data::migration::DataMigrator, global::CONFIG, tests::GlobalTestDefault};
|
||||
use crate::{cache::migration::CacheMigrator, data::migration::DataMigrator, global::CONFIG, tests::{TEST_CONFIG}};
|
||||
|
||||
pub async fn get_or_init_test_data_database() -> &'static DatabaseConnection{
|
||||
DATA_DATABASE_CONNECTION.get_or_init(CONFIG.get_or_init_test_default().await.storage.get_cache_database_path(), DataMigrator).await
|
||||
DATA_DATABASE_CONNECTION.get_or_try_init(&*TEST_CONFIG, DataMigrator).await.unwrap()
|
||||
}
|
||||
pub async fn get_or_init_test_cache_database() -> &'static DatabaseConnection{
|
||||
CACHE_DATABASE_CONNECTION.get_or_init(CONFIG.get_or_init_test_default()await.storage.get_cache_database_path(), CacheMigrator).await
|
||||
CACHE_DATABASE_CONNECTION.get_or_try_init(&*TEST_CONFIG, CacheMigrator).await.unwrap()
|
||||
}
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
use std::{any::type_name, collections::HashMap, net::{IpAddr, Ipv4Addr}, path::{Path, PathBuf}, sync::LazyLock};
|
||||
|
||||
use crate::{config::{P2pConfig, PartialP2pConfig, StorageConfig}, error::Error };
|
||||
#[cfg(any(test, feature="test"))]
|
||||
use crate::tests::{GlobalTestDefault, TestDefault};
|
||||
use futures::StreamExt;
|
||||
use libp2p::{swarm::SwarmEvent, Multiaddr, PeerId};
|
||||
use sea_orm::{prelude::*, Database};
|
||||
use sea_orm_migration::MigratorTrait;
|
||||
|
@ -19,83 +16,9 @@ pub fn generate_uuid() -> Uuid {
|
|||
Uuid::new_v7(Timestamp::now(ContextV7::new()))
|
||||
}
|
||||
|
||||
pub static PRODUCT_NAME: LazyLock<String> = LazyLock::new(|| {
|
||||
env!("CARGO_PKG_NAME").to_string()
|
||||
});
|
||||
|
||||
pub static DEFAULT_LISTEN_IPS: &[IpAddr] = &[IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))];
|
||||
|
||||
pub static DEFAULT_CONFIG_FILE_NAME: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
PathBuf::from(String::new() + env!("CARGO_PKG_NAME") + ".toml")
|
||||
});
|
||||
|
||||
|
||||
pub static DEFAULT_DATABASE_FILE_NAME: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
PathBuf::from(String::new() + env!("CARGO_PKG_NAME") + ".sqlite")
|
||||
});
|
||||
fn uninitialized_message<T>(var: T) -> String {
|
||||
format!("{} is uninitialized!", &stringify!(var))
|
||||
}
|
||||
|
||||
pub struct GlobalConstant<T> {
|
||||
pub name: &'static str,
|
||||
inner: OnceCell<T>
|
||||
}
|
||||
|
||||
impl<T> GlobalConstant<T> {
|
||||
pub const fn const_new(name: &'static str ) -> Self {
|
||||
Self{
|
||||
name: name,
|
||||
inner: OnceCell::const_new()
|
||||
}
|
||||
}
|
||||
pub async fn get_or_init(&'static self, source: T) -> &'static T {
|
||||
self.inner.get_or_init(|| async {
|
||||
source
|
||||
}).await
|
||||
}
|
||||
pub fn get(&'static self) -> Option<&'static T> {
|
||||
self.inner.get()
|
||||
}
|
||||
pub fn get_and_unwrap(&'static self) -> &'static T {
|
||||
self.get().expect(&format!("{} is uninitialized!", self.name))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature="test"))]
|
||||
impl<T> GlobalTestDefault<T> for GlobalConstant<T>
|
||||
where
|
||||
T: TestDefault + 'static
|
||||
{
|
||||
async fn get_or_init_test_default(&'static self) -> &'static T {
|
||||
self.get_or_init(T::test_default()).await
|
||||
}
|
||||
}
|
||||
|
||||
struct GlobalRwLock<T> {
|
||||
pub name: &'static str,
|
||||
inner: OnceCell<RwLock<T>>
|
||||
}
|
||||
|
||||
impl<T> GlobalRwLock<T> {
|
||||
pub const fn const_new(name: &'static str) -> Self {
|
||||
Self{
|
||||
name: name,
|
||||
inner: OnceCell::const_new()
|
||||
}
|
||||
}
|
||||
pub fn get(&'static self) -> &'static RwLock<T> {
|
||||
self.inner.get().expect(&format!("{} is uninitialized", self.name))
|
||||
}
|
||||
pub async fn write(&'static self) -> RwLockWriteGuard<'_ ,T> {
|
||||
self.get().write().await
|
||||
}
|
||||
pub async fn read(&'static self) -> RwLockReadGuard<'_, T> {
|
||||
self.get().read().await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
}
|
||||
|
|
|
@ -11,3 +11,4 @@ pub mod rpc;
|
|||
#[cfg(any(test, feature="test"))]
|
||||
pub mod tests;
|
||||
pub mod utils;
|
||||
pub mod server;
|
||||
|
|
|
@ -69,34 +69,34 @@ impl From<ping::Event> for Event {
|
|||
|
||||
async fn try_get_or_insert_cached_peer(peer_id: &PeerId, peer_addr: &Multiaddr) -> Result<(CachedPeerModel, CachedAddressModel), Error> {
|
||||
match (
|
||||
CachedPeerEntity::find().filter(CachedPeerColumn::PeerId.eq(PeerIdValue::from(peer_id.clone()))).one(CACHE_DATABASE_CONNECTION.get()).await?,
|
||||
CachedAddressEntity::find().filter(CachedAddressColumn::Multiaddress.eq(MultiaddrValue::from(peer_addr.clone()))).one(CACHE_DATABASE_CONNECTION.get()).await?,
|
||||
CachedPeerEntity::find().filter(CachedPeerColumn::PeerId.eq(PeerIdValue::from(peer_id.clone()))).one(CACHE_DATABASE_CONNECTION.get_unchecked()).await?,
|
||||
CachedAddressEntity::find().filter(CachedAddressColumn::Multiaddress.eq(MultiaddrValue::from(peer_addr.clone()))).one(CACHE_DATABASE_CONNECTION.get_unchecked()).await?,
|
||||
) {
|
||||
(Some(x), Some(y) ) => {
|
||||
if x.id == y.cached_peer_id {
|
||||
event!(Level::TRACE, "Known peer: {}, {}", peer_id, peer_addr);
|
||||
let mut addr: CachedAddressActiveModel = y.into();
|
||||
addr.updated_at = Set(Local::now().to_utc());
|
||||
let updated = addr.update(CACHE_DATABASE_CONNECTION.get()).await?;
|
||||
let updated = addr.update(CACHE_DATABASE_CONNECTION.get_unchecked()).await?;
|
||||
Ok((x, updated))
|
||||
} else {
|
||||
y.delete(CACHE_DATABASE_CONNECTION.get()).await?;
|
||||
Ok((x.clone(), CachedAddressActiveModel::new(x.id, peer_addr.clone()).insert(CACHE_DATABASE_CONNECTION.get()).await?))
|
||||
y.delete(CACHE_DATABASE_CONNECTION.get().expect("Cache database should initialized beforehand!")).await?;
|
||||
Ok((x.clone(), CachedAddressActiveModel::new(x.id, peer_addr.clone()).insert(CACHE_DATABASE_CONNECTION.get_unchecked()).await?))
|
||||
}
|
||||
}
|
||||
(Some(x), None) => {
|
||||
event!(Level::INFO, "New address {} for {}", peer_addr, peer_id);
|
||||
Ok((x.clone(),CachedAddressActiveModel::new(x.id, peer_addr.clone()).insert(CACHE_DATABASE_CONNECTION.get()).await?))
|
||||
Ok((x.clone(),CachedAddressActiveModel::new(x.id, peer_addr.clone()).insert(CACHE_DATABASE_CONNECTION.get_unchecked()).await?))
|
||||
},
|
||||
(None, x) => {
|
||||
event!(Level::INFO, "Add new peer: {}", peer_id);
|
||||
let inserted = CachedPeerActiveModel::new(peer_id.clone()).insert(CACHE_DATABASE_CONNECTION.get()).await?;
|
||||
let inserted = CachedPeerActiveModel::new(peer_id.clone()).insert(CACHE_DATABASE_CONNECTION.get_unchecked()).await?;
|
||||
if let Some(y) = x {
|
||||
event!(Level::INFO, "Remove {} from {}", peer_addr, peer_id);
|
||||
y.delete(CACHE_DATABASE_CONNECTION.get()).await?;
|
||||
y.delete(CACHE_DATABASE_CONNECTION.get_unchecked()).await?;
|
||||
};
|
||||
event!(Level::INFO, "Add address {} to {}", peer_addr, peer_id);
|
||||
Ok((inserted.clone(), CachedAddressActiveModel::new(inserted.id, peer_addr.clone()).insert(CACHE_DATABASE_CONNECTION.get()).await?))
|
||||
Ok((inserted.clone(), CachedAddressActiveModel::new(inserted.id, peer_addr.clone()).insert(CACHE_DATABASE_CONNECTION.get_unchecked()).await?))
|
||||
},
|
||||
|
||||
|
||||
|
|
|
@ -16,9 +16,9 @@ impl crate::proto::cached_peer_service_server::CachedPeerService for CachedPeerS
|
|||
println!("Got a request: {:?}", request);
|
||||
|
||||
let reply = CachedPeerListResponse {
|
||||
peers: join_all( CachedPeerEntity::find().all(CACHE_DATABASE_CONNECTION.get()).await.or_else(|e| Err(Status::from_error(Box::new(e))))?.iter().map(|x| async move {
|
||||
peers: join_all( CachedPeerEntity::find().all(CACHE_DATABASE_CONNECTION.get_unchecked()).await.or_else(|e| Err(Status::from_error(Box::new(e))))?.iter().map(|x| async move {
|
||||
let addresses = CachedAddressEntity::find()
|
||||
.all(CACHE_DATABASE_CONNECTION.get())
|
||||
.all(CACHE_DATABASE_CONNECTION.get_unchecked())
|
||||
.await
|
||||
.or_else(|e| Err(Status::from_error(Box::new(e))))?;
|
||||
Ok::<CachedPeerMessage, Status>(CachedPeerMessage::from((x, &addresses)))
|
||||
|
|
13
core/src/server.rs
Normal file
13
core/src/server.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
use crate::{config::{Config, P2pConfig, RpcConfig}, error::Error};
|
||||
|
||||
pub trait ServerTrait {
|
||||
async fn serve_p2p(config: &P2pConfig) -> Result<(), Error>;
|
||||
async fn serve_rpc(config: &RpcConfig) -> Result<(), Error>;
|
||||
async fn serve_all(config: &Config) -> Result<(), Error> {
|
||||
tokio::try_join!(
|
||||
Self::serve_p2p(&config.p2p),
|
||||
Self::serve_rpc(&config.rpc)
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -3,29 +3,22 @@ use std::{path::PathBuf, sync::LazyLock};
|
|||
use sea_orm::{sea_query::{FromValueTuple, IntoValueTuple, ValueType}, ActiveModelBehavior, ActiveModelTrait, ColumnTrait, Condition, DatabaseConnection, EntityTrait, IntoActiveModel, ModelTrait, PrimaryKeyToColumn, PrimaryKeyTrait, Value};
|
||||
use sea_orm::QueryFilter;
|
||||
use tempfile::TempDir;
|
||||
use crate::{ config::PartialConfig, message::Message};
|
||||
use crate::{ config::{Config, PartialConfig, PartialP2pConfig, PartialRpcConfig, StorageConfig}, message::Message};
|
||||
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
|
||||
pub static TEST_CONFIG: LazyLock<Config> = LazyLock::new(|| {
|
||||
let test_dir = TempDir::new().unwrap().keep();
|
||||
let data_dir = test_dir.join("data");
|
||||
let cache_dir = test_dir.join("cache");
|
||||
|
||||
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)
|
||||
|
||||
Config {
|
||||
p2p: PartialP2pConfig::default().with_new_secret().try_into().unwrap(),
|
||||
storage: StorageConfig {
|
||||
data_directory: data_dir,
|
||||
cache_directory: cache_dir,
|
||||
},
|
||||
rpc: PartialRpcConfig::default().try_into().unwrap(),
|
||||
}
|
||||
});
|
||||
|
||||
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")
|
||||
});
|
||||
|
||||
pub trait TestDefault {
|
||||
fn test_default() -> Self;
|
||||
}
|
||||
|
||||
pub trait GlobalTestDefault<T: 'static> {
|
||||
async fn get_or_init_test_default(&'static self) -> &'static T;
|
||||
}
|
||||
|
|
15
desktop/src/cli/config/check.rs
Normal file
15
desktop/src/cli/config/check.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
use clap::Args;
|
||||
use crate::utils::runnable::Runnable;
|
||||
use crate::cli::ConfigArgs;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct ConfigCheckCommandArgs{
|
||||
#[command(flatten)]
|
||||
config: ConfigArgs
|
||||
}
|
||||
|
||||
impl Runnable for ConfigCheckCommandArgs {
|
||||
async fn run(self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
17
desktop/src/cli/config/list.rs
Normal file
17
desktop/src/cli/config/list.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use clap::Args;
|
||||
use crate::utils::runnable::Runnable;
|
||||
use crate::cli::ConfigArgs;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct ConfigListCommandArgs{
|
||||
#[command(flatten)]
|
||||
config: ConfigArgs,
|
||||
#[arg(short,long)]
|
||||
all: bool
|
||||
}
|
||||
|
||||
impl Runnable for ConfigListCommandArgs {
|
||||
async fn run(self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
38
desktop/src/cli/config/mod.rs
Normal file
38
desktop/src/cli/config/mod.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
mod check;
|
||||
mod list;
|
||||
|
||||
pub use check::*;
|
||||
pub use list::*;
|
||||
|
||||
use caretta_core::utils::runnable::Runnable;
|
||||
use clap::{Args, Subcommand};
|
||||
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct ConfigCommandArgs {
|
||||
#[command(subcommand)]
|
||||
pub command: ConfigSubcommand
|
||||
}
|
||||
|
||||
impl Runnable for ConfigCommandArgs {
|
||||
async fn run(self) {
|
||||
self.command.run().await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum ConfigSubcommand {
|
||||
Check(ConfigCheckCommandArgs),
|
||||
List(ConfigListCommandArgs),
|
||||
}
|
||||
|
||||
impl Runnable for ConfigSubcommand {
|
||||
async fn run(self) {
|
||||
match self {
|
||||
Self::Check(x) => x.run().await,
|
||||
Self::List(x) => x.run().await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
use clap::Args;
|
||||
use crate::utils::runnable::Runnable;
|
||||
use crate::cli::{ConfigArgs, RunnableCommand};
|
||||
use crate::cli::ConfigArgs;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct DeviceListCommandArgs{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use clap::Args;
|
||||
use crate::utils::runnable::Runnable;
|
||||
use crate::cli::{ConfigArgs, DeviceArgs, RunnableCommand};
|
||||
use crate::cli::{ConfigArgs, DeviceArgs};
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct DeviceRemoveCommandArgs{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use clap::Args;
|
||||
use crate::utils::runnable::Runnable;
|
||||
use crate::cli::{ConfigArgs, RunnableCommand};
|
||||
use crate::cli::ConfigArgs;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct DeviceScanCommandArgs{
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
use caretta_core::utils::runnable::Runnable;
|
||||
use clap::Args;
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct LogsCommandArgs {
|
||||
|
||||
#[arg(short='n', long)]
|
||||
lines: Option<u32>,
|
||||
}
|
||||
|
||||
impl Runnable for LogsCommandArgs {
|
||||
async fn run(self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
mod args;
|
||||
mod config;
|
||||
mod device;
|
||||
mod logs;
|
||||
mod peer;
|
||||
|
||||
pub use args::*;
|
||||
pub use config::*;
|
||||
pub use device::*;
|
||||
pub use logs::*;
|
||||
pub use peer::*;
|
||||
|
||||
pub trait RunnableCommand {
|
||||
async fn run(self);
|
||||
}
|
17
desktop/src/cli/peer/info.rs
Normal file
17
desktop/src/cli/peer/info.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use clap::Args;
|
||||
use crate::utils::runnable::Runnable;
|
||||
use crate::cli::{ConfigArgs, PeerArgs};
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct PeerInfoCommandArgs{
|
||||
#[command(flatten)]
|
||||
config: ConfigArgs,
|
||||
#[command(flatten)]
|
||||
peer: PeerArgs,
|
||||
}
|
||||
|
||||
impl Runnable for PeerInfoCommandArgs {
|
||||
async fn run(self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
use clap::Args;
|
||||
use crate::utils::runnable::Runnable;
|
||||
use crate::cli::{ConfigArgs, RunnableCommand};
|
||||
use crate::cli::ConfigArgs;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct DeviceListCommandArgs{
|
||||
pub struct PeerListCommandArgs{
|
||||
#[command(flatten)]
|
||||
config: ConfigArgs
|
||||
}
|
||||
|
||||
impl Runnable for DeviceListCommandArgs {
|
||||
impl Runnable for PeerListCommandArgs {
|
||||
async fn run(self) {
|
||||
todo!()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
mod info;
|
||||
mod list;
|
||||
mod ping;
|
||||
|
||||
pub use info::*;
|
||||
pub use list::*;
|
||||
pub use ping::*;
|
||||
|
||||
use caretta_core::utils::runnable::Runnable;
|
||||
use clap::{Args, Subcommand};
|
||||
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct PeerCommandArgs {
|
||||
#[command(subcommand)]
|
||||
pub command: PeerSubcommand
|
||||
}
|
||||
|
||||
impl Runnable for PeerCommandArgs {
|
||||
async fn run(self) {
|
||||
self.command.run().await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum PeerSubcommand {
|
||||
Info(PeerInfoCommandArgs),
|
||||
List(PeerListCommandArgs),
|
||||
Ping(PeerPingCommandArgs),
|
||||
}
|
||||
|
||||
impl Runnable for PeerSubcommand {
|
||||
async fn run(self) {
|
||||
match self {
|
||||
Self::Info(x) => x.run().await,
|
||||
Self::List(x) => x.run().await,
|
||||
Self::Ping(x) => x.run().await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
17
desktop/src/cli/peer/ping.rs
Normal file
17
desktop/src/cli/peer/ping.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use clap::Args;
|
||||
use crate::utils::runnable::Runnable;
|
||||
use crate::cli::{ConfigArgs, PeerArgs};
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct PeerPingCommandArgs{
|
||||
#[command(flatten)]
|
||||
config: ConfigArgs,
|
||||
#[command(flatten)]
|
||||
peer: PeerArgs,
|
||||
}
|
||||
|
||||
impl Runnable for PeerPingCommandArgs {
|
||||
async fn run(self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
pub mod rpc;
|
||||
|
||||
pub mod server;
|
31
examples/core/src/server.rs
Normal file
31
examples/core/src/server.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
use caretta::{config::P2pConfig, server::ServerTrait};
|
||||
|
||||
pub struct Server{};
|
||||
|
||||
impl ServerTrait for Server {
|
||||
async fn serve_p2p(config: P2pConfig) -> Result<(), caretta::error::Error> {
|
||||
let mut swarm = libp2p::SwarmBuilder::with_existing_identity(self.secret)
|
||||
.with_tokio()
|
||||
.with_tcp(
|
||||
tcp::Config::default(),
|
||||
noise::Config::new,
|
||||
yamux::Config::default,
|
||||
)?
|
||||
.with_behaviour(|keypair| p2p::Behaviour::try_from(keypair).unwrap())?
|
||||
.build();
|
||||
swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?;
|
||||
loop{
|
||||
let swarm_event = swarm.select_next_some().await;
|
||||
tokio::spawn(async move{
|
||||
match swarm_event {
|
||||
SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {address:?}"),
|
||||
SwarmEvent::Behaviour(event) => {
|
||||
println!("{event:?}");
|
||||
event.run().await;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,8 +12,9 @@ pub struct Cli {
|
|||
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum CliCommand {
|
||||
//Config(ConfigCommandArgs),
|
||||
//Device(DeviceCommandArgs),
|
||||
//Log(LogCommandArgs),
|
||||
Config(ConfigCommandArgs),
|
||||
Device(DeviceCommandArgs),
|
||||
Logs(LogsCommandArgs),
|
||||
Peer(PeerSubcommand),
|
||||
Server(ServerCommandArgs),
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
use clap::Args;
|
||||
use caretta::{error::Error, utils::runnable::Runnable};
|
||||
use caretta::{error::Error, global::CONFIG, utils::runnable::Runnable};
|
||||
use libp2p::{noise, ping, swarm::{NetworkBehaviour, SwarmEvent}, tcp, yamux, Swarm};
|
||||
|
||||
use super::ConfigArgs;
|
||||
|
@ -11,9 +11,6 @@ pub struct ServerCommandArgs {
|
|||
}
|
||||
impl Runnable for ServerCommandArgs {
|
||||
async fn run(self) {
|
||||
let swarm_handler = P2P_CONFIG.get_and_unwrap().clone().launch_swarm();
|
||||
let server_handler = caretta_example_core::rpc::server::start_server();
|
||||
|
||||
let (swarm_result, server_result) = tokio::try_join!(swarm_handler, server_handler).unwrap();
|
||||
let config = CONFIG.get_or_init(self.config.try_into()?).await;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue