Rename project to caretta
This commit is contained in:
parent
25ea7ed652
commit
c39a28388d
100 changed files with 550 additions and 583 deletions
|
@ -1,5 +1,5 @@
|
|||
[workspace]
|
||||
members = [ "lazy-supplements-*", "examples/*" ]
|
||||
members = [ "core", "desktop", "macros", "mobile", "examples/*" ]
|
||||
resolver = "3"
|
||||
|
||||
[workspace.package]
|
||||
|
@ -14,7 +14,7 @@ chrono = "0.4.41"
|
|||
ciborium = "0.2.2"
|
||||
clap = { version = "4.5.38", features = ["derive"] }
|
||||
dioxus = { version = "0.6.0", features = [] }
|
||||
lazy-supplements-core.path = "lazy-supplements-core"
|
||||
caretta-core.path = "core"
|
||||
libp2p = { version = "0.55.0", features = ["macros", "mdns", "noise", "ping", "tcp", "tokio", "yamux" ] }
|
||||
sea-orm = { version = "1.1.11", features = ["sqlx-sqlite", "runtime-tokio-native-tls", "macros", "with-chrono", "with-uuid"] }
|
||||
sea-orm-migration = { version = "1.1.0", features = ["runtime-tokio-rustls", "sqlx-postgres"] }
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
# Lazy Supplements Framework
|
||||
# Caretta Framework
|
||||
|
||||
A local-first application framework for lazy person
|
||||
A local-first application framework.
|
||||
|
||||
## Features
|
||||
- Local first
|
||||
- Decentralized data synchronization with libp2p
|
||||
- Device management
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "lazy-supplements-core"
|
||||
name = "caretta-core"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
description.workspace = true
|
||||
|
@ -10,7 +10,7 @@ repository.workspace = true
|
|||
default = []
|
||||
desktop = ["dep:clap", "macros"]
|
||||
mobile = ["macros"]
|
||||
macros = ["dep:lazy-supplements-macros"]
|
||||
macros = ["dep:caretta-macros"]
|
||||
test = ["dep:tempfile", "macros"]
|
||||
|
||||
[dependencies]
|
||||
|
@ -20,7 +20,7 @@ chrono-tz = "0.10.3"
|
|||
ciborium.workspace = true
|
||||
clap = {workspace = true, optional = true}
|
||||
futures = "0.3.31"
|
||||
lazy-supplements-macros = { path = "../lazy-supplements-macros", optional = true }
|
||||
caretta-macros = { path = "../macros", optional = true }
|
||||
libp2p.workspace = true
|
||||
libp2p-core = { version = "0.43.0", features = ["serde"] }
|
||||
libp2p-identity = { version = "0.2.11", features = ["ed25519", "peerid", "rand", "serde"] }
|
57
core/src/cache/entity/cached_address.rs
vendored
Normal file
57
core/src/cache/entity/cached_address.rs
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use chrono::{Days, Local};
|
||||
use libp2p::{multiaddr, Multiaddr, PeerId};
|
||||
use sea_orm::{entity::{
|
||||
prelude::*, *
|
||||
}, sea_query};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{cache, data::value::{MultiaddrValue, PeerIdValue}};
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)]
|
||||
#[sea_orm(table_name = "cached_address")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: u32,
|
||||
#[sea_orm(indexed)]
|
||||
pub created_at: DateTimeUtc,
|
||||
#[sea_orm(indexed)]
|
||||
pub last_used_at: DateTimeUtc,
|
||||
#[sea_orm(indexed)]
|
||||
pub cached_peer_id: u32,
|
||||
#[sea_orm(indexed)]
|
||||
pub address: MultiaddrValue,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::CachedPeerEntity",
|
||||
from = "Column::CachedPeerId",
|
||||
to = "super::CachedPeerColumn::Id"
|
||||
)]
|
||||
CachedPeer,
|
||||
}
|
||||
impl Related<super::CachedPeerEntity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::CachedPeer.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl ActiveModel {
|
||||
pub fn new(cached_peer_id: u32, multiaddr: Multiaddr) -> Self {
|
||||
let timestamp: DateTimeUtc = Local::now().to_utc();
|
||||
Self{
|
||||
cached_peer_id: Set(cached_peer_id),
|
||||
address: Set(MultiaddrValue::from(multiaddr)),
|
||||
created_at: Set(timestamp),
|
||||
last_used_at: Set(timestamp),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
48
core/src/cache/entity/cached_peer.rs
vendored
Normal file
48
core/src/cache/entity/cached_peer.rs
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use chrono::{Days, Local};
|
||||
use libp2p::{multiaddr, Multiaddr, PeerId};
|
||||
use sea_orm::{entity::{
|
||||
prelude::*, *
|
||||
}, sea_query};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::data::value::{MultiaddrValue, PeerIdValue};
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)]
|
||||
#[sea_orm(table_name = "cached_peer")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: u32,
|
||||
#[sea_orm(indexed)]
|
||||
pub created_at: DateTimeUtc,
|
||||
#[sea_orm(indexed)]
|
||||
pub peer_id: PeerIdValue,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::CachedAddressEntity")]
|
||||
CachedAddress,
|
||||
}
|
||||
|
||||
impl Related<super::CachedAddressEntity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::CachedAddress.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl ActiveModel {
|
||||
pub fn new(peer_id: PeerId) -> Self {
|
||||
let timestamp: DateTimeUtc = Local::now().to_utc();
|
||||
Self{
|
||||
peer_id: Set(PeerIdValue::from(peer_id)),
|
||||
created_at: Set(timestamp),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
46
core/src/cache/entity/mod.rs
vendored
Normal file
46
core/src/cache/entity/mod.rs
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
mod cached_peer;
|
||||
mod cached_address;
|
||||
|
||||
pub use cached_peer::{
|
||||
ActiveModel as CachedPeerActiveModel,
|
||||
Column as CachedPeerColumn,
|
||||
Model as CachedPeerModel,
|
||||
Entity as CachedPeerEntity,
|
||||
};
|
||||
|
||||
|
||||
pub use cached_address::{
|
||||
ActiveModel as CachedAddressActiveModel,
|
||||
Column as CachedAddressColumn,
|
||||
Model as CachedAddressModel,
|
||||
Entity as CachedAddressEntity,
|
||||
};
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::{cache::entity::cached_peer, global::get_or_init_test_cache_database};
|
||||
|
||||
use super::*;
|
||||
|
||||
use libp2p::{identity::{self, Keypair}, multiaddr, swarm::handler::multi, Multiaddr, PeerId};
|
||||
use sea_orm::ActiveModelTrait;
|
||||
|
||||
#[tokio::test]
|
||||
async fn insert() {
|
||||
let db = get_or_init_test_cache_database().await;
|
||||
let peer_id = Keypair::generate_ed25519().public().to_peer_id();
|
||||
let multiaddr = Multiaddr::empty()
|
||||
.with(Ipv4Addr::new(127,0,0,1).into())
|
||||
.with(multiaddr::Protocol::Tcp(0));
|
||||
let inserted_cached_peer: CachedPeerModel = CachedPeerActiveModel::new(peer_id.clone())
|
||||
.insert(db).await.unwrap();
|
||||
let inserted_cached_address: CachedAddressModel = CachedAddressActiveModel::new(inserted_cached_peer.id, multiaddr.clone())
|
||||
.insert(db).await.unwrap();
|
||||
assert_eq!(PeerId::from(inserted_cached_peer.peer_id), peer_id);
|
||||
assert_eq!(Multiaddr::from(inserted_cached_address.address), multiaddr);
|
||||
}
|
||||
|
||||
}
|
139
core/src/cache/migration/m20220101_000001_create_cache_tables.rs
vendored
Normal file
139
core/src/cache/migration/m20220101_000001_create_cache_tables.rs
vendored
Normal file
|
@ -0,0 +1,139 @@
|
|||
use sea_orm_migration::{prelude::*, schema::*};
|
||||
|
||||
use crate::migration::TableMigration;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
CachedPeer::up(manager).await?;
|
||||
CachedAddress::up(manager).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
CachedAddress::down(manager).await?;
|
||||
CachedPeer::down(manager).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden, DeriveMigrationName)]
|
||||
enum CachedPeer {
|
||||
Table,
|
||||
Id,
|
||||
PeerId,
|
||||
CreatedAt,
|
||||
}
|
||||
|
||||
static IDX_CACHED_ADDRESS: &str = "idx_CACHED_ADDRESS";
|
||||
static IDX_CACHED_PEER_PEER_ID: &str = "idx_cached_peer_peer_id";
|
||||
static IDX_CACHED_PEER_CREATED_AT: &str = "idx_cached_peer_created_at";
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl TableMigration for CachedPeer {
|
||||
async fn up<'a>(manager: &'a SchemaManager<'a>) -> Result<(), DbErr> {
|
||||
manager.create_table(
|
||||
Table::create()
|
||||
.table(Self::Table)
|
||||
.if_not_exists()
|
||||
.col(pk_auto(Self::Id))
|
||||
.col(string_len(Self::PeerId, 255))
|
||||
.col(timestamp(Self::CreatedAt))
|
||||
.to_owned()
|
||||
).await?;
|
||||
manager.create_index(
|
||||
Index::create()
|
||||
.name(IDX_CACHED_PEER_PEER_ID)
|
||||
.table(Self::Table)
|
||||
.col(Self::PeerId)
|
||||
.to_owned()
|
||||
).await?;
|
||||
manager.create_index(
|
||||
Index::create()
|
||||
.name(IDX_CACHED_PEER_CREATED_AT)
|
||||
.table(Self::Table)
|
||||
.col(Self::CreatedAt)
|
||||
.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
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden, DeriveMigrationName)]
|
||||
enum CachedAddress {
|
||||
Table,
|
||||
Id,
|
||||
CachedPeerId,
|
||||
CreatedAt,
|
||||
LastUsedAt,
|
||||
Address,
|
||||
}
|
||||
|
||||
static IDX_CACHED_ADDRESS_ADDRESS: &str = "idx_cached_address_address";
|
||||
static IDX_CACHED_ADDRESS_CACHED_PEER_ID: &str = "idx_cached_address_cached_peer_id";
|
||||
static IDX_CACHED_ADDRESS_CREATED_AT: &str = "idx_cached_address_created_at";
|
||||
static IDX_CACHED_ADDRESS_LAST_USED_AT: &str = "idx_cached_address_last_used_at";
|
||||
static FK_CACHED_ADDRESS_CACHED_PEER: &str = "fk_cached_address_cached_peer";
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl TableMigration for CachedAddress {
|
||||
async fn up<'a>(manager: &'a SchemaManager<'a>) -> Result<(), DbErr> {
|
||||
manager.create_table(
|
||||
Table::create()
|
||||
.table(Self::Table)
|
||||
.if_not_exists()
|
||||
.col(pk_auto(Self::Id))
|
||||
.col(integer(Self::CachedPeerId))
|
||||
.foreign_key(ForeignKey::create()
|
||||
.name(FK_CACHED_ADDRESS_CACHED_PEER)
|
||||
.from(Self::Table,Self::CachedPeerId)
|
||||
.to(CachedPeer::Table, CachedPeer::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade)
|
||||
.on_update(ForeignKeyAction::Cascade)
|
||||
)
|
||||
.col(timestamp(Self::CreatedAt))
|
||||
.col(timestamp(Self::LastUsedAt))
|
||||
.col(text_uniq(Self::Address))
|
||||
.to_owned()
|
||||
).await?;
|
||||
manager.create_index(
|
||||
Index::create()
|
||||
.name(IDX_CACHED_ADDRESS_CACHED_PEER_ID)
|
||||
.table(Self::Table)
|
||||
.col(Self::CachedPeerId)
|
||||
.to_owned()
|
||||
).await?;
|
||||
manager.create_index(
|
||||
Index::create()
|
||||
.name(IDX_CACHED_ADDRESS_ADDRESS)
|
||||
.table(Self::Table)
|
||||
.col(Self::Address)
|
||||
.to_owned()
|
||||
).await?;
|
||||
manager.create_index(
|
||||
Index::create()
|
||||
.name(IDX_CACHED_ADDRESS_CREATED_AT)
|
||||
.table(Self::Table)
|
||||
.col(Self::CreatedAt)
|
||||
.to_owned()
|
||||
).await?;
|
||||
manager.create_index(
|
||||
Index::create()
|
||||
.name(IDX_CACHED_ADDRESS_LAST_USED_AT)
|
||||
.table(Self::Table)
|
||||
.col(Self::LastUsedAt)
|
||||
.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
|
||||
}
|
||||
}
|
35
core/src/data/entity/mod.rs
Normal file
35
core/src/data/entity/mod.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
mod trusted_node;
|
||||
mod record_deletion;
|
||||
|
||||
pub use trusted_node::{
|
||||
ActiveModel as TrustedNodeActiveModel,
|
||||
Column as TrustedNodeColumn,
|
||||
Entity as TrustedNodeEntity,
|
||||
Model as TrustedNodeModel,
|
||||
};
|
||||
|
||||
pub use record_deletion::{
|
||||
ActiveModel as RecordDeletionActiveModel,
|
||||
Column as RecordDeletionColumn,
|
||||
Entity as RecordDeletionEntity,
|
||||
Model as RecordDeletionModel,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{data::value::PeerIdValue, global::{generate_uuid, get_or_init_test_data_database}};
|
||||
|
||||
use super::*;
|
||||
|
||||
use libp2p::{identity, PeerId};
|
||||
use sea_orm::ActiveModelTrait;
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_insert() {
|
||||
let db = get_or_init_test_data_database().await;
|
||||
|
||||
let node = TrustedNodeActiveModel::new(PeerId::random(), "test note".to_owned()).insert(db).await.unwrap();
|
||||
let _ = RecordDeletionActiveModel::new(node.id, "test_table".to_string(), generate_uuid()).insert(db).await.unwrap();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
use chrono::Local;
|
||||
use sea_orm::entity::{
|
||||
*,
|
||||
prelude::*
|
||||
};
|
||||
use sea_orm::{entity::{
|
||||
prelude::*, *
|
||||
}, sea_query::table};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::data::syncable::*;
|
||||
|
||||
|
@ -29,33 +28,15 @@ pub enum Relation{}
|
|||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl ActiveModel {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(node_id: Uuid, table_name: String, record_id: Uuid) -> Self {
|
||||
let timestamp: DateTimeUtc = Local::now().to_utc();
|
||||
Self{
|
||||
id: Set(crate::global::generate_uuid()),
|
||||
created_at: Set(timestamp),
|
||||
..Default::default()
|
||||
created_by: Set(node_id),
|
||||
table_name: Set(table_name),
|
||||
record_id: Set(record_id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::global::get_or_init_test_data_database;
|
||||
|
||||
use super::*;
|
||||
|
||||
use uuid::{Timestamp, Uuid};
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_insert_record_deletion() {
|
||||
let db = get_or_init_test_data_database().await;
|
||||
|
||||
assert!(ActiveModel{
|
||||
table_name: Set("test_table".to_string()),
|
||||
record_id: Set(crate::global::generate_uuid()),
|
||||
..ActiveModel::new()
|
||||
}.insert(db).await.is_ok());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
use chrono::Local;
|
||||
use libp2p::PeerId;
|
||||
use sea_orm::entity::{
|
||||
*,
|
||||
prelude::*
|
||||
|
@ -32,34 +33,17 @@ pub enum Relation {}
|
|||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl ActiveModel {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(peer_id: PeerId, note: String) -> Self {
|
||||
let timestamp: DateTimeUtc = Local::now().to_utc();
|
||||
Self{
|
||||
id: Set(crate::global::generate_uuid()),
|
||||
peer_id: Set(PeerIdValue::from(peer_id)),
|
||||
created_at: Set(timestamp),
|
||||
updated_at: Set(timestamp),
|
||||
..Default::default()
|
||||
synced_at: Set(None),
|
||||
is_prefered: Set(false),
|
||||
note: Set(note),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::global::get_or_init_test_data_database;
|
||||
|
||||
use super::*;
|
||||
|
||||
use libp2p::{identity, PeerId};
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_insert_node() {
|
||||
let db = get_or_init_test_data_database().await;
|
||||
|
||||
ActiveModel{
|
||||
peer_id: Set(PeerIdValue::from(PeerId::random())),
|
||||
note: Set("test note".to_owned()),
|
||||
..ActiveModel::new()
|
||||
}.insert(db).await.unwrap();
|
||||
}
|
||||
|
||||
}
|
|
@ -62,10 +62,13 @@ enum RecordDeletion {
|
|||
Table,
|
||||
Id,
|
||||
CreatedAt,
|
||||
CreatedBy,
|
||||
TableName,
|
||||
RecordId,
|
||||
}
|
||||
|
||||
static FK_RECORD_DELETION_TRUSTED_NODE: &str = "fk_record_deletion_trusted_node";
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl TableMigration for RecordDeletion {
|
||||
async fn up<'a>(manager: &'a SchemaManager<'a>) -> Result<(), DbErr> {
|
||||
|
@ -75,6 +78,14 @@ impl TableMigration for RecordDeletion {
|
|||
.if_not_exists()
|
||||
.col(pk_uuid(Self::Id))
|
||||
.col(timestamp_with_time_zone(Self::CreatedAt))
|
||||
.col(uuid(Self::CreatedBy))
|
||||
.foreign_key(ForeignKey::create()
|
||||
.name(FK_RECORD_DELETION_TRUSTED_NODE)
|
||||
.from(Self::Table,Self::CreatedBy)
|
||||
.to(TrustedNode::Table, TrustedNode::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade)
|
||||
.on_update(ForeignKeyAction::Cascade)
|
||||
)
|
||||
.col(string(Self::TableName))
|
||||
.col(uuid(Self::RecordId))
|
||||
.to_owned()
|
|
@ -1,6 +1,6 @@
|
|||
use sea_orm::{prelude::*, query::*, sea_query::SimpleExpr, *};
|
||||
#[cfg(feature="macros")]
|
||||
pub use lazy_supplements_macros::SyncableModel;
|
||||
pub use caretta_macros::SyncableModel;
|
||||
pub trait SyncableModel: ModelTrait<Entity = Self::SyncableEntity> {
|
||||
type SyncableEntity: SyncableEntity<SyncableModel = Self>;
|
||||
fn get_timestamp(&self) -> DateTimeUtc;
|
|
@ -9,8 +9,6 @@ use sea_orm::{prelude::*, Database};
|
|||
use sea_orm_migration::MigratorTrait;
|
||||
use tokio::sync::{OnceCell, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
|
||||
mod peers;
|
||||
pub use peers::*;
|
||||
mod config;
|
||||
pub use config::*;
|
||||
mod database_connection;
|
104
core/src/p2p/mod.rs
Normal file
104
core/src/p2p/mod.rs
Normal file
|
@ -0,0 +1,104 @@
|
|||
pub mod error;
|
||||
use chrono::Local;
|
||||
use libp2p::{ identity::Keypair, mdns, ping, swarm, Multiaddr, PeerId};
|
||||
use sea_orm::{prelude::DateTimeUtc, ActiveModelTrait, ActiveValue::Set, ColumnTrait, EntityTrait, ModelTrait, QueryFilter};
|
||||
use tracing::{event, Level};
|
||||
|
||||
use crate::{cache::entity::{CachedPeerActiveModel, CachedAddressActiveModel, CachedAddressColumn, CachedAddressEntity, CachedAddressModel, CachedPeerColumn, CachedPeerEntity, CachedPeerModel}, data::value::{MultiaddrValue, PeerIdValue}, error::Error, global::CACHE_DATABASE_CONNECTION};
|
||||
|
||||
#[derive(swarm::NetworkBehaviour)]
|
||||
#[behaviour(to_swarm = "Event")]
|
||||
pub struct Behaviour {
|
||||
pub mdns: mdns::tokio::Behaviour,
|
||||
pub ping: ping::Behaviour,
|
||||
}
|
||||
|
||||
impl TryFrom<&Keypair> for Behaviour {
|
||||
type Error = Error;
|
||||
fn try_from(keypair: &Keypair) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
mdns: mdns::tokio::Behaviour::new(
|
||||
mdns::Config::default(),
|
||||
keypair.public().into(),
|
||||
)?,
|
||||
ping: libp2p::ping::Behaviour::new(ping::Config::new()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Event {
|
||||
Mdns(mdns::Event),
|
||||
Ping(ping::Event),
|
||||
}
|
||||
|
||||
impl Event {
|
||||
pub async fn run(&self)
|
||||
{
|
||||
match self {
|
||||
Self::Mdns(x) => {
|
||||
match x {
|
||||
mdns::Event::Discovered(e) => {
|
||||
for peer in e.iter() {
|
||||
event!(Level::TRACE, "Peer discovered via mdns: {}, {}", &peer.0, &peer.1);
|
||||
match try_get_or_insert_cached_peer(&peer.0, &peer.1).await {
|
||||
Ok(_) => {},
|
||||
Err(e) => {
|
||||
event!(Level::WARN, "{:?}", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<mdns::Event> for Event {
|
||||
fn from(event: mdns::Event) -> Self {
|
||||
Self::Mdns(event)
|
||||
}
|
||||
}
|
||||
impl From<ping::Event> for Event {
|
||||
fn from(event: ping::Event) -> Self {
|
||||
Self::Ping(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::Address.eq(MultiaddrValue::from(peer_addr.clone()))).one(CACHE_DATABASE_CONNECTION.get()).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.last_used_at = Set(Local::now().to_utc());
|
||||
let updated = addr.update(CACHE_DATABASE_CONNECTION.get()).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?))
|
||||
}
|
||||
}
|
||||
(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?))
|
||||
},
|
||||
(None, x) => {
|
||||
event!(Level::INFO, "Add new peer: {}", peer_id);
|
||||
let inserted = CachedPeerActiveModel::new(peer_id.clone()).insert(CACHE_DATABASE_CONNECTION.get()).await?;
|
||||
if let Some(y) = x {
|
||||
event!(Level::INFO, "Remove {} from {}", peer_addr, peer_id);
|
||||
y.delete(CACHE_DATABASE_CONNECTION.get()).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?))
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
#[cfg(feature="macros")]
|
||||
pub use lazy_supplements_macros::Emptiable;
|
||||
pub use caretta_macros::Emptiable;
|
||||
|
||||
pub trait Emptiable{
|
||||
fn empty() -> Self;
|
|
@ -1,5 +1,5 @@
|
|||
#[cfg(feature="macros")]
|
||||
pub use lazy_supplements_macros::Mergeable;
|
||||
pub use caretta_macros::Mergeable;
|
||||
pub trait Mergeable: Sized {
|
||||
fn merge(&mut self, other: Self);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
#[cfg(feature="macros")]
|
||||
pub use lazy_supplements_macros::Runnable;
|
||||
pub use caretta_macros::Runnable;
|
||||
|
||||
pub trait Runnable {
|
||||
async fn run(self);
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "lazy-supplements-desktop"
|
||||
name = "caretta-desktop"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
description.workspace = true
|
||||
|
@ -8,23 +8,25 @@ repository.workspace = true
|
|||
|
||||
[features]
|
||||
default = []
|
||||
test = ["lazy-supplements-core/test"]
|
||||
test = ["caretta-core/test"]
|
||||
|
||||
[dependencies]
|
||||
ciborium.workspace = true
|
||||
clap.workspace = true
|
||||
dirs = "6.0.0"
|
||||
lazy-supplements-core = { workspace = true, features = ["desktop"] }
|
||||
caretta-core = { workspace = true, features = ["desktop"] }
|
||||
libp2p.workspace = true
|
||||
prost = "0.14.1"
|
||||
sea-orm.workspace = true
|
||||
serde.workspace = true
|
||||
thiserror.workspace = true
|
||||
tokio.workspace = true
|
||||
tonic = "0.14.0"
|
||||
tonic-prost = "0.14.0"
|
||||
uuid.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
lazy-supplements-core = {workspace = true, features = ["test"]}
|
||||
caretta-core = {workspace = true, features = ["test"]}
|
||||
|
||||
[build-dependencies]
|
||||
tonic-prost-build = "0.14.0"
|
4
desktop/build.rs
Normal file
4
desktop/build.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
tonic_prost_build::compile_protos("proto/caretta.proto")?;
|
||||
Ok(())
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
syntax = "proto3";
|
||||
package lazy_supplements;
|
||||
package caretta;
|
||||
|
||||
enum PeerListOrderBy {
|
||||
CREATED_AT = 0;
|
||||
|
@ -18,11 +18,13 @@ message CachedPeerListRequest {
|
|||
|
||||
}
|
||||
|
||||
message CachedPeer {
|
||||
message CachedPeerMessage {
|
||||
string peer_id = 1;
|
||||
repeated string multi_addresss = 2;
|
||||
|
||||
repeated string multi_addresss = 2;
|
||||
|
||||
}
|
||||
|
||||
message CachedPeerListResponse {
|
||||
repeated CachedPeer peers = 1;
|
||||
repeated CachedPeerMessage peers = 1;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
use std::{net::IpAddr, path::PathBuf};
|
||||
|
||||
use clap::Args;
|
||||
use lazy_supplements_core::config::{BaseConfig, ConfigError};
|
||||
use caretta_core::config::{BaseConfig, ConfigError};
|
||||
use crate::config::{PartialP2pConfig, PartialStorageConfig};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
|
@ -1,5 +1,5 @@
|
|||
use clap::Args;
|
||||
use lazy_supplements_core::utils::runnable::Runnable;
|
||||
use caretta_core::utils::runnable::Runnable;
|
||||
use libp2p::{noise, ping, swarm::{NetworkBehaviour, SwarmEvent}, tcp, yamux, Swarm};
|
||||
|
||||
use crate::{error::Error, global::P2P_CONFIG};
|
|
@ -1,9 +1,9 @@
|
|||
pub mod rpc;
|
||||
|
||||
use clap::Args;
|
||||
pub use lazy_supplements_core::config::*;
|
||||
pub use caretta_core::config::*;
|
||||
|
||||
use lazy_supplements_core::utils::{emptiable::Emptiable, mergeable::Mergeable};
|
||||
use caretta_core::utils::{emptiable::Emptiable, mergeable::Mergeable};
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(unix)]
|
||||
pub use rpc::*;
|
|
@ -1,6 +1,6 @@
|
|||
use std::{net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener}, path::PathBuf};
|
||||
use clap::Args;
|
||||
use lazy_supplements_core::{config::PartialConfig, utils::{emptiable::Emptiable, mergeable::Mergeable}};
|
||||
use caretta_core::{config::PartialConfig, utils::{emptiable::Emptiable, mergeable::Mergeable}};
|
||||
use libp2p::mdns::Config;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
use std::{path::PathBuf, sync::LazyLock};
|
||||
|
||||
pub use lazy_supplements_core::global::*;
|
||||
pub use caretta_core::global::*;
|
||||
|
||||
pub static DEFAULT_DATA_DIR_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
let dir = if let Some(x) = dirs::data_local_dir() {
|
|
@ -1,9 +1,9 @@
|
|||
pub mod cli;
|
||||
pub mod config;
|
||||
pub mod global;
|
||||
pub mod ipc;
|
||||
pub mod rpc;
|
||||
pub mod utils;
|
||||
pub use lazy_supplements_core::{
|
||||
pub use caretta_core::{
|
||||
cache,
|
||||
data,
|
||||
error,
|
13
desktop/src/rpc/mod.rs
Normal file
13
desktop/src/rpc/mod.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
pub mod server;
|
||||
|
||||
pub mod proto {
|
||||
use caretta_core::cache::entity::CachedPeerModel;
|
||||
|
||||
tonic::include_proto!("caretta");
|
||||
|
||||
impl From<CachedPeerModel> for CachedPeerMessage {
|
||||
fn from(s: CachedPeerModel) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
20
desktop/src/rpc/server/cached_peer.rs
Normal file
20
desktop/src/rpc/server/cached_peer.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use caretta_core::{cache::entity::CachedPeerEntity, global::DATA_DATABASE_CONNECTION};
|
||||
use tonic::{Request, Response, Status};
|
||||
|
||||
use crate::rpc::proto::{cached_peer_service_server::{CachedPeerService, CachedPeerServiceServer}, CachedPeerListRequest, CachedPeerListResponse};
|
||||
use sea_orm::prelude::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct CachedPeerServer {}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl CachedPeerService for CachedPeerServer {
|
||||
async fn list(&self, request: Request<CachedPeerListRequest>) -> Result<Response<CachedPeerListResponse>, Status> {
|
||||
println!("Got a request: {:?}", request);
|
||||
|
||||
let reply = CachedPeerListResponse {
|
||||
peers: CachedPeerEntity::find().all(DATA_DATABASE_CONNECTION.get()).await?
|
||||
};
|
||||
}
|
||||
|
||||
}
|
1
desktop/src/rpc/server/mod.rs
Normal file
1
desktop/src/rpc/server/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod cached_peer;
|
1
desktop/src/utils.rs
Normal file
1
desktop/src/utils.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub use caretta_core::utils::*;
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "lazy-supplements-examples-core"
|
||||
name = "caretta-examples-core"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
description.workspace = true
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "lazy-supplements-examples-desktop"
|
||||
name = "caretta-examples-desktop"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
@ -8,8 +8,8 @@ edition = "2021"
|
|||
[dependencies]
|
||||
clap.workspace = true
|
||||
dioxus.workspace = true
|
||||
lazy-supplements-desktop.path = "../../lazy-supplements-desktop"
|
||||
lazy-supplements-examples-core.path = "../core"
|
||||
caretta-desktop.path = "../../desktop"
|
||||
caretta-examples-core.path = "../core"
|
||||
|
||||
[features]
|
||||
default = ["desktop"]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use clap::{Parser, Subcommand};
|
||||
use lazy_supplements_desktop::cli::*;
|
||||
use caretta_desktop::cli::*;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Cli {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
mod cli;
|
||||
mod ipc;
|
||||
fn main() {
|
||||
dioxus::launch(lazy_supplements_examples_core::ui::plain::App);
|
||||
dioxus::launch(caretta_examples_core::ui::plain::App);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "lazy-supplements-examples-mobile"
|
||||
name = "caretta-examples-mobile"
|
||||
version = "0.1.0"
|
||||
authors = ["fluo10 <fluo10.dev@fireturtle.net>"]
|
||||
edition = "2021"
|
||||
|
@ -8,7 +8,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
dioxus.workspace = true
|
||||
lazy-supplements-examples-core.path = "../core"
|
||||
caretta-examples-core.path = "../core"
|
||||
|
||||
[features]
|
||||
default = ["mobile"]
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
fn main() {
|
||||
dioxus::launch(lazy_supplements_examples_core::ui::plain::App);
|
||||
dioxus::launch(caretta_examples_core::ui::plain::App);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
mod peer;
|
||||
|
||||
pub use peer::{
|
||||
ActiveModel as ActivePeerModel,
|
||||
Column as PeerColumn,
|
||||
Model as PeerModel,
|
||||
Entity as PeerEntity,
|
||||
};
|
73
lazy-supplements-core/src/cache/entity/peer.rs
vendored
73
lazy-supplements-core/src/cache/entity/peer.rs
vendored
|
@ -1,73 +0,0 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use chrono::{Days, Local};
|
||||
use libp2p::{multiaddr, Multiaddr, PeerId};
|
||||
use sea_orm::{entity::{
|
||||
prelude::*, *
|
||||
}, sea_query};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::data::value::{MultiaddrValue, PeerIdValue};
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)]
|
||||
#[sea_orm(table_name = "peer")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: Uuid,
|
||||
#[sea_orm(indexed)]
|
||||
pub created_at: DateTimeUtc,
|
||||
#[sea_orm(indexed)]
|
||||
pub updated_at: DateTimeUtc,
|
||||
#[sea_orm(indexed)]
|
||||
pub expires_at: DateTimeUtc,
|
||||
#[sea_orm(indexed)]
|
||||
pub peer_id: PeerIdValue,
|
||||
#[sea_orm(indexed)]
|
||||
pub address: MultiaddrValue,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl ActiveModel {
|
||||
pub fn new(peer_id: PeerId, multiaddr: Multiaddr) -> Self {
|
||||
let timestamp: DateTimeUtc = Local::now().to_utc();
|
||||
Self{
|
||||
peer_id: Set(PeerIdValue::from(peer_id)),
|
||||
address: Set(MultiaddrValue::from(multiaddr)),
|
||||
created_at: Set(timestamp),
|
||||
updated_at: Set(timestamp),
|
||||
expires_at: Set(timestamp.checked_add_days(Days::new(30)).unwrap()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::{cache::entity::peer, global::get_or_init_test_cache_database};
|
||||
|
||||
use super::*;
|
||||
|
||||
use libp2p::{identity::{self, Keypair}, swarm::handler::multi};
|
||||
|
||||
#[tokio::test]
|
||||
async fn insert() {
|
||||
let db = get_or_init_test_cache_database().await;
|
||||
let peer_id = Keypair::generate_ed25519().public().to_peer_id();
|
||||
let multiaddr = Multiaddr::empty()
|
||||
.with(Ipv4Addr::new(127,0,0,1).into())
|
||||
.with(multiaddr::Protocol::Tcp(0));
|
||||
let inserted: Model = ActiveModel::new(peer_id.clone(), multiaddr.clone())
|
||||
.insert(db).await.unwrap();
|
||||
assert_eq!(PeerId::from(inserted.peer_id), peer_id);
|
||||
assert_eq!(Multiaddr::from(inserted.address), multiaddr);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
use sea_orm_migration::{prelude::*, schema::*};
|
||||
|
||||
use crate::migration::TableMigration;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
Peer::up(manager).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
Peer::down(manager).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden, DeriveMigrationName)]
|
||||
enum Peer {
|
||||
Table,
|
||||
Id,
|
||||
PeerId,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
ExpiresAt,
|
||||
Address,
|
||||
}
|
||||
|
||||
static IDX_PEER_ADDRESS: &str = "idx_peer_address";
|
||||
static IDX_PEER_PEER_ID: &str = "idx_peer_peer_id";
|
||||
static IDX_PEER_CREATED_AT: &str = "idx_peer_created_at";
|
||||
static IDX_PEER_UPDATED_AT: &str = "idx_peer_updated_at";
|
||||
static IDX_PEER_EXPIRES_AT: &str = "idx_peer_expires_at";
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl TableMigration for Peer {
|
||||
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(string_len(Self::PeerId, 255))
|
||||
.col(timestamp(Self::CreatedAt))
|
||||
.col(timestamp(Self::UpdatedAt))
|
||||
.col(timestamp(Self::ExpiresAt))
|
||||
.col(text_uniq(Self::Address))
|
||||
.to_owned()
|
||||
).await?;
|
||||
manager.create_index(
|
||||
Index::create()
|
||||
.name(IDX_PEER_PEER_ID)
|
||||
.table(Self::Table)
|
||||
.col(Self::PeerId)
|
||||
.to_owned()
|
||||
).await?;
|
||||
manager.create_index(
|
||||
Index::create()
|
||||
.name(IDX_PEER_ADDRESS)
|
||||
.table(Self::Table)
|
||||
.col(Self::Address)
|
||||
.to_owned()
|
||||
).await?;
|
||||
manager.create_index(
|
||||
Index::create()
|
||||
.name(IDX_PEER_CREATED_AT)
|
||||
.table(Self::Table)
|
||||
.col(Self::CreatedAt)
|
||||
.to_owned()
|
||||
).await?;
|
||||
manager.create_index(
|
||||
Index::create()
|
||||
.name(IDX_PEER_UPDATED_AT)
|
||||
.table(Self::Table)
|
||||
.col(Self::UpdatedAt)
|
||||
.to_owned()
|
||||
).await?;
|
||||
manager.create_index(
|
||||
Index::create()
|
||||
.name(IDX_PEER_EXPIRES_AT)
|
||||
.table(Self::Table)
|
||||
.col(Self::ExpiresAt)
|
||||
.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,16 +0,0 @@
|
|||
mod trusted_node;
|
||||
mod record_deletion;
|
||||
|
||||
pub use trusted_node::{
|
||||
ActiveModel as TrustedNodeActiveModel,
|
||||
Column as TrustedNodeColumn,
|
||||
Entity as TrustedNodeEntity,
|
||||
Model as TrustedNodeModel,
|
||||
};
|
||||
|
||||
pub use record_deletion::{
|
||||
ActiveModel as RecordDeletionActiveModel,
|
||||
Column as RecordDeletionColumn,
|
||||
Entity as RecordDeletionEntity,
|
||||
Model as RecordDeletionModel,
|
||||
};
|
|
@ -1,11 +0,0 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use libp2p::bytes::buf::UninitSlice;
|
||||
use tokio::sync::{OnceCell, RwLock, RwLockReadGuard};
|
||||
|
||||
use crate::cache::entity::PeerModel;
|
||||
|
||||
use super::GlobalRwLock;
|
||||
|
||||
pub static PEERS: GlobalRwLock<HashSet<PeerModel>> = GlobalRwLock::const_new(stringify!(PEERS));
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
pub mod error;
|
||||
use libp2p::{ identity::Keypair, mdns, ping, swarm};
|
||||
use sea_orm::{ActiveModelTrait, ActiveValue::Set, ColumnTrait, EntityTrait, QueryFilter};
|
||||
|
||||
use crate::{cache::entity::{ActivePeerModel, PeerColumn, PeerEntity}, error::Error, global::{CACHE_DATABASE_CONNECTION, PEERS}};
|
||||
|
||||
#[derive(swarm::NetworkBehaviour)]
|
||||
#[behaviour(to_swarm = "Event")]
|
||||
pub struct Behaviour {
|
||||
pub mdns: mdns::tokio::Behaviour,
|
||||
pub ping: ping::Behaviour,
|
||||
}
|
||||
|
||||
impl TryFrom<&Keypair> for Behaviour {
|
||||
type Error = Error;
|
||||
fn try_from(keypair: &Keypair) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
mdns: mdns::tokio::Behaviour::new(
|
||||
mdns::Config::default(),
|
||||
keypair.public().into(),
|
||||
)?,
|
||||
ping: libp2p::ping::Behaviour::new(ping::Config::new()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Event {
|
||||
Mdns(mdns::Event),
|
||||
Ping(ping::Event),
|
||||
}
|
||||
|
||||
impl Event {
|
||||
pub async fn run(&self)
|
||||
{
|
||||
match self {
|
||||
Self::Mdns(x) => {
|
||||
match x {
|
||||
mdns::Event::Discovered(e) => {
|
||||
for peer in e.iter() {
|
||||
match PeerEntity::find().filter(PeerColumn::PeerId.contains(&peer.0.to_string())).one(CACHE_DATABASE_CONNECTION.get()).await {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
ActivePeerModel::new(peer.0.clone(), peer.1.clone())
|
||||
.insert(CACHE_DATABASE_CONNECTION.get()).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<mdns::Event> for Event {
|
||||
fn from(event: mdns::Event) -> Self {
|
||||
Self::Mdns(event)
|
||||
}
|
||||
}
|
||||
impl From<ping::Event> for Event {
|
||||
fn from(event: ping::Event) -> Self {
|
||||
Self::Ping(event)
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
tonic_prost_build::compile_protos("proto/lazy_supplements.proto")?;
|
||||
Ok(())
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#[cfg(unix)]
|
||||
pub mod unix;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub mod windows;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub use unix::*;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub use windows::*;
|
|
@ -1,50 +0,0 @@
|
|||
use std::path::Path;
|
||||
use tokio::{io::Interest, net::UnixStream};
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
ipc::message::{Request, Response, ResponseContent},
|
||||
};
|
||||
|
||||
|
||||
pub async fn request<T, U>(path: T, request: U) -> Result<ResponseContent, Error>
|
||||
where
|
||||
T: AsRef<Path>,
|
||||
U: Into<Request>
|
||||
{
|
||||
let stream = UnixStream::connect(path).await?;
|
||||
let ready = stream.ready(Interest::WRITABLE).await?;
|
||||
let request: Request = request.into();
|
||||
let mut response_buf = Vec::new();
|
||||
if let Err(e) = ciborium::into_writer(&request, &mut response_buf) {
|
||||
todo!();
|
||||
};
|
||||
match stream.try_write(&response_buf) {
|
||||
Ok(x) => {
|
||||
println!("write {} bytes", x)
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e.into())
|
||||
}
|
||||
}
|
||||
loop {
|
||||
let ready_write = stream.ready(Interest::READABLE).await?;
|
||||
let mut read_buf : Vec<u8> = Vec::new();
|
||||
match stream.try_read_buf(&mut read_buf) {
|
||||
Ok(x) => {
|
||||
println!("read {} bytes", x)
|
||||
}
|
||||
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e.into())
|
||||
}
|
||||
}
|
||||
let mut buf : Vec<u8> = Vec::new();
|
||||
let response: Response = ciborium::from_reader_with_buffer(read_buf.as_slice(), &mut buf)?;
|
||||
if response.id == request.id {
|
||||
return Ok(response.content)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
mod response;
|
||||
mod request;
|
||||
pub use response::*;
|
||||
pub use request::*;
|
|
@ -1,24 +0,0 @@
|
|||
use lazy_supplements_core::global::generate_uuid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct Request {
|
||||
pub id: Uuid,
|
||||
pub content: RequestContent,
|
||||
}
|
||||
|
||||
impl From<RequestContent> for Request {
|
||||
fn from(c: RequestContent) -> Self {
|
||||
Self{
|
||||
id: generate_uuid(),
|
||||
content: c
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub enum RequestContent {
|
||||
Ping,
|
||||
ListPeers,
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
use lazy_supplements_core::{
|
||||
global::generate_uuid,
|
||||
cache::entity::PeerModel,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct Response {
|
||||
pub id: Uuid,
|
||||
pub content: ResponseContent,
|
||||
}
|
||||
|
||||
impl From<ResponseContent> for Response {
|
||||
fn from(c: ResponseContent) -> Self {
|
||||
Self{
|
||||
id: generate_uuid(),
|
||||
content: c
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub enum ResponseContent {
|
||||
Pong,
|
||||
ListPeers(Vec<PeerModel>)
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
pub mod client;
|
||||
pub mod server;
|
||||
pub mod message;
|
|
@ -1,11 +0,0 @@
|
|||
#[cfg(unix)]
|
||||
pub mod unix;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub mod windows;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub use unix::*;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub use windows::*;
|
|
@ -1,69 +0,0 @@
|
|||
use std::{collections::VecDeque, path::Path, sync::Arc};
|
||||
|
||||
use lazy_supplements_core::error::Error;
|
||||
use tokio::{io::Interest, net::UnixStream, sync::Mutex};
|
||||
|
||||
use crate::ipc::message::{RequestContent, Response, ResponseContent};
|
||||
|
||||
pub async fn listen<T>(path: T) -> Result<(), Error>
|
||||
where T: AsRef<Path> {
|
||||
let stream = UnixStream::connect(path).await?;
|
||||
let write_que: Arc<Mutex<VecDeque<Vec<u8>>>> = Arc::new(Mutex::new(VecDeque::new()));
|
||||
let mut write_next: Option<Vec<u8>> = None;
|
||||
loop {
|
||||
let ready = stream.ready(Interest::READABLE).await?;
|
||||
if ready.is_readable() {
|
||||
let mut data = Vec::new();
|
||||
match stream.try_read(&mut data) {
|
||||
Ok(x) => {
|
||||
println!("read {} bytes", x)
|
||||
}
|
||||
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e.into())
|
||||
}
|
||||
}
|
||||
let write_que2 = write_que.clone();
|
||||
tokio::spawn( async move {
|
||||
let mut buf = Vec::new();
|
||||
let request: crate::ipc::message::Request = ciborium::from_reader_with_buffer(data.as_slice(), &mut buf).unwrap();
|
||||
let response_id = request.id;
|
||||
let response_content: ResponseContent = match request.content {
|
||||
RequestContent::Ping => {
|
||||
ResponseContent::Pong
|
||||
}
|
||||
RequestContent::ListPeers => todo!(),
|
||||
};
|
||||
let mut response_buf = Vec::new();
|
||||
if let Err(e) = ciborium::into_writer(&Response{
|
||||
id: response_id,
|
||||
content: response_content,
|
||||
}, &mut response_buf) {
|
||||
todo!();
|
||||
};
|
||||
let mut que = write_que2.lock().await;
|
||||
que.push_back(response_buf);
|
||||
|
||||
});
|
||||
} else if ready.is_writable() {
|
||||
if let Some(x) = write_next.take() {
|
||||
|
||||
match stream.try_write(&x) {
|
||||
Ok(x) => {
|
||||
println!("write {} bytes", x)
|
||||
}
|
||||
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut locked_que = write_que.lock().await;
|
||||
write_next = locked_que.pop_front();
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
pub use lazy_supplements_core::utils::*;
|
|
@ -1,10 +0,0 @@
|
|||
[package]
|
||||
name = "lazy-supplements-relay"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
description.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
libp2p.workspace = true
|
|
@ -1,3 +0,0 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "lazy-supplements-macros"
|
||||
name = "caretta-macros"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
description.workspace = true
|
||||
|
@ -17,7 +17,7 @@ syn = { version = "2.0.104", features = ["full"] }
|
|||
|
||||
[dev-dependencies]
|
||||
chrono.workspace = true
|
||||
lazy-supplements-core.workspace = true
|
||||
caretta-core.workspace = true
|
||||
sea-orm.workspace = true
|
||||
tokio.workspace = true
|
||||
uuid.workspace = true
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use lazy_supplements_core::utils::emptiable::Emptiable;
|
||||
use lazy_supplements_macros::Emptiable;
|
||||
use caretta_core::utils::emptiable::Emptiable;
|
||||
use caretta_macros::Emptiable;
|
||||
|
||||
#[derive(Debug, PartialEq, Emptiable)]
|
||||
struct EmptiableStruct{
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use lazy_supplements_core::utils::mergeable::Mergeable;
|
||||
use lazy_supplements_macros::Mergeable;
|
||||
use caretta_core::utils::mergeable::Mergeable;
|
||||
use caretta_macros::Mergeable;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Mergeable)]
|
||||
struct MergeableStruct {
|
|
@ -1,5 +1,5 @@
|
|||
use lazy_supplements_core::utils::runnable::Runnable;
|
||||
use lazy_supplements_macros::Runnable;
|
||||
use caretta_core::utils::runnable::Runnable;
|
||||
use caretta_macros::Runnable;
|
||||
|
||||
struct RunnableStruct1;
|
||||
|
|
@ -6,8 +6,8 @@ use sea_orm::{
|
|||
prelude::*
|
||||
}
|
||||
};
|
||||
use lazy_supplements_core::data::syncable::*;
|
||||
use lazy_supplements_macros::SyncableModel;
|
||||
use caretta_core::data::syncable::*;
|
||||
use caretta_macros::SyncableModel;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, SyncableModel)]
|
||||
#[sea_orm(table_name = "syncable")]
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "lazy-supplements-mobile"
|
||||
name = "caretta-mobile"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
description.workspace = true
|
||||
|
@ -8,7 +8,7 @@ repository.workspace = true
|
|||
|
||||
[features]
|
||||
default = []
|
||||
test = ["lazy-supplements-core/test"]
|
||||
test = ["caretta-core/test"]
|
||||
|
||||
[dependencies]
|
||||
lazy-supplements-core.workspace = true
|
||||
caretta-core.workspace = true
|
Loading…
Add table
Reference in a new issue