From d30188e7d941589e0ca1e17b9b61062ad01d0173 Mon Sep 17 00:00:00 2001 From: fluo10 Date: Fri, 5 Sep 2025 06:22:36 +0900 Subject: [PATCH] Move iroh.proto to new crate --- Cargo.toml | 8 +++- core/Cargo.toml | 8 ++-- core/src/error.rs | 6 ++- core/src/proto/iroh/remote_info_request.rs | 11 ----- core/src/proto/mod.rs | 2 - core/src/rpc/service/cached_peer.rs | 29 -------------- core/src/rpc/service/mod.rs | 2 +- iroh-proto/Cargo.toml | 21 ++++++++++ iroh-proto/build.rs | 4 ++ {core => iroh-proto}/proto/iroh.proto | 12 ++++-- iroh-proto/src/error.rs | 9 +++++ iroh-proto/src/lib.rs | 3 ++ .../src/proto}/direct_addr_info_message.rs | 9 ++--- .../src/proto}/last_control_message.rs | 2 +- .../iroh => iroh-proto/src/proto}/mod.rs | 1 + .../src/proto}/remote_info_iter_request.rs | 2 +- .../src/proto}/remote_info_message.rs | 9 ++--- iroh-proto/src/proto/remote_info_request.rs | 19 +++++++++ iroh-proto/src/proto/remote_info_response.rs | 16 ++++++++ .../src/proto}/source_message.rs | 4 +- iroh-proto/src/server.rs | 40 +++++++++++++++++++ 21 files changed, 150 insertions(+), 67 deletions(-) delete mode 100644 core/src/proto/iroh/remote_info_request.rs delete mode 100644 core/src/rpc/service/cached_peer.rs create mode 100644 iroh-proto/Cargo.toml create mode 100644 iroh-proto/build.rs rename {core => iroh-proto}/proto/iroh.proto (82%) create mode 100644 iroh-proto/src/error.rs create mode 100644 iroh-proto/src/lib.rs rename {core/src/proto/iroh => iroh-proto/src/proto}/direct_addr_info_message.rs (64%) rename {core/src/proto/iroh => iroh-proto/src/proto}/last_control_message.rs (90%) rename {core/src/proto/iroh => iroh-proto/src/proto}/mod.rs (87%) rename {core/src/proto/iroh => iroh-proto/src/proto}/remote_info_iter_request.rs (62%) rename {core/src/proto/iroh => iroh-proto/src/proto}/remote_info_message.rs (69%) create mode 100644 iroh-proto/src/proto/remote_info_request.rs create mode 100644 iroh-proto/src/proto/remote_info_response.rs rename {core/src/proto/iroh => iroh-proto/src/proto}/source_message.rs (80%) create mode 100644 iroh-proto/src/server.rs diff --git a/Cargo.toml b/Cargo.toml index 841e014..33d5c76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ caretta-sync-macros = { path="macros", optional = true} caretta-sync-core = {workspace = true, features = ["test"]} [workspace] -members = [ ".", "core", "macros", "cli", "mobile", "examples/*" , "bevy"] +members = [ ".", "core", "macros", "cli", "mobile", "examples/*" , "bevy", "iroh-proto"] resolver = "3" [workspace.package] @@ -46,9 +46,15 @@ futures = { version = "0.3.31", features = ["executor"] } serde = { version = "1.0.219", features = ["derive"] } thiserror = "2.0.12" tokio = { version = "1.45.0", features = ["macros", "rt", "rt-multi-thread"] } +tokio-stream = "0.1.17" tonic = "0.14.0" url = { version = "2.5.7", features = ["serde"] } uuid = { version = "1.17.0", features = ["v7"] } +iroh = { version = "0.91.2", features = ["discovery-local-network", "discovery-pkarr-dht"] } +prost = "0.14.1" +prost-types = "0.14.1" +tonic-prost-build = "0.14.0" +tonic-prost = "0.14.0" [profile.dev] opt-level = 1 diff --git a/core/Cargo.toml b/core/Cargo.toml index ebdfdf0..6652bdd 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -19,9 +19,9 @@ ciborium.workspace = true clap = {workspace = true, optional = true} dirs = "6.0.0" futures.workspace = true -iroh = { version = "0.91.2", features = ["discovery-local-network", "discovery-pkarr-dht"] } -prost = "0.14.1" -prost-types = "0.14.1" +iroh.workspace = true +prost.workspace = true +prost-types.workspace = true rusqlite = { version = "0.37.0", features = ["bundled"] } serde.workspace = true sysinfo = "0.37.0" @@ -51,4 +51,4 @@ objc2-app-kit = "0.3.1" tempfile = "3.20.0" [build-dependencies] -tonic-prost-build = "0.14.0" +tonic-prost-build.workspace = true diff --git a/core/src/error.rs b/core/src/error.rs index 396588d..27eaffe 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -1,4 +1,4 @@ -use std::ffi::OsString; +use std::{array::TryFromSliceError, ffi::OsString}; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -23,6 +23,10 @@ pub enum Error { #[cfg(feature="cli")] #[error("Parse args error: {0}")] ParseCommand(#[from] clap::Error), + #[error("Signature error: {0}")] + Signature(#[from] ed25519_dalek::SignatureError), + #[error("slice parse error: {0}")] + SliceTryFrom(#[from] TryFromSliceError), #[error("toml deserialization error: {0}")] TomlDe(#[from] toml::de::Error), #[error("toml serialization error: {0}")] diff --git a/core/src/proto/iroh/remote_info_request.rs b/core/src/proto/iroh/remote_info_request.rs deleted file mode 100644 index dee8a7a..0000000 --- a/core/src/proto/iroh/remote_info_request.rs +++ /dev/null @@ -1,11 +0,0 @@ -use iroh::NodeId; - -use crate::proto::iroh::RemoteInfoRequest; - -impl From for RemoteInfoRequest { - fn from(value: NodeId) -> Self { - Self { - node_id : value.to_string() - } - } -} \ No newline at end of file diff --git a/core/src/proto/mod.rs b/core/src/proto/mod.rs index 3b7ae71..ef08101 100644 --- a/core/src/proto/mod.rs +++ b/core/src/proto/mod.rs @@ -1,3 +1 @@ -pub mod iroh; - tonic::include_proto!("caretta_sync"); \ No newline at end of file diff --git a/core/src/rpc/service/cached_peer.rs b/core/src/rpc/service/cached_peer.rs deleted file mode 100644 index ca49b7e..0000000 --- a/core/src/rpc/service/cached_peer.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::{global::{DATABASE_CONNECTION}, proto::CachedAddressMessage}; -use futures::future::join_all; -use tonic::{Request, Response, Status}; - -use crate::proto::{cached_peer_service_server::{CachedPeerServiceServer}, CachedPeerListRequest, CachedPeerListResponse, CachedPeerMessage}; - -#[derive(Debug, Default)] -pub struct CachedPeerService {} - - - -#[tonic::async_trait] -impl crate::proto::cached_peer_service_server::CachedPeerService for CachedPeerService { - async fn list(&self, request: Request) -> Result, Status> { - println!("Got a request: {:?}", request); - - let reply = CachedPeerListResponse { - peers: join_all( CachedPeerEntity::find().all(DATABASE_CONNECTIONS.get_cache_unchecked()).await.or_else(|e| Err(Status::from_error(Box::new(e))))?.iter().map(|x| async move { - let addresses = CachedAddressEntity::find() - .all(DATABASE_CONNECTIONS.get_cache_unchecked()) - .await - .or_else(|e| Err(Status::from_error(Box::new(e))))?; - Ok::(CachedPeerMessage::from((x, &addresses))) - })).await.into_iter().collect::,_>>()?, - }; - - Ok(Response::new(reply)) - } -} diff --git a/core/src/rpc/service/mod.rs b/core/src/rpc/service/mod.rs index ed2c36c..695135f 100644 --- a/core/src/rpc/service/mod.rs +++ b/core/src/rpc/service/mod.rs @@ -1 +1 @@ -pub mod cached_peer; \ No newline at end of file +pub mod iroh; \ No newline at end of file diff --git a/iroh-proto/Cargo.toml b/iroh-proto/Cargo.toml new file mode 100644 index 0000000..7a7d6a9 --- /dev/null +++ b/iroh-proto/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "iroh-proto" +edition.workspace = true +version = "0.1.0-alpha" +description = "protobuf definition and tonic server implemention for fetch iroh server infomation" +license.workspace = true +repository.workspace = true + +[dependencies] +ed25519-dalek = { version = "2.2.0", features = ["signature"] } +futures.workspace = true +iroh.workspace = true +prost.workspace = true +prost-types.workspace = true +tokio-stream.workspace = true +tonic.workspace = true +tonic-prost.workspace = true +thiserror.workspace = true + +[build-dependencies] +tonic-prost-build.workspace = true diff --git a/iroh-proto/build.rs b/iroh-proto/build.rs new file mode 100644 index 0000000..f474f89 --- /dev/null +++ b/iroh-proto/build.rs @@ -0,0 +1,4 @@ +fn main() -> Result<(), Box> { + tonic_prost_build::compile_protos("proto/iroh.proto")?; + Ok(()) +} \ No newline at end of file diff --git a/core/proto/iroh.proto b/iroh-proto/proto/iroh.proto similarity index 82% rename from core/proto/iroh.proto rename to iroh-proto/proto/iroh.proto index 09d01a1..6a70c77 100644 --- a/core/proto/iroh.proto +++ b/iroh-proto/proto/iroh.proto @@ -4,18 +4,22 @@ import "google/protobuf/timestamp.proto"; import "google/protobuf/duration.proto"; service Iroh { - rpc RemoteInfo(RemoteInfoRequest) returns (RemoteInfoMessage); - rpc RemoteInfoIter(RemoteInfoIterRequest) returns (stream RemoteInfoMessage); + rpc RemoteInfo(RemoteInfoRequest) returns (RemoteInfoResponse); + rpc RemoteInfoIter(RemoteInfoIterRequest) returns (stream RemoteInfoResponse); } message RemoteInfoRequest { - string node_id = 1; + bytes node_id = 1; } message RemoteInfoIterRequest {} +message RemoteInfoResponse { + RemoteInfoMessage remote_info = 1; +} + message RemoteInfoMessage { - string node_id = 1; + bytes node_id = 1; string relay_url = 2; repeated DirectAddrInfoMessage addrs = 3; string conn_type = 4; diff --git a/iroh-proto/src/error.rs b/iroh-proto/src/error.rs new file mode 100644 index 0000000..3f7fbdb --- /dev/null +++ b/iroh-proto/src/error.rs @@ -0,0 +1,9 @@ +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Duration parse error: {0}")] + Duration(#[from] prost_types::DurationError), + #[error("Signature error: {0}")] + Signature(#[from] ed25519_dalek::SignatureError), + #[error("slice parse error: {0}")] + SliceTryFrom(#[from] std::array::TryFromSliceError) +} diff --git a/iroh-proto/src/lib.rs b/iroh-proto/src/lib.rs new file mode 100644 index 0000000..f00f166 --- /dev/null +++ b/iroh-proto/src/lib.rs @@ -0,0 +1,3 @@ +pub mod error; +pub mod proto; +pub mod server; \ No newline at end of file diff --git a/core/src/proto/iroh/direct_addr_info_message.rs b/iroh-proto/src/proto/direct_addr_info_message.rs similarity index 64% rename from core/src/proto/iroh/direct_addr_info_message.rs rename to iroh-proto/src/proto/direct_addr_info_message.rs index 30d2a0b..fe5ac45 100644 --- a/core/src/proto/iroh/direct_addr_info_message.rs +++ b/iroh-proto/src/proto/direct_addr_info_message.rs @@ -1,18 +1,17 @@ use iroh::endpoint::DirectAddrInfo; -use prost_types::DurationError; -use crate::proto::iroh::{DirectAddrInfoMessage, SourceMessage}; +use crate::{error::Error, proto::{DirectAddrInfoMessage, LastControlMessage, SourceMessage}}; impl TryFrom for DirectAddrInfoMessage { - type Error = DurationError; + type Error = Error; fn try_from(value: DirectAddrInfo) -> Result { Ok(DirectAddrInfoMessage { addr: value.addr.to_string(), latency: value.latency.map(|x| x.try_into()).transpose()?, - last_control: value.last_control.map(|x| super::LastControlMessage::try_from(x)).transpose()?, + last_control: value.last_control.map(|x| LastControlMessage::try_from(x)).transpose()?, last_payload: value.last_payload.map(|x| x.try_into()).transpose()?, last_alive: value.last_alive.map(|x| x.try_into()).transpose()?, - sources: value.sources.into_iter().map(|x| SourceMessage::try_from(x)).collect::, DurationError>>()? + sources: value.sources.into_iter().map(|x| SourceMessage::try_from(x)).collect::, Error>>()? }) } } \ No newline at end of file diff --git a/core/src/proto/iroh/last_control_message.rs b/iroh-proto/src/proto/last_control_message.rs similarity index 90% rename from core/src/proto/iroh/last_control_message.rs rename to iroh-proto/src/proto/last_control_message.rs index 79aeab6..9b13148 100644 --- a/core/src/proto/iroh/last_control_message.rs +++ b/iroh-proto/src/proto/last_control_message.rs @@ -3,7 +3,7 @@ use std::time::Duration; use iroh::endpoint::ControlMsg; use prost_types::DurationError; -use crate::proto::iroh::LastControlMessage; +use crate::proto::LastControlMessage; impl TryFrom<(Duration, ControlMsg)> for LastControlMessage { type Error = DurationError; diff --git a/core/src/proto/iroh/mod.rs b/iroh-proto/src/proto/mod.rs similarity index 87% rename from core/src/proto/iroh/mod.rs rename to iroh-proto/src/proto/mod.rs index 3449309..d4a58f2 100644 --- a/core/src/proto/iroh/mod.rs +++ b/iroh-proto/src/proto/mod.rs @@ -3,6 +3,7 @@ mod last_control_message; mod remote_info_iter_request; mod remote_info_message; mod remote_info_request; +mod remote_info_response; mod source_message; tonic::include_proto!("iroh"); \ No newline at end of file diff --git a/core/src/proto/iroh/remote_info_iter_request.rs b/iroh-proto/src/proto/remote_info_iter_request.rs similarity index 62% rename from core/src/proto/iroh/remote_info_iter_request.rs rename to iroh-proto/src/proto/remote_info_iter_request.rs index a6f09a2..6ba7abb 100644 --- a/core/src/proto/iroh/remote_info_iter_request.rs +++ b/iroh-proto/src/proto/remote_info_iter_request.rs @@ -1,4 +1,4 @@ -use crate::proto::iroh::RemoteInfoIterRequest; +use crate::proto::RemoteInfoIterRequest; impl RemoteInfoIterRequest { pub fn new() -> Self { diff --git a/core/src/proto/iroh/remote_info_message.rs b/iroh-proto/src/proto/remote_info_message.rs similarity index 69% rename from core/src/proto/iroh/remote_info_message.rs rename to iroh-proto/src/proto/remote_info_message.rs index b81f66a..15dcae3 100644 --- a/core/src/proto/iroh/remote_info_message.rs +++ b/iroh-proto/src/proto/remote_info_message.rs @@ -1,17 +1,16 @@ use iroh::endpoint::RemoteInfo; -use prost_types::DurationError; -use crate::proto::iroh::{DirectAddrInfoMessage, RemoteInfoMessage}; +use crate::{error::Error, proto::{DirectAddrInfoMessage, RemoteInfoMessage}}; impl TryFrom for RemoteInfoMessage { - type Error = DurationError; + type Error = Error; fn try_from(value: RemoteInfo) -> Result { Ok(Self { - node_id: value.node_id.to_string(), + node_id: Vec::from(value.node_id.as_bytes()), relay_url: value.relay_url.map_or(String::from(""), |x| x.relay_url.to_string()), addrs: value.addrs.into_iter() .map(|x| DirectAddrInfoMessage::try_from(x)) - .collect::,DurationError>>()?, + .collect::,Error>>()?, conn_type: value.conn_type.to_string(), latency: value.latency.map(|x| x.try_into()).transpose()?, last_used: value.last_used.map(|x| x.try_into()).transpose()?, diff --git a/iroh-proto/src/proto/remote_info_request.rs b/iroh-proto/src/proto/remote_info_request.rs new file mode 100644 index 0000000..0cad4a8 --- /dev/null +++ b/iroh-proto/src/proto/remote_info_request.rs @@ -0,0 +1,19 @@ +use iroh::NodeId; + +use crate::proto::RemoteInfoRequest; + +impl From for RemoteInfoRequest { + fn from(value: NodeId) -> Self { + Self { + node_id : Vec::from(value.as_bytes()) + } + } +} + +impl TryFrom for NodeId { + type Error = crate::error::Error; + fn try_from(value: RemoteInfoRequest) -> Result { + let slice: [u8; 32] = value.node_id[0..32].try_into()?; + Ok(NodeId::from_bytes(&slice)?) + } +} \ No newline at end of file diff --git a/iroh-proto/src/proto/remote_info_response.rs b/iroh-proto/src/proto/remote_info_response.rs new file mode 100644 index 0000000..5e3a17f --- /dev/null +++ b/iroh-proto/src/proto/remote_info_response.rs @@ -0,0 +1,16 @@ +use crate::{ proto::{RemoteInfoMessage, RemoteInfoResponse}}; + +impl From for RemoteInfoResponse { + fn from(value: RemoteInfoMessage) -> Self { + Self { + remote_info: Some(value) + } + } +} +impl From> for RemoteInfoResponse { + fn from(value: Option) -> Self { + Self{ + remote_info: value, + } + } +} \ No newline at end of file diff --git a/core/src/proto/iroh/source_message.rs b/iroh-proto/src/proto/source_message.rs similarity index 80% rename from core/src/proto/iroh/source_message.rs rename to iroh-proto/src/proto/source_message.rs index dc984b5..e137fde 100644 --- a/core/src/proto/iroh/source_message.rs +++ b/iroh-proto/src/proto/source_message.rs @@ -2,10 +2,10 @@ use std::time::Duration; use iroh::endpoint::Source; -use crate::proto::iroh::SourceMessage; +use crate::{error::Error, proto::SourceMessage}; impl TryFrom<(Source, Duration)> for SourceMessage { - type Error = prost_types::DurationError; + type Error = Error; fn try_from(src: (Source, Duration)) -> Result { let (source, duration )= src; Ok(Self { diff --git a/iroh-proto/src/server.rs b/iroh-proto/src/server.rs new file mode 100644 index 0000000..305ba50 --- /dev/null +++ b/iroh-proto/src/server.rs @@ -0,0 +1,40 @@ +use std::pin::Pin; + +use iroh::{Endpoint, NodeId}; +use tonic::{Response, Request, Status}; +use tokio_stream::Stream; + +use crate::proto::{RemoteInfoIterRequest, RemoteInfoMessage, RemoteInfoRequest, RemoteInfoResponse}; + +#[tonic::async_trait] +pub trait AsEndpoint: Send + Sync + 'static { + async fn as_endpoint(&self) -> &Endpoint; +} +pub struct IrohServer +where + T: AsEndpoint +{ + endpoint: T +} + +#[tonic::async_trait] +impl crate::proto::iroh_server::Iroh for IrohServer +where + T: AsEndpoint +{ + type RemoteInfoIterStream = Pin> + Send>>; + async fn remote_info(&self, request: Request) -> Result, Status> { + let node_id = NodeId::try_from(request.into_inner()).or_else(|e| { + Err(Status::from_error(Box::new(e))) + })?; + let remote_info: Option = self.endpoint.as_endpoint().await.remote_info(node_id).map(|x| x.try_into()).transpose().or_else(|e| { + Err(Status::from_error(Box::new(e))) + })?; + Ok(Response::new(RemoteInfoResponse::from(remote_info))) + } + async fn remote_info_iter(&self, _: Request) -> Result, Status> { + let iter = self.endpoint.as_endpoint().await.remote_info_iter(); + let stream = futures::stream::iter(iter); + todo!() + } +} \ No newline at end of file