Compare commits
2 commits
6e13cef237
...
de211d2b71
| Author | SHA1 | Date | |
|---|---|---|---|
| de211d2b71 | |||
| 20c963f6c8 |
19 changed files with 398 additions and 132 deletions
5
.vscode/extensions.json
vendored
Normal file
5
.vscode/extensions.json
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"zxh404.vscode-proto3"
|
||||||
|
]
|
||||||
|
}
|
||||||
8
.vscode/settings.json
vendored
Normal file
8
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"protoc": {
|
||||||
|
"options": [
|
||||||
|
"--proto_path=${workspaceRoot}/tripod-id/proto",
|
||||||
|
"--proto_path=${workspaceRoot}/core/proto"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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"]
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
40
core/proto/caretta_sync.authorized_node.proto
Normal file
40
core/proto/caretta_sync.authorized_node.proto
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
70
core/proto/caretta_sync.remote_node.proto
Normal file
70
core/proto/caretta_sync.remote_node.proto
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ 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
|
||||||
|
|
@ -11,15 +11,15 @@ pub fn migrate(tx: &Transaction) -> Result<(), Error>{
|
||||||
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,
|
||||||
|
|
|
||||||
|
|
@ -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}};
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0
core/src/proto/authorization_request.rs
Normal file
0
core/src/proto/authorization_request.rs
Normal file
0
core/src/proto/authorized_node.rs
Normal file
0
core/src/proto/authorized_node.rs
Normal file
171
core/src/proto/common.rs
Normal file
171
core/src/proto/common.rs
Normal 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());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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()?),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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),
|
||||||
}
|
}
|
||||||
13
core/src/proto/generated.rs
Normal file
13
core/src/proto/generated.rs
Normal 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");
|
||||||
|
}
|
||||||
|
|
@ -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");
|
|
||||||
|
|
|
||||||
16
core/src/proto/remote_node.rs
Normal file
16
core/src/proto/remote_node.rs
Normal 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()?),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue