A local-first private AI assistant for everyday use. Runs on-device models with encrypted P2P sync, and supports sharing chats publicly on ATProto.
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: Added p2p device discovery and linking

madclaws ad1cb1c4 1d2a86cf

+426 -138
+90
Cargo.lock
··· 874 874 version = "1.11.1" 875 875 source = "registry+https://github.com/rust-lang/crates.io-index" 876 876 checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" 877 + dependencies = [ 878 + "serde", 879 + ] 877 880 878 881 [[package]] 879 882 name = "cbor4ii" ··· 2025 2028 checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" 2026 2029 2027 2030 [[package]] 2031 + name = "fixedbitset" 2032 + version = "0.5.7" 2033 + source = "registry+https://github.com/rust-lang/crates.io-index" 2034 + checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" 2035 + 2036 + [[package]] 2028 2037 name = "flatbuffers" 2029 2038 version = "25.12.19" 2030 2039 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2252 2261 dependencies = [ 2253 2262 "futures-core", 2254 2263 "futures-sink", 2264 + ] 2265 + 2266 + [[package]] 2267 + name = "futures-concurrency" 2268 + version = "7.7.1" 2269 + source = "registry+https://github.com/rust-lang/crates.io-index" 2270 + checksum = "175cd8cca9e1d45b87f18ffa75088f2099e3c4fe5e2f83e42de112560bea8ea6" 2271 + dependencies = [ 2272 + "fixedbitset", 2273 + "futures-core", 2274 + "futures-lite", 2275 + "pin-project", 2276 + "smallvec", 2255 2277 ] 2256 2278 2257 2279 [[package]] ··· 2540 2562 version = "0.5.2" 2541 2563 source = "registry+https://github.com/rust-lang/crates.io-index" 2542 2564 checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" 2565 + 2566 + [[package]] 2567 + name = "hex" 2568 + version = "0.4.3" 2569 + source = "registry+https://github.com/rust-lang/crates.io-index" 2570 + checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 2543 2571 2544 2572 [[package]] 2545 2573 name = "hf-hub" ··· 3101 3129 ] 3102 3130 3103 3131 [[package]] 3132 + name = "iroh-gossip" 3133 + version = "0.97.0" 3134 + source = "registry+https://github.com/rust-lang/crates.io-index" 3135 + checksum = "4db5b64f3cb0a0c8b68b57888acd4cefcd2f0774f1a132d2a498cbb2a92fbc55" 3136 + dependencies = [ 3137 + "blake3", 3138 + "bytes", 3139 + "data-encoding", 3140 + "derive_more", 3141 + "ed25519-dalek 3.0.0-pre.1", 3142 + "futures-concurrency", 3143 + "futures-lite", 3144 + "futures-util", 3145 + "hex", 3146 + "indexmap", 3147 + "iroh", 3148 + "iroh-base", 3149 + "iroh-metrics", 3150 + "irpc", 3151 + "n0-error", 3152 + "n0-future", 3153 + "postcard", 3154 + "rand 0.9.2", 3155 + "serde", 3156 + "tokio", 3157 + "tokio-util", 3158 + "tracing", 3159 + ] 3160 + 3161 + [[package]] 3104 3162 name = "iroh-metrics" 3105 3163 version = "0.38.3" 3106 3164 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3199 3257 "n0-error", 3200 3258 "postcard", 3201 3259 "serde", 3260 + ] 3261 + 3262 + [[package]] 3263 + name = "irpc" 3264 + version = "0.13.0" 3265 + source = "registry+https://github.com/rust-lang/crates.io-index" 3266 + checksum = "4f47b7c52662d673df377b5ac40c121c7ff56eb764e520fae6543686132f7957" 3267 + dependencies = [ 3268 + "futures-util", 3269 + "irpc-derive", 3270 + "n0-error", 3271 + "n0-future", 3272 + "serde", 3273 + "tokio", 3274 + "tokio-util", 3275 + "tracing", 3276 + ] 3277 + 3278 + [[package]] 3279 + name = "irpc-derive" 3280 + version = "0.10.0" 3281 + source = "registry+https://github.com/rust-lang/crates.io-index" 3282 + checksum = "83c1a4b460634aeed6dc01236a0047867de70e30562d91a0ad031dcb3ac33fb4" 3283 + dependencies = [ 3284 + "proc-macro2", 3285 + "quote", 3286 + "syn 2.0.117", 3202 3287 ] 3203 3288 3204 3289 [[package]] ··· 3690 3775 source = "registry+https://github.com/rust-lang/crates.io-index" 3691 3776 checksum = "af4782b4baf92d686d161c15460c83d16ebcfd215918763903e9619842665cae" 3692 3777 dependencies = [ 3778 + "anyhow", 3693 3779 "n0-error-macros", 3694 3780 "spez", 3695 3781 ] ··· 5968 6054 "axum", 5969 6055 "axum-macros", 5970 6056 "clap", 6057 + "data-encoding", 5971 6058 "futures-util", 5972 6059 "hf-hub", 5973 6060 "iroh", 6061 + "iroh-gossip", 5974 6062 "iroh-ping", 5975 6063 "iroh-tickets", 5976 6064 "keyring", 5977 6065 "owo-colors", 6066 + "postcard", 5978 6067 "reqwest", 5979 6068 "rusqlite", 5980 6069 "rusqlite_migration", ··· 5983 6072 "serde", 5984 6073 "serde_json", 5985 6074 "serial_test", 6075 + "sha2 0.10.9", 5986 6076 "tempfile", 5987 6077 "tilekit", 5988 6078 "tokio",
+11 -1
tilekit/src/accounts.rs
··· 3 3 use std::str::FromStr; 4 4 5 5 use anyhow::Result; 6 - use ed25519_dalek::{SecretKey, SigningKey, VerifyingKey, ed25519::signature::rand_core::OsRng}; 6 + use ed25519_dalek::{ 7 + SecretKey, SigningKey, 8 + ed25519::signature::rand_core::{OsRng, RngCore}, 9 + }; 7 10 use keyring::Entry; 8 11 use ucan::did::Ed25519Did; 9 12 ··· 47 50 let ed_did = Ed25519Did::from_str(did)?; 48 51 Ok(ed_did.0.to_bytes()) 49 52 } 53 + 54 + pub fn get_random_bytes() -> [u8; 16] { 55 + let mut value = [0u8; 16]; 56 + OsRng.fill_bytes(&mut value); 57 + value 58 + } 59 + 50 60 #[cfg(test)] 51 61 mod tests { 52 62 use keyring::{mock, set_default_credential_builder};
+4
tiles/Cargo.toml
··· 25 25 iroh-ping = "0.9.0" 26 26 iroh-tickets = "0.4.0" 27 27 axum-macros = "0.5.0" 28 + iroh-gossip = "0.97.0" 29 + postcard = "1.1.3" 30 + data-encoding = "2.10.0" 31 + sha2 = "0.10.9" 28 32 29 33 [dev-dependencies] 30 34 tempfile = "3"
+2 -2
tiles/src/core/accounts.rs
··· 23 23 pub nickname: String, 24 24 } 25 25 26 - #[derive(Debug)] 26 + #[derive(Debug, Clone)] 27 27 pub enum ACCOUNT { 28 28 LOCAL, 29 29 } ··· 61 61 62 62 //TODO: add doc, mirrors user table schema 63 63 #[allow(dead_code)] 64 - #[derive(Debug)] 64 + #[derive(Debug, Clone)] 65 65 pub struct User { 66 66 pub id: uuid::Uuid, 67 67 pub user_id: String,
+1
tiles/src/core/mod.rs
··· 12 12 pub mod health; 13 13 pub mod network; 14 14 pub mod storage; 15 + 15 16 // Entrypoint of the core 16 17 pub fn init() -> Result<()> { 17 18 init_db()?;
-109
tiles/src/core/network.rs
··· 1 - //! The main module for networking 2 - 3 - use std::{any::Any, str::FromStr}; 4 - 5 - use anyhow::Result; 6 - use iroh::{ 7 - Endpoint, EndpointId, PublicKey, SecretKey, 8 - endpoint::{BindError, presets}, 9 - protocol::Router, 10 - }; 11 - use iroh_ping::Ping; 12 - use iroh_tickets::endpoint::EndpointTicket; 13 - use tilekit::accounts::get_secret_key; 14 - 15 - use crate::core::{ 16 - accounts::get_current_user, 17 - storage::db::{DBTYPE, get_db_conn}, 18 - }; 19 - 20 - // Entrypoint of network connection 21 - pub async fn init(ticket: Option<&str>) -> Result<()> { 22 - if let Some(ticket_addr) = ticket { 23 - let sender_endpoint = Endpoint::bind(presets::N0).await?; 24 - println!("{:?}", sender_endpoint.addr()); 25 - let se_clone = sender_endpoint.clone(); 26 - let send_pinger = Ping::new(); 27 - let rtt = send_pinger 28 - .ping( 29 - &sender_endpoint, 30 - EndpointTicket::from_str(ticket_addr)? 31 - .endpoint_addr() 32 - .clone(), 33 - ) 34 - .await?; 35 - 36 - println!("ping took: {:?} to complete", rtt); 37 - se_clone.close().await; 38 - } else { 39 - let endpoint = Endpoint::bind(presets::N0).await?; 40 - let ep = endpoint.clone(); 41 - let ep2 = endpoint.clone(); 42 - endpoint.online().await; 43 - 44 - let ping = Ping::new(); 45 - 46 - let ticket = EndpointTicket::new(endpoint.addr()); 47 - 48 - println!("ticket\n{:?}", ticket.to_string()); 49 - 50 - let recv_router = Router::builder(ep).accept(iroh_ping::ALPN, ping).spawn(); 51 - ep2.close().await; 52 - recv_router.shutdown().await?; 53 - } 54 - Ok(()) 55 - } 56 - 57 - pub async fn link(ticket: Option<String>) -> Result<()> { 58 - let ping = Ping::new(); 59 - if let Some(ticket) = ticket { 60 - let endpoint = create_endpoint(false).await?; 61 - endpoint.online().await; 62 - let endpoint_close = endpoint.clone(); 63 - let rtt = ping 64 - .ping( 65 - &endpoint, 66 - EndpointTicket::from_str(&ticket)?.endpoint_addr().clone(), 67 - ) 68 - .await?; 69 - 70 - println!("ping took: {:?} to complete", rtt); 71 - endpoint_close.close().await; 72 - } else { 73 - let endpoint = create_endpoint(true).await?; 74 - endpoint.online().await; 75 - let endpoint_close = endpoint.clone(); 76 - let ticket = EndpointTicket::new(endpoint.addr()); 77 - 78 - println!("ticket\n{:?}", ticket.to_string()); 79 - let recv_router = Router::builder(endpoint) 80 - .accept(iroh_ping::ALPN, ping) 81 - .spawn(); 82 - 83 - tokio::signal::ctrl_c().await?; 84 - recv_router.shutdown().await?; 85 - endpoint_close.close().await; 86 - } 87 - Ok(()) 88 - } 89 - 90 - async fn create_endpoint(use_app_key: bool) -> Result<Endpoint> { 91 - if use_app_key { 92 - let user_db_conn = get_db_conn(DBTYPE::COMMON)?; 93 - let user = get_current_user(&user_db_conn)?; 94 - 95 - let signing_key = get_secret_key("tiles", &user.user_id)?; 96 - 97 - let secret_key = SecretKey::from_bytes(&signing_key); 98 - 99 - Endpoint::builder(presets::N0) 100 - .secret_key(secret_key) 101 - .bind() 102 - .await 103 - .map_err(<BindError as Into<anyhow::Error>>::into) 104 - } else { 105 - Endpoint::bind(presets::N0) 106 - .await 107 - .map_err(<BindError as Into<anyhow::Error>>::into) 108 - } 109 - }
+247
tiles/src/core/network/mod.rs
··· 1 + //! The main module for networking 2 + 3 + pub mod ticket; 4 + use std::{io, str::FromStr}; 5 + 6 + use anyhow::Result; 7 + use futures_util::TryStreamExt; 8 + use iroh::{ 9 + Endpoint, SecretKey, 10 + endpoint::{BindError, presets}, 11 + protocol::Router, 12 + }; 13 + use iroh_gossip::{ 14 + Gossip, TopicId, 15 + api::{Event, GossipReceiver, GossipSender}, 16 + }; 17 + use iroh_ping::Ping; 18 + use iroh_tickets::endpoint::EndpointTicket; 19 + use tilekit::accounts::{get_random_bytes, get_secret_key}; 20 + 21 + use crate::core::{ 22 + accounts::{self, get_current_user}, 23 + network::ticket::LinkTicket, 24 + storage::db::{DBTYPE, get_db_conn}, 25 + }; 26 + use sha2::{Digest, Sha256}; 27 + 28 + #[derive(serde::Serialize, serde::Deserialize)] 29 + struct NetworkMessage { 30 + body: MessageBody, 31 + 32 + // to prevent iroh's deduplication on same msg 33 + nonce: [u8; 16], 34 + } 35 + 36 + impl NetworkMessage { 37 + fn new(body: MessageBody) -> Self { 38 + Self { 39 + body, 40 + nonce: get_random_bytes(), 41 + } 42 + } 43 + fn from_bytes(bytes: &[u8]) -> Result<Self> { 44 + postcard::from_bytes(bytes).map_err(Into::into) 45 + } 46 + fn to_bytes(&self) -> Vec<u8> { 47 + postcard::to_stdvec(&self).expect("Failed to convert to bytes w postcard") 48 + } 49 + } 50 + 51 + #[derive(serde::Serialize, serde::Deserialize)] 52 + enum MessageBody { 53 + LinkRequest { did: String, nickname: String }, 54 + LinkAccepted { did: String, nickname: String }, 55 + LinkRejected { did: String, nickname: String }, 56 + } 57 + 58 + // Entrypoint of network connection 59 + pub async fn init(ticket: Option<&str>) -> Result<()> { 60 + if let Some(ticket_addr) = ticket { 61 + let sender_endpoint = Endpoint::bind(presets::N0).await?; 62 + println!("{:?}", sender_endpoint.addr()); 63 + let se_clone = sender_endpoint.clone(); 64 + let send_pinger = Ping::new(); 65 + let rtt = send_pinger 66 + .ping( 67 + &sender_endpoint, 68 + EndpointTicket::from_str(ticket_addr)? 69 + .endpoint_addr() 70 + .clone(), 71 + ) 72 + .await?; 73 + 74 + println!("ping took: {:?} to complete", rtt); 75 + se_clone.close().await; 76 + } else { 77 + let endpoint = Endpoint::bind(presets::N0).await?; 78 + let ep = endpoint.clone(); 79 + let ep2 = endpoint.clone(); 80 + endpoint.online().await; 81 + 82 + let ping = Ping::new(); 83 + 84 + let ticket = EndpointTicket::new(endpoint.addr()); 85 + 86 + println!("ticket\n{:?}", ticket.to_string()); 87 + 88 + let recv_router = Router::builder(ep).accept(iroh_ping::ALPN, ping).spawn(); 89 + ep2.close().await; 90 + recv_router.shutdown().await?; 91 + } 92 + Ok(()) 93 + } 94 + 95 + pub async fn link(ticket: Option<String>) -> Result<()> { 96 + let user_db_conn = get_db_conn(DBTYPE::COMMON)?; 97 + let user = get_current_user(&user_db_conn)?; 98 + if let Some(ticket) = ticket { 99 + let link_ticket = LinkTicket::from_str(&ticket)?; 100 + 101 + let endpoint = create_endpoint(false, &user).await?; 102 + endpoint.online().await; 103 + let gossip = Gossip::builder().spawn(endpoint.clone()); 104 + 105 + let recv_router = Router::builder(endpoint.clone()) 106 + .accept(iroh_gossip::ALPN, gossip.clone()) 107 + .spawn(); 108 + 109 + let (sender, mut receiver) = gossip 110 + .subscribe(link_ticket.topic_id, vec![link_ticket.addr.id]) 111 + .await? 112 + .split(); 113 + 114 + println!( 115 + "Connecting to {}({}).....", 116 + link_ticket.nickname, link_ticket.did 117 + ); 118 + receiver.joined().await?; 119 + tokio::spawn(subsribe_loop(receiver, sender.clone(), user.clone())); 120 + 121 + let link_req_msg = NetworkMessage::new(MessageBody::LinkRequest { 122 + did: user.user_id, 123 + nickname: user.username, 124 + }); 125 + sender.broadcast(link_req_msg.to_bytes().into()).await?; 126 + 127 + println!( 128 + "Sent link request to {}({})", 129 + link_ticket.nickname, link_ticket.did 130 + ); 131 + 132 + println!("Waiting for response..."); 133 + tokio::signal::ctrl_c().await?; 134 + recv_router.shutdown().await?; 135 + endpoint.close().await; 136 + } else { 137 + let endpoint = create_endpoint(false, &user).await?; 138 + endpoint.online().await; 139 + 140 + let gossip = Gossip::builder().spawn(endpoint.clone()); 141 + 142 + let recv_router = Router::builder(endpoint.clone()) 143 + .accept(iroh_gossip::ALPN, gossip.clone()) 144 + .spawn(); 145 + 146 + let topic_id = create_topic_id("com.tilesprivacy.tiles.link"); 147 + 148 + let (sender, receiver) = gossip.subscribe(topic_id, vec![]).await?.split(); 149 + 150 + let ticket = LinkTicket::new( 151 + topic_id, 152 + endpoint.addr(), 153 + user.user_id.clone(), 154 + user.username.clone(), 155 + ); 156 + 157 + println!("Link Ticket: {:?}\n", ticket.to_string()); 158 + println!( 159 + "Use this link ticket with `tiles link <ticket>` on the system you want to connect to\n" 160 + ); 161 + 162 + println!("Don't close this session until the link process is done\n"); 163 + 164 + tokio::spawn(subsribe_loop(receiver, sender.clone(), user.clone())); 165 + tokio::signal::ctrl_c().await?; 166 + recv_router.shutdown().await?; 167 + endpoint.close().await; 168 + } 169 + Ok(()) 170 + } 171 + 172 + async fn subsribe_loop( 173 + mut receiver: GossipReceiver, 174 + sender: GossipSender, 175 + user: accounts::User, 176 + ) -> Result<()> { 177 + while let Some(event) = receiver.try_next().await? { 178 + // println!("some event {:?}", event); 179 + if let Event::Received(msg) = event { 180 + match NetworkMessage::from_bytes(&msg.content)?.body { 181 + MessageBody::LinkRequest { did, nickname } => { 182 + println!( 183 + "Received link request from {}({}), Do you want to link Y/N", 184 + nickname, did 185 + ); 186 + let stdin = io::stdin(); 187 + let mut input = String::new(); 188 + stdin.read_line(&mut input)?; 189 + input = input.trim().to_owned(); 190 + let link_res_resp = if input.to_lowercase() == "y" { 191 + // TODO: Add the device to DB 192 + 193 + NetworkMessage::new(MessageBody::LinkAccepted { 194 + did: user.user_id.clone(), 195 + nickname: user.username.clone(), 196 + }) 197 + } else { 198 + println!("You can exit now by ctrl-c"); 199 + NetworkMessage::new(MessageBody::LinkRejected { 200 + did: user.user_id.clone(), 201 + nickname: user.username.clone(), 202 + }) 203 + }; 204 + input.clear(); 205 + sender.broadcast(link_res_resp.to_bytes().into()).await?; 206 + } 207 + MessageBody::LinkAccepted { did, nickname } => { 208 + println!("Link accepted by {}({})", nickname, did); 209 + // But shouldn't we add the incoming user to DB? 210 + println!("You can exit now by ctrl-c"); 211 + } 212 + MessageBody::LinkRejected { did, nickname } => { 213 + println!( 214 + "Oops looks like your link request has been rejected by {}({}), exit (ctrl-c) and try again", 215 + nickname, did 216 + ); 217 + } 218 + } 219 + } 220 + } 221 + Ok(()) 222 + } 223 + 224 + async fn create_endpoint(use_app_key: bool, user: &accounts::User) -> Result<Endpoint> { 225 + if use_app_key { 226 + let signing_key = get_secret_key("tiles", &user.user_id)?; 227 + 228 + let secret_key = SecretKey::from_bytes(&signing_key); 229 + 230 + Endpoint::builder(presets::N0) 231 + .secret_key(secret_key) 232 + .bind() 233 + .await 234 + .map_err(<BindError as Into<anyhow::Error>>::into) 235 + } else { 236 + Endpoint::bind(presets::N0) 237 + .await 238 + .map_err(<BindError as Into<anyhow::Error>>::into) 239 + } 240 + } 241 + 242 + fn create_topic_id(topic_name: &str) -> TopicId { 243 + let mut hasher = Sha256::new(); 244 + hasher.update(topic_name.as_bytes()); 245 + let topic_id_bytes = hasher.finalize(); 246 + TopicId::from_bytes(topic_id_bytes.into()) 247 + }
+54
tiles/src/core/network/ticket.rs
··· 1 + //! Tickets for Networking 2 + use std::{fmt::Display, str::FromStr}; 3 + 4 + use iroh::EndpointAddr; 5 + use iroh_gossip::TopicId; 6 + use iroh_tickets::Ticket; 7 + 8 + //TODO: Add tests 9 + #[derive(serde::Serialize, serde::Deserialize, Debug)] 10 + pub struct LinkTicket { 11 + pub nickname: String, 12 + pub did: String, 13 + pub addr: EndpointAddr, 14 + pub topic_id: TopicId, 15 + } 16 + 17 + impl Ticket for LinkTicket { 18 + const KIND: &'static str = "link"; 19 + 20 + fn to_bytes(&self) -> Vec<u8> { 21 + postcard::to_stdvec(&self).expect("serde_json to bytes couldnt be done") 22 + } 23 + 24 + fn from_bytes(bytes: &[u8]) -> Result<Self, iroh_tickets::ParseError> { 25 + postcard::from_bytes(bytes).map_err(Into::into) 26 + } 27 + } 28 + 29 + impl Display for LinkTicket { 30 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 31 + let mut text = data_encoding::BASE32_NOPAD.encode(&self.to_bytes()[..]); 32 + text.make_ascii_lowercase(); 33 + write!(f, "{}", text) 34 + } 35 + } 36 + 37 + impl FromStr for LinkTicket { 38 + type Err = anyhow::Error; 39 + fn from_str(s: &str) -> Result<Self, Self::Err> { 40 + let ticket_bytes = data_encoding::BASE32_NOPAD.decode(s.to_uppercase().as_bytes())?; 41 + LinkTicket::from_bytes(&ticket_bytes).map_err(Into::into) 42 + } 43 + } 44 + 45 + impl LinkTicket { 46 + pub fn new(topic_id: TopicId, addr: EndpointAddr, did: String, nickname: String) -> Self { 47 + LinkTicket { 48 + addr, 49 + topic_id, 50 + did, 51 + nickname, 52 + } 53 + } 54 + }
+15 -26
tiles/src/daemon.rs
··· 7 7 }; 8 8 9 9 use anyhow::{Result, anyhow}; 10 - use axum::{ 11 - Router, 12 - extract::{Query, State}, 13 - response::IntoResponse, 14 - routing::get, 15 - }; 16 - use axum_macros::debug_handler; 10 + use axum::{Router, extract::State, routing::get}; 17 11 use reqwest::Client; 18 12 use std::fs::OpenOptions; 19 13 use std::sync::Mutex; 20 14 use tokio::sync::oneshot::{self, Receiver}; 21 15 22 - use crate::{ 23 - core::network, 24 - utils::config::{ConfigProvider, DefaultProvider}, 25 - }; 16 + use crate::utils::config::{ConfigProvider, DefaultProvider}; 26 17 27 18 struct AppState { 28 19 pub shutdown_sender: Mutex<Option<oneshot::Sender<bool>>>, 29 20 } 30 21 31 - #[derive(serde::Deserialize)] 32 - pub struct SendParams { 33 - ticket: String, 34 - } 22 + // #[derive(serde::Deserialize)] 23 + // pub struct SendParams { 24 + // ticket: String, 25 + // } 35 26 36 27 const DEFAULT_PORT: u32 = 1729; 37 28 pub async fn start_cmd(port: Option<u32>) -> Result<()> { ··· 89 80 let app = Router::new() 90 81 .route("/", get(root)) 91 82 .route("/shutdown", get(shutdown)) 92 - .route("/link/sender", get(send_ping)) 93 - .route("/link/receiver", get(receive_ping)) 94 83 .with_state(shared_state); 95 84 96 85 let addr = format!("127.0.0.1:{}", dyn_port); ··· 115 104 let _ = sender_real.send(true); 116 105 } 117 106 118 - #[debug_handler] 119 - async fn send_ping(State(_state): State<Arc<AppState>>, Query(params): Query<SendParams>) { 120 - println!("Trying to send ping"); 121 - let _ = network::init(Some(&params.ticket)).await; 122 - } 107 + // #[debug_handler] 108 + // async fn send_ping(State(_state): State<Arc<AppState>>, Query(params): Query<SendParams>) { 109 + // println!("Trying to send ping"); 110 + // let _ = network::init(Some(&params.ticket)).await; 111 + // } 123 112 124 - async fn receive_ping(State(_state): State<Arc<AppState>>) { 125 - println!("Trying to receive ping"); 126 - let _ = network::init(None).await; 127 - } 113 + // async fn receive_ping(State(_state): State<Arc<AppState>>) { 114 + // println!("Trying to receive ping"); 115 + // let _ = network::init(None).await; 116 + // } 128 117 129 118 async fn stop_server(port: Option<u32>) -> Result<()> { 130 119 let dyn_port = get_port(port);
+2
tiles/src/main.rs
··· 62 62 /// Daemon configurations 63 63 Daemon(DaemonArgs), 64 64 65 + /// Link with other devices p2p 65 66 Link { 67 + /// The ticket from a peer which can be used to link to it 66 68 ticket: Option<String>, 67 69 }, 68 70 }