diff --git a/core/build.rs b/core/build.rs index 75cce15..dbc3291 100644 --- a/core/build.rs +++ b/core/build.rs @@ -4,7 +4,8 @@ fn main() -> Result<(), Box> { .compile_protos( &[ "proto/caretta_sync.authorization_request.proto", - "proto/caretta_sync.peer_info.proto", + "proto/caretta_sync.authorized_node.proto", + "proto/caretta_sync.remote_node.proto", "proto/caretta_sync.common.proto" ], &["proto", "../tripod-id/proto"] diff --git a/core/proto/caretta_sync.authorization_request.proto b/core/proto/caretta_sync.authorization_request.proto index 8b28dbf..dc6d85c 100644 --- a/core/proto/caretta_sync.authorization_request.proto +++ b/core/proto/caretta_sync.authorization_request.proto @@ -1,7 +1,9 @@ syntax = "proto3"; -package caretta_sync; +package caretta_sync.authorization_request; import "caretta_sync.common.proto"; +import "caretta_sync.authorized_node.proto"; +import "caretta_sync.remote_node.proto"; import "tripod_id.proto"; import "google/protobuf/timestamp.proto"; import "google/protobuf/duration.proto"; @@ -20,11 +22,12 @@ enum AuthorizationRequestKind { } message AuthorizationRequestSendRequest { - caretta_sync.common.PeerIdentifier peer = 1; + caretta_sync.remote_node.RemoteNodeIdentifier remote_node = 1; } message AuthorizationRequestSendResponse { - string passcode = 1; + caretta_sync.remote_node.RemoteNodeInfo remote_node_info = 1; + string passcode = 2; } message AuthorizationRequestInfo { @@ -49,7 +52,7 @@ message AuthorizationRequestAcceptRequest { } message AuthorizationRequestAcceptResponse { - caretta_sync.common.AuthorizedNodeInfo authorized_node_info = 1; + caretta_sync.authorized_node.AuthorizedNodeInfo authorized_node_info = 1; } message AuthorizationRequestRejectRequest { diff --git a/core/proto/caretta_sync.authorized_node.proto b/core/proto/caretta_sync.authorized_node.proto new file mode 100644 index 0000000..0b01ec8 --- /dev/null +++ b/core/proto/caretta_sync.authorized_node.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; + +// The package contain service and messages about node already authorized. +// The authorized node includes not only remote authorized peers but also local node itself. +package caretta_sync.authorized_node; + +import "tripod_id.proto"; +import "caretta_sync.remote_node.proto"; +import "caretta_sync.common.proto"; + +service AuthorizadNode { + rpc Info(AuthorizedNodeInfoRequest) returns (AuthorizedNodeInfoResponse); + rpc InfoStream(stream AuthorizedNodeInfoStreamRequest) returns (stream AuthorizedNodeInfoStreamResponse); +} + +message AuthorizedNodeIdentifier { + oneof identifier { + tripod_id.Single id = 1; + caretta_sync.common.PublicKey public_key = 2; + } +} + +message AuthorizedNodeInfo { + tripod_id.Single id = 1; + caretta_sync.common.PublicKey public_key = 2; + string note = 3; +} + +message AuthorizedNodeInfoRequest { + AuthorizedNodeIdentifier node = 1; +} +message AuthorizedNodeInfoResponse { + AuthorizedNodeInfo node_info = 1; +} + +message AuthorizedNodeInfoStreamRequest{} + +message AuthorizedNodeInfoStreamResponse { + AuthorizedNodeInfo node_info = 1; +} \ No newline at end of file diff --git a/core/proto/caretta_sync.common.proto b/core/proto/caretta_sync.common.proto index b43a41d..bf758e8 100644 --- a/core/proto/caretta_sync.common.proto +++ b/core/proto/caretta_sync.common.proto @@ -2,33 +2,40 @@ syntax = "proto3"; package caretta_sync.common; -import "tripod_id.proto"; - message PublicKey { bytes key = 1; } message Uuid { - uint64 first_half = 1; - uint64 second_half = 2; + uint64 high_bits = 1; + uint64 low_bits = 2; } -message PeerIdentifier { - oneof peer_identifier { - tripod_id.Double id = 1; - PublicKey public_key = 2; +message Url { + string url = 1; +} + +message SocketAddr { + oneof socket_addr { + SocketAddrV4 v4 = 1; + SocketAddrV6 v6 = 2; } } -message AuthorizedNodeIdentifier { - oneof identifier { - tripod_id.Single id = 1; - PublicKey public_key = 2; - } +message SocketAddrV4 { + Ipv4Addr ip = 1; + uint32 port = 2; } -message AuthorizedNodeInfo { - tripod_id.Single id = 1; - PublicKey public_key = 2; - string note = 3; +message Ipv4Addr { + uint32 bits = 1; +} + +message SocketAddrV6 { + Ipv6Addr ip = 1; + uint32 port = 2; +} +message Ipv6Addr { + uint64 high_bits = 1; + uint64 low_bits = 2; } \ No newline at end of file diff --git a/core/proto/caretta_sync.peer_info.proto b/core/proto/caretta_sync.peer_info.proto deleted file mode 100644 index 27ea993..0000000 --- a/core/proto/caretta_sync.peer_info.proto +++ /dev/null @@ -1,56 +0,0 @@ -syntax = "proto3"; -package caretta_sync; - -import "caretta_sync.common.proto"; -import "tripod_id.proto"; -import "google/protobuf/timestamp.proto"; -import "google/protobuf/duration.proto"; -import "google/protobuf/empty.proto"; - -service Peer { - rpc Info(PeerInfoRequest) returns (PeerInfoResponse); - rpc InfoStream(stream PeerInfoStreamRequest) returns (stream PeerInfoStreamResponse); -} - -message PeerInfoRequest { - caretta_sync.common.PeerIdentifier peer = 1; -} - -message PeerInfoStreamRequest {} - -message PeerInfoResponse { - PeerInfo peer_info = 1; -} - -message PeerInfoStreamResponse { - PeerInfo peer_info = 1; -} - -message PeerInfo { - tripod_id.Double id = 1; - caretta_sync.common.PublicKey public_key = 2; - string relay_url = 3; - repeated DirectAddrInfo addrs = 4; - string conn_type = 5; - google.protobuf.Duration latency = 6; - google.protobuf.Duration last_used = 7; -} - -message DirectAddrInfo { - string addr = 1; - google.protobuf.Duration latency = 2; - LastControl last_control = 3; - google.protobuf.Duration last_payload = 4; - google.protobuf.Duration last_alive = 5; - repeated Source sources = 6; -} - -message LastControl { - google.protobuf.Duration duration = 1; - string control_msg = 2; -} - -message Source { - string source = 1; - google.protobuf.Duration duration = 2; -} diff --git a/core/proto/caretta_sync.remote_node.proto b/core/proto/caretta_sync.remote_node.proto new file mode 100644 index 0000000..5d179dd --- /dev/null +++ b/core/proto/caretta_sync.remote_node.proto @@ -0,0 +1,70 @@ +syntax = "proto3"; +package caretta_sync.remote_node; + +import "caretta_sync.common.proto"; +import "tripod_id.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/empty.proto"; + +service RemoteNode { + rpc Info(RemoteNodeInfoRequest) returns (RemoteNodeInfoResponse); + rpc InfoStream(stream RemoteNodeInfoStreamRequest) returns (stream RemoteNodeInfoStreamResponse); +} + +message RemoteNodeIdentifier { + oneof remote_node_identifier { + tripod_id.Double id = 1; + caretta_sync.common.PublicKey public_key = 2; + } +} + +message RemoteNodeInfoRequest { + RemoteNodeIdentifier remote_node = 1; +} + +message RemoteNodeInfoStreamRequest {} + +message RemoteNodeInfoResponse { + RemoteNodeInfo remote_node_info = 1; +} + +message RemoteNodeInfoStreamResponse { + RemoteNodeInfo remote_node_info = 1; +} + +message RemoteNodeInfo { + tripod_id.Double id = 1; + bool authorized = 2; + caretta_sync.common.PublicKey public_key = 3; + string relay_url = 4; + repeated RemoteNodeDirectAddrInfo addrs = 5; + string conn_type = 6; + google.protobuf.Duration latency = 7; + google.protobuf.Duration last_used = 8; +} + +message RemoteNodeRelayUrlInfo { + caretta_sync.common.Url relay_url = 1; + google.protobuf.Duration last_alive = 2; + google.protobuf.Duration latency = 3; +} + +message RemoteNodeDirectAddrInfo { + string addr = 1; + google.protobuf.Duration latency = 2; + RemoteNodeLastControl last_control = 3; + google.protobuf.Duration last_payload = 4; + google.protobuf.Duration last_alive = 5; + repeated RemoteNodeSource sources = 6; +} + +message RemoteNodeLastControl { + google.protobuf.Duration duration = 1; + string control_msg = 2; +} + +message RemoteNodeSource { + string source = 1; + google.protobuf.Duration duration = 2; +} diff --git a/core/src/data/local/migration/v1.rs b/core/src/data/local/migration/v1.rs index 8b80938..7d05a7d 100644 --- a/core/src/data/local/migration/v1.rs +++ b/core/src/data/local/migration/v1.rs @@ -2,24 +2,24 @@ use rusqlite::{Connection, Error, Transaction}; pub fn migrate(tx: &Transaction) -> Result<(), Error>{ tx.execute_batch( - "CREATE TABLE peer ( + "CREATE TABLE remote_node ( id INTEGER PRIMARY KEY, public_id INTEGER NOT NULL UNIQUE, public_key BLOB UNIQUE NOT NULL ); CREATE TABLE authorization_request ( - id INTEGER PRIMARY KEY, - uuid BLOB NOT NULL UNIQUE, - public_id INTEGER NOT NULL UNIQUE, - peer_id INTEGER NOT NULL UNIQUE, - created_at TEXT NOT NULL, - closed_at TEXT, - FOREIGN KEY(peer_id) REFERENCES peer(id) + id INTEGER PRIMARY KEY, + uuid BLOB NOT NULL UNIQUE, + public_id INTEGER NOT NULL UNIQUE, + remote_node_id INTEGER NOT NULL UNIQUE, + created_at TEXT NOT NULL, + closed_at TEXT, + FOREIGN KEY(remote_node_id) REFERENCES remote_node(id) ); CREATE TABLE received_authorization_request ( id INTEGER PRIMARY KEY, authorization_request_id INTEGER NOT NULL UNIQUE, - peer_note TEXT, + node_note TEXT, FOREIGN KEY(authorization_request_id) REFERENCES authorization_request(id) ); CREATE TABLE sent_authorization_request ( @@ -28,9 +28,10 @@ pub fn migrate(tx: &Transaction) -> Result<(), Error>{ passcode TEXT NOT NULL, FOREIGN KEY(authorization_request_id) REFERENCES authorization_request(id) ); - CREATE TABLE authorized_peer ( + CREATE TABLE authorized_remote_node ( id INTEGER PRIMARY KEY, - uid INTEGER NOT NULL UNIQUE, + uuid BLOB UNIQUE NOT NULL, + public_id INTEGER NOT NULL UNIQUE, public_key BLOB NOT NULL UNIQUE, note TEXT NOT NULL, last_synced_at TEXT, diff --git a/core/src/data/local/mod.rs b/core/src/data/local/mod.rs index 35d957a..00f907f 100644 --- a/core/src/data/local/mod.rs +++ b/core/src/data/local/mod.rs @@ -1,5 +1,5 @@ // mod authorization_request; -mod peer; +mod remote_node; pub mod migration; use std::{cell::OnceCell, convert::Infallible, iter::Map, path::Path, sync::{LazyLock, OnceLock}}; diff --git a/core/src/data/local/peer.rs b/core/src/data/local/remote_node.rs similarity index 65% rename from core/src/data/local/peer.rs rename to core/src/data/local/remote_node.rs index 50fb724..06f494b 100644 --- a/core/src/data/local/peer.rs +++ b/core/src/data/local/remote_node.rs @@ -1,4 +1,4 @@ -//! Structs about cached peer. +//! Structs about cached remote_node. use std::os::unix::raw::time_t; @@ -10,33 +10,33 @@ use uuid::Uuid; use crate::{data::local::{self, InsertableLocalRecord, LocalRecord, LocalRecordId, NoLocalRecordId, SelectableLocalRecord}, global::LOCAL_DATABASE_CONNECTION}; -/// Peer information cached in local database. +/// RemoteNode information cached in local database. /// /// - Currently this only contain local uid and public key (=node id) of iroh. /// - This is a junction table enable to use caretta-id to specify items in the UI, especially on the CLI. -/// - Actual peer information is managed by iroh endpoint and not contained in this model. -/// - Once a peer is authorized, it is assigned a global (=synced) ID as authorized_peer so essentially this local id targets unauthorized peers. +/// - Actual remote_node information is managed by iroh endpoint and not contained in this model. +/// - Once a remote_node is authorized, it is assigned a global (=synced) ID as authorized_remote_node so essentially this local id targets unauthorized remote_nodes. /// #[derive(Clone, Debug, PartialEq)] -pub struct PeerRecord { +pub struct RemoteNodeRecord { /// serial primary key. pub id: T, - /// public tripod id of peer. - /// this id is use only the node itself and not synced so another node has different local_peer_id even if its public_key is same. + /// public tripod id of remote_node. + /// this id is use only the node itself and not synced so another node has different local_remote_node_id even if its public_key is same. pub public_id: Double, /// Iroh public key pub public_key: PublicKey, } -impl PeerRecord { +impl RemoteNodeRecord { pub fn get_or_insert_by_public_key(public_key: &PublicKey) -> Result { match Self::get_by_public_key(public_key)? { Some(x) => Ok(x), None => { - let new = PeerRecord{ + let new = RemoteNodeRecord{ id: NoLocalRecordId{}, public_id: rand::random(), public_key: public_key.clone() @@ -54,8 +54,8 @@ impl PeerRecord { } } -impl LocalRecord for PeerRecord { - const TABLE_NAME: &str = "peer"; +impl LocalRecord for RemoteNodeRecord { + const TABLE_NAME: &str = "remote_node"; const COLUMNS: &[&str] = &[ "id", "public_id", @@ -65,7 +65,7 @@ impl LocalRecord for PeerRecord { type RowValues = (T, Double, [u8;32]); } -impl SelectableLocalRecord for PeerRecord { +impl SelectableLocalRecord for RemoteNodeRecord { fn from_row(row: &rusqlite::Row<'_>) -> Result { Ok(Self { id: row.get(0)?, @@ -75,7 +75,7 @@ impl SelectableLocalRecord for PeerRecord { } } -impl TryFrom<(LocalRecordId, Double, [u8;32])> for PeerRecord { +impl TryFrom<(LocalRecordId, Double, [u8;32])> for RemoteNodeRecord { type Error = rusqlite::Error; fn try_from(value: (LocalRecordId, Double, [u8;32])) -> Result { Ok(Self { @@ -86,13 +86,13 @@ impl TryFrom<(LocalRecordId, Double, [u8;32])> for PeerRecord { } } -impl InsertableLocalRecord for PeerRecord { - type LocalRecord = PeerRecord; +impl InsertableLocalRecord for RemoteNodeRecord { + type LocalRecord = RemoteNodeRecord; } -impl From> for (NoLocalRecordId, Double, [u8;32]){ - fn from(value: PeerRecord) -> Self { +impl From> for (NoLocalRecordId, Double, [u8;32]){ + fn from(value: RemoteNodeRecord) -> Self { (value.id, value.public_id, value.public_key.as_bytes().to_owned()) } @@ -108,12 +108,12 @@ mod tests { use super::*; #[test] - fn insert_get_peer_record() { + fn insert_get_remote_node_record() { LOCAL_DATABASE_CONNECTION.get_or_init(&TEST_CONFIG.storage.get_local_database_path()); let key = SecretKey::generate(&mut rand::rngs::OsRng); let pubkey = key.public(); - let record = PeerRecord::get_or_insert_by_public_key(&pubkey).unwrap(); - assert_eq!(record, PeerRecord::get_by_public_id(&record.public_id).unwrap().unwrap()); - assert_eq!(record, PeerRecord::get_by_public_key(&record.public_key).unwrap().unwrap()); + let record = RemoteNodeRecord::get_or_insert_by_public_key(&pubkey).unwrap(); + assert_eq!(record, RemoteNodeRecord::get_by_public_id(&record.public_id).unwrap().unwrap()); + assert_eq!(record, RemoteNodeRecord::get_by_public_key(&record.public_key).unwrap().unwrap()); } } \ No newline at end of file diff --git a/core/src/proto/authorization_request.rs b/core/src/proto/authorization_request.rs new file mode 100644 index 0000000..e69de29 diff --git a/core/src/proto/authorized_node.rs b/core/src/proto/authorized_node.rs new file mode 100644 index 0000000..e69de29 diff --git a/core/src/proto/common.rs b/core/src/proto/common.rs new file mode 100644 index 0000000..2c8ef1d --- /dev/null +++ b/core/src/proto/common.rs @@ -0,0 +1,171 @@ +pub use crate::proto::generated::common; + +use crate::proto::{error::{ProtoDeserializeError, ProtoSerializeError}}; + +impl From for common::PublicKey { + fn from(value: iroh::PublicKey) -> Self { + common::PublicKey{ key: Vec::from(value.as_bytes()) } + } +} + +impl TryFrom for iroh::PublicKey { + type Error = ProtoDeserializeError; + fn try_from(value: common::PublicKey) -> Result { + let slice: [u8; 32] = value.key[0..32].try_into()?; + Ok(iroh::PublicKey::from_bytes(&slice)?) + } +} + +impl From for common::Uuid { + fn from(value: uuid::Uuid) -> Self { + let (first_half, second_half) = value.as_u64_pair(); + Self { + high_bits: first_half, + low_bits: second_half + } + } +} + +impl From for uuid::Uuid { + fn from(value: common::Uuid) -> Self { + uuid::Uuid::from_u64_pair(value.high_bits, value.low_bits) + } +} + + + +impl From for common::Url { + fn from(value: url::Url) -> Self { + todo!() + } +} + +impl TryFrom for url::Url { + type Error = ProtoDeserializeError; + fn try_from(value: common::Url) -> Result { + todo!() + } +} + +impl From for common::SocketAddr { + fn from(value: std::net::SocketAddr) -> Self { + Self{ + socket_addr: Some(match value { + std::net::SocketAddr::V4(x) => common::socket_addr::SocketAddr::V4(common::SocketAddrV4::from(x)), + std::net::SocketAddr::V6(x) => common::socket_addr::SocketAddr::V6(common::SocketAddrV6::from(x)), + })} + } +} + +impl TryFrom for std::net::SocketAddr { + type Error = ProtoDeserializeError; + fn try_from(value: common::SocketAddr) -> Result { + Ok(match value.socket_addr.ok_or(Self::Error::MissingField("SocketAddr.socket_addr"))? { + common::socket_addr::SocketAddr::V4(x) => std::net::SocketAddr::V4(x.try_into()?), + common::socket_addr::SocketAddr::V6(x) => std::net::SocketAddr::V6(x.try_into()?), + }) + } +} + +impl From for common::SocketAddrV4 { + fn from(value: std::net::SocketAddrV4) -> Self { + Self { + ip : Some(value.ip().clone().into()), + port: value.port().into(), + } + } +} + +impl TryFrom for std::net::SocketAddrV4 { + type Error = ProtoDeserializeError; + fn try_from(value: common::SocketAddrV4) -> Result { + Ok(Self::new(value.ip.ok_or(ProtoDeserializeError::MissingField("SocketAddrV4.ip"))?.into(), value.port.try_into()?)) + } +} + +impl From for common::Ipv4Addr { + fn from(value: std::net::Ipv4Addr) -> Self { + Self{ + bits: value.to_bits() + } + } +} +impl From for std::net::Ipv4Addr { + fn from(value: common::Ipv4Addr) -> Self{ + Self::from_bits(value.bits) + } +} + +impl From for common::SocketAddrV6 { + fn from(value: std::net::SocketAddrV6) -> Self { + Self{ + ip: Some(value.ip().clone().into()), + port: value.port().into() + } + } +} + +impl TryFrom for std::net::SocketAddrV6 { + type Error = ProtoDeserializeError; + fn try_from(value: common::SocketAddrV6) -> Result { + Ok(Self::new( + value.ip.ok_or(ProtoDeserializeError::MissingField("SocketAddrV6.ip"))?.into(), + value.port.try_into()?, + 0, + 0 + )) + } +} + +impl From for common::Ipv6Addr { + fn from(value: std::net::Ipv6Addr) -> Self { + let bits = value.to_bits(); + + Self{ + high_bits: (bits >> 64) as u64, + low_bits: bits as u64, + } + } +} +impl From for std::net::Ipv6Addr{ + + fn from(value: common::Ipv6Addr) -> Self { + Self::from_bits( + ((value.high_bits as u128) << 64) + (value.low_bits as u128) + ) + } +} + +#[cfg(test)] +mod tests { + use std::{net::{self, Ipv4Addr}, u16}; + + use super::*; + fn validate_uuid_conversion(uuid: uuid::Uuid) -> bool{ + let message = common::Uuid::from(uuid); + uuid == uuid::Uuid::from(message) + } + + #[test] + fn uuid_conversion() { + assert!(validate_uuid_conversion(uuid::Uuid::nil())); + assert!(validate_uuid_conversion(uuid::Uuid::max())); + assert!(validate_uuid_conversion(uuid::Uuid::now_v7())); + } + + fn validate_socket_addr_conversion(socket_addr: net::SocketAddr) -> Result { + let message = common::SocketAddr::from(socket_addr); + Ok(socket_addr == message.try_into()?) + } + + #[test] + fn socket_addr_conversion() { + assert!(validate_socket_addr_conversion(net::SocketAddr::new(net::IpAddr::V4(net::Ipv4Addr::new(0, 0, 0, 0)),u16::MIN)).unwrap()); + assert!(validate_socket_addr_conversion(net::SocketAddr::new(net::IpAddr::V4(net::Ipv4Addr::BROADCAST),u16::MAX)).unwrap()); + assert!(validate_socket_addr_conversion(net::SocketAddr::new(net::IpAddr::V6(net::Ipv6Addr::new(0,0,0,0,0,0,0,0)), u16::MAX)).unwrap()); + assert!(validate_socket_addr_conversion(net::SocketAddr::new(net::IpAddr::V6(net::Ipv6Addr::new(u16::MAX, u16::MAX, u16::MAX, u16::MAX, u16::MAX, u16::MAX, u16::MAX, u16::MAX)), u16::MIN)).unwrap()); + + + } + +} \ No newline at end of file diff --git a/core/src/proto/convert/source_message.rs b/core/src/proto/convert/source_message.rs deleted file mode 100644 index bea57f3..0000000 --- a/core/src/proto/convert/source_message.rs +++ /dev/null @@ -1,16 +0,0 @@ -use std::time::Duration; - -use iroh::endpoint::Source; - -use crate::{error::Error, proto::{error::ProtoSerializeError, SourceMessage}}; - -impl TryFrom<(Source, Duration)> for SourceMessage { - type Error = ProtoSerializeError; - fn try_from(src: (Source, Duration)) -> Result { - let (source, duration )= src; - Ok(Self { - source: source.to_string(), - duration: Some(duration.try_into()?), - }) - } -} \ No newline at end of file diff --git a/core/src/proto/error.rs b/core/src/proto/error.rs index b5088a7..9d2e79b 100644 --- a/core/src/proto/error.rs +++ b/core/src/proto/error.rs @@ -12,4 +12,6 @@ pub enum ProtoDeserializeError { Signature(#[from] ed25519_dalek::SignatureError), #[error("slice parse error: {0}")] SliceTryFrom(#[from] std::array::TryFromSliceError), + #[error("Int parse error: {0}")] + IntTryFrom(#[from] std::num::TryFromIntError), } \ No newline at end of file diff --git a/core/src/proto/generated.rs b/core/src/proto/generated.rs new file mode 100644 index 0000000..162c44d --- /dev/null +++ b/core/src/proto/generated.rs @@ -0,0 +1,13 @@ +pub mod authorization_request { + tonic::include_proto!("caretta_sync.authorization_request"); +} +pub mod authorized_node { + tonic::include_proto!("caretta_sync.authorized_node"); +} +pub mod common { + tonic::include_proto!("caretta_sync.common"); +} + +pub mod remote_node { + tonic::include_proto!("caretta_sync.remote_node"); +} \ No newline at end of file diff --git a/core/src/proto/mod.rs b/core/src/proto/mod.rs index 681aa53..98f851e 100644 --- a/core/src/proto/mod.rs +++ b/core/src/proto/mod.rs @@ -1,6 +1,7 @@ -mod convert; +pub mod authorization_request; +mod authorized_node; +mod remote_node; +mod common; mod error; -mod server; - -tonic::include_proto!("caretta_sync"); -tonic::include_proto!("caretta_sync.common"); \ No newline at end of file +//mod server; +mod generated; diff --git a/core/src/proto/remote_node.rs b/core/src/proto/remote_node.rs new file mode 100644 index 0000000..ff6f117 --- /dev/null +++ b/core/src/proto/remote_node.rs @@ -0,0 +1,16 @@ +use std::time::Duration; + + +use crate::{error::Error, proto::{error::ProtoSerializeError, generated::remote_node}}; + + +impl TryFrom<(iroh::endpoint::Source, Duration)> for remote_node::RemoteNodeSource { + type Error = ProtoSerializeError; + fn try_from(src: (iroh::endpoint::Source, Duration)) -> Result { + let (source, duration )= src; + Ok(Self { + source: source.to_string(), + duration: Some(duration.try_into()?), + }) + } +} \ No newline at end of file