Add wrapper value for Multiaddr and PeerId

This commit is contained in:
fluo10 2025-06-24 22:06:25 +09:00
parent 3356684530
commit 8fbf8a16ec
11 changed files with 216 additions and 139 deletions

View file

@ -1,13 +1,5 @@
mod multi_address;
mod peer;
pub use multi_address::{
ActiveModel as ActiveMultiAddressModel,
Column as MultiAddressColumn,
Model as MultiAddressModel,
Entity as MultiAddressEntity,
};
pub use peer::{
ActiveModel as ActivePeerModel,
Column as PeerColumn,

View file

@ -1,61 +0,0 @@
use chrono::Local;
use sea_orm::entity::{
*,
prelude::*
};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "node")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: u32,
#[sea_orm(indexed)]
pub created_at: DateTimeUtc,
#[sea_orm(indexed)]
pub updated_at: DateTimeUtc,
#[sea_orm(indexed)]
pub synced_at: Option<DateTimeUtc>,
#[sea_orm(indexed)]
pub peer_id: String,
#[sea_orm(column_type = "Text")]
pub note: String,
}
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
impl ActiveModel {
pub fn new() -> Self {
let timestamp: DateTimeUtc = Local::now().to_utc();
Self{
created_at: Set(timestamp),
updated_at: Set(timestamp),
..Default::default()
}
}
}
#[cfg(test)]
mod tests {
use crate::global::get_or_init_test_cache_database;
use super::*;
use libp2p::identity;
#[tokio::test]
async fn check_insert_node() {
let db = get_or_init_test_cache_database().await;
ActiveModel{
peer_id: Set(identity::Keypair::generate_ed25519().public().to_peer_id().to_string()),
note: Set("test note".to_owned()),
..ActiveModel::new()
}.insert(db).await.unwrap();
}
}

View file

@ -1,13 +1,17 @@
use chrono::Local;
use sea_orm::entity::{
*,
prelude::*
};
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, Serialize, Deserialize)]
#[sea_orm(table_name = "node")]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "peer")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: u32,
@ -16,20 +20,28 @@ pub struct Model {
#[sea_orm(indexed)]
pub updated_at: DateTimeUtc,
#[sea_orm(indexed)]
pub peer_id: String,
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() -> Self {
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()
}
}
@ -37,20 +49,25 @@ impl ActiveModel {
#[cfg(test)]
mod tests {
use crate::global::get_or_init_test_cache_database;
use std::net::Ipv4Addr;
use crate::{cache::entity::peer, global::get_or_init_test_cache_database};
use super::*;
use libp2p::identity;
use libp2p::{identity::{self, Keypair}, swarm::handler::multi};
#[tokio::test]
async fn check_insert_node() {
async fn insert() {
let db = get_or_init_test_cache_database().await;
ActiveModel{
peer_id: Set(identity::Keypair::generate_ed25519().public().to_peer_id().to_string()),
..ActiveModel::new()
}.insert(db).await.unwrap();
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);
}
}

View file

@ -9,18 +9,16 @@ pub struct Migration;
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
Peer::up(manager).await?;
Address::up(manager).await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
Peer::down(manager).await?;
Address::down(manager).await?;
Ok(())
}
}
#[derive(DeriveIden)]
#[derive(DeriveIden, DeriveMigrationName)]
enum Peer {
Table,
Id,
@ -28,9 +26,14 @@ enum Peer {
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 {
@ -40,10 +43,11 @@ impl TableMigration for Peer {
.table(Self::Table)
.if_not_exists()
.col(pk_auto(Self::Id))
.col(string_len(Self::PeerId, 255))
.col(timestamp(Self::CreatedAt))
.col(timestamp(Self::UpdatedAt))
.col(timestamp(Self::ExpiresAt))
.col(string_len_uniq(Self::PeerId, 255))
.col(text_uniq(Self::Address))
.to_owned()
).await?;
manager.create_index(
@ -53,53 +57,32 @@ impl TableMigration for Peer {
.col(Self::PeerId)
.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 Address {
Table,
Id,
PeerId,
CreatedAt,
UpdatedAt,
ExpiresAt,
MultiAddress,
}
static IDX_ADDRESS_MULTIADDRESS: &str = "idx_address_multiaddress";
static FK_ADDRESS_PEER: &str = "fk_address_peer";
#[async_trait::async_trait]
impl TableMigration for Address {
async fn up<'a>(manager: &'a SchemaManager<'a>) -> Result<(), DbErr> {
manager.create_table(
Table::create()
manager.create_index(
Index::create()
.name(IDX_PEER_ADDRESS)
.table(Self::Table)
.if_not_exists()
.col(pk_auto(Self::Id))
.col(integer(Self::PeerId))
.col(timestamp(Self::CreatedAt))
.col(timestamp(Self::UpdatedAt))
.col(timestamp(Self::ExpiresAt))
.col(text_uniq(Self::MultiAddress))
.foreign_key(
ForeignKey::create()
.name(FK_ADDRESS_PEER)
.from(Self::Table, Self::PeerId)
.to(Peer::Table, Peer::Id)
)
.col(Self::Address)
.to_owned()
).await?;
manager.create_index(
Index::create()
.name(IDX_ADDRESS_MULTIADDRESS)
.name(IDX_PEER_CREATED_AT)
.table(Self::Table)
.col(Self::MultiAddress)
.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(())

View file

@ -2,6 +2,9 @@ use std::path::PathBuf;
#[cfg(feature="desktop")]
use clap::Args;
#[cfg(any(test, feature="test"))]
use tempfile::tempdir;
use crate::{config::{ConfigError, PartialConfig}};
use libp2p::mdns::Config;
use serde::{Deserialize, Serialize};
@ -30,8 +33,9 @@ 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 }
let temp_dir = tempdir().unwrap().keep();
Self { data_directory: temp_dir.clone(), cache_directory: temp_dir }
}
}

View file

@ -1,2 +1,3 @@
pub mod entity;
pub mod migration;
pub mod migration;
pub mod value;

View file

@ -0,0 +1,5 @@
mod multiaddr;
mod peer_id;
pub use multiaddr::MultiaddrValue;
pub use peer_id::PeerIdValue;

View file

@ -0,0 +1,68 @@
use std::str::FromStr;
use libp2p::Multiaddr;
use sea_orm::{sea_query::ValueTypeErr, DbErr};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct MultiaddrValue(Multiaddr);
impl From<Multiaddr> for MultiaddrValue {
fn from(source: Multiaddr) -> Self {
Self(source)
}
}
impl From<MultiaddrValue> for Multiaddr {
fn from(source: MultiaddrValue) -> Self {
source.0
}
}
impl From<MultiaddrValue> for sea_orm::Value {
fn from(value: MultiaddrValue) -> Self {
Self::from(value.0.to_string())
}
}
impl sea_orm::TryGetable for MultiaddrValue {
fn try_get_by<I: sea_orm::ColIdx>(res: &sea_orm::QueryResult, idx: I)
-> std::result::Result<Self, sea_orm::TryGetError> {
match <String as sea_orm::TryGetable>::try_get_by(res, idx){
Ok(x) => match Multiaddr::from_str(&x) {
Ok(y) => Ok(Self(y)),
Err(_) => Err(DbErr::Type("Multiaddr".to_string()).into()),
},
Err(x) => Err(x),
}
}
}
impl sea_orm::sea_query::ValueType for MultiaddrValue {
fn try_from(v: sea_orm::Value) -> std::result::Result<Self, sea_orm::sea_query::ValueTypeErr> {
match <String as sea_orm::sea_query::ValueType>::try_from(v) {
Ok(x) => match Multiaddr::from_str(&x) {
Ok(y) => Ok(Self(y)),
Err(_) => Err(ValueTypeErr{}),
},
Err(e) => Err(e)
}
}
fn type_name() -> std::string::String {
stringify!(MultiaddrValue).to_owned()
}
fn array_type() -> sea_orm::sea_query::ArrayType {
sea_orm::sea_query::ArrayType::String
}
fn column_type() -> sea_orm::sea_query::ColumnType {
sea_orm::sea_query::ColumnType::Text
}
}
impl sea_orm::sea_query::Nullable for MultiaddrValue {
fn null() -> sea_orm::Value {
<String as sea_orm::sea_query::Nullable>::null()
}
}

View file

@ -0,0 +1,68 @@
use std::str::FromStr;
use libp2p::PeerId;
use sea_orm::{sea_query::ValueTypeErr, DbErr};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq)]
pub struct PeerIdValue(PeerId);
impl From<PeerId> for PeerIdValue {
fn from(source: PeerId) -> Self {
Self(source)
}
}
impl From<PeerIdValue> for PeerId {
fn from(source: PeerIdValue) -> Self {
source.0
}
}
impl From<PeerIdValue> for sea_orm::Value {
fn from(value: PeerIdValue) -> Self {
Self::from(value.0.to_string())
}
}
impl sea_orm::TryGetable for PeerIdValue {
fn try_get_by<I: sea_orm::ColIdx>(res: &sea_orm::QueryResult, idx: I)
-> std::result::Result<Self, sea_orm::TryGetError> {
match <String as sea_orm::TryGetable>::try_get_by(res, idx){
Ok(x) => match PeerId::from_str(&x) {
Ok(y) => Ok(Self(y)),
Err(_) => Err(DbErr::Type("PeerId".to_string()).into()),
},
Err(x) => Err(x),
}
}
}
impl sea_orm::sea_query::ValueType for PeerIdValue {
fn try_from(v: sea_orm::Value) -> std::result::Result<Self, sea_orm::sea_query::ValueTypeErr> {
match <String as sea_orm::sea_query::ValueType>::try_from(v) {
Ok(x) => match PeerId::from_str(&x) {
Ok(y) => Ok(Self(y)),
Err(_) => Err(ValueTypeErr{}),
},
Err(e) => Err(e)
}
}
fn type_name() -> std::string::String {
stringify!(PeerIdValue).to_owned()
}
fn array_type() -> sea_orm::sea_query::ArrayType {
sea_orm::sea_query::ArrayType::String
}
fn column_type() -> sea_orm::sea_query::ColumnType {
sea_orm::sea_query::ColumnType::Text
}
}
impl sea_orm::sea_query::Nullable for PeerIdValue {
fn null() -> sea_orm::Value {
<String as sea_orm::sea_query::Nullable>::null()
}
}

View file

@ -40,10 +40,8 @@ impl Event {
match PeerEntity::find().filter(PeerColumn::PeerId.contains(&peer.0.to_string())).one(CACHE_DATABASE_CONNECTION.get()).await {
Ok(_) => {}
Err(_) => {
ActivePeerModel{
peer_id: Set(peer.0.to_string()),
..ActivePeerModel::new()
}.insert(CACHE_DATABASE_CONNECTION.get()).await;
ActivePeerModel::new(peer.0.clone(), peer.1.clone())
.insert(CACHE_DATABASE_CONNECTION.get()).await;
}
}
}

View file

@ -1,5 +1,7 @@
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};
@ -43,4 +45,4 @@ where T: DeserializeOwned + Serialize + PartialEq + std::fmt::Debug
let buf = toml::to_string(&src).unwrap();
let dst: T = toml::from_str(&buf).unwrap();
assert_eq!(src, dst);
}
}