Add TestDefault trait
This commit is contained in:
parent
3a2f53dd46
commit
3356684530
15 changed files with 241 additions and 174 deletions
|
@ -2,13 +2,15 @@ mod multi_address;
|
||||||
mod peer;
|
mod peer;
|
||||||
|
|
||||||
pub use multi_address::{
|
pub use multi_address::{
|
||||||
ActiveModel as MultiAddressActiveModel,
|
ActiveModel as ActiveMultiAddressModel,
|
||||||
|
Column as MultiAddressColumn,
|
||||||
Model as MultiAddressModel,
|
Model as MultiAddressModel,
|
||||||
Entity as MultiAddressEntity,
|
Entity as MultiAddressEntity,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use peer::{
|
pub use peer::{
|
||||||
ActiveModel as PeerActiveModel,
|
ActiveModel as ActivePeerModel,
|
||||||
|
Column as PeerColumn,
|
||||||
Model as PeerModel,
|
Model as PeerModel,
|
||||||
Entity as PeerEntity,
|
Entity as PeerEntity,
|
||||||
};
|
};
|
|
@ -41,14 +41,15 @@ impl ActiveModel {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::global::get_or_init_test_cache_database;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use libp2p::identity;
|
use libp2p::identity;
|
||||||
use crate::global::GLOBAL;
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn check_insert_node() {
|
async fn check_insert_node() {
|
||||||
let db = crate::global::get_or_init_temporary_main_database().await;
|
let db = get_or_init_test_cache_database().await;
|
||||||
|
|
||||||
ActiveModel{
|
ActiveModel{
|
||||||
peer_id: Set(identity::Keypair::generate_ed25519().public().to_peer_id().to_string()),
|
peer_id: Set(identity::Keypair::generate_ed25519().public().to_peer_id().to_string()),
|
||||||
|
|
|
@ -37,14 +37,15 @@ impl ActiveModel {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::global::get_or_init_test_cache_database;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use libp2p::identity;
|
use libp2p::identity;
|
||||||
use crate::global::GLOBAL;
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn check_insert_node() {
|
async fn check_insert_node() {
|
||||||
let db = crate::global::get_or_init_temporary_main_database().await;
|
let db = get_or_init_test_cache_database().await;
|
||||||
|
|
||||||
ActiveModel{
|
ActiveModel{
|
||||||
peer_id: Set(identity::Keypair::generate_ed25519().public().to_peer_id().to_string()),
|
peer_id: Set(identity::Keypair::generate_ed25519().public().to_peer_id().to_string()),
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::path::PathBuf;
|
||||||
|
|
||||||
#[cfg(feature="desktop")]
|
#[cfg(feature="desktop")]
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use crate::config::{ConfigError, PartialConfig};
|
use crate::{config::{ConfigError, PartialConfig}};
|
||||||
use libp2p::mdns::Config;
|
use libp2p::mdns::Config;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -10,14 +10,7 @@ static DATA_DATABASE_NAME: &str = "data.sqlite";
|
||||||
static CACHE_DATABASE_NAME: &str = "cache.sqlite";
|
static CACHE_DATABASE_NAME: &str = "cache.sqlite";
|
||||||
|
|
||||||
#[cfg(any(test, feature="test"))]
|
#[cfg(any(test, feature="test"))]
|
||||||
static TEST_DATA_DATABASE_PATH: std::sync::LazyLock<tempfile::TempPath> = std::sync::LazyLock::new(|| {
|
use crate::tests::{GlobalTestDefault, TestDefault};
|
||||||
let mut temp_path = tempfile::NamedTempFile::new().unwrap().into_temp_path();
|
|
||||||
temp_path.disable_cleanup(true);
|
|
||||||
println!("{}", temp_path.as_os_str().to_str().unwrap());
|
|
||||||
temp_path
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StorageConfig {
|
pub struct StorageConfig {
|
||||||
|
@ -26,11 +19,6 @@ pub struct StorageConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StorageConfig {
|
impl StorageConfig {
|
||||||
#[cfg(any(test, feature="test"))]
|
|
||||||
pub fn new_test() -> Self {
|
|
||||||
let mut temp_path = tempfile::NamedTempFile::new().unwrap().into_temp_path().keep().unwrap();
|
|
||||||
Self { data_directory: temp_path.clone(), cache_directory: temp_path }
|
|
||||||
}
|
|
||||||
pub fn get_data_database_path(&self) -> PathBuf{
|
pub fn get_data_database_path(&self) -> PathBuf{
|
||||||
self.data_directory.join(DATA_DATABASE_NAME)
|
self.data_directory.join(DATA_DATABASE_NAME)
|
||||||
}
|
}
|
||||||
|
@ -39,6 +27,14 @@ impl StorageConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(test, feature="test"))]
|
||||||
|
impl TestDefault for StorageConfig {
|
||||||
|
fn test_default() -> Self {
|
||||||
|
let temp_path = tempfile::NamedTempFile::new().unwrap().into_temp_path().keep().unwrap();
|
||||||
|
Self { data_directory: temp_path.clone(), cache_directory: temp_path }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<PartialStorageConfig> for StorageConfig {
|
impl TryFrom<PartialStorageConfig> for StorageConfig {
|
||||||
type Error = ConfigError;
|
type Error = ConfigError;
|
||||||
|
|
||||||
|
|
|
@ -42,14 +42,15 @@ impl ActiveModel {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::global::get_or_init_test_data_database;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use libp2p::identity;
|
use libp2p::identity;
|
||||||
use crate::global::GLOBAL;
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn check_insert_node() {
|
async fn check_insert_node() {
|
||||||
let db = crate::global::get_or_init_temporary_main_database().await;
|
let db = get_or_init_test_data_database().await;
|
||||||
|
|
||||||
ActiveModel{
|
ActiveModel{
|
||||||
peer_id: Set(identity::Keypair::generate_ed25519().public().to_peer_id().to_string()),
|
peer_id: Set(identity::Keypair::generate_ed25519().public().to_peer_id().to_string()),
|
||||||
|
|
|
@ -35,14 +35,15 @@ impl ActiveModel {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::global::get_or_init_test_data_database;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use uuid::{Timestamp, Uuid};
|
use uuid::{Timestamp, Uuid};
|
||||||
use crate::global::get_or_init_temporary_main_database;
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn check_insert_record_deletion() {
|
async fn check_insert_record_deletion() {
|
||||||
let db = get_or_init_temporary_main_database().await;
|
let db = get_or_init_test_data_database().await;
|
||||||
|
|
||||||
assert!(ActiveModel{
|
assert!(ActiveModel{
|
||||||
table_name: Set("test_table".to_string()),
|
table_name: Set("test_table".to_string()),
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
use crate::{config::StorageConfig, error::Error, global::SimpleGlobal};
|
use crate::{config::{P2pConfig, StorageConfig}, error::Error, global::GlobalConstant};
|
||||||
use tokio::sync::OnceCell;
|
|
||||||
use uuid::fmt::Simple;
|
|
||||||
|
|
||||||
pub static STORAGE_CONFIG: SimpleGlobal<StorageConfig> = SimpleGlobal::const_new();
|
pub static STORAGE_CONFIG: GlobalConstant<StorageConfig> = GlobalConstant::const_new(stringify!(STORAGE_CONFIG));
|
||||||
|
pub static P2P_CONFIG: GlobalConstant<P2pConfig> = GlobalConstant::const_new(stringify!(P2P_CONFIG));
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::global::{config::P2P_CONFIG, STORAGE_CONFIG};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_global_constant_names() {
|
||||||
|
assert_eq!(STORAGE_CONFIG.name, stringify!(STORAGE_CONFIG));
|
||||||
|
assert_eq!(P2P_CONFIG.name, stringify!(P2P_CONFIG));
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,35 +5,51 @@ use sea_orm_migration::MigratorTrait;
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
|
|
||||||
static DATA_DATABASE_CONNECTION: GlobalDatabaseConnection = GlobalDatabaseConnection::const_new();
|
pub static DATA_DATABASE_CONNECTION: GlobalDatabaseConnection = GlobalDatabaseConnection::const_new(stringify!(DATA_DATABASE_CONNECTION));
|
||||||
static CACHE_DATABASE_CONNECTION: GlobalDatabaseConnection = GlobalDatabaseConnection::const_new();
|
pub static CACHE_DATABASE_CONNECTION: GlobalDatabaseConnection = GlobalDatabaseConnection::const_new(stringify!(CACHE_DATABASE_CONNECTION));
|
||||||
|
|
||||||
struct GlobalDatabaseConnection {
|
pub struct GlobalDatabaseConnection {
|
||||||
|
name: &'static str,
|
||||||
inner: OnceCell<DatabaseConnection>
|
inner: OnceCell<DatabaseConnection>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalDatabaseConnection {
|
impl GlobalDatabaseConnection {
|
||||||
pub const fn const_new() -> Self {
|
pub const fn const_new(name: &'static str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
name: name,
|
||||||
inner: OnceCell::const_new()
|
inner: OnceCell::const_new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get(&'static self) -> Option<&'static DatabaseConnection> {
|
pub fn get(&'static self) -> &'static DatabaseConnection {
|
||||||
self.inner.get()
|
self.inner.get().expect(&format!("{} is uninitialized!", self.name))
|
||||||
}
|
}
|
||||||
pub fn get_and_unwrap(&'static self) -> &'static DatabaseConnection {
|
pub async fn get_or_init<T, U>(&'static self, path: T, _: U) -> &'static DatabaseConnection
|
||||||
self.get().expect(&format!("{} is uninitialized!", &stringify!(self)))
|
|
||||||
}
|
|
||||||
pub async fn get_or_try_init<T, U>(&'static self, path: T, _: U) -> Result<&'static DatabaseConnection, Error>
|
|
||||||
where
|
where
|
||||||
T: AsRef<Path>,
|
T: AsRef<Path>,
|
||||||
U: MigratorTrait
|
U: MigratorTrait
|
||||||
{
|
{
|
||||||
let url = "sqlite://".to_string() + path.as_ref().to_str().unwrap() + "?mode=rwc";
|
let url = "sqlite://".to_string() + path.as_ref().to_str().unwrap() + "?mode=rwc";
|
||||||
Ok(self.inner.get_or_try_init(|| async {
|
self.inner.get_or_try_init(|| async {
|
||||||
let db = Database::connect(&url).await?;
|
let db = Database::connect(&url).await?;
|
||||||
U::up(&db, None).await?;
|
U::up(&db, None).await?;
|
||||||
Ok::<DatabaseConnection, DbErr>(db)
|
Ok::<DatabaseConnection, DbErr>(db)
|
||||||
}).await?)
|
}).await.expect(&format!("Fail to initialize {}!", self.name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub use tests::*;
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::{cache::migration::CacheMigrator, data::migration::DataMigrator, global::STORAGE_CONFIG, tests::GlobalTestDefault};
|
||||||
|
|
||||||
|
pub async fn get_or_init_test_data_database() -> &'static DatabaseConnection{
|
||||||
|
DATA_DATABASE_CONNECTION.get_or_init(STORAGE_CONFIG.get_or_init_test_default().await.get_data_database_path(), DataMigrator).await
|
||||||
|
}
|
||||||
|
pub async fn get_or_init_test_cache_database() -> &'static DatabaseConnection{
|
||||||
|
CACHE_DATABASE_CONNECTION.get_or_init(STORAGE_CONFIG.get_or_init_test_default().await.get_cache_database_path(), CacheMigrator).await
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,14 +1,16 @@
|
||||||
use std::{any::type_name, collections::HashMap, net::{IpAddr, Ipv4Addr}, path::{Path, PathBuf}, sync::LazyLock};
|
use std::{any::type_name, collections::HashMap, net::{IpAddr, Ipv4Addr}, path::{Path, PathBuf}, sync::LazyLock};
|
||||||
|
|
||||||
use crate::{config::{P2pConfig, PartialP2pConfig, StorageConfig}, error::Error};
|
use crate::{config::{P2pConfig, PartialP2pConfig, StorageConfig}, error::Error };
|
||||||
|
#[cfg(any(test, feature="test"))]
|
||||||
|
use crate::tests::{GlobalTestDefault, TestDefault};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use libp2p::{swarm::SwarmEvent, Multiaddr, PeerId};
|
use libp2p::{swarm::SwarmEvent, Multiaddr, PeerId};
|
||||||
use sea_orm::{prelude::*, Database};
|
use sea_orm::{prelude::*, Database};
|
||||||
use sea_orm_migration::MigratorTrait;
|
use sea_orm_migration::MigratorTrait;
|
||||||
use tokio::sync::{OnceCell, RwLock};
|
use tokio::sync::{OnceCell, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
|
|
||||||
mod peers;
|
mod peers;
|
||||||
pub use peers::GlobalPeers;
|
pub use peers::PEERS;
|
||||||
mod config;
|
mod config;
|
||||||
pub use config::STORAGE_CONFIG;
|
pub use config::STORAGE_CONFIG;
|
||||||
mod database_connection;
|
mod database_connection;
|
||||||
|
@ -37,13 +39,17 @@ fn uninitialized_message<T>(var: T) -> String {
|
||||||
format!("{} is uninitialized!", &stringify!(var))
|
format!("{} is uninitialized!", &stringify!(var))
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SimpleGlobal<T> {
|
pub struct GlobalConstant<T> {
|
||||||
|
pub name: &'static str,
|
||||||
inner: OnceCell<T>
|
inner: OnceCell<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> SimpleGlobal<T> {
|
impl<T> GlobalConstant<T> {
|
||||||
pub const fn const_new() -> Self {
|
pub const fn const_new(name: &'static str ) -> Self {
|
||||||
Self{inner: OnceCell::const_new()}
|
Self{
|
||||||
|
name: name,
|
||||||
|
inner: OnceCell::const_new()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub async fn get_or_init(&'static self, source: T) -> &'static T {
|
pub async fn get_or_init(&'static self, source: T) -> &'static T {
|
||||||
self.inner.get_or_init(|| async {
|
self.inner.get_or_init(|| async {
|
||||||
|
@ -58,46 +64,40 @@ impl<T> SimpleGlobal<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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> {
|
struct GlobalRwLock<T> {
|
||||||
|
pub name: &'static str,
|
||||||
inner: OnceCell<RwLock<T>>
|
inner: OnceCell<RwLock<T>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> GlobalRwLock<T> {
|
impl<T> GlobalRwLock<T> {
|
||||||
pub const fn const_new() -> Self {
|
pub const fn const_new(name: &'static str) -> Self {
|
||||||
Self{inner: OnceCell::const_new()}
|
Self{
|
||||||
|
name: name,
|
||||||
|
inner: OnceCell::const_new()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async fn write(&'static self) -> tokio::sync::RwLockWriteGuard<'_ ,T> {
|
pub fn get(&'static self) -> &'static RwLock<T> {
|
||||||
self.get_peers_once_cell().get().expect(UNINITIALIZED_MESSAGE).write().await
|
self.inner.get().expect(&format!("{} is uninitialized", self.name))
|
||||||
}
|
}
|
||||||
async fn read(&'static self) -> RwLockReadGuard<'_, T> {
|
pub async fn write(&'static self) -> RwLockWriteGuard<'_ ,T> {
|
||||||
self.get_peers_once_cell().get().expect(UNINITIALIZED_MESSAGE).read().await
|
self.get().write().await
|
||||||
|
}
|
||||||
|
pub async fn read(&'static self) -> RwLockReadGuard<'_, T> {
|
||||||
|
self.get().read().await
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub struct TestGlobal {
|
|
||||||
pub storage_config: &'static StorageConfig,
|
|
||||||
pub data_database_connection: &'static DatabaseConnection,
|
|
||||||
pub cache_database_connection: &'static DatabaseConnection,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{cache::migration::CacheMigrator, data::migration::DataMigrator};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
static TEST_DATA_DIRECTORY: LazyLock<PathBuf> = todo!();
|
|
||||||
static TEST_DATA_DATABASE_PATH: LazyLock<PathBuf> = todo!();
|
|
||||||
static TEST_CACHE_DIRECTORY: LazyLock<PathBuf> = todo!();
|
|
||||||
static TEST_CACHE_DATABASE_PATH: LazyLock<PathBuf> = todo!();
|
|
||||||
static TEST_STORAGE_CONFIG: LazyLock<StorageConfig> = todo!();
|
|
||||||
|
|
||||||
pub async fn get_or_try_init_test() -> TestGlobal {
|
|
||||||
TestGlobal {
|
|
||||||
storage_config: get_or_init_storage_config(StorageConfig{data_directory: TEST_DATA_DIRECTORY.clone(), cache_directory: TEST_CACHE_DIRECTORY.clone()}).await,
|
|
||||||
data_database_connection: get_or_try_init_data_database_connection(&*TEST_DATA_DATABASE_PATH, DataMigrator ).await.unwrap(),
|
|
||||||
cache_database_connection: get_or_try_init_cache_database_connection(&*TEST_CACHE_DATABASE_PATH, CacheMigrator).await.unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,7 @@ use tokio::sync::{OnceCell, RwLock, RwLockReadGuard};
|
||||||
|
|
||||||
use crate::cache::entity::PeerModel;
|
use crate::cache::entity::PeerModel;
|
||||||
|
|
||||||
static UNINITIALIZED_MESSAGE: &str = "Global peer set uninitialized!";
|
use super::GlobalRwLock;
|
||||||
pub trait GlobalPeers {
|
|
||||||
fn get_peers_once_cell(&'static self) -> &OnceCell<RwLock<HashSet<PeerModel>>>;
|
pub static PEERS: GlobalRwLock<HashSet<PeerModel>> = GlobalRwLock::const_new(stringify!(PEERS));
|
||||||
async fn write_peers(&'static self) -> tokio::sync::RwLockWriteGuard<'_ ,HashSet<PeerModel>> {
|
|
||||||
self.get_peers_once_cell().get().expect(UNINITIALIZED_MESSAGE).write().await
|
|
||||||
}
|
|
||||||
async fn read_peers(&'static self) -> RwLockReadGuard<'_, HashSet<PeerModel>> {
|
|
||||||
self.get_peers_once_cell().get().expect(UNINITIALIZED_MESSAGE).read().await
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,7 @@
|
||||||
use libp2p::{ identity::Keypair, mdns, ping, swarm};
|
use libp2p::{ identity::Keypair, mdns, ping, swarm};
|
||||||
|
use sea_orm::{ActiveModelTrait, ActiveValue::Set, ColumnTrait, EntityTrait, QueryFilter};
|
||||||
|
|
||||||
use crate::{error::Error, global::GlobalPeers};
|
use crate::{cache::entity::{ActivePeerModel, PeerColumn, PeerEntity}, error::Error, global::{CACHE_DATABASE_CONNECTION, PEERS}};
|
||||||
|
|
||||||
#[derive(swarm::NetworkBehaviour)]
|
#[derive(swarm::NetworkBehaviour)]
|
||||||
#[behaviour(to_swarm = "Event")]
|
#[behaviour(to_swarm = "Event")]
|
||||||
|
@ -29,20 +30,23 @@ pub enum Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Event {
|
impl Event {
|
||||||
pub async fn run<T>(self, global: &T)
|
pub async fn run(&self)
|
||||||
where
|
|
||||||
T: GlobalPeers
|
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Self::Mdns(x) => {
|
Self::Mdns(x) => {
|
||||||
match x {
|
match x {
|
||||||
mdns::Event::Discovered(e) => {
|
mdns::Event::Discovered(e) => {
|
||||||
for peer in e {
|
for peer in e.iter() {
|
||||||
global.write_peers().await;
|
match PeerEntity::find().filter(PeerColumn::PeerId.contains(&peer.0.to_string())).one(CACHE_DATABASE_CONNECTION.get()).await {
|
||||||
peers.insert(peer.0, peer.1);
|
Ok(_) => {}
|
||||||
|
Err(_) => {
|
||||||
|
ActivePeerModel{
|
||||||
|
peer_id: Set(peer.0.to_string()),
|
||||||
|
..ActivePeerModel::new()
|
||||||
|
}.insert(CACHE_DATABASE_CONNECTION.get()).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let peers = global.read_peers().await;
|
|
||||||
println!("Peers: {peers:?}");
|
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,14 @@ pub static TEST_DATABASE_PATH: std::sync::LazyLock<PathBuf> = std::sync::LazyLoc
|
||||||
TEST_DIR_PATH.join("lazy-supplements.sqlite")
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn test_cbor_serialize_deserialize<T>(src: T)
|
pub fn test_cbor_serialize_deserialize<T>(src: T)
|
||||||
where T: DeserializeOwned + Serialize + PartialEq + std::fmt::Debug
|
where T: DeserializeOwned + Serialize + PartialEq + std::fmt::Debug
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use clap::Args;
|
|
||||||
use lazy_supplements_core::config::{ConfigError, PartialConfig};
|
|
||||||
use libp2p::mdns::Config;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
pub struct DesktopConfig {
|
|
||||||
pub data_directory: PathBuf,
|
|
||||||
pub data_database: PathBuf,
|
|
||||||
pub cache_directory: PathBuf,
|
|
||||||
pub cache_database: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<PartialDesktopConfig> for DesktopConfig {
|
|
||||||
type Error = ConfigError;
|
|
||||||
|
|
||||||
fn try_from(value: PartialDesktopConfig) -> Result<Self, Self::Error> {
|
|
||||||
Ok(Self {
|
|
||||||
data_directory: value.data_directory.ok_or(ConfigError::MissingConfig("data_directory".to_string()))?,
|
|
||||||
data_database: value.data_database.ok_or(ConfigError::MissingConfig("data_database".to_string()))?,
|
|
||||||
cache_directory: value.cache_directory.ok_or(ConfigError::MissingConfig("cache_directory".to_string()))?,
|
|
||||||
cache_database: value.cache_database.ok_or(ConfigError::MissingConfig("cache_database".to_string()))?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Args, Clone, Debug, Deserialize, Serialize)]
|
|
||||||
pub struct PartialDesktopConfig {
|
|
||||||
#[arg(long)]
|
|
||||||
pub data_directory: Option<PathBuf>,
|
|
||||||
#[arg(long)]
|
|
||||||
pub data_database: Option<PathBuf>,
|
|
||||||
#[arg(long)]
|
|
||||||
pub cache_directory: Option<PathBuf>,
|
|
||||||
#[arg(long)]
|
|
||||||
pub cache_database: Option<PathBuf>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DesktopConfig> for PartialDesktopConfig {
|
|
||||||
fn from(config: DesktopConfig) -> PartialDesktopConfig {
|
|
||||||
Self {
|
|
||||||
data_database: Some(config.data_database),
|
|
||||||
data_directory: Some(config.data_directory),
|
|
||||||
cache_database: Some(config.cache_database),
|
|
||||||
cache_directory: Some(config.cache_directory),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialConfig<DesktopConfig> for PartialDesktopConfig {
|
|
||||||
fn empty() -> Self {
|
|
||||||
Self{
|
|
||||||
data_database: None,
|
|
||||||
cache_database: None,
|
|
||||||
data_directory: None,
|
|
||||||
cache_directory: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn default() -> Self {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
fn merge(&mut self, other: Self) {
|
|
||||||
if let Some(x) = other.data_directory {
|
|
||||||
self.data_directory = Some(x);
|
|
||||||
}
|
|
||||||
if let Some(x) = other.data_database {
|
|
||||||
self.data_database = Some(x);
|
|
||||||
}
|
|
||||||
if let Some(x) = other.cache_directory {
|
|
||||||
self.cache_directory = Some(x);
|
|
||||||
}
|
|
||||||
if let Some(x) = other.cache_database {
|
|
||||||
self.cache_database = Some(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -33,7 +33,7 @@ impl From<UnixConfig> for PartialUnixConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialConfig<UnixConfig> for PartialUnixConfig {
|
impl PartialConfig for PartialUnixConfig {
|
||||||
fn empty() -> Self {
|
fn empty() -> Self {
|
||||||
Self { socket_path: None }
|
Self { socket_path: None }
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,3 +36,115 @@ pub static DEFAULT_PARTIAL_CORE_CONFIG: LazyLock<PartialCoreConfig> = LazyLock::
|
||||||
port: Some(0),
|
port: Some(0),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pub struct Global {
|
||||||
|
pub p2p_config: OnceCell<P2pConfig>,
|
||||||
|
pub main_database: OnceCell<DatabaseConnection>,
|
||||||
|
pub cache_database: OnceCell<DatabaseConnection>,
|
||||||
|
pub peers: OnceCell<RwLock<HashMap<PeerId, Multiaddr>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Global {
|
||||||
|
pub fn get_p2p_config(&self) -> Option<&P2pConfig> {
|
||||||
|
self.p2p_config.get()
|
||||||
|
}
|
||||||
|
pub async fn get_or_init_p2p_config(&self, config: P2pConfig) -> &P2pConfig {
|
||||||
|
self.p2p_config.get_or_init(|| async {config}).await
|
||||||
|
}
|
||||||
|
pub async fn get_or_init_peers(&self) -> &RwLock<HashMap<PeerId, Multiaddr>> {
|
||||||
|
self.peers.get_or_init(|| async {
|
||||||
|
RwLock::new(HashMap::new())
|
||||||
|
}).await
|
||||||
|
}
|
||||||
|
pub async fn read_peers(&self) -> tokio::sync::RwLockReadGuard<'_, HashMap<PeerId, Multiaddr>>{
|
||||||
|
self.get_or_init_peers().await.read().await
|
||||||
|
}
|
||||||
|
pub async fn write_peers(&self) -> tokio::sync::RwLockWriteGuard<'_, HashMap<PeerId, Multiaddr>>{
|
||||||
|
self.get_or_init_peers().await.write().await
|
||||||
|
}
|
||||||
|
pub async fn launch_swarm(&self) -> Result<(), Error> {
|
||||||
|
let mut swarm = self.get_p2p_config().unwrap().clone().try_into_swarm().await?;
|
||||||
|
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;
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlobalDatabase for Global {
|
||||||
|
fn get_main_database(&self) -> Option<&DatabaseConnection> {
|
||||||
|
self.main_database.get()
|
||||||
|
}
|
||||||
|
async fn get_or_try_init_main_database<T, U>(&self, path: T, _: U) -> Result<&DatabaseConnection, Error>
|
||||||
|
where
|
||||||
|
T: AsRef<Path>,
|
||||||
|
U: MigratorTrait,
|
||||||
|
{
|
||||||
|
let url = "sqlite://".to_string() + path.as_ref().to_str().unwrap() + "?mode=rwc";
|
||||||
|
|
||||||
|
Ok(self.main_database.get_or_try_init(|| async {
|
||||||
|
let db = Database::connect(&url).await?;
|
||||||
|
U::up(&db, None).await?;
|
||||||
|
Ok::<DatabaseConnection, DbErr>(db)
|
||||||
|
}).await?)
|
||||||
|
}
|
||||||
|
fn get_cache_database(&self) -> Option<&DatabaseConnection> {
|
||||||
|
self.cache_database.get()
|
||||||
|
}
|
||||||
|
async fn get_or_try_init_cache_database<T, U>(&self, path: T, _: U) -> Result<&DatabaseConnection, Error>
|
||||||
|
where
|
||||||
|
T: AsRef<Path>,
|
||||||
|
U: MigratorTrait,
|
||||||
|
{
|
||||||
|
let url = "sqlite://".to_string() + path.as_ref().to_str().unwrap() + "?mode=rwc";
|
||||||
|
|
||||||
|
Ok(self.cache_database.get_or_try_init(|| async {
|
||||||
|
let db = Database::connect(&url).await?;
|
||||||
|
U::up(&db, None).await?;
|
||||||
|
Ok::<DatabaseConnection, DbErr>(db)
|
||||||
|
}).await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub use tests::{get_or_init_temporary_main_database, get_or_init_temporary_cache_database};
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests {
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
|
use sea_orm_migration::MigratorTrait;
|
||||||
|
|
||||||
|
use crate::{global::GLOBAL, cache::migration::CacheMigrator, data::migration::MainMigrator};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub async fn get_or_init_temporary_main_database() -> &'static DatabaseConnection {
|
||||||
|
GLOBAL.get_or_try_init_temporary_main_database(MainMigrator).await.unwrap()
|
||||||
|
}
|
||||||
|
pub async fn get_or_init_temporary_cache_database() -> &'static DatabaseConnection {
|
||||||
|
GLOBAL.get_or_try_init_temporary_cache_database(CacheMigrator).await.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn connect_main_database () {
|
||||||
|
let db = get_or_init_temporary_main_database().await;
|
||||||
|
assert!(db.ping().await.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn connect_cache_database () {
|
||||||
|
let db = get_or_init_temporary_cache_database().await;
|
||||||
|
assert!(db.ping().await.is_ok());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue