Add unix socket listner

This commit is contained in:
fluo10 2025-06-17 07:20:24 +09:00
parent 833dc9ed3c
commit 70107257c2
23 changed files with 299 additions and 11 deletions

View file

@ -10,6 +10,7 @@ license = "MIT OR Apache-2.0"
repository = "https://forgejo.fireturlte.net/lazy-supplements"
[workspace.dependencies]
ciborium = "0.2.2"
dioxus = { version = "0.6.0", features = [] }
lazy-supplements-core.path = "lazy-supplements-core"
libp2p = { version = "0.55.0", features = ["macros", "mdns", "noise", "ping", "tcp", "tokio", "yamux" ] }
@ -17,3 +18,4 @@ sea-orm-migration = { version = "1.1.0", features = ["runtime-tokio-rustls", "sq
serde = { version = "1.0.219", features = ["derive"] }
thiserror = "2.0.12"
tokio = { version = "1.45.0", features = ["macros", "rt", "rt-multi-thread"] }
uuid = { version = "1.17.0", features = ["v7"] }

View file

@ -25,7 +25,7 @@ tokio.workspace = true
toml = "0.8.22"
tracing = "0.1.41"
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
uuid = { version = "1.17.0", features = ["v7"] }
uuid.workspace = true
[dev-dependencies]
tempfile = "3.20.0"

View file

@ -0,0 +1,14 @@
mod multi_address;
mod peer;
pub use multi_address::{
ActiveModel as MultiAddressActiveModel,
Model as MultiAddressModel,
Entity as MultiAddressEntity,
};
pub use peer::{
ActiveModel as PeerActiveModel,
Model as PeerModel,
Entity as PeerEntity,
};

View file

@ -0,0 +1,60 @@
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 super::*;
use libp2p::identity;
use crate::global::GLOBAL;
#[tokio::test]
async fn check_insert_node() {
let db = crate::global::get_or_init_temporary_main_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

@ -0,0 +1,55 @@
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 peer_id: 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 super::*;
use libp2p::identity;
use crate::global::GLOBAL;
#[tokio::test]
async fn check_insert_node() {
let db = crate::global::get_or_init_temporary_main_database().await;
ActiveModel{
peer_id: Set(identity::Keypair::generate_ed25519().public().to_peer_id().to_string()),
..ActiveModel::new()
}.insert(db).await.unwrap();
}
}

View file

@ -14,8 +14,3 @@ pub use record_deletion::{
Entity as RecordDeletionEntity,
Model as RecordDeletionModel,
};
use uuid::{ContextV7, Timestamp, Uuid};
pub fn generate_uuid() -> Uuid {
Uuid::new_v7(Timestamp::now(ContextV7::new()))
}

View file

@ -32,7 +32,7 @@ impl ActiveModel {
pub fn new() -> Self {
let timestamp: DateTimeUtc = Local::now().to_utc();
Self{
id: Set(super::generate_uuid()),
id: Set(crate::global::generate_uuid()),
created_at: Set(timestamp),
updated_at: Set(timestamp),
..Default::default()

View file

@ -26,7 +26,7 @@ impl ActiveModel {
pub fn new() -> Self {
let timestamp: DateTimeUtc = Local::now().to_utc();
Self{
id: Set(super::generate_uuid()),
id: Set(crate::global::generate_uuid()),
created_at: Set(timestamp),
..Default::default()
}
@ -46,7 +46,7 @@ mod tests {
assert!(ActiveModel{
table_name: Set("test_table".to_string()),
record_id: Set(super::super::generate_uuid()),
record_id: Set(crate::global::generate_uuid()),
..ActiveModel::new()
}.insert(db).await.is_ok());
}

View file

@ -9,6 +9,11 @@ use tokio::sync::{OnceCell, RwLock};
mod database;
use database::GlobalDatabase;
use uuid::{ContextV7, Timestamp, Uuid};
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()

View file

@ -0,0 +1,4 @@
pub trait Message {
fn into_vec_u8(self) -> Vec<u8>;
fn from_vec_u8() -> Self;
}

View file

@ -3,6 +3,7 @@ pub mod config;
pub mod data;
pub mod error;
pub mod global;
pub mod ipc;
pub mod migration;
pub mod p2p;
#[cfg(any(test, feature="test"))]

View file

@ -11,6 +11,7 @@ default = []
test = ["lazy-supplements-core/test"]
[dependencies]
ciborium.workspace = true
clap = { version = "4.5.38", features = ["derive"] }
dirs = "6.0.0"
lazy-supplements-core.workspace = true
@ -18,6 +19,7 @@ libp2p.workspace = true
serde.workspace = true
thiserror.workspace = true
tokio.workspace = true
uuid.workspace = true
[dev-dependencies]
lazy-supplements-core = {workspace = true, features = ["test"]}
lazy-supplements-core = {workspace = true, features = ["test"]}

View file

@ -0,0 +1,11 @@
#[cfg(unix)]
pub mod unix;
#[cfg(windows)]
pub mod windows;
#[cfg(unix)]
pub use unix::*;
#[cfg(windows)]
pub use windows::*;

View file

@ -0,0 +1,4 @@
mod response;
mod request;
pub use response::*;
pub use request::*;

View file

@ -0,0 +1,24 @@
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,
}

View file

@ -0,0 +1,27 @@
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>)
}

View file

@ -0,0 +1,3 @@
pub mod client;
pub mod server;
pub mod message;

View file

@ -0,0 +1,11 @@
#[cfg(unix)]
pub mod unix;
#[cfg(windows)]
pub mod windows;
#[cfg(unix)]
pub use unix::*;
#[cfg(windows)]
pub use windows::*;

View file

@ -0,0 +1,69 @@
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();
}
}

View file

@ -1,8 +1,9 @@
pub mod cli;
pub mod error;
pub mod global;
pub mod ipc;
pub use lazy_supplements_core::{
cache,
config,
data,
};
};