Compare commits

..

2 commits

Author SHA1 Message Date
de211d2b71 Add protobuf vscode config 2025-09-30 08:09:04 +09:00
20c963f6c8 Rename peer to remote_node 2025-09-30 08:07:50 +09:00
19 changed files with 398 additions and 132 deletions

5
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,5 @@
{
"recommendations": [
"zxh404.vscode-proto3"
]
}

8
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,8 @@
{
"protoc": {
"options": [
"--proto_path=${workspaceRoot}/tripod-id/proto",
"--proto_path=${workspaceRoot}/core/proto"
]
}
}

View file

@ -4,7 +4,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.compile_protos( .compile_protos(
&[ &[
"proto/caretta_sync.authorization_request.proto", "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/caretta_sync.common.proto"
], ],
&["proto", "../tripod-id/proto"] &["proto", "../tripod-id/proto"]

View file

@ -1,7 +1,9 @@
syntax = "proto3"; syntax = "proto3";
package caretta_sync; package caretta_sync.authorization_request;
import "caretta_sync.common.proto"; import "caretta_sync.common.proto";
import "caretta_sync.authorized_node.proto";
import "caretta_sync.remote_node.proto";
import "tripod_id.proto"; import "tripod_id.proto";
import "google/protobuf/timestamp.proto"; import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto"; import "google/protobuf/duration.proto";
@ -20,11 +22,12 @@ enum AuthorizationRequestKind {
} }
message AuthorizationRequestSendRequest { message AuthorizationRequestSendRequest {
caretta_sync.common.PeerIdentifier peer = 1; caretta_sync.remote_node.RemoteNodeIdentifier remote_node = 1;
} }
message AuthorizationRequestSendResponse { message AuthorizationRequestSendResponse {
string passcode = 1; caretta_sync.remote_node.RemoteNodeInfo remote_node_info = 1;
string passcode = 2;
} }
message AuthorizationRequestInfo { message AuthorizationRequestInfo {
@ -49,7 +52,7 @@ message AuthorizationRequestAcceptRequest {
} }
message AuthorizationRequestAcceptResponse { message AuthorizationRequestAcceptResponse {
caretta_sync.common.AuthorizedNodeInfo authorized_node_info = 1; caretta_sync.authorized_node.AuthorizedNodeInfo authorized_node_info = 1;
} }
message AuthorizationRequestRejectRequest { message AuthorizationRequestRejectRequest {

View file

@ -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;
}

View file

@ -2,33 +2,40 @@ syntax = "proto3";
package caretta_sync.common; package caretta_sync.common;
import "tripod_id.proto";
message PublicKey { message PublicKey {
bytes key = 1; bytes key = 1;
} }
message Uuid { message Uuid {
uint64 first_half = 1; uint64 high_bits = 1;
uint64 second_half = 2; uint64 low_bits = 2;
} }
message PeerIdentifier { message Url {
oneof peer_identifier { string url = 1;
tripod_id.Double id = 1; }
PublicKey public_key = 2;
message SocketAddr {
oneof socket_addr {
SocketAddrV4 v4 = 1;
SocketAddrV6 v6 = 2;
} }
} }
message AuthorizedNodeIdentifier { message SocketAddrV4 {
oneof identifier { Ipv4Addr ip = 1;
tripod_id.Single id = 1; uint32 port = 2;
PublicKey public_key = 2;
}
} }
message AuthorizedNodeInfo { message Ipv4Addr {
tripod_id.Single id = 1; uint32 bits = 1;
PublicKey public_key = 2; }
string note = 3;
message SocketAddrV6 {
Ipv6Addr ip = 1;
uint32 port = 2;
}
message Ipv6Addr {
uint64 high_bits = 1;
uint64 low_bits = 2;
} }

View file

@ -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;
}

View file

@ -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;
}

View file

@ -2,24 +2,24 @@ use rusqlite::{Connection, Error, Transaction};
pub fn migrate(tx: &Transaction) -> Result<(), Error>{ pub fn migrate(tx: &Transaction) -> Result<(), Error>{
tx.execute_batch( tx.execute_batch(
"CREATE TABLE peer ( "CREATE TABLE remote_node (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
public_id INTEGER NOT NULL UNIQUE, public_id INTEGER NOT NULL UNIQUE,
public_key BLOB UNIQUE NOT NULL public_key BLOB UNIQUE NOT NULL
); );
CREATE TABLE authorization_request ( CREATE TABLE authorization_request (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
uuid BLOB NOT NULL UNIQUE, uuid BLOB NOT NULL UNIQUE,
public_id INTEGER NOT NULL UNIQUE, public_id INTEGER NOT NULL UNIQUE,
peer_id INTEGER NOT NULL UNIQUE, remote_node_id INTEGER NOT NULL UNIQUE,
created_at TEXT NOT NULL, created_at TEXT NOT NULL,
closed_at TEXT, closed_at TEXT,
FOREIGN KEY(peer_id) REFERENCES peer(id) FOREIGN KEY(remote_node_id) REFERENCES remote_node(id)
); );
CREATE TABLE received_authorization_request ( CREATE TABLE received_authorization_request (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
authorization_request_id INTEGER NOT NULL UNIQUE, authorization_request_id INTEGER NOT NULL UNIQUE,
peer_note TEXT, node_note TEXT,
FOREIGN KEY(authorization_request_id) REFERENCES authorization_request(id) FOREIGN KEY(authorization_request_id) REFERENCES authorization_request(id)
); );
CREATE TABLE sent_authorization_request ( CREATE TABLE sent_authorization_request (
@ -28,9 +28,10 @@ pub fn migrate(tx: &Transaction) -> Result<(), Error>{
passcode TEXT NOT NULL, passcode TEXT NOT NULL,
FOREIGN KEY(authorization_request_id) REFERENCES authorization_request(id) FOREIGN KEY(authorization_request_id) REFERENCES authorization_request(id)
); );
CREATE TABLE authorized_peer ( CREATE TABLE authorized_remote_node (
id INTEGER PRIMARY KEY, 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, public_key BLOB NOT NULL UNIQUE,
note TEXT NOT NULL, note TEXT NOT NULL,
last_synced_at TEXT, last_synced_at TEXT,

View file

@ -1,5 +1,5 @@
// mod authorization_request; // mod authorization_request;
mod peer; mod remote_node;
pub mod migration; pub mod migration;
use std::{cell::OnceCell, convert::Infallible, iter::Map, path::Path, sync::{LazyLock, OnceLock}}; use std::{cell::OnceCell, convert::Infallible, iter::Map, path::Path, sync::{LazyLock, OnceLock}};

View file

@ -1,4 +1,4 @@
//! Structs about cached peer. //! Structs about cached remote_node.
use std::os::unix::raw::time_t; 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}; 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. /// - 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. /// - 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. /// - Actual remote_node 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. /// - 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)] #[derive(Clone, Debug, PartialEq)]
pub struct PeerRecord<T> { pub struct RemoteNodeRecord<T> {
/// serial primary key. /// serial primary key.
pub id: T, pub id: T,
/// public tripod id of peer. /// public tripod id of remote_node.
/// 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. /// 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, pub public_id: Double,
/// Iroh public key /// Iroh public key
pub public_key: PublicKey, pub public_key: PublicKey,
} }
impl PeerRecord<LocalRecordId> { impl RemoteNodeRecord<LocalRecordId> {
pub fn get_or_insert_by_public_key(public_key: &PublicKey) -> Result<Self, rusqlite::Error> { pub fn get_or_insert_by_public_key(public_key: &PublicKey) -> Result<Self, rusqlite::Error> {
match Self::get_by_public_key(public_key)? { match Self::get_by_public_key(public_key)? {
Some(x) => Ok(x), Some(x) => Ok(x),
None => { None => {
let new = PeerRecord{ let new = RemoteNodeRecord{
id: NoLocalRecordId{}, id: NoLocalRecordId{},
public_id: rand::random(), public_id: rand::random(),
public_key: public_key.clone() public_key: public_key.clone()
@ -54,8 +54,8 @@ impl PeerRecord<LocalRecordId> {
} }
} }
impl<T> LocalRecord for PeerRecord<T> { impl<T> LocalRecord for RemoteNodeRecord<T> {
const TABLE_NAME: &str = "peer"; const TABLE_NAME: &str = "remote_node";
const COLUMNS: &[&str] = &[ const COLUMNS: &[&str] = &[
"id", "id",
"public_id", "public_id",
@ -65,7 +65,7 @@ impl<T> LocalRecord for PeerRecord<T> {
type RowValues = (T, Double, [u8;32]); type RowValues = (T, Double, [u8;32]);
} }
impl SelectableLocalRecord for PeerRecord<LocalRecordId> { impl SelectableLocalRecord for RemoteNodeRecord<LocalRecordId> {
fn from_row(row: &rusqlite::Row<'_>) -> Result<Self, rusqlite::Error> { fn from_row(row: &rusqlite::Row<'_>) -> Result<Self, rusqlite::Error> {
Ok(Self { Ok(Self {
id: row.get(0)?, id: row.get(0)?,
@ -75,7 +75,7 @@ impl SelectableLocalRecord for PeerRecord<LocalRecordId> {
} }
} }
impl TryFrom<(LocalRecordId, Double, [u8;32])> for PeerRecord<LocalRecordId> { impl TryFrom<(LocalRecordId, Double, [u8;32])> for RemoteNodeRecord<LocalRecordId> {
type Error = rusqlite::Error; type Error = rusqlite::Error;
fn try_from(value: (LocalRecordId, Double, [u8;32])) -> Result<Self, Self::Error> { fn try_from(value: (LocalRecordId, Double, [u8;32])) -> Result<Self, Self::Error> {
Ok(Self { Ok(Self {
@ -86,13 +86,13 @@ impl TryFrom<(LocalRecordId, Double, [u8;32])> for PeerRecord<LocalRecordId> {
} }
} }
impl InsertableLocalRecord for PeerRecord<NoLocalRecordId> { impl InsertableLocalRecord for RemoteNodeRecord<NoLocalRecordId> {
type LocalRecord = PeerRecord<LocalRecordId>; type LocalRecord = RemoteNodeRecord<LocalRecordId>;
} }
impl From<PeerRecord<NoLocalRecordId>> for (NoLocalRecordId, Double, [u8;32]){ impl From<RemoteNodeRecord<NoLocalRecordId>> for (NoLocalRecordId, Double, [u8;32]){
fn from(value: PeerRecord<NoLocalRecordId>) -> Self { fn from(value: RemoteNodeRecord<NoLocalRecordId>) -> Self {
(value.id, value.public_id, value.public_key.as_bytes().to_owned()) (value.id, value.public_id, value.public_key.as_bytes().to_owned())
} }
@ -108,12 +108,12 @@ mod tests {
use super::*; use super::*;
#[test] #[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()); LOCAL_DATABASE_CONNECTION.get_or_init(&TEST_CONFIG.storage.get_local_database_path());
let key = SecretKey::generate(&mut rand::rngs::OsRng); let key = SecretKey::generate(&mut rand::rngs::OsRng);
let pubkey = key.public(); let pubkey = key.public();
let record = PeerRecord::get_or_insert_by_public_key(&pubkey).unwrap(); let record = RemoteNodeRecord::get_or_insert_by_public_key(&pubkey).unwrap();
assert_eq!(record, PeerRecord::get_by_public_id(&record.public_id).unwrap().unwrap()); assert_eq!(record, RemoteNodeRecord::get_by_public_id(&record.public_id).unwrap().unwrap());
assert_eq!(record, PeerRecord::get_by_public_key(&record.public_key).unwrap().unwrap()); assert_eq!(record, RemoteNodeRecord::get_by_public_key(&record.public_key).unwrap().unwrap());
} }
} }

View file

View file

171
core/src/proto/common.rs Normal file
View file

@ -0,0 +1,171 @@
pub use crate::proto::generated::common;
use crate::proto::{error::{ProtoDeserializeError, ProtoSerializeError}};
impl From<iroh::PublicKey> for common::PublicKey {
fn from(value: iroh::PublicKey) -> Self {
common::PublicKey{ key: Vec::from(value.as_bytes()) }
}
}
impl TryFrom<common::PublicKey> for iroh::PublicKey {
type Error = ProtoDeserializeError;
fn try_from(value: common::PublicKey) -> Result<Self, Self::Error> {
let slice: [u8; 32] = value.key[0..32].try_into()?;
Ok(iroh::PublicKey::from_bytes(&slice)?)
}
}
impl From<uuid::Uuid> 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<common::Uuid> for uuid::Uuid {
fn from(value: common::Uuid) -> Self {
uuid::Uuid::from_u64_pair(value.high_bits, value.low_bits)
}
}
impl From<url::Url> for common::Url {
fn from(value: url::Url) -> Self {
todo!()
}
}
impl TryFrom<common::Url> for url::Url {
type Error = ProtoDeserializeError;
fn try_from(value: common::Url) -> Result<Self, Self::Error> {
todo!()
}
}
impl From<std::net::SocketAddr> 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<common::SocketAddr> for std::net::SocketAddr {
type Error = ProtoDeserializeError;
fn try_from(value: common::SocketAddr) -> Result<Self, Self::Error> {
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<std::net::SocketAddrV4> for common::SocketAddrV4 {
fn from(value: std::net::SocketAddrV4) -> Self {
Self {
ip : Some(value.ip().clone().into()),
port: value.port().into(),
}
}
}
impl TryFrom<common::SocketAddrV4> for std::net::SocketAddrV4 {
type Error = ProtoDeserializeError;
fn try_from(value: common::SocketAddrV4) -> Result<Self, Self::Error> {
Ok(Self::new(value.ip.ok_or(ProtoDeserializeError::MissingField("SocketAddrV4.ip"))?.into(), value.port.try_into()?))
}
}
impl From<std::net::Ipv4Addr> for common::Ipv4Addr {
fn from(value: std::net::Ipv4Addr) -> Self {
Self{
bits: value.to_bits()
}
}
}
impl From<common::Ipv4Addr> for std::net::Ipv4Addr {
fn from(value: common::Ipv4Addr) -> Self{
Self::from_bits(value.bits)
}
}
impl From<std::net::SocketAddrV6> for common::SocketAddrV6 {
fn from(value: std::net::SocketAddrV6) -> Self {
Self{
ip: Some(value.ip().clone().into()),
port: value.port().into()
}
}
}
impl TryFrom<common::SocketAddrV6> for std::net::SocketAddrV6 {
type Error = ProtoDeserializeError;
fn try_from(value: common::SocketAddrV6) -> Result<Self, Self::Error> {
Ok(Self::new(
value.ip.ok_or(ProtoDeserializeError::MissingField("SocketAddrV6.ip"))?.into(),
value.port.try_into()?,
0,
0
))
}
}
impl From<std::net::Ipv6Addr> 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<common::Ipv6Addr> 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<bool, ProtoDeserializeError> {
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());
}
}

View file

@ -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<Self, Self::Error> {
let (source, duration )= src;
Ok(Self {
source: source.to_string(),
duration: Some(duration.try_into()?),
})
}
}

View file

@ -12,4 +12,6 @@ pub enum ProtoDeserializeError {
Signature(#[from] ed25519_dalek::SignatureError), Signature(#[from] ed25519_dalek::SignatureError),
#[error("slice parse error: {0}")] #[error("slice parse error: {0}")]
SliceTryFrom(#[from] std::array::TryFromSliceError), SliceTryFrom(#[from] std::array::TryFromSliceError),
#[error("Int parse error: {0}")]
IntTryFrom(#[from] std::num::TryFromIntError),
} }

View file

@ -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");
}

View file

@ -1,6 +1,7 @@
mod convert; pub mod authorization_request;
mod authorized_node;
mod remote_node;
mod common;
mod error; mod error;
mod server; //mod server;
mod generated;
tonic::include_proto!("caretta_sync");
tonic::include_proto!("caretta_sync.common");

View file

@ -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<Self, Self::Error> {
let (source, duration )= src;
Ok(Self {
source: source.to_string(),
duration: Some(duration.try_into()?),
})
}
}