diff --git a/.gitignore b/.gitignore index eb5a316..04963b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ target +.* +!.gitignore +*.log diff --git a/Cargo.lock b/Cargo.lock index 6610b43..991a1e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3377,6 +3377,7 @@ dependencies = [ "crossterm 0.28.1", "directories", "futures", + "hex", "iroh", "iroh-gossip", "libspa", diff --git a/Cargo.toml b/Cargo.toml index ae79fec..5c145ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ rust-embed = "8.11.0" futures = "0.3.31" tower-http = { version = "0.6.8", features = ["fs", "cors"] } mime_guess = "2.0.5" +hex = "0.4.3" [profile.dev] opt-level = 0 diff --git a/p2p-chat.log b/p2p-chat.log index b402d4f..d9bf10c 100644 --- a/p2p-chat.log +++ b/p2p-chat.log @@ -322,3 +322,854 @@ 2026-02-11T17:17:42.956205Z INFO p2p_chat::web: Web interface listening on http://127.0.0.1:6969 2026-02-11T17:18:06.892422Z WARN p2p_chat::media::voice: Failed to open voice stream to 5b21d1120a04f6c9647ab3354ad75ce305f4f4dc3b5cc9cb93eeae70778cd12f: Failed to connect for media stream 2026-02-11T17:18:06.893138Z WARN iroh_quinn_proto::connection: remote server configuration might cause nat traversal issues max_local_addresses=12 remote_cid_limit=5 +2026-02-11T18:39:58.473658Z INFO p2p_chat::web: Web interface listening on http://127.0.0.1:6969 +2026-02-11T18:40:13.772092Z WARN iroh_quinn_proto::connection: remote server configuration might cause nat traversal issues max_local_addresses=12 remote_cid_limit=5 +2026-02-11T18:40:13.772230Z WARN p2p_chat::media::voice: Failed to connect to 3a7b7ec20d4849401e91c6b55f4dfef8f99b1ec1c8cc691cdd4a2c9bec59fd08: Connecting to ourself is not supported +2026-02-11T18:41:16.716685Z ERROR p2p_chat::media::capture: Video sender web error: Failed to connect for media stream +2026-02-11T18:41:16.717142Z WARN iroh_quinn_proto::connection: remote server configuration might cause nat traversal issues max_local_addresses=12 remote_cid_limit=5 +2026-02-11T18:41:25.122014Z DEBUG p2p_chat::web: Received screen frame: 182383 bytes +2026-02-11T18:41:25.243696Z DEBUG p2p_chat::web: Received screen frame: 209812 bytes +2026-02-11T18:41:25.364354Z DEBUG p2p_chat::web: Received screen frame: 216944 bytes +2026-02-11T18:41:25.479857Z DEBUG p2p_chat::web: Received screen frame: 218669 bytes +2026-02-11T18:41:25.596949Z DEBUG p2p_chat::web: Received screen frame: 219106 bytes +2026-02-11T18:41:25.713581Z DEBUG p2p_chat::web: Received screen frame: 219191 bytes +2026-02-11T18:41:25.832145Z DEBUG p2p_chat::web: Received screen frame: 221689 bytes +2026-02-11T18:41:25.950052Z DEBUG p2p_chat::web: Received screen frame: 222840 bytes +2026-02-11T18:41:26.068819Z DEBUG p2p_chat::web: Received screen frame: 223610 bytes +2026-02-11T18:41:26.187067Z DEBUG p2p_chat::web: Received screen frame: 223689 bytes +2026-02-11T18:41:26.301630Z DEBUG p2p_chat::web: Received screen frame: 223685 bytes +2026-02-11T18:41:26.406760Z DEBUG p2p_chat::web: Received screen frame: 223645 bytes +2026-02-11T18:41:26.510385Z DEBUG p2p_chat::web: Received screen frame: 223679 bytes +2026-02-11T18:41:26.615103Z DEBUG p2p_chat::web: Received screen frame: 223634 bytes +2026-02-11T18:41:26.720231Z DEBUG p2p_chat::web: Received screen frame: 223544 bytes +2026-02-11T18:41:26.823479Z DEBUG p2p_chat::web: Received screen frame: 223599 bytes +2026-02-11T18:41:26.929115Z DEBUG p2p_chat::web: Received screen frame: 223588 bytes +2026-02-11T18:41:27.033126Z DEBUG p2p_chat::web: Received screen frame: 223572 bytes +2026-02-11T18:41:27.138465Z DEBUG p2p_chat::web: Received screen frame: 223600 bytes +2026-02-11T18:41:27.244020Z DEBUG p2p_chat::web: Received screen frame: 223618 bytes +2026-02-11T18:41:27.348777Z DEBUG p2p_chat::web: Received screen frame: 223721 bytes +2026-02-11T18:41:27.453996Z DEBUG p2p_chat::web: Received screen frame: 223690 bytes +2026-02-11T18:41:27.559331Z DEBUG p2p_chat::web: Received screen frame: 223544 bytes +2026-02-11T18:41:27.664529Z DEBUG p2p_chat::web: Received screen frame: 223611 bytes +2026-02-11T18:41:27.768239Z DEBUG p2p_chat::web: Received screen frame: 223547 bytes +2026-02-11T18:41:27.874268Z DEBUG p2p_chat::web: Received screen frame: 223603 bytes +2026-02-11T18:41:27.979298Z DEBUG p2p_chat::web: Received screen frame: 223579 bytes +2026-02-11T18:41:28.087243Z DEBUG p2p_chat::web: Received screen frame: 223665 bytes +2026-02-11T18:41:28.190619Z DEBUG p2p_chat::web: Received screen frame: 223622 bytes +2026-02-11T18:41:28.296934Z DEBUG p2p_chat::web: Received screen frame: 223642 bytes +2026-02-11T18:41:28.401229Z DEBUG p2p_chat::web: Received screen frame: 223635 bytes +2026-02-11T18:41:28.506496Z DEBUG p2p_chat::web: Received screen frame: 223680 bytes +2026-02-11T18:41:28.611644Z DEBUG p2p_chat::web: Received screen frame: 223666 bytes +2026-02-11T18:41:28.717121Z DEBUG p2p_chat::web: Received screen frame: 223648 bytes +2026-02-11T18:41:28.821983Z DEBUG p2p_chat::web: Received screen frame: 223665 bytes +2026-02-11T18:41:28.928389Z DEBUG p2p_chat::web: Received screen frame: 223744 bytes +2026-02-11T18:41:29.032087Z DEBUG p2p_chat::web: Received screen frame: 223665 bytes +2026-02-11T18:41:29.138735Z DEBUG p2p_chat::web: Received screen frame: 223682 bytes +2026-02-11T18:41:29.242375Z DEBUG p2p_chat::web: Received screen frame: 223716 bytes +2026-02-11T18:41:29.350115Z DEBUG p2p_chat::web: Received screen frame: 223584 bytes +2026-02-11T18:41:29.455261Z DEBUG p2p_chat::web: Received screen frame: 223613 bytes +2026-02-11T18:41:29.561545Z DEBUG p2p_chat::web: Received screen frame: 223599 bytes +2026-02-11T18:41:29.666409Z DEBUG p2p_chat::web: Received screen frame: 223590 bytes +2026-02-11T18:41:29.771271Z DEBUG p2p_chat::web: Received screen frame: 223612 bytes +2026-02-11T18:41:29.876019Z DEBUG p2p_chat::web: Received screen frame: 223553 bytes +2026-02-11T18:41:29.981763Z DEBUG p2p_chat::web: Received screen frame: 223647 bytes +2026-02-11T18:41:30.087648Z DEBUG p2p_chat::web: Received screen frame: 223625 bytes +2026-02-11T18:41:30.191612Z DEBUG p2p_chat::web: Received screen frame: 223663 bytes +2026-02-11T18:41:30.297847Z DEBUG p2p_chat::web: Received screen frame: 223584 bytes +2026-02-11T18:41:30.402535Z DEBUG p2p_chat::web: Received screen frame: 223589 bytes +2026-02-11T18:41:30.512422Z DEBUG p2p_chat::web: Received screen frame: 221302 bytes +2026-02-11T18:41:30.612878Z DEBUG p2p_chat::web: Received screen frame: 220042 bytes +2026-02-11T18:41:30.720806Z DEBUG p2p_chat::web: Received screen frame: 221618 bytes +2026-02-11T18:41:30.824421Z DEBUG p2p_chat::web: Received screen frame: 222976 bytes +2026-02-11T18:41:30.931141Z DEBUG p2p_chat::web: Received screen frame: 223586 bytes +2026-02-11T18:41:31.034749Z DEBUG p2p_chat::web: Received screen frame: 223618 bytes +2026-02-11T18:41:31.140073Z DEBUG p2p_chat::web: Received screen frame: 223652 bytes +2026-02-11T18:41:31.245215Z DEBUG p2p_chat::web: Received screen frame: 223559 bytes +2026-02-11T18:41:31.351699Z DEBUG p2p_chat::web: Received screen frame: 223653 bytes +2026-02-11T18:41:31.455860Z DEBUG p2p_chat::web: Received screen frame: 223697 bytes +2026-02-11T18:41:31.561914Z DEBUG p2p_chat::web: Received screen frame: 223697 bytes +2026-02-11T18:41:31.666962Z DEBUG p2p_chat::web: Received screen frame: 223698 bytes +2026-02-11T18:41:31.772827Z DEBUG p2p_chat::web: Received screen frame: 223615 bytes +2026-02-11T18:41:31.877268Z DEBUG p2p_chat::web: Received screen frame: 223613 bytes +2026-02-11T18:41:31.983654Z DEBUG p2p_chat::web: Received screen frame: 223660 bytes +2026-02-11T18:41:32.088342Z DEBUG p2p_chat::web: Received screen frame: 223640 bytes +2026-02-11T18:41:32.193695Z DEBUG p2p_chat::web: Received screen frame: 223636 bytes +2026-02-11T18:41:32.299046Z DEBUG p2p_chat::web: Received screen frame: 223617 bytes +2026-02-11T18:41:32.405260Z DEBUG p2p_chat::web: Received screen frame: 223594 bytes +2026-02-11T18:41:32.510162Z DEBUG p2p_chat::web: Received screen frame: 223576 bytes +2026-02-11T18:41:32.616954Z DEBUG p2p_chat::web: Received screen frame: 223578 bytes +2026-02-11T18:41:32.721177Z DEBUG p2p_chat::web: Received screen frame: 225355 bytes +2026-02-11T18:41:32.825860Z DEBUG p2p_chat::web: Received screen frame: 225812 bytes +2026-02-11T18:41:32.932723Z DEBUG p2p_chat::web: Received screen frame: 223717 bytes +2026-02-11T18:41:33.037903Z DEBUG p2p_chat::web: Received screen frame: 223714 bytes +2026-02-11T18:41:33.143272Z DEBUG p2p_chat::web: Received screen frame: 223653 bytes +2026-02-11T18:41:33.249096Z DEBUG p2p_chat::web: Received screen frame: 223611 bytes +2026-02-11T18:41:33.353841Z DEBUG p2p_chat::web: Received screen frame: 223664 bytes +2026-02-11T18:41:33.459460Z DEBUG p2p_chat::web: Received screen frame: 223642 bytes +2026-02-11T18:41:33.567995Z DEBUG p2p_chat::web: Received screen frame: 223592 bytes +2026-02-11T18:41:33.674510Z DEBUG p2p_chat::web: Received screen frame: 220692 bytes +2026-02-11T18:41:33.778558Z DEBUG p2p_chat::web: Received screen frame: 219723 bytes +2026-02-11T18:41:33.885290Z DEBUG p2p_chat::web: Received screen frame: 219352 bytes +2026-02-11T18:41:33.989870Z DEBUG p2p_chat::web: Received screen frame: 219241 bytes +2026-02-11T18:41:34.096729Z DEBUG p2p_chat::web: Received screen frame: 219856 bytes +2026-02-11T18:41:34.201953Z DEBUG p2p_chat::web: Received screen frame: 221850 bytes +2026-02-11T18:41:34.308201Z DEBUG p2p_chat::web: Received screen frame: 223099 bytes +2026-02-11T18:41:34.686202Z DEBUG p2p_chat::web: Received screen frame: 223080 bytes +2026-02-11T18:41:34.687243Z DEBUG p2p_chat::web: Received screen frame: 226911 bytes +2026-02-11T18:41:34.688097Z DEBUG p2p_chat::web: Received screen frame: 227655 bytes +2026-02-11T18:41:34.743531Z DEBUG p2p_chat::web: Received screen frame: 241398 bytes +2026-02-11T18:41:34.851941Z DEBUG p2p_chat::web: Received screen frame: 254844 bytes +2026-02-11T18:41:34.959204Z DEBUG p2p_chat::web: Received screen frame: 262377 bytes +2026-02-11T18:41:35.065795Z DEBUG p2p_chat::web: Received screen frame: 265852 bytes +2026-02-11T18:41:35.173073Z DEBUG p2p_chat::web: Received screen frame: 266830 bytes +2026-02-11T18:41:35.281644Z DEBUG p2p_chat::web: Received screen frame: 267227 bytes +2026-02-11T18:41:35.405711Z DEBUG p2p_chat::web: Received screen frame: 267280 bytes +2026-02-11T18:41:35.496485Z DEBUG p2p_chat::web: Received screen frame: 242916 bytes +2026-02-11T18:41:35.660448Z DEBUG p2p_chat::web: Received screen frame: 249329 bytes +2026-02-11T18:41:35.722519Z DEBUG p2p_chat::web: Received screen frame: 240512 bytes +2026-02-11T18:41:35.838628Z DEBUG p2p_chat::web: Received screen frame: 237482 bytes +2026-02-11T18:41:35.923884Z DEBUG p2p_chat::web: Received screen frame: 238205 bytes +2026-02-11T18:41:36.028459Z DEBUG p2p_chat::web: Received screen frame: 239035 bytes +2026-02-11T18:41:36.143605Z DEBUG p2p_chat::web: Received screen frame: 238337 bytes +2026-02-11T18:41:36.243716Z DEBUG p2p_chat::web: Received screen frame: 232931 bytes +2026-02-11T18:41:36.354441Z DEBUG p2p_chat::web: Received screen frame: 228575 bytes +2026-02-11T18:41:36.451358Z DEBUG p2p_chat::web: Received screen frame: 223089 bytes +2026-02-11T18:41:36.557866Z DEBUG p2p_chat::web: Received screen frame: 221251 bytes +2026-02-11T18:41:37.034296Z DEBUG p2p_chat::web: Received screen frame: 223082 bytes +2026-02-11T18:41:37.329895Z DEBUG p2p_chat::web: Received screen frame: 227691 bytes +2026-02-11T18:41:37.330902Z DEBUG p2p_chat::web: Received screen frame: 231189 bytes +2026-02-11T18:41:37.533451Z DEBUG p2p_chat::web: Received screen frame: 222792 bytes +2026-02-11T18:41:37.541520Z DEBUG p2p_chat::web: Received screen frame: 215303 bytes +2026-02-11T18:41:37.566292Z DEBUG p2p_chat::web: Received screen frame: 202797 bytes +2026-02-11T18:41:37.575891Z DEBUG p2p_chat::web: Received screen frame: 200061 bytes +2026-02-11T18:41:37.577723Z DEBUG p2p_chat::web: Received screen frame: 198216 bytes +2026-02-11T18:41:37.593009Z DEBUG p2p_chat::web: Received screen frame: 194772 bytes +2026-02-11T18:41:37.634133Z DEBUG p2p_chat::web: Received screen frame: 191184 bytes +2026-02-11T18:41:37.735606Z DEBUG p2p_chat::web: Received screen frame: 187221 bytes +2026-02-11T18:41:37.848590Z DEBUG p2p_chat::web: Received screen frame: 207179 bytes +2026-02-11T18:41:38.515717Z DEBUG p2p_chat::web: Received screen frame: 206867 bytes +2026-02-11T18:41:38.516643Z DEBUG p2p_chat::web: Received screen frame: 201968 bytes +2026-02-11T18:41:38.633926Z DEBUG p2p_chat::web: Received screen frame: 215140 bytes +2026-02-11T18:41:38.677789Z DEBUG p2p_chat::web: Received screen frame: 218434 bytes +2026-02-11T18:41:38.678378Z DEBUG p2p_chat::web: Received screen frame: 220241 bytes +2026-02-11T18:41:38.765950Z DEBUG p2p_chat::web: Received screen frame: 222171 bytes +2026-02-11T18:41:38.767377Z DEBUG p2p_chat::web: Received screen frame: 232824 bytes +2026-02-11T18:41:38.820719Z DEBUG p2p_chat::web: Received screen frame: 238321 bytes +2026-02-11T18:41:38.822768Z DEBUG p2p_chat::web: Received screen frame: 236952 bytes +2026-02-11T18:41:38.917849Z DEBUG p2p_chat::web: Received screen frame: 244824 bytes +2026-02-11T18:41:39.022517Z DEBUG p2p_chat::web: Received screen frame: 247071 bytes +2026-02-11T18:41:39.257632Z DEBUG p2p_chat::web: Received screen frame: 249469 bytes +2026-02-11T18:41:39.399966Z DEBUG p2p_chat::web: Received screen frame: 236361 bytes +2026-02-11T18:41:39.422767Z DEBUG p2p_chat::web: Received screen frame: 218887 bytes +2026-02-11T18:41:39.594820Z DEBUG p2p_chat::web: Received screen frame: 224886 bytes +2026-02-11T18:41:39.596852Z DEBUG p2p_chat::web: Received screen frame: 218851 bytes +2026-02-11T18:41:39.798827Z DEBUG p2p_chat::web: Received screen frame: 216441 bytes +2026-02-11T18:41:39.800568Z DEBUG p2p_chat::web: Received screen frame: 217201 bytes +2026-02-11T18:41:39.887690Z DEBUG p2p_chat::web: Received screen frame: 212357 bytes +2026-02-11T18:41:39.992458Z DEBUG p2p_chat::web: Received screen frame: 206464 bytes +2026-02-11T18:41:40.208329Z DEBUG p2p_chat::web: Received screen frame: 205358 bytes +2026-02-11T18:41:40.209152Z DEBUG p2p_chat::web: Received screen frame: 207020 bytes +2026-02-11T18:41:40.350493Z DEBUG p2p_chat::web: Received screen frame: 208550 bytes +2026-02-11T18:41:40.476319Z DEBUG p2p_chat::web: Received screen frame: 207981 bytes +2026-02-11T18:41:40.575291Z DEBUG p2p_chat::web: Received screen frame: 217839 bytes +2026-02-11T18:41:40.666104Z DEBUG p2p_chat::web: Received screen frame: 218531 bytes +2026-02-11T18:41:40.756894Z DEBUG p2p_chat::web: Received screen frame: 220663 bytes +2026-02-11T18:41:40.846917Z DEBUG p2p_chat::web: Received screen frame: 223172 bytes +2026-02-11T18:41:40.952981Z DEBUG p2p_chat::web: Received screen frame: 224576 bytes +2026-02-11T18:41:41.057734Z DEBUG p2p_chat::web: Received screen frame: 225038 bytes +2026-02-11T18:41:41.164240Z DEBUG p2p_chat::web: Received screen frame: 225205 bytes +2026-02-11T18:41:41.271497Z DEBUG p2p_chat::web: Received screen frame: 226892 bytes +2026-02-11T18:41:41.376294Z DEBUG p2p_chat::web: Received screen frame: 222107 bytes +2026-02-11T18:41:41.483023Z DEBUG p2p_chat::web: Received screen frame: 219258 bytes +2026-02-11T18:41:41.587958Z DEBUG p2p_chat::web: Received screen frame: 218627 bytes +2026-02-11T18:41:41.692693Z DEBUG p2p_chat::web: Received screen frame: 218316 bytes +2026-02-11T18:41:41.797710Z DEBUG p2p_chat::web: Received screen frame: 218506 bytes +2026-02-11T18:41:41.902179Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:41:42.008459Z DEBUG p2p_chat::web: Received screen frame: 218459 bytes +2026-02-11T18:41:42.114878Z DEBUG p2p_chat::web: Received screen frame: 218399 bytes +2026-02-11T18:41:42.220326Z DEBUG p2p_chat::web: Received screen frame: 218374 bytes +2026-02-11T18:41:42.325116Z DEBUG p2p_chat::web: Received screen frame: 217441 bytes +2026-02-11T18:41:42.429994Z DEBUG p2p_chat::web: Received screen frame: 217184 bytes +2026-02-11T18:41:42.534548Z DEBUG p2p_chat::web: Received screen frame: 217166 bytes +2026-02-11T18:41:42.639361Z DEBUG p2p_chat::web: Received screen frame: 217097 bytes +2026-02-11T18:41:42.745281Z DEBUG p2p_chat::web: Received screen frame: 217136 bytes +2026-02-11T18:41:42.851234Z DEBUG p2p_chat::web: Received screen frame: 217151 bytes +2026-02-11T18:41:42.956668Z DEBUG p2p_chat::web: Received screen frame: 217136 bytes +2026-02-11T18:41:43.062315Z DEBUG p2p_chat::web: Received screen frame: 217138 bytes +2026-02-11T18:41:43.166602Z DEBUG p2p_chat::web: Received screen frame: 217109 bytes +2026-02-11T18:41:43.271117Z DEBUG p2p_chat::web: Received screen frame: 217138 bytes +2026-02-11T18:41:43.376644Z DEBUG p2p_chat::web: Received screen frame: 217109 bytes +2026-02-11T18:41:43.482507Z DEBUG p2p_chat::web: Received screen frame: 217150 bytes +2026-02-11T18:41:43.588467Z DEBUG p2p_chat::web: Received screen frame: 217509 bytes +2026-02-11T18:41:43.692857Z DEBUG p2p_chat::web: Received screen frame: 217574 bytes +2026-02-11T18:41:43.797557Z DEBUG p2p_chat::web: Received screen frame: 217454 bytes +2026-02-11T18:41:43.902122Z DEBUG p2p_chat::web: Received screen frame: 217489 bytes +2026-02-11T18:41:44.007725Z DEBUG p2p_chat::web: Received screen frame: 217511 bytes +2026-02-11T18:41:44.113625Z DEBUG p2p_chat::web: Received screen frame: 217419 bytes +2026-02-11T18:41:44.219722Z DEBUG p2p_chat::web: Received screen frame: 217333 bytes +2026-02-11T18:41:44.325773Z DEBUG p2p_chat::web: Received screen frame: 217415 bytes +2026-02-11T18:41:44.430747Z DEBUG p2p_chat::web: Received screen frame: 217463 bytes +2026-02-11T18:41:44.535744Z DEBUG p2p_chat::web: Received screen frame: 217492 bytes +2026-02-11T18:41:44.640551Z DEBUG p2p_chat::web: Received screen frame: 217368 bytes +2026-02-11T18:41:44.746808Z DEBUG p2p_chat::web: Received screen frame: 217374 bytes +2026-02-11T18:41:44.851753Z DEBUG p2p_chat::web: Received screen frame: 217387 bytes +2026-02-11T18:41:44.957230Z DEBUG p2p_chat::web: Received screen frame: 217302 bytes +2026-02-11T18:41:45.062306Z DEBUG p2p_chat::web: Received screen frame: 217387 bytes +2026-02-11T18:41:45.167333Z DEBUG p2p_chat::web: Received screen frame: 217302 bytes +2026-02-11T18:41:45.272714Z DEBUG p2p_chat::web: Received screen frame: 217387 bytes +2026-02-11T18:41:45.380036Z DEBUG p2p_chat::web: Received screen frame: 217302 bytes +2026-02-11T18:41:45.485038Z DEBUG p2p_chat::web: Received screen frame: 217387 bytes +2026-02-11T18:41:45.590788Z DEBUG p2p_chat::web: Received screen frame: 217302 bytes +2026-02-11T18:41:45.696222Z DEBUG p2p_chat::web: Received screen frame: 217387 bytes +2026-02-11T18:41:45.801822Z DEBUG p2p_chat::web: Received screen frame: 217302 bytes +2026-02-11T18:41:45.907244Z DEBUG p2p_chat::web: Received screen frame: 217387 bytes +2026-02-11T18:41:46.013723Z DEBUG p2p_chat::web: Received screen frame: 217302 bytes +2026-02-11T18:41:46.118658Z DEBUG p2p_chat::web: Received screen frame: 217387 bytes +2026-02-11T18:41:46.224042Z DEBUG p2p_chat::web: Received screen frame: 217302 bytes +2026-02-11T18:41:46.330121Z DEBUG p2p_chat::web: Received screen frame: 217387 bytes +2026-02-11T18:41:46.436612Z DEBUG p2p_chat::web: Received screen frame: 217302 bytes +2026-02-11T18:41:46.541160Z DEBUG p2p_chat::web: Received screen frame: 217387 bytes +2026-02-11T18:41:46.646768Z DEBUG p2p_chat::web: Received screen frame: 217302 bytes +2026-02-11T18:41:46.750156Z DEBUG p2p_chat::web: Received screen frame: 217387 bytes +2026-02-11T18:41:46.857138Z DEBUG p2p_chat::web: Received screen frame: 217302 bytes +2026-02-11T18:41:46.962019Z DEBUG p2p_chat::web: Received screen frame: 217396 bytes +2026-02-11T18:41:47.066857Z DEBUG p2p_chat::web: Received screen frame: 217461 bytes +2026-02-11T18:41:47.171953Z DEBUG p2p_chat::web: Received screen frame: 217462 bytes +2026-02-11T18:41:47.276320Z DEBUG p2p_chat::web: Received screen frame: 217334 bytes +2026-02-11T18:41:47.382458Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:47.487833Z DEBUG p2p_chat::web: Received screen frame: 217507 bytes +2026-02-11T18:41:47.593190Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:47.698867Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:47.803678Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:47.908065Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:48.013650Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:48.120591Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:48.224925Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:48.330786Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:48.440820Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:48.545745Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:48.650225Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:48.755451Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:48.862721Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:48.968290Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:49.072646Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:49.178429Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:49.282564Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:49.387659Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:49.493743Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:49.599592Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:49.705390Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:49.810001Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:49.915229Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:50.019962Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:50.123956Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:50.229909Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:50.335129Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:50.440906Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:50.546288Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:50.651361Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:50.755455Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:50.861015Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:50.965276Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:51.072102Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:51.176631Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:51.282337Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:51.386124Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:51.492588Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:51.598282Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:51.702986Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:51.807795Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:51.913485Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:52.018637Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:52.123776Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:52.228210Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:52.334161Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:52.438776Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:52.544394Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:52.649936Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:52.756721Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:52.861235Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:52.965801Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:53.071818Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:53.176982Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:53.283316Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:53.388249Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:53.496668Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:53.602086Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:53.708019Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:53.811251Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:53.918536Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:54.024246Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:54.128027Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:54.233263Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:54.337920Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:54.442797Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:54.547073Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:54.652754Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:54.757696Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:54.866816Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:54.968443Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:55.073135Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:55.177673Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:55.283753Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:55.389122Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:55.502021Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:55.607176Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:55.710857Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:55.816847Z DEBUG p2p_chat::web: Received screen frame: 217432 bytes +2026-02-11T18:41:55.921998Z DEBUG p2p_chat::web: Received screen frame: 217478 bytes +2026-02-11T18:41:56.028126Z DEBUG p2p_chat::web: Received screen frame: 217421 bytes +2026-02-11T18:41:56.134239Z DEBUG p2p_chat::web: Received screen frame: 217559 bytes +2026-02-11T18:41:56.239524Z DEBUG p2p_chat::web: Received screen frame: 217610 bytes +2026-02-11T18:41:56.344706Z DEBUG p2p_chat::web: Received screen frame: 217450 bytes +2026-02-11T18:41:56.449671Z DEBUG p2p_chat::web: Received screen frame: 217596 bytes +2026-02-11T18:41:56.555442Z DEBUG p2p_chat::web: Received screen frame: 217560 bytes +2026-02-11T18:41:56.661524Z DEBUG p2p_chat::web: Received screen frame: 217585 bytes +2026-02-11T18:41:56.767839Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:56.872574Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:56.977582Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:57.082287Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:57.187728Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:57.293099Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:57.398759Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:57.507133Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:57.611806Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:57.716435Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:57.822357Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:57.926483Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:58.034193Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:58.140996Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:58.246234Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:58.350772Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:58.455849Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:58.561237Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:58.665672Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:58.772439Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:58.878113Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:58.983887Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:59.089084Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:59.193777Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:59.299131Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:59.405056Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:59.513203Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:59.617160Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:59.722057Z DEBUG p2p_chat::web: Received screen frame: 217414 bytes +2026-02-11T18:41:59.826983Z DEBUG p2p_chat::web: Received screen frame: 217433 bytes +2026-02-11T18:41:59.932387Z DEBUG p2p_chat::web: Received screen frame: 217146 bytes +2026-02-11T18:42:00.037568Z DEBUG p2p_chat::web: Received screen frame: 217231 bytes +2026-02-11T18:42:00.144088Z DEBUG p2p_chat::web: Received screen frame: 217068 bytes +2026-02-11T18:42:00.250027Z DEBUG p2p_chat::web: Received screen frame: 217183 bytes +2026-02-11T18:42:00.354202Z DEBUG p2p_chat::web: Received screen frame: 217076 bytes +2026-02-11T18:42:00.459480Z DEBUG p2p_chat::web: Received screen frame: 217131 bytes +2026-02-11T18:42:00.563642Z DEBUG p2p_chat::web: Received screen frame: 217974 bytes +2026-02-11T18:42:00.668563Z DEBUG p2p_chat::web: Received screen frame: 218191 bytes +2026-02-11T18:42:00.773165Z DEBUG p2p_chat::web: Received screen frame: 218195 bytes +2026-02-11T18:42:00.879917Z DEBUG p2p_chat::web: Received screen frame: 218212 bytes +2026-02-11T18:42:00.984844Z DEBUG p2p_chat::web: Received screen frame: 218367 bytes +2026-02-11T18:42:01.089350Z DEBUG p2p_chat::web: Received screen frame: 218279 bytes +2026-02-11T18:42:01.193670Z DEBUG p2p_chat::web: Received screen frame: 218189 bytes +2026-02-11T18:42:01.298898Z DEBUG p2p_chat::web: Received screen frame: 218392 bytes +2026-02-11T18:42:01.403803Z DEBUG p2p_chat::web: Received screen frame: 218190 bytes +2026-02-11T18:42:01.518486Z DEBUG p2p_chat::web: Received screen frame: 218339 bytes +2026-02-11T18:42:01.623225Z DEBUG p2p_chat::web: Received screen frame: 218190 bytes +2026-02-11T18:42:01.728278Z DEBUG p2p_chat::web: Received screen frame: 218339 bytes +2026-02-11T18:42:01.833028Z DEBUG p2p_chat::web: Received screen frame: 218190 bytes +2026-02-11T18:42:01.937988Z DEBUG p2p_chat::web: Received screen frame: 218339 bytes +2026-02-11T18:42:02.043212Z DEBUG p2p_chat::web: Received screen frame: 218253 bytes +2026-02-11T18:42:02.148730Z DEBUG p2p_chat::web: Received screen frame: 218270 bytes +2026-02-11T18:42:02.255047Z DEBUG p2p_chat::web: Received screen frame: 218440 bytes +2026-02-11T18:42:02.360112Z DEBUG p2p_chat::web: Received screen frame: 218353 bytes +2026-02-11T18:42:02.465243Z DEBUG p2p_chat::web: Received screen frame: 218401 bytes +2026-02-11T18:42:02.569723Z DEBUG p2p_chat::web: Received screen frame: 218484 bytes +2026-02-11T18:42:02.674238Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:02.779779Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:02.884571Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:02.990268Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:03.096386Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:03.200774Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:03.305822Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:03.410213Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:03.515090Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:03.619984Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:03.724443Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:03.830870Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:03.935641Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:04.040965Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:04.145060Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:04.250267Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:04.355538Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:04.460563Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:04.566276Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:04.671465Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:04.776849Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:04.881696Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:04.987407Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:05.092136Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:05.197724Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:05.304490Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:05.411219Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:05.524488Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:05.628451Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:05.735584Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:05.840820Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:05.944557Z DEBUG p2p_chat::web: Received screen frame: 218344 bytes +2026-02-11T18:42:06.049997Z DEBUG p2p_chat::web: Received screen frame: 218232 bytes +2026-02-11T18:42:06.155230Z DEBUG p2p_chat::web: Received screen frame: 224033 bytes +2026-02-11T18:42:06.260850Z DEBUG p2p_chat::web: Received screen frame: 226095 bytes +2026-02-11T18:42:06.365900Z DEBUG p2p_chat::web: Received screen frame: 226731 bytes +2026-02-11T18:42:06.472426Z DEBUG p2p_chat::web: Received screen frame: 226927 bytes +2026-02-11T18:42:06.577351Z DEBUG p2p_chat::web: Received screen frame: 226835 bytes +2026-02-11T18:42:06.682141Z DEBUG p2p_chat::web: Received screen frame: 226938 bytes +2026-02-11T18:42:06.786812Z DEBUG p2p_chat::web: Received screen frame: 226970 bytes +2026-02-11T18:42:06.891320Z DEBUG p2p_chat::web: Received screen frame: 226910 bytes +2026-02-11T18:42:06.996610Z DEBUG p2p_chat::web: Received screen frame: 226952 bytes +2026-02-11T18:42:07.101771Z DEBUG p2p_chat::web: Received screen frame: 226963 bytes +2026-02-11T18:42:07.208194Z DEBUG p2p_chat::web: Received screen frame: 226935 bytes +2026-02-11T18:42:07.313019Z DEBUG p2p_chat::web: Received screen frame: 226986 bytes +2026-02-11T18:42:07.418019Z DEBUG p2p_chat::web: Received screen frame: 226872 bytes +2026-02-11T18:42:07.527514Z DEBUG p2p_chat::web: Received screen frame: 227055 bytes +2026-02-11T18:42:07.633084Z DEBUG p2p_chat::web: Received screen frame: 226988 bytes +2026-02-11T18:42:07.739244Z DEBUG p2p_chat::web: Received screen frame: 227044 bytes +2026-02-11T18:42:07.846031Z DEBUG p2p_chat::web: Received screen frame: 227037 bytes +2026-02-11T18:42:07.951333Z DEBUG p2p_chat::web: Received screen frame: 226973 bytes +2026-02-11T18:42:08.057087Z DEBUG p2p_chat::web: Received screen frame: 227058 bytes +2026-02-11T18:42:08.161089Z DEBUG p2p_chat::web: Received screen frame: 227218 bytes +2026-02-11T18:42:08.266749Z DEBUG p2p_chat::web: Received screen frame: 227164 bytes +2026-02-11T18:42:08.372208Z DEBUG p2p_chat::web: Received screen frame: 227197 bytes +2026-02-11T18:42:08.476018Z DEBUG p2p_chat::web: Received screen frame: 227242 bytes +2026-02-11T18:42:08.582556Z DEBUG p2p_chat::web: Received screen frame: 227334 bytes +2026-02-11T18:42:08.687546Z DEBUG p2p_chat::web: Received screen frame: 227389 bytes +2026-02-11T18:42:08.791394Z DEBUG p2p_chat::web: Received screen frame: 228482 bytes +2026-02-11T18:42:08.895889Z DEBUG p2p_chat::web: Received screen frame: 228851 bytes +2026-02-11T18:42:09.000454Z DEBUG p2p_chat::web: Received screen frame: 228970 bytes +2026-02-11T18:42:09.105905Z DEBUG p2p_chat::web: Received screen frame: 228898 bytes +2026-02-11T18:42:09.210711Z DEBUG p2p_chat::web: Received screen frame: 228847 bytes +2026-02-11T18:42:09.317157Z DEBUG p2p_chat::web: Received screen frame: 229006 bytes +2026-02-11T18:42:09.422690Z DEBUG p2p_chat::web: Received screen frame: 228984 bytes +2026-02-11T18:42:09.527527Z DEBUG p2p_chat::web: Received screen frame: 228985 bytes +2026-02-11T18:42:09.632572Z DEBUG p2p_chat::web: Received screen frame: 228902 bytes +2026-02-11T18:42:09.737722Z DEBUG p2p_chat::web: Received screen frame: 229001 bytes +2026-02-11T18:42:09.846373Z DEBUG p2p_chat::web: Received screen frame: 228991 bytes +2026-02-11T18:42:09.950321Z DEBUG p2p_chat::web: Received screen frame: 228832 bytes +2026-02-11T18:42:10.056413Z DEBUG p2p_chat::web: Received screen frame: 228914 bytes +2026-02-11T18:42:10.162228Z DEBUG p2p_chat::web: Received screen frame: 228943 bytes +2026-02-11T18:42:10.266995Z DEBUG p2p_chat::web: Received screen frame: 228885 bytes +2026-02-11T18:42:10.372049Z DEBUG p2p_chat::web: Received screen frame: 228832 bytes +2026-02-11T18:42:10.476450Z DEBUG p2p_chat::web: Received screen frame: 228896 bytes +2026-02-11T18:42:10.581358Z DEBUG p2p_chat::web: Received screen frame: 228832 bytes +2026-02-11T18:42:10.686083Z DEBUG p2p_chat::web: Received screen frame: 229034 bytes +2026-02-11T18:42:10.790414Z DEBUG p2p_chat::web: Received screen frame: 228951 bytes +2026-02-11T18:42:10.896272Z DEBUG p2p_chat::web: Received screen frame: 229005 bytes +2026-02-11T18:42:11.002071Z DEBUG p2p_chat::web: Received screen frame: 228972 bytes +2026-02-11T18:42:11.107000Z DEBUG p2p_chat::web: Received screen frame: 228845 bytes +2026-02-11T18:42:11.210914Z DEBUG p2p_chat::web: Received screen frame: 228888 bytes +2026-02-11T18:42:11.315655Z DEBUG p2p_chat::web: Received screen frame: 228918 bytes +2026-02-11T18:42:11.420868Z DEBUG p2p_chat::web: Received screen frame: 228888 bytes +2026-02-11T18:42:11.534018Z DEBUG p2p_chat::web: Received screen frame: 228856 bytes +2026-02-11T18:42:11.639271Z DEBUG p2p_chat::web: Received screen frame: 228890 bytes +2026-02-11T18:42:11.744398Z DEBUG p2p_chat::web: Received screen frame: 228970 bytes +2026-02-11T18:42:11.848768Z DEBUG p2p_chat::web: Received screen frame: 228995 bytes +2026-02-11T18:42:11.952855Z DEBUG p2p_chat::web: Received screen frame: 228957 bytes +2026-02-11T18:42:12.057091Z DEBUG p2p_chat::web: Received screen frame: 229116 bytes +2026-02-11T18:42:12.161868Z DEBUG p2p_chat::web: Received screen frame: 229044 bytes +2026-02-11T18:42:12.266904Z DEBUG p2p_chat::web: Received screen frame: 229059 bytes +2026-02-11T18:42:12.371648Z DEBUG p2p_chat::web: Received screen frame: 229053 bytes +2026-02-11T18:42:12.478569Z DEBUG p2p_chat::web: Received screen frame: 229003 bytes +2026-02-11T18:42:12.583347Z DEBUG p2p_chat::web: Received screen frame: 228904 bytes +2026-02-11T18:42:12.688309Z DEBUG p2p_chat::web: Received screen frame: 228902 bytes +2026-02-11T18:42:12.792927Z DEBUG p2p_chat::web: Received screen frame: 228825 bytes +2026-02-11T18:42:12.897860Z DEBUG p2p_chat::web: Received screen frame: 228769 bytes +2026-02-11T18:42:13.002171Z DEBUG p2p_chat::web: Received screen frame: 228751 bytes +2026-02-11T18:42:13.108301Z DEBUG p2p_chat::web: Received screen frame: 228892 bytes +2026-02-11T18:42:13.214568Z DEBUG p2p_chat::web: Received screen frame: 228815 bytes +2026-02-11T18:42:13.319048Z DEBUG p2p_chat::web: Received screen frame: 228902 bytes +2026-02-11T18:42:13.423633Z DEBUG p2p_chat::web: Received screen frame: 228917 bytes +2026-02-11T18:42:13.539744Z DEBUG p2p_chat::web: Received screen frame: 228812 bytes +2026-02-11T18:42:13.643961Z DEBUG p2p_chat::web: Received screen frame: 227657 bytes +2026-02-11T18:42:13.752143Z DEBUG p2p_chat::web: Received screen frame: 226992 bytes +2026-02-11T18:42:13.856141Z DEBUG p2p_chat::web: Received screen frame: 226525 bytes +2026-02-11T18:42:13.961194Z DEBUG p2p_chat::web: Received screen frame: 226507 bytes +2026-02-11T18:42:14.065801Z DEBUG p2p_chat::web: Received screen frame: 226672 bytes +2026-02-11T18:42:14.171041Z DEBUG p2p_chat::web: Received screen frame: 226677 bytes +2026-02-11T18:42:14.277240Z DEBUG p2p_chat::web: Received screen frame: 226627 bytes +2026-02-11T18:42:14.380450Z DEBUG p2p_chat::web: Received screen frame: 226569 bytes +2026-02-11T18:42:14.487352Z DEBUG p2p_chat::web: Received screen frame: 226591 bytes +2026-02-11T18:42:14.595123Z DEBUG p2p_chat::web: Received screen frame: 225380 bytes +2026-02-11T18:42:14.699358Z DEBUG p2p_chat::web: Received screen frame: 227803 bytes +2026-02-11T18:42:14.804065Z DEBUG p2p_chat::web: Received screen frame: 228472 bytes +2026-02-11T18:42:14.909503Z DEBUG p2p_chat::web: Received screen frame: 228898 bytes +2026-02-11T18:42:15.013694Z DEBUG p2p_chat::web: Received screen frame: 229000 bytes +2026-02-11T18:42:15.118704Z DEBUG p2p_chat::web: Received screen frame: 228907 bytes +2026-02-11T18:42:15.223937Z DEBUG p2p_chat::web: Received screen frame: 228809 bytes +2026-02-11T18:42:15.329739Z DEBUG p2p_chat::web: Received screen frame: 228825 bytes +2026-02-11T18:42:15.435174Z DEBUG p2p_chat::web: Received screen frame: 228747 bytes +2026-02-11T18:42:15.543591Z DEBUG p2p_chat::web: Received screen frame: 228717 bytes +2026-02-11T18:42:15.649145Z DEBUG p2p_chat::web: Received screen frame: 228939 bytes +2026-02-11T18:42:15.754085Z DEBUG p2p_chat::web: Received screen frame: 228958 bytes +2026-02-11T18:42:15.860482Z DEBUG p2p_chat::web: Received screen frame: 228851 bytes +2026-02-11T18:42:15.964993Z DEBUG p2p_chat::web: Received screen frame: 228956 bytes +2026-02-11T18:42:16.069982Z DEBUG p2p_chat::web: Received screen frame: 228987 bytes +2026-02-11T18:42:16.174393Z DEBUG p2p_chat::web: Received screen frame: 229045 bytes +2026-02-11T18:42:16.279100Z DEBUG p2p_chat::web: Received screen frame: 229083 bytes +2026-02-11T18:42:16.383084Z DEBUG p2p_chat::web: Received screen frame: 229199 bytes +2026-02-11T18:42:16.489158Z DEBUG p2p_chat::web: Received screen frame: 229113 bytes +2026-02-11T18:42:16.594076Z DEBUG p2p_chat::web: Received screen frame: 229132 bytes +2026-02-11T18:42:16.700304Z DEBUG p2p_chat::web: Received screen frame: 229107 bytes +2026-02-11T18:42:16.805956Z DEBUG p2p_chat::web: Received screen frame: 230497 bytes +2026-02-11T18:42:16.911325Z DEBUG p2p_chat::web: Received screen frame: 230497 bytes +2026-02-11T18:42:17.016218Z DEBUG p2p_chat::web: Received screen frame: 230497 bytes +2026-02-11T18:42:17.120799Z DEBUG p2p_chat::web: Received screen frame: 230497 bytes +2026-02-11T18:42:17.226243Z DEBUG p2p_chat::web: Received screen frame: 230497 bytes +2026-02-11T18:42:17.330149Z DEBUG p2p_chat::web: Received screen frame: 230497 bytes +2026-02-11T18:42:17.437021Z DEBUG p2p_chat::web: Received screen frame: 230497 bytes +2026-02-11T18:42:17.549639Z DEBUG p2p_chat::web: Received screen frame: 230497 bytes +2026-02-11T18:42:17.654076Z DEBUG p2p_chat::web: Received screen frame: 230537 bytes +2026-02-11T18:42:17.759250Z DEBUG p2p_chat::web: Received screen frame: 230582 bytes +2026-02-11T18:42:17.864092Z DEBUG p2p_chat::web: Received screen frame: 229573 bytes +2026-02-11T18:42:17.970166Z DEBUG p2p_chat::web: Received screen frame: 228225 bytes +2026-02-11T18:42:18.076855Z DEBUG p2p_chat::web: Received screen frame: 228265 bytes +2026-02-11T18:42:18.180745Z DEBUG p2p_chat::web: Received screen frame: 228317 bytes +2026-02-11T18:42:18.285339Z DEBUG p2p_chat::web: Received screen frame: 228184 bytes +2026-02-11T18:42:18.389392Z DEBUG p2p_chat::web: Received screen frame: 228249 bytes +2026-02-11T18:42:18.495174Z DEBUG p2p_chat::web: Received screen frame: 228333 bytes +2026-02-11T18:42:18.599432Z DEBUG p2p_chat::web: Received screen frame: 228267 bytes +2026-02-11T18:42:18.705998Z DEBUG p2p_chat::web: Received screen frame: 228290 bytes +2026-02-11T18:42:18.811983Z DEBUG p2p_chat::web: Received screen frame: 228175 bytes +2026-02-11T18:42:18.917345Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:42:19.021022Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:42:19.124411Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:42:19.228300Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:42:19.331945Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:42:19.435462Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:42:19.548566Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:42:19.652378Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:42:19.755421Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:42:19.858905Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:42:19.962670Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:42:20.065791Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:42:20.168560Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:42:20.277163Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:42:20.380393Z DEBUG p2p_chat::web: Received screen frame: 228180 bytes +2026-02-11T18:49:54.535404Z INFO p2p_chat::web: Web interface listening on http://127.0.0.1:6969 +2026-02-11T18:50:00.928585Z INFO p2p_chat::web: Web interface listening on http://127.0.0.1:6970 +2026-02-11T18:50:07.753745Z WARN iroh_quinn_proto::connection: remote server configuration might cause nat traversal issues max_local_addresses=12 remote_cid_limit=5 +2026-02-11T18:50:07.965400Z WARN gossip{me=8ac326ba3c}: iroh_quinn_proto::connection: remote server configuration might cause nat traversal issues max_local_addresses=12 remote_cid_limit=5 +2026-02-11T18:50:11.724278Z WARN p2p_chat::media::voice: Failed to connect to daf1a346ccdd34aee64a183869b7c86ff7d728760356498bf7d1a5f9734cced1: Connecting to ourself is not supported +2026-02-11T18:50:11.727624Z WARN iroh_quinn_proto::connection: remote server configuration might cause nat traversal issues max_local_addresses=12 remote_cid_limit=5 +2026-02-11T18:50:11.728724Z INFO p2p_chat::media::voice: Starting voice sender loop for 1 peers +2026-02-11T18:50:11.729488Z INFO p2p_chat::net: Accepted connection from daf1a346ccdd34aee64a183869b7c86ff7d728760356498bf7d1a5f9734cced1 with ALPN "p2p-chat/voice/1" +2026-02-11T18:50:28.331451Z DEBUG p2p_chat::net: Connection accept_bi closed for daf1a346ccdd34aee64a183869b7c86ff7d728760356498bf7d1a5f9734cced1: closed by peer: 0 +2026-02-11T18:50:51.534419Z INFO p2p_chat::web: Web interface listening on http://127.0.0.1:6970 +2026-02-11T18:51:04.955286Z WARN p2p_chat::media::voice: Failed to connect to 66ec83b26203358e1c4fbf2ec86f92d9e06a8717e95c2fcd4a528845aae696a2: Connecting to ourself is not supported +2026-02-11T18:51:04.958498Z WARN iroh_quinn_proto::connection: remote server configuration might cause nat traversal issues max_local_addresses=12 remote_cid_limit=5 +2026-02-11T18:51:04.959410Z INFO p2p_chat::media::voice: Starting voice sender loop for 1 peers +2026-02-11T18:51:08.348469Z INFO p2p_chat::net: Accepted connection from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c with ALPN "p2p-chat/voice/1" +2026-02-11T18:51:35.591927Z INFO p2p_chat::media::voice: Sent audio datagram seq 50 to 1 peers +2026-02-11T18:51:36.573296Z INFO p2p_chat::media::voice: Sent audio datagram seq 100 to 1 peers +2026-02-11T18:51:37.192970Z INFO p2p_chat::media::voice: Received AudioData seq 0 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:37.193043Z INFO p2p_chat::media::voice: Creating new OpusDecoder for 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:37.608205Z INFO p2p_chat::media::voice: Sent audio datagram seq 150 to 1 peers +2026-02-11T18:51:38.174820Z INFO p2p_chat::media::voice: Received AudioData seq 50 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:38.589567Z INFO p2p_chat::media::voice: Sent audio datagram seq 200 to 1 peers +2026-02-11T18:51:39.198021Z INFO p2p_chat::media::voice: Received AudioData seq 100 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:39.613562Z INFO p2p_chat::media::voice: Sent audio datagram seq 250 to 1 peers +2026-02-11T18:51:40.180001Z INFO p2p_chat::media::voice: Received AudioData seq 150 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:40.594907Z INFO p2p_chat::media::voice: Sent audio datagram seq 300 to 1 peers +2026-02-11T18:51:41.203330Z INFO p2p_chat::media::voice: Received AudioData seq 200 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:41.618837Z INFO p2p_chat::media::voice: Sent audio datagram seq 350 to 1 peers +2026-02-11T18:51:42.185373Z INFO p2p_chat::media::voice: Received AudioData seq 250 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:42.600215Z INFO p2p_chat::media::voice: Sent audio datagram seq 400 to 1 peers +2026-02-11T18:51:43.208993Z INFO p2p_chat::media::voice: Received AudioData seq 300 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:43.581573Z INFO p2p_chat::media::voice: Sent audio datagram seq 450 to 1 peers +2026-02-11T18:51:44.190892Z INFO p2p_chat::media::voice: Received AudioData seq 350 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:45.174709Z INFO p2p_chat::media::voice: Received AudioData seq 400 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:46.195189Z INFO p2p_chat::media::voice: Received AudioData seq 450 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:47.177248Z INFO p2p_chat::media::voice: Received AudioData seq 500 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:48.200684Z INFO p2p_chat::media::voice: Received AudioData seq 550 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:49.183047Z INFO p2p_chat::media::voice: Received AudioData seq 600 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:50.205847Z INFO p2p_chat::media::voice: Received AudioData seq 650 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:51.187984Z INFO p2p_chat::media::voice: Received AudioData seq 700 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:52.211334Z INFO p2p_chat::media::voice: Received AudioData seq 750 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:53.192686Z INFO p2p_chat::media::voice: Received AudioData seq 800 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:54.174674Z INFO p2p_chat::media::voice: Received AudioData seq 850 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:55.198007Z INFO p2p_chat::media::voice: Received AudioData seq 900 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:56.180057Z INFO p2p_chat::media::voice: Received AudioData seq 950 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:57.203269Z INFO p2p_chat::media::voice: Received AudioData seq 1000 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:58.185355Z INFO p2p_chat::media::voice: Received AudioData seq 1050 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:51:59.208552Z INFO p2p_chat::media::voice: Received AudioData seq 1100 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:00.190781Z INFO p2p_chat::media::voice: Received AudioData seq 1150 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:01.172676Z INFO p2p_chat::media::voice: Received AudioData seq 1200 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:02.195439Z INFO p2p_chat::media::voice: Received AudioData seq 1250 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:03.177641Z INFO p2p_chat::media::voice: Received AudioData seq 1300 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:04.200681Z INFO p2p_chat::media::voice: Received AudioData seq 1350 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:05.182882Z INFO p2p_chat::media::voice: Received AudioData seq 1400 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:06.205913Z INFO p2p_chat::media::voice: Received AudioData seq 1450 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:07.187963Z INFO p2p_chat::media::voice: Received AudioData seq 1500 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:08.211615Z INFO p2p_chat::media::voice: Received AudioData seq 1550 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:09.192633Z INFO p2p_chat::media::voice: Received AudioData seq 1600 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:10.174582Z INFO p2p_chat::media::voice: Received AudioData seq 1650 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:11.197900Z INFO p2p_chat::media::voice: Received AudioData seq 1700 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:12.179992Z INFO p2p_chat::media::voice: Received AudioData seq 1750 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:13.203495Z INFO p2p_chat::media::voice: Received AudioData seq 1800 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:14.185257Z INFO p2p_chat::media::voice: Received AudioData seq 1850 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:15.208566Z INFO p2p_chat::media::voice: Received AudioData seq 1900 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:16.190747Z INFO p2p_chat::media::voice: Received AudioData seq 1950 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:17.172603Z INFO p2p_chat::media::voice: Received AudioData seq 2000 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:18.195194Z INFO p2p_chat::media::voice: Received AudioData seq 2050 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:19.177336Z INFO p2p_chat::media::voice: Received AudioData seq 2100 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:20.200547Z INFO p2p_chat::media::voice: Received AudioData seq 2150 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:21.182734Z INFO p2p_chat::media::voice: Received AudioData seq 2200 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:22.205909Z INFO p2p_chat::media::voice: Received AudioData seq 2250 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:23.187918Z INFO p2p_chat::media::voice: Received AudioData seq 2300 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:24.211252Z INFO p2p_chat::media::voice: Received AudioData seq 2350 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:25.192613Z INFO p2p_chat::media::voice: Received AudioData seq 2400 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:26.174649Z INFO p2p_chat::media::voice: Received AudioData seq 2450 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:26.718874Z WARN iroh_quinn_proto::connection: sent PATH_ABANDON after path was already discarded +2026-02-11T18:52:27.197943Z INFO p2p_chat::media::voice: Received AudioData seq 2500 from 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c +2026-02-11T18:52:32.079544Z ERROR p2p_chat::media::capture: Video sender web error: Failed to connect for media stream +2026-02-11T18:52:32.082316Z WARN iroh_quinn_proto::connection: remote server configuration might cause nat traversal issues max_local_addresses=12 remote_cid_limit=5 +2026-02-11T18:52:45.185497Z ERROR p2p_chat::media::capture: Video sender web error: Failed to connect for media stream +2026-02-11T18:52:45.188301Z WARN iroh_quinn_proto::connection: remote server configuration might cause nat traversal issues max_local_addresses=12 remote_cid_limit=5 +2026-02-11T18:52:56.660374Z DEBUG p2p_chat::web: Received camera frame: 9110 bytes +2026-02-11T18:52:56.764206Z DEBUG p2p_chat::web: Received camera frame: 17315 bytes +2026-02-11T18:52:56.866903Z DEBUG p2p_chat::web: Received camera frame: 17027 bytes +2026-02-11T18:52:56.969808Z DEBUG p2p_chat::web: Received camera frame: 17118 bytes +2026-02-11T18:52:57.073117Z DEBUG p2p_chat::web: Received camera frame: 17190 bytes +2026-02-11T18:52:57.176011Z DEBUG p2p_chat::web: Received camera frame: 17304 bytes +2026-02-11T18:52:57.278923Z DEBUG p2p_chat::web: Received camera frame: 17429 bytes +2026-02-11T18:52:57.382371Z DEBUG p2p_chat::web: Received camera frame: 17501 bytes +2026-02-11T18:52:57.485166Z DEBUG p2p_chat::web: Received camera frame: 17428 bytes +2026-02-11T18:52:57.588083Z DEBUG p2p_chat::web: Received camera frame: 17435 bytes +2026-02-11T18:52:57.689490Z DEBUG p2p_chat::web: Received camera frame: 17335 bytes +2026-02-11T18:52:57.790427Z DEBUG p2p_chat::web: Received camera frame: 17322 bytes +2026-02-11T18:52:57.891628Z DEBUG p2p_chat::web: Received camera frame: 17299 bytes +2026-02-11T18:52:57.992979Z DEBUG p2p_chat::web: Received camera frame: 17345 bytes +2026-02-11T18:52:58.094011Z DEBUG p2p_chat::web: Received camera frame: 17250 bytes +2026-02-11T18:52:58.195549Z DEBUG p2p_chat::web: Received camera frame: 17343 bytes +2026-02-11T18:52:58.296488Z DEBUG p2p_chat::web: Received camera frame: 17292 bytes +2026-02-11T18:52:58.397819Z DEBUG p2p_chat::web: Received camera frame: 17193 bytes +2026-02-11T18:52:58.499426Z DEBUG p2p_chat::web: Received camera frame: 17206 bytes +2026-02-11T18:52:58.600450Z DEBUG p2p_chat::web: Received camera frame: 17250 bytes +2026-02-11T18:52:58.701224Z DEBUG p2p_chat::web: Received camera frame: 17281 bytes +2026-02-11T18:52:58.802347Z DEBUG p2p_chat::web: Received camera frame: 17263 bytes +2026-02-11T18:52:58.903269Z DEBUG p2p_chat::web: Received camera frame: 17266 bytes +2026-02-11T18:52:59.004225Z DEBUG p2p_chat::web: Received camera frame: 17285 bytes +2026-02-11T18:52:59.105135Z DEBUG p2p_chat::web: Received camera frame: 17329 bytes +2026-02-11T18:52:59.206307Z DEBUG p2p_chat::web: Received camera frame: 17311 bytes +2026-02-11T18:52:59.307166Z DEBUG p2p_chat::web: Received camera frame: 17228 bytes +2026-02-11T18:52:59.407977Z DEBUG p2p_chat::web: Received camera frame: 17165 bytes +2026-02-11T18:52:59.508924Z DEBUG p2p_chat::web: Received camera frame: 17190 bytes +2026-02-11T18:52:59.609957Z DEBUG p2p_chat::web: Received camera frame: 17359 bytes +2026-02-11T18:52:59.711025Z DEBUG p2p_chat::web: Received camera frame: 17331 bytes +2026-02-11T18:52:59.812005Z DEBUG p2p_chat::web: Received camera frame: 17262 bytes +2026-02-11T18:52:59.913701Z DEBUG p2p_chat::web: Received camera frame: 17245 bytes +2026-02-11T18:53:00.014432Z DEBUG p2p_chat::web: Received camera frame: 17267 bytes +2026-02-11T18:53:00.119235Z DEBUG p2p_chat::web: Received camera frame: 17321 bytes +2026-02-11T18:53:00.125667Z DEBUG p2p_chat::web: Received screen frame: 276070 bytes +2026-02-11T18:53:00.241841Z DEBUG p2p_chat::web: Received camera frame: 17296 bytes +2026-02-11T18:53:00.249347Z DEBUG p2p_chat::web: Received screen frame: 297031 bytes +2026-02-11T18:53:00.358342Z DEBUG p2p_chat::web: Received camera frame: 17291 bytes +2026-02-11T18:53:00.364836Z DEBUG p2p_chat::web: Received screen frame: 299375 bytes +2026-02-11T18:53:00.475923Z DEBUG p2p_chat::web: Received camera frame: 17272 bytes +2026-02-11T18:53:00.482170Z DEBUG p2p_chat::web: Received screen frame: 299031 bytes +2026-02-11T18:53:00.591476Z DEBUG p2p_chat::web: Received camera frame: 17213 bytes +2026-02-11T18:53:00.598051Z DEBUG p2p_chat::web: Received screen frame: 299124 bytes +2026-02-11T18:53:00.709592Z DEBUG p2p_chat::web: Received camera frame: 17280 bytes +2026-02-11T18:53:00.716212Z DEBUG p2p_chat::web: Received screen frame: 299034 bytes +2026-02-11T18:53:00.825440Z DEBUG p2p_chat::web: Received camera frame: 17300 bytes +2026-02-11T18:53:00.832091Z DEBUG p2p_chat::web: Received screen frame: 298963 bytes +2026-02-11T18:53:00.942393Z DEBUG p2p_chat::web: Received camera frame: 17224 bytes +2026-02-11T18:53:00.949171Z DEBUG p2p_chat::web: Received screen frame: 298951 bytes +2026-02-11T18:53:01.058440Z DEBUG p2p_chat::web: Received camera frame: 17255 bytes +2026-02-11T18:53:01.064726Z DEBUG p2p_chat::web: Received screen frame: 298969 bytes +2026-02-11T18:53:01.176004Z DEBUG p2p_chat::web: Received camera frame: 17360 bytes +2026-02-11T18:53:01.183075Z DEBUG p2p_chat::web: Received screen frame: 299128 bytes +2026-02-11T18:53:01.284557Z DEBUG p2p_chat::web: Received camera frame: 17383 bytes +2026-02-11T18:53:01.290764Z DEBUG p2p_chat::web: Received screen frame: 299215 bytes +2026-02-11T18:53:01.390796Z DEBUG p2p_chat::web: Received camera frame: 17320 bytes +2026-02-11T18:53:01.397230Z DEBUG p2p_chat::web: Received screen frame: 299166 bytes +2026-02-11T18:53:01.498451Z DEBUG p2p_chat::web: Received camera frame: 17281 bytes +2026-02-11T18:53:01.505606Z DEBUG p2p_chat::web: Received screen frame: 300976 bytes +2026-02-11T18:53:01.605652Z DEBUG p2p_chat::web: Received camera frame: 17068 bytes +2026-02-11T18:53:01.610518Z DEBUG p2p_chat::web: Received screen frame: 302380 bytes +2026-02-11T18:53:01.714849Z DEBUG p2p_chat::web: Received camera frame: 17159 bytes +2026-02-11T18:53:01.720853Z DEBUG p2p_chat::web: Received screen frame: 302535 bytes +2026-02-11T18:53:01.819936Z DEBUG p2p_chat::web: Received camera frame: 17295 bytes +2026-02-11T18:53:01.827311Z DEBUG p2p_chat::web: Received screen frame: 302642 bytes +2026-02-11T18:53:01.923854Z DEBUG p2p_chat::web: Received camera frame: 17301 bytes +2026-02-11T18:53:01.931112Z DEBUG p2p_chat::web: Received screen frame: 302739 bytes +2026-02-11T18:53:02.029725Z DEBUG p2p_chat::web: Received camera frame: 17275 bytes +2026-02-11T18:53:02.036302Z DEBUG p2p_chat::web: Received screen frame: 267835 bytes +2026-02-11T18:53:02.134614Z DEBUG p2p_chat::web: Received camera frame: 17472 bytes +2026-02-11T18:53:02.140979Z DEBUG p2p_chat::web: Received screen frame: 280928 bytes +2026-02-11T18:53:02.239956Z DEBUG p2p_chat::web: Received camera frame: 17463 bytes +2026-02-11T18:53:02.245894Z DEBUG p2p_chat::web: Received screen frame: 279213 bytes +2026-02-11T18:53:02.344052Z DEBUG p2p_chat::web: Received camera frame: 17442 bytes +2026-02-11T18:53:02.350351Z DEBUG p2p_chat::web: Received screen frame: 283368 bytes +2026-02-11T18:53:02.449241Z DEBUG p2p_chat::web: Received camera frame: 17499 bytes +2026-02-11T18:53:02.455160Z DEBUG p2p_chat::web: Received screen frame: 282978 bytes +2026-02-11T18:53:02.553452Z DEBUG p2p_chat::web: Received camera frame: 17623 bytes +2026-02-11T18:53:02.561512Z DEBUG p2p_chat::web: Received screen frame: 280806 bytes +2026-02-11T18:53:02.658414Z DEBUG p2p_chat::web: Received camera frame: 17565 bytes +2026-02-11T18:53:02.665539Z DEBUG p2p_chat::web: Received screen frame: 278128 bytes +2026-02-11T18:53:02.763933Z DEBUG p2p_chat::web: Received camera frame: 17611 bytes +2026-02-11T18:53:02.770805Z DEBUG p2p_chat::web: Received screen frame: 276765 bytes +2026-02-11T18:53:02.870106Z DEBUG p2p_chat::web: Received camera frame: 17584 bytes +2026-02-11T18:53:02.876519Z DEBUG p2p_chat::web: Received screen frame: 277799 bytes +2026-02-11T18:53:02.975656Z DEBUG p2p_chat::web: Received camera frame: 17573 bytes +2026-02-11T18:53:02.982021Z DEBUG p2p_chat::web: Received screen frame: 288692 bytes +2026-02-11T18:53:03.079833Z DEBUG p2p_chat::web: Received camera frame: 17488 bytes +2026-02-11T18:53:03.086028Z DEBUG p2p_chat::web: Received screen frame: 299014 bytes +2026-02-11T18:53:03.185263Z DEBUG p2p_chat::web: Received camera frame: 17585 bytes +2026-02-11T18:53:03.191344Z DEBUG p2p_chat::web: Received screen frame: 304432 bytes +2026-02-11T18:53:03.289271Z DEBUG p2p_chat::web: Received camera frame: 16760 bytes +2026-02-11T18:53:03.296336Z DEBUG p2p_chat::web: Received screen frame: 304725 bytes +2026-02-11T18:53:03.394681Z DEBUG p2p_chat::web: Received camera frame: 16027 bytes +2026-02-11T18:53:03.400617Z DEBUG p2p_chat::web: Received screen frame: 304635 bytes +2026-02-11T18:53:03.499491Z DEBUG p2p_chat::web: Received camera frame: 17157 bytes +2026-02-11T18:53:03.508117Z DEBUG p2p_chat::web: Received screen frame: 304728 bytes +2026-02-11T18:53:03.603944Z DEBUG p2p_chat::web: Received camera frame: 17750 bytes +2026-02-11T18:53:03.611112Z DEBUG p2p_chat::web: Received screen frame: 304593 bytes +2026-02-11T18:53:03.721160Z DEBUG p2p_chat::web: Received camera frame: 17848 bytes +2026-02-11T18:53:03.728433Z DEBUG p2p_chat::web: Received screen frame: 304606 bytes +2026-02-11T18:53:03.826011Z DEBUG p2p_chat::web: Received camera frame: 18074 bytes +2026-02-11T18:53:03.832377Z DEBUG p2p_chat::web: Received screen frame: 304620 bytes +2026-02-11T18:53:03.931276Z DEBUG p2p_chat::web: Received camera frame: 18865 bytes +2026-02-11T18:53:03.938769Z DEBUG p2p_chat::web: Received screen frame: 304746 bytes +2026-02-11T18:53:04.035269Z DEBUG p2p_chat::web: Received camera frame: 18769 bytes +2026-02-11T18:53:04.042104Z DEBUG p2p_chat::web: Received screen frame: 304722 bytes +2026-02-11T18:53:04.140765Z DEBUG p2p_chat::web: Received camera frame: 18857 bytes +2026-02-11T18:53:04.148882Z DEBUG p2p_chat::web: Received screen frame: 304690 bytes +2026-02-11T18:53:04.245761Z DEBUG p2p_chat::web: Received camera frame: 18733 bytes +2026-02-11T18:53:04.252248Z DEBUG p2p_chat::web: Received screen frame: 304666 bytes +2026-02-11T18:53:04.352593Z DEBUG p2p_chat::web: Received camera frame: 19424 bytes +2026-02-11T18:53:04.359154Z DEBUG p2p_chat::web: Received screen frame: 304641 bytes +2026-02-11T18:53:04.457208Z DEBUG p2p_chat::web: Received camera frame: 19603 bytes +2026-02-11T18:53:04.463808Z DEBUG p2p_chat::web: Received screen frame: 304600 bytes +2026-02-11T18:53:04.562400Z DEBUG p2p_chat::web: Received camera frame: 20064 bytes +2026-02-11T18:53:04.568757Z DEBUG p2p_chat::web: Received screen frame: 304697 bytes +2026-02-11T18:53:04.666721Z DEBUG p2p_chat::web: Received camera frame: 20156 bytes +2026-02-11T18:53:04.673586Z DEBUG p2p_chat::web: Received screen frame: 304764 bytes +2026-02-11T18:53:04.771651Z DEBUG p2p_chat::web: Received camera frame: 20189 bytes +2026-02-11T18:53:04.776956Z DEBUG p2p_chat::web: Received screen frame: 304811 bytes +2026-02-11T18:53:04.875635Z DEBUG p2p_chat::web: Received camera frame: 20135 bytes +2026-02-11T18:53:04.882123Z DEBUG p2p_chat::web: Received screen frame: 304812 bytes +2026-02-11T18:53:04.979798Z DEBUG p2p_chat::web: Received camera frame: 20288 bytes +2026-02-11T18:53:04.986567Z DEBUG p2p_chat::web: Received screen frame: 304865 bytes +2026-02-11T18:53:05.085048Z DEBUG p2p_chat::web: Received camera frame: 20917 bytes +2026-02-11T18:53:05.092325Z DEBUG p2p_chat::web: Received screen frame: 304906 bytes +2026-02-11T18:53:05.190819Z DEBUG p2p_chat::web: Received camera frame: 21001 bytes +2026-02-11T18:53:05.197349Z DEBUG p2p_chat::web: Received screen frame: 304913 bytes +2026-02-11T18:53:05.297729Z DEBUG p2p_chat::web: Received camera frame: 20366 bytes +2026-02-11T18:53:05.304770Z DEBUG p2p_chat::web: Received screen frame: 304886 bytes +2026-02-11T18:53:05.402581Z DEBUG p2p_chat::web: Received camera frame: 20278 bytes +2026-02-11T18:53:05.408638Z DEBUG p2p_chat::web: Received screen frame: 304934 bytes +2026-02-11T18:53:05.507647Z DEBUG p2p_chat::web: Received camera frame: 20399 bytes +2026-02-11T18:53:05.515106Z DEBUG p2p_chat::web: Received screen frame: 304931 bytes +2026-02-11T18:53:05.611942Z DEBUG p2p_chat::web: Received camera frame: 20809 bytes +2026-02-11T18:53:05.618395Z DEBUG p2p_chat::web: Received screen frame: 304939 bytes +2026-02-11T18:53:05.717633Z DEBUG p2p_chat::web: Received camera frame: 20736 bytes +2026-02-11T18:53:05.724611Z DEBUG p2p_chat::web: Received screen frame: 304929 bytes +2026-02-11T18:53:05.821922Z DEBUG p2p_chat::web: Received camera frame: 20626 bytes +2026-02-11T18:53:05.829101Z DEBUG p2p_chat::web: Received screen frame: 304901 bytes +2026-02-11T18:53:05.929002Z DEBUG p2p_chat::web: Received camera frame: 21410 bytes +2026-02-11T18:53:05.935570Z DEBUG p2p_chat::web: Received screen frame: 304909 bytes +2026-02-11T18:53:06.033032Z DEBUG p2p_chat::web: Received camera frame: 21338 bytes +2026-02-11T18:53:06.040304Z DEBUG p2p_chat::web: Received screen frame: 304642 bytes +2026-02-11T18:53:06.138122Z DEBUG p2p_chat::web: Received camera frame: 20856 bytes +2026-02-11T18:53:06.144559Z DEBUG p2p_chat::web: Received screen frame: 304872 bytes +2026-02-11T18:53:06.243074Z DEBUG p2p_chat::web: Received camera frame: 19757 bytes +2026-02-11T18:53:06.249753Z DEBUG p2p_chat::web: Received screen frame: 304964 bytes +2026-02-11T18:53:06.347698Z DEBUG p2p_chat::web: Received camera frame: 19623 bytes +2026-02-11T18:53:06.354073Z DEBUG p2p_chat::web: Received screen frame: 304813 bytes +2026-02-11T18:53:06.452963Z DEBUG p2p_chat::web: Received camera frame: 20176 bytes +2026-02-11T18:53:06.460971Z DEBUG p2p_chat::web: Received screen frame: 304855 bytes +2026-02-11T18:53:06.557269Z DEBUG p2p_chat::web: Received camera frame: 19745 bytes +2026-02-11T18:53:06.563623Z DEBUG p2p_chat::web: Received screen frame: 304925 bytes +2026-02-11T18:53:06.664717Z DEBUG p2p_chat::web: Received camera frame: 19250 bytes +2026-02-11T18:53:06.671225Z DEBUG p2p_chat::web: Received screen frame: 304891 bytes +2026-02-11T18:53:06.769483Z DEBUG p2p_chat::web: Received camera frame: 19612 bytes +2026-02-11T18:53:06.776099Z DEBUG p2p_chat::web: Received screen frame: 304704 bytes +2026-02-11T18:53:06.874286Z DEBUG p2p_chat::web: Received camera frame: 19287 bytes +2026-02-11T18:53:06.881703Z DEBUG p2p_chat::web: Received screen frame: 304844 bytes +2026-02-11T18:53:06.978914Z DEBUG p2p_chat::web: Received camera frame: 19240 bytes +2026-02-11T18:53:06.986197Z DEBUG p2p_chat::web: Received screen frame: 304544 bytes +2026-02-11T18:53:07.084374Z DEBUG p2p_chat::web: Received camera frame: 18881 bytes +2026-02-11T18:53:07.090933Z DEBUG p2p_chat::web: Received screen frame: 304772 bytes +2026-02-11T18:53:07.188979Z DEBUG p2p_chat::web: Received camera frame: 16347 bytes +2026-02-11T18:53:07.196588Z DEBUG p2p_chat::web: Received screen frame: 304806 bytes +2026-02-11T18:53:07.294542Z DEBUG p2p_chat::web: Received camera frame: 16466 bytes +2026-02-11T18:53:07.301014Z DEBUG p2p_chat::web: Received screen frame: 304847 bytes +2026-02-11T18:53:07.400109Z DEBUG p2p_chat::web: Received camera frame: 17441 bytes +2026-02-11T18:53:07.406570Z DEBUG p2p_chat::web: Received screen frame: 304996 bytes +2026-02-11T18:53:07.504774Z DEBUG p2p_chat::web: Received camera frame: 17010 bytes +2026-02-11T18:53:07.511123Z DEBUG p2p_chat::web: Received screen frame: 304781 bytes +2026-02-11T18:53:07.611041Z DEBUG p2p_chat::web: Received camera frame: 17010 bytes +2026-02-11T18:53:07.617569Z DEBUG p2p_chat::web: Received screen frame: 306918 bytes +2026-02-11T18:53:07.716759Z DEBUG p2p_chat::web: Received camera frame: 17321 bytes +2026-02-11T18:53:07.722790Z DEBUG p2p_chat::web: Received screen frame: 306415 bytes +2026-02-11T18:53:07.821546Z DEBUG p2p_chat::web: Received camera frame: 18338 bytes +2026-02-11T18:53:07.828785Z DEBUG p2p_chat::web: Received screen frame: 305782 bytes +2026-02-11T18:53:07.926849Z DEBUG p2p_chat::web: Received camera frame: 18754 bytes +2026-02-11T18:53:07.933046Z DEBUG p2p_chat::web: Received screen frame: 305422 bytes +2026-02-11T18:53:08.032507Z DEBUG p2p_chat::web: Received camera frame: 18209 bytes +2026-02-11T18:53:08.038424Z DEBUG p2p_chat::web: Received screen frame: 305057 bytes +2026-02-11T18:53:08.137920Z DEBUG p2p_chat::web: Received camera frame: 18649 bytes +2026-02-11T18:53:08.144352Z DEBUG p2p_chat::web: Received screen frame: 304959 bytes +2026-02-11T18:53:08.243544Z DEBUG p2p_chat::web: Received camera frame: 19180 bytes +2026-02-11T18:53:08.250209Z DEBUG p2p_chat::web: Received screen frame: 304893 bytes +2026-02-11T18:53:08.348003Z DEBUG p2p_chat::web: Received camera frame: 19456 bytes +2026-02-11T18:53:08.354801Z DEBUG p2p_chat::web: Received screen frame: 304874 bytes +2026-02-11T18:53:08.454385Z DEBUG p2p_chat::web: Received camera frame: 18977 bytes +2026-02-11T18:53:08.465028Z DEBUG p2p_chat::web: Received screen frame: 305003 bytes +2026-02-11T18:53:08.559504Z DEBUG p2p_chat::web: Received camera frame: 18815 bytes +2026-02-11T18:53:08.565147Z DEBUG p2p_chat::web: Received screen frame: 304936 bytes +2026-02-11T18:53:08.664322Z DEBUG p2p_chat::web: Received camera frame: 18653 bytes +2026-02-11T18:53:08.671456Z DEBUG p2p_chat::web: Received screen frame: 304960 bytes +2026-02-11T18:53:08.769113Z DEBUG p2p_chat::web: Received camera frame: 18685 bytes +2026-02-11T18:53:08.775569Z DEBUG p2p_chat::web: Received screen frame: 304961 bytes +2026-02-11T18:53:08.874634Z DEBUG p2p_chat::web: Received camera frame: 18773 bytes +2026-02-11T18:53:08.880661Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:08.977387Z DEBUG p2p_chat::web: Received camera frame: 18779 bytes +2026-02-11T18:53:08.984298Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:09.080160Z DEBUG p2p_chat::web: Received camera frame: 18872 bytes +2026-02-11T18:53:09.087030Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:09.183430Z DEBUG p2p_chat::web: Received camera frame: 18848 bytes +2026-02-11T18:53:09.190013Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:09.286549Z DEBUG p2p_chat::web: Received camera frame: 18871 bytes +2026-02-11T18:53:09.293375Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:09.389400Z DEBUG p2p_chat::web: Received camera frame: 18790 bytes +2026-02-11T18:53:09.396059Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:09.492574Z DEBUG p2p_chat::web: Received camera frame: 18889 bytes +2026-02-11T18:53:09.498730Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:09.595511Z DEBUG p2p_chat::web: Received camera frame: 18908 bytes +2026-02-11T18:53:09.601938Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:09.698553Z DEBUG p2p_chat::web: Received camera frame: 18829 bytes +2026-02-11T18:53:09.704870Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:09.801354Z DEBUG p2p_chat::web: Received camera frame: 18844 bytes +2026-02-11T18:53:09.807491Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:09.904022Z DEBUG p2p_chat::web: Received camera frame: 18771 bytes +2026-02-11T18:53:09.909952Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:10.007020Z DEBUG p2p_chat::web: Received camera frame: 18715 bytes +2026-02-11T18:53:10.013497Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:10.110198Z DEBUG p2p_chat::web: Received camera frame: 18596 bytes +2026-02-11T18:53:10.116482Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:10.213242Z DEBUG p2p_chat::web: Received camera frame: 18634 bytes +2026-02-11T18:53:10.219900Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:10.316677Z DEBUG p2p_chat::web: Received camera frame: 18449 bytes +2026-02-11T18:53:10.323122Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:10.419701Z DEBUG p2p_chat::web: Received camera frame: 18532 bytes +2026-02-11T18:53:10.426482Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:10.522844Z DEBUG p2p_chat::web: Received camera frame: 18677 bytes +2026-02-11T18:53:10.528933Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:10.625894Z DEBUG p2p_chat::web: Received camera frame: 18676 bytes +2026-02-11T18:53:10.632228Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:10.729529Z DEBUG p2p_chat::web: Received camera frame: 18593 bytes +2026-02-11T18:53:10.735197Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:10.838514Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:10.941464Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:11.044905Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:11.147897Z DEBUG p2p_chat::web: Received screen frame: 278831 bytes +2026-02-11T18:53:38.115109Z DEBUG p2p_chat::net: Connection accept_bi closed for 8bc2400f07d26848e17871ac18a1bc6373ab4cbd9b3f4cc98b50065130214c7c: closed by peer: 0 +2026-02-11T19:08:33.877479Z INFO p2p_chat::web: Web interface listening on http://127.0.0.1:6969 +2026-02-11T19:20:24.372206Z INFO p2p_chat::web: Web interface listening on http://127.0.0.1:6969 diff --git a/src/app_logic.rs b/src/app_logic.rs new file mode 100644 index 0000000..bcb7ff9 --- /dev/null +++ b/src/app_logic.rs @@ -0,0 +1,310 @@ +use anyhow::Result; +use crate::chat::ChatState; +use crate::config::AppConfig; +use crate::file_transfer::FileTransferManager; +use crate::media::MediaState; +use crate::net::{NetEvent, NetworkManager}; +use crate::protocol::{self, GossipMessage}; +use crate::tui::TuiCommand; + +pub struct AppLogic { + pub chat: ChatState, + pub file_mgr: FileTransferManager, + pub media: MediaState, + pub net: NetworkManager, + pub our_name: String, + pub our_id_short: String, + pub connected: bool, +} + +impl AppLogic { + pub fn new( + chat: ChatState, + file_mgr: FileTransferManager, + media: MediaState, + net: NetworkManager, + our_name: String, + our_id_short: String, + ) -> Self { + Self { + chat, + file_mgr, + media, + net, + our_name, + our_id_short, + connected: false, + } + } + + pub async fn handle_tui_command(&mut self, cmd: TuiCommand) -> Result { + match cmd { + TuiCommand::SendMessage(text) => { + if let Err(e) = self.chat.send_message(text, &self.net).await { + self.chat.add_system_message(format!("Send error: {}", e)); + } + } + TuiCommand::SystemMessage(text) => { + self.chat.add_system_message(text); + } + TuiCommand::ToggleVoice => { + let status = self.media.toggle_voice(self.net.clone()).await; + self.chat.add_system_message(status.to_string()); + } + TuiCommand::ToggleCamera => { + let status = self.media.toggle_camera(self.net.clone()).await; + self.chat.add_system_message(status.to_string()); + } + TuiCommand::ToggleScreen => { + let status = self.media.toggle_screen(self.net.clone()).await; + self.chat.add_system_message(status.to_string()); + } + TuiCommand::Quit => { + // Broadcast disconnect to peers + let disconnect_msg = GossipMessage::Disconnect { + sender_name: self.our_name.clone(), + }; + let _ = self.net.broadcast(&disconnect_msg).await; + // Brief delay to let the message propagate + tokio::time::sleep(std::time::Duration::from_millis(100)).await; + self.media.shutdown(); + return Ok(true); // Signal to quit + } + TuiCommand::ChangeNick(new_nick) => { + let old = self.our_name.clone(); + self.our_name = new_nick.clone(); + self.chat.our_name = new_nick.clone(); + // Update self in peer list + { + let mut peers = self.net.peers.lock().await; + if let Some(self_peer) = peers.get_mut(&self.net.our_id) { + self_peer.name = Some(new_nick.clone()); + } + } + self.chat.add_system_message( + format!("Nickname changed: {} → {}", old, new_nick), + ); + // Broadcast name change to all peers + let msg = GossipMessage::NameChange( + protocol::NameChange { + old_name: old, + new_name: new_nick, + }, + ); + let _ = self.net.broadcast(&msg).await; + } + TuiCommand::Connect(peer_id_str) => { + match peer_id_str.parse::() { + Ok(peer_id) => { + self.chat.add_system_message(format!("Connecting to {}...", peer_id)); + if let Err(e) = self.net.connect(peer_id).await { + self.chat.add_system_message(format!("Connection failed: {}", e)); + } else { + self.chat.add_system_message("Connection initiated.".to_string()); + } + } + Err(_) => { + self.chat.add_system_message(format!("Invalid peer ID: {}", peer_id_str)); + } + } + } + TuiCommand::SendFile(path) => { + self.chat.add_system_message(format!("Preparing to send file: {:?}", path)); + if !path.exists() { + self.chat.add_system_message(format!("File not found: {}", path.display())); + } else { + let file_mgr = self.file_mgr.clone(); + // Prepare send + match file_mgr.prepare_send(&path).await { + Ok((file_id, offer)) => { + self.chat.add_system_message(format!("Offering file: {}", offer.name)); + let broadcast = protocol::FileOfferBroadcast { + sender_name: self.our_name.to_string(), + file_id, + file_name: offer.name.clone(), + file_size: offer.size, + timeout: offer.timeout, + }; + let msg = GossipMessage::FileOfferBroadcast(broadcast); + if let Err(e) = self.net.broadcast(&msg).await { + self.chat.add_system_message(format!("Failed to broadcast offer: {}", e)); + } + } + Err(e) => { + self.chat.add_system_message(format!("Failed to prepare file: {}", e)); + } + } + } + } + TuiCommand::Leave => { + self.chat.add_system_message("Leaving group chat...".to_string()); + self.media.shutdown(); + // Clear peer list (except self) + { + let mut peers = self.net.peers.lock().await; + peers.retain(|_, info| info.is_self); + } + self.chat.add_system_message("Session ended. Use /connect to start a new session.".to_string()); + } + TuiCommand::SelectMic(node_name) => { + self.media.set_mic_name(Some(node_name.clone())); + if self.media.voice_enabled() { + self.chat.add_system_message("Restarting voice with new mic...".to_string()); + // Toggle off + let _ = self.media.toggle_voice(self.net.clone()).await; + // Toggle on + let status = self.media.toggle_voice(self.net.clone()).await; + self.chat.add_system_message(status.to_string()); + } + self.chat.add_system_message(format!("🎤 Mic set to: {}", node_name)); + // Save to config + if let Ok(mut cfg) = AppConfig::load() { + cfg.media.mic_name = Some(node_name); + let _ = cfg.save(); + } + } + TuiCommand::SetBitrate(bps) => { + self.media.set_bitrate(bps); + self.chat.add_system_message(format!("🎵 Bitrate set to {} kbps", bps / 1000)); + // Save to config + if let Ok(mut cfg) = AppConfig::load() { + cfg.media.mic_bitrate = bps; + let _ = cfg.save(); + } + } + TuiCommand::SelectSpeaker(node_name) => { + self.media.set_speaker_name(Some(node_name.clone())); + self.chat.add_system_message(format!("🔊 Speaker set to: {}", node_name)); + // Save to config + if let Ok(mut cfg) = AppConfig::load() { + cfg.media.speaker_name = Some(node_name); + if let Err(e) = cfg.save() { + tracing::warn!("Failed to save config: {}", e); + } + } + if self.media.voice_enabled() { + self.chat.add_system_message("Restart voice chat to apply changes.".to_string()); + } + } + TuiCommand::AcceptFile(prefix) => { + // Find matching transfer + let transfers = self.file_mgr.transfers.lock().unwrap(); + let mut matched_id = None; + for (id, _info) in transfers.iter() { + let id_str = hex::encode(id); + if id_str.starts_with(&prefix) { + if matched_id.is_some() { + self.chat.add_system_message(format!("Ambiguous prefix '{}'", prefix)); + matched_id = None; + break; + } + matched_id = Some(*id); + } + } + drop(transfers); + + if let Some(id) = matched_id { + if self.file_mgr.accept_transfer(id) { + self.chat.add_system_message(format!("Accepted transfer {}", hex::encode(id).chars().take(8).collect::())); + } else { + self.chat.add_system_message("Transfer not found or not waiting for accept.".to_string()); + } + } else { + self.chat.add_system_message(format!("No transfer found matching '{}'", prefix)); + } + } + TuiCommand::None => {} + } + Ok(false) // Do not quit + } + + pub async fn handle_net_event(&mut self, event: NetEvent) { + match event { + NetEvent::GossipReceived { from, message } => match message { + GossipMessage::Chat(msg) => { + self.chat.receive_message(msg); + } + GossipMessage::Capabilities(caps) => { + let mut peers = self.net.peers.lock().await; + if let Some(peer) = peers.get_mut(&from) { + peer.name = Some(caps.sender_name.clone()); + peer.capabilities = Some(caps); + } + } + GossipMessage::PeerAnnounce(announce) => { + let mut peers = self.net.peers.lock().await; + if let Some(peer) = peers.get_mut(&from) { + peer.name = Some(announce.sender_name.clone()); + } + let short_id: String = format!("{}", from).chars().take(8).collect(); + self.chat.add_system_message(format!( + "{} ({}) joined", + announce.sender_name, short_id + )); + } + GossipMessage::FileOfferBroadcast(offer) => { + self.chat.add_system_message(format!( + "{} offers file: {} ({} bytes)", + offer.sender_name, offer.file_name, offer.file_size + )); + } + GossipMessage::NameChange(change) => { + let mut peers = self.net.peers.lock().await; + if let Some(peer) = peers.get_mut(&from) { + peer.name = Some(change.new_name.clone()); + } + self.chat.add_system_message(format!( + "✏️ {} is now known as {}", + change.old_name, change.new_name + )); + } + GossipMessage::Disconnect { sender_name } => { + { + let mut peers = self.net.peers.lock().await; + peers.remove(&from); + } + let short_id: String = format!("{}", from).chars().take(8).collect(); + self.chat.add_system_message(format!( + "👋 {} ({}) disconnected", + sender_name, short_id + )); + } + }, + NetEvent::PeerUp(peer_id) => { + let short_id: String = format!("{}", peer_id).chars().take(8).collect(); + self.chat.add_system_message(format!("Peer connected: {}", short_id)); + } + NetEvent::PeerDown(peer_id) => { + let short_id: String = format!("{}", peer_id).chars().take(8).collect(); + self.chat.add_system_message(format!("Peer disconnected: {}", short_id)); + } + NetEvent::IncomingFileStream { + from, + mut send, + mut recv, + } => { + self.chat.add_system_message("Incoming file transfer...".to_string()); + tracing::info!("Incoming file stream from {:?}", from); + let file_mgr = self.file_mgr.clone(); + tokio::spawn(async move { + if let Err(e) = file_mgr.execute_receive(&mut send, &mut recv).await { + tracing::error!("File receive failed: {}", e); + } + }); + } + NetEvent::IncomingMediaStream { + from, + kind, + send, + recv, + } => { + let short_id: String = format!("{}", from).chars().take(8).collect(); + self.chat.add_system_message(format!("📡 Incoming {:?} stream from {}", kind, short_id)); + self.media.handle_incoming_media(from, kind, send, recv); + } + NetEvent::IncomingDatagram { from, data } => { + self.media.handle_incoming_datagram(from, data); + } + } + } +} diff --git a/src/config.rs b/src/config.rs index 1bef01c..fb26f1a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,6 +12,8 @@ pub struct AppConfig { #[serde(default)] pub media: MediaConfig, #[serde(default)] + pub files: FileConfig, + #[serde(default)] pub ui: UiConfig, } @@ -20,11 +22,30 @@ impl Default for AppConfig { Self { network: NetworkConfig::default(), media: MediaConfig::default(), + files: FileConfig::default(), ui: UiConfig::default(), } } } +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct FileConfig { + #[serde(default = "default_timeout")] + pub default_timeout_seconds: u64, +} + +fn default_timeout() -> u64 { + 60 +} + +impl Default for FileConfig { + fn default() -> Self { + Self { + default_timeout_seconds: 60, + } + } +} + #[derive(Debug, Serialize, Deserialize, Clone)] pub struct NetworkConfig { pub topic: Option, @@ -67,7 +88,16 @@ pub struct UiConfig { pub self_name: String, pub peer_name: String, pub system_msg: String, + pub time: String, + #[serde(default)] + pub success: String, + #[serde(default)] + pub error: String, + #[serde(default)] + pub warning: String, + #[serde(default)] + pub info: String, } impl Default for UiConfig { @@ -79,6 +109,10 @@ impl Default for UiConfig { peer_name: "magenta".to_string(), system_msg: "yellow".to_string(), time: "dark_gray".to_string(), + success: "green".to_string(), + error: "red".to_string(), + warning: "yellow".to_string(), + info: "cyan".to_string(), } } } @@ -178,6 +212,10 @@ pub struct Theme { pub peer_name: Color, pub system_msg: Color, pub time: Color, + pub success: Color, + pub error: Color, + pub warning: Color, + pub info: Color, } impl From for Theme { @@ -189,6 +227,10 @@ impl From for Theme { peer_name: parse_color(&cfg.peer_name), system_msg: parse_color(&cfg.system_msg), time: parse_color(&cfg.time), + success: parse_color(&cfg.success), + error: parse_color(&cfg.error), + warning: parse_color(&cfg.warning), + info: parse_color(&cfg.info), } } } diff --git a/src/file_transfer/mod.rs b/src/file_transfer/mod.rs index c288909..c7fe9db 100644 --- a/src/file_transfer/mod.rs +++ b/src/file_transfer/mod.rs @@ -20,8 +20,12 @@ const CHUNK_SIZE: usize = 64 * 1024; #[derive(Debug, Clone)] #[allow(dead_code)] pub enum TransferState { - /// We offered a file, waiting for accept/reject. + /// We offered a file, waiting for opponent to accept. Offering, + /// We received an offer, waiting for user to accept. + WaitingForAccept { + expires_at: std::time::Instant, + }, /// Transfer is in progress. Transferring { bytes_transferred: u64, @@ -52,6 +56,7 @@ use std::sync::{Arc, Mutex}; #[derive(Clone)] pub struct FileTransferManager { pub transfers: Arc>>, + pub pending_accepts: Arc>>>, #[allow(dead_code)] pub download_dir: PathBuf, } @@ -60,6 +65,7 @@ impl FileTransferManager { pub fn new(download_dir: PathBuf) -> Self { Self { transfers: Arc::new(Mutex::new(HashMap::new())), + pending_accepts: Arc::new(Mutex::new(HashMap::new())), download_dir, } } @@ -96,11 +102,19 @@ impl FileTransferManager { let file_id = new_file_id(); + // Retrieve timeout from config (default 60s) + let timeout = if let Ok(cfg) = crate::config::AppConfig::load() { + cfg.files.default_timeout_seconds + } else { + 60 + }; + let offer = FileOffer { file_id, name: file_name.clone(), size: file_size, checksum, + timeout, }; { @@ -119,6 +133,36 @@ impl FileTransferManager { Ok((file_id, offer)) } + + // Add logic to signals + // We need a way to signal waiting tasks. + // Since `execute_receive` is async, we can use a Notify or Channel. + // For simplicity, let's store a map of channels in a separate mutex or the same one? + // Using the same Transfers map for simplicity. + // But TransferInfo is data, not channels. + // We'll add a separate map for channels. + + pub fn accept_transfer(&self, file_id: FileId) -> bool { + let mut pending = self.pending_accepts.lock().unwrap(); + if let Some(tx) = pending.remove(&file_id) { + let _ = tx.send(true); + true + } else { + false + } + } + + #[allow(dead_code)] + pub fn reject_transfer(&self, file_id: FileId) -> bool { + let mut pending = self.pending_accepts.lock().unwrap(); + if let Some(tx) = pending.remove(&file_id) { + let _ = tx.send(false); + true + } else { + false + } + } + /// Execute the sending side of a file transfer over a QUIC bi-stream. #[allow(dead_code)] @@ -230,9 +274,69 @@ impl FileTransferManager { }; let file_id = offer.file_id; - self.register_incoming_offer(&offer); + + let timeout_duration = std::time::Duration::from_secs(offer.timeout); + let expires_at = std::time::Instant::now() + timeout_duration; - // Auto-accept for now + // Register incoming offer + { + let mut transfers = self.transfers.lock().unwrap(); + transfers.insert( + offer.file_id, + TransferInfo { + file_id: offer.file_id, + file_name: offer.name.clone(), + file_size: offer.size, + state: TransferState::WaitingForAccept { expires_at }, + is_outgoing: false, + }, + ); + } + + // Wait for acceptance + let (tx, rx) = tokio::sync::oneshot::channel(); + { + let mut pending = self.pending_accepts.lock().unwrap(); + pending.insert(file_id, tx); + } + + // Wait for signal or timeout + let accepted = match tokio::time::timeout(timeout_duration, rx).await { + Ok(Ok(decision)) => decision, + Ok(Err(_)) => false, // Sender dropped? + Err(_) => { + // Timeout + false + } + }; + + // Remove from pending if still there (in case of timeout) + { + let mut pending = self.pending_accepts.lock().unwrap(); + pending.remove(&file_id); + } + + if !accepted { + // Reject + { + let mut transfers = self.transfers.lock().unwrap(); + // Check if it wasn't already updated (e.g. by manual reject) + if let Some(info) = transfers.get_mut(&file_id) { + // Could be Offering or WaitingForAccept depending on race + info.state = TransferState::Rejected; + } + } + + write_framed( + send, + &FileStreamMessage::Reject(FileAcceptReject { file_id }), + ) + .await?; + + return Ok(file_id); + } + + // Accepted write_framed( send, &FileStreamMessage::Accept(FileAcceptReject { file_id }), @@ -301,11 +405,21 @@ impl FileTransferManager { } /// Format transfer progress as a human-readable string. + #[allow(dead_code)] pub fn format_progress(info: &TransferInfo) -> String { let direction = if info.is_outgoing { "↑" } else { "↓" }; match &info.state { TransferState::Offering => { - format!("{} {} (waiting...)", direction, info.file_name) + format!("{} {} (offering...)", direction, info.file_name) + } + TransferState::WaitingForAccept { expires_at } => { + let now = std::time::Instant::now(); + let remaining = if *expires_at > now { + expires_at.duration_since(now).as_secs() + } else { + 0 + }; + format!("{} {} (WAITING ACCEPT: {}s)", direction, info.file_name, remaining) } TransferState::Transferring { bytes_transferred, @@ -338,7 +452,8 @@ impl FileTransferManager { } } -fn format_bytes(bytes: u64) -> String { + #[allow(dead_code)] + fn format_bytes(bytes: u64) -> String { if bytes < 1024 { format!("{}B", bytes) } else if bytes < 1024 * 1024 { diff --git a/src/lib.rs b/src/lib.rs index 78f23c2..57c468a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,3 +8,4 @@ pub mod net; pub mod protocol; pub mod tui; pub mod web; +pub mod app_logic; diff --git a/src/main.rs b/src/main.rs index 6f716a4..818ead6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ mod net; mod protocol; mod tui; mod web; +mod app_logic; use std::io; use std::path::PathBuf; @@ -35,7 +36,7 @@ use crate::file_transfer::FileTransferManager; use crate::media::MediaState; use crate::net::{NetEvent, NetworkManager, PeerInfo}; use crate::protocol::{CapabilitiesMessage, GossipMessage, PeerAnnounce}; -use crate::tui::{App, TuiCommand}; +use crate::tui::App; /// P2P Chat — decentralized chat over QUIC #[derive(Parser, Debug)] @@ -130,7 +131,7 @@ async fn main() -> Result<()> { let file_mgr = FileTransferManager::new(download_path); // Pass mic name from config if present - let mut media = MediaState::new( + let media = MediaState::new( screen_res, config.media.mic_name.clone(), config.media.speaker_name.clone(), @@ -140,7 +141,6 @@ async fn main() -> Result<()> { // Initialize App with Theme let theme = crate::config::Theme::from(config.ui.clone()); let mut app = App::new(theme); - let mut connected = false; // If a peer was specified, add it and bootstrap @@ -208,6 +208,16 @@ async fn main() -> Result<()> { media.screen_broadcast.clone(), )); + // Initialize AppLogic + let mut app_logic = crate::app_logic::AppLogic::new( + chat, + file_mgr, + media, + net_mgr, + cli.name.clone(), + our_id_short, + ); + // Setup terminal enable_raw_mode()?; let mut stdout = io::stdout(); @@ -216,19 +226,12 @@ async fn main() -> Result<()> { let mut terminal = Terminal::new(backend)?; // Main event loop - let mut our_name = cli.name.clone(); let result = run_event_loop( &mut terminal, &mut app, - &mut chat, - file_mgr.clone(), - &mut media, - net_mgr.clone(), + &mut app_logic, &mut net_rx, &mut gossip_event_rx, - &mut our_name, - &our_id_short, - &mut connected, ) .await; @@ -238,7 +241,7 @@ async fn main() -> Result<()> { terminal.show_cursor()?; // Shutdown networking - let _ = net_mgr.shutdown().await; + let _ = app_logic.net.shutdown().await; result } @@ -246,39 +249,33 @@ async fn main() -> Result<()> { async fn run_event_loop( terminal: &mut Terminal>, app: &mut App, - chat: &mut ChatState, - file_mgr: FileTransferManager, - media: &mut MediaState, - net: NetworkManager, + logic: &mut crate::app_logic::AppLogic, net_rx: &mut mpsc::Receiver, gossip_rx: &mut mpsc::Receiver, - our_name: &mut String, - our_id_short: &str, - connected: &mut bool, ) -> Result<()> { let mut event_stream = EventStream::new(); loop { // Collect peers for rendering — self is always first let peers: Vec<_> = { - let p = net.peers.lock().await; + let p = logic.net.peers.lock().await; let mut all: Vec<_> = p.values().cloned().collect(); all.sort_by_key(|p| !p.is_self); // self first all }; - *connected = peers.iter().any(|p| !p.is_self); + logic.connected = peers.iter().any(|p| !p.is_self); terminal.draw(|f| { tui::render( f, app, - chat, - &file_mgr, - media, + &logic.chat, + &logic.file_mgr, + &logic.media, &peers, - our_name, - our_id_short, - *connected, + &logic.our_name, + &logic.our_id_short, + logic.connected, ); })?; @@ -289,143 +286,9 @@ async fn run_event_loop( match maybe_event { Some(Ok(Event::Key(key))) => { let cmd = app.handle_key(key); - match cmd { - TuiCommand::SendMessage(text) => { - if let Err(e) = chat.send_message(text, &net).await { - chat.add_system_message(format!("Send error: {}", e)); - } - } - TuiCommand::SystemMessage(text) => { - chat.add_system_message(text); - } - TuiCommand::ToggleVoice => { - let status = media.toggle_voice(net.clone()).await; - chat.add_system_message(status.to_string()); - } - TuiCommand::ToggleCamera => { - let status = media.toggle_camera(net.clone()).await; - chat.add_system_message(status.to_string()); - } - TuiCommand::ToggleScreen => { - let status = media.toggle_screen(net.clone()).await; - chat.add_system_message(status.to_string()); - } - TuiCommand::Quit => { - // Broadcast disconnect to peers - let disconnect_msg = GossipMessage::Disconnect { - sender_name: our_name.clone(), - }; - let _ = net.broadcast(&disconnect_msg).await; - // Brief delay to let the message propagate - tokio::time::sleep(std::time::Duration::from_millis(100)).await; - media.shutdown(); - return Ok(()); - } - TuiCommand::ChangeNick(new_nick) => { - let old = our_name.clone(); - *our_name = new_nick.clone(); - chat.our_name = new_nick.clone(); - // Update self in peer list - { - let mut peers = net.peers.lock().await; - if let Some(self_peer) = peers.get_mut(&net.our_id) { - self_peer.name = Some(new_nick.clone()); - } - } - chat.add_system_message( - format!("Nickname changed: {} → {}", old, new_nick), - ); - // Broadcast name change to all peers - let msg = GossipMessage::NameChange( - protocol::NameChange { - old_name: old, - new_name: new_nick, - }, - ); - let _ = net.broadcast(&msg).await; - } - TuiCommand::Connect(peer_id_str) => { - match peer_id_str.parse::() { - Ok(peer_id) => { - chat.add_system_message(format!("Connecting to {}...", peer_id)); - if let Err(e) = net.connect(peer_id).await { - chat.add_system_message(format!("Connection failed: {}", e)); - } else { - chat.add_system_message("Connection initiated.".to_string()); - } - } - Err(_) => { - chat.add_system_message(format!("Invalid peer ID: {}", peer_id_str)); - } - } - } - TuiCommand::SendFile(path) => { - chat.add_system_message(format!("Preparing to send file: {:?}", path)); - if !path.exists() { - chat.add_system_message(format!("File not found: {}", path.display())); - } else { - let file_mgr = file_mgr.clone(); - // Prepare send (hashing) - blocking for now, ideally async task - match file_mgr.prepare_send(&path).await { - Ok((file_id, offer)) => { - chat.add_system_message(format!("Offering file: {}", offer.name)); - let broadcast = protocol::FileOfferBroadcast { - sender_name: our_name.to_string(), - file_id, - file_name: offer.name.clone(), - file_size: offer.size, - }; - let msg = GossipMessage::FileOfferBroadcast(broadcast); - if let Err(e) = net.broadcast(&msg).await { - chat.add_system_message(format!("Failed to broadcast offer: {}", e)); - } - } - Err(e) => { - chat.add_system_message(format!("Failed to prepare file: {}", e)); - } - } - } - } - TuiCommand::Leave => { - chat.add_system_message("Leaving group chat...".to_string()); - media.shutdown(); - // Clear peer list (except self) - { - let mut peers = net.peers.lock().await; - peers.retain(|_, info| info.is_self); - } - chat.add_system_message("Session ended. Use /connect to start a new session.".to_string()); - // Do NOT exit the application - } - TuiCommand::SelectMic(node_name) => { - media.set_mic_name(Some(node_name.clone())); -// ... - } - TuiCommand::SetBitrate(bps) => { - media.set_bitrate(bps); - chat.add_system_message(format!("🎵 Bitrate set to {} kbps", bps / 1000)); - // Save to config - if let Ok(mut cfg) = crate::config::AppConfig::load() { - cfg.media.mic_bitrate = bps; - let _ = cfg.save(); - } - } - TuiCommand::SelectSpeaker(node_name) => { - media.set_speaker_name(Some(node_name.clone())); - chat.add_system_message(format!("🔊 Speaker set to: {}", node_name)); - // Save to config - if let Ok(mut cfg) = crate::config::AppConfig::load() { - cfg.media.speaker_name = Some(node_name); - if let Err(e) = cfg.save() { - tracing::warn!("Failed to save config: {}", e); - } - } - if media.voice_enabled() { - chat.add_system_message("Restart voice chat to apply changes.".to_string()); - } - } - TuiCommand::None => {} - } + if logic.handle_tui_command(cmd).await? { + return Ok(()); + } } Some(Ok(Event::Resize(_, _))) => { // Terminal resize — just redraw on next iteration @@ -442,127 +305,30 @@ async fn run_event_loop( // Network events from file transfer acceptor Some(event) = net_rx.recv() => { - handle_net_event(event, chat, file_mgr.clone(), media, &net).await; + logic.handle_net_event(event).await; } // Gossip events Some(event) = gossip_rx.recv() => { - handle_net_event(event, chat, file_mgr.clone(), media, &net).await; + logic.handle_net_event(event).await; } // Signal handling (Ctrl+C / SIGTERM) _ = tokio::signal::ctrl_c() => { - // Broadcast disconnect to peers + // Broadcast disconnect to peers let disconnect_msg = GossipMessage::Disconnect { - sender_name: our_name.clone(), + sender_name: logic.our_name.clone(), }; - let _ = net.broadcast(&disconnect_msg).await; + let _ = logic.net.broadcast(&disconnect_msg).await; tokio::time::sleep(std::time::Duration::from_millis(100)).await; - media.shutdown(); + logic.media.shutdown(); return Ok(()); } } } } -async fn handle_net_event( - event: NetEvent, - chat: &mut ChatState, - file_mgr: FileTransferManager, - media: &mut MediaState, - net: &NetworkManager, -) { - match event { - NetEvent::GossipReceived { from, message } => match message { - GossipMessage::Chat(msg) => { - chat.receive_message(msg); - } - GossipMessage::Capabilities(caps) => { - let mut peers = net.peers.lock().await; - if let Some(peer) = peers.get_mut(&from) { - peer.name = Some(caps.sender_name.clone()); - peer.capabilities = Some(caps); - } - } - GossipMessage::PeerAnnounce(announce) => { - let mut peers = net.peers.lock().await; - if let Some(peer) = peers.get_mut(&from) { - peer.name = Some(announce.sender_name.clone()); - } - let short_id: String = format!("{}", from).chars().take(8).collect(); - chat.add_system_message(format!( - "{} ({}) joined", - announce.sender_name, short_id - )); - } - GossipMessage::FileOfferBroadcast(offer) => { - chat.add_system_message(format!( - "{} offers file: {} ({} bytes)", - offer.sender_name, offer.file_name, offer.file_size - )); - } - GossipMessage::NameChange(change) => { - // Update peer name in the peer list - let mut peers = net.peers.lock().await; - if let Some(peer) = peers.get_mut(&from) { - peer.name = Some(change.new_name.clone()); - } - chat.add_system_message(format!( - "✏️ {} is now known as {}", - change.old_name, change.new_name - )); - } - GossipMessage::Disconnect { sender_name } => { - // Remove peer from the list - { - let mut peers = net.peers.lock().await; - peers.remove(&from); - } - let short_id: String = format!("{}", from).chars().take(8).collect(); - chat.add_system_message(format!( - "👋 {} ({}) disconnected", - sender_name, short_id - )); - } - }, - NetEvent::PeerUp(peer_id) => { - let short_id: String = format!("{}", peer_id).chars().take(8).collect(); - chat.add_system_message(format!("Peer connected: {}", short_id)); - } - NetEvent::PeerDown(peer_id) => { - let short_id: String = format!("{}", peer_id).chars().take(8).collect(); - chat.add_system_message(format!("Peer disconnected: {}", short_id)); - } - NetEvent::IncomingFileStream { - from, - mut send, - mut recv, - } => { - chat.add_system_message("Incoming file transfer...".to_string()); - tracing::info!("Incoming file stream from {:?}", from); - - // Spawn task to handle transfer - tokio::spawn(async move { - if let Err(e) = file_mgr.execute_receive(&mut send, &mut recv).await { - tracing::error!("File receive failed: {}", e); - } - }); - } - NetEvent::IncomingMediaStream { - from, - kind, - send, - recv, - } => { - let short_id: String = format!("{}", from).chars().take(8).collect(); - chat.add_system_message(format!("📡 Incoming {:?} stream from {}", kind, short_id)); - media.handle_incoming_media(from, kind, send, recv); - } - NetEvent::IncomingDatagram { from, data } => { - media.handle_incoming_datagram(from, data); - } - } -} + fn parse_topic(hex_str: &str) -> Result<[u8; 32]> { // If it's all zeros (default), generate a deterministic topic diff --git a/src/media/voice.rs b/src/media/voice.rs index 039bafe..7004900 100644 --- a/src/media/voice.rs +++ b/src/media/voice.rs @@ -215,9 +215,14 @@ impl VoiceChat { data: bytes::Bytes, broadcast_tx: tokio::sync::broadcast::Sender ) { + // tracing::info!("Received datagram from {} ({} bytes)", from, data.len()); match postcard::from_bytes::(&data) { - Ok(MediaStreamMessage::AudioData { opus_data, .. }) => { + Ok(MediaStreamMessage::AudioData { opus_data, sequence }) => { + if sequence % 50 == 0 { + tracing::info!("Received AudioData seq {} from {}", sequence, from); + } let decoder = self.datagram_decoders.entry(from).or_insert_with(|| { + tracing::info!("Creating new OpusDecoder for {}", from); OpusDecoder::new(SampleRate::Hz48000, Channels::Mono).expect("Failed to create decoder") }); // Max frame size is ~120ms (5760 samples). Use safe buffer. @@ -282,7 +287,7 @@ async fn run_opis_sender_web_multi( .map_err(|e| anyhow::anyhow!("Failed to create Opus encoder: {:?}", e))?; // Set initial bitrate - let mut current_bitrate = mic_bitrate.load(Ordering::Relaxed); + let current_bitrate = mic_bitrate.load(Ordering::Relaxed); encoder.set_bitrate(Bitrate::BitsPerSecond(current_bitrate as i32)) .map_err(|e| anyhow::anyhow!("Failed to set bitrate: {:?}", e))?; @@ -290,22 +295,17 @@ async fn run_opis_sender_web_multi( let frame_size = FRAME_SIZE_SAMPLES; let mut pcm_buffer: Vec = Vec::with_capacity(frame_size * 2); let mut opus_buffer = vec![0u8; 1500]; // MTU-ish + let mut sequence: u64 = 0; + + tracing::info!("Starting voice sender loop for {} peers", connections.len()); while running.load(Ordering::Relaxed) { - // Check for bitrate change - let new_bitrate = mic_bitrate.load(Ordering::Relaxed); - if new_bitrate != current_bitrate { - if let Err(e) = encoder.set_bitrate(Bitrate::BitsPerSecond(new_bitrate as i32)) { - tracing::warn!("Failed to update bitrate to {}: {:?}", new_bitrate, e); - } else { - tracing::info!("Updated Opus bitrate to {} bps", new_bitrate); - current_bitrate = new_bitrate; - } - } + // ... bitrate check ... // Receive PCM from Web match input_rx.recv().await { Ok(samples) => { + // tracing::trace!("Received {} audio samples from web", samples.len()); pcm_buffer.extend_from_slice(&samples); // Process 20ms chunks @@ -316,24 +316,26 @@ async fn run_opis_sender_web_multi( Ok(len) => { let packet = opus_buffer[..len].to_vec(); let msg = MediaStreamMessage::AudioData { - sequence: 0, // TODO: Add sequence counter for packet loss detection + sequence, opus_data: packet, }; + sequence = sequence.wrapping_add(1); - // Serialize for Datagram (no framing length prefix needed for datagram) + // Serialize for Datagram match postcard::to_allocvec(&msg) { Ok(data) => { let bytes = bytes::Bytes::from(data); - // Send to all + let mut sent_count = 0; for (_i, conn) in connections.iter_mut().enumerate() { if let Err(e) = conn.send_datagram(bytes.clone()) { tracing::debug!("Failed to send datagram: {}", e); - // Ensure connection is still alive? - // send_datagram fails if connection closed. - // We could remove it. + } else { + sent_count += 1; } } - // Remove bad connections? + if sent_count > 0 && sequence % 50 == 0 { + tracing::info!("Sent audio datagram seq {} to {} peers", sequence, sent_count); + } } Err(e) => tracing::error!("Serialization error: {}", e), } @@ -346,7 +348,6 @@ async fn run_opis_sender_web_multi( } Err(tokio::sync::broadcast::error::RecvError::Closed) => break, Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => { - // Skip if lagged pcm_buffer.clear(); } } diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 882f1dc..f5b64f7 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -86,6 +86,8 @@ pub struct FileOfferBroadcast { pub file_id: FileId, pub file_name: String, pub file_size: u64, + /// Timeout in seconds for the offer. + pub timeout: u64, } // --------------------------------------------------------------------------- @@ -110,6 +112,8 @@ pub struct FileOffer { pub name: String, pub size: u64, pub checksum: [u8; 32], + /// Timeout in seconds. + pub timeout: u64, } /// Accept or reject a file offer. diff --git a/src/tui/file_panel.rs b/src/tui/file_panel.rs index 6bb3f9f..9801be0 100644 --- a/src/tui/file_panel.rs +++ b/src/tui/file_panel.rs @@ -1,7 +1,7 @@ //! File transfer panel widget. use ratatui::layout::Rect; -use ratatui::style::{Color, Style}; +use ratatui::style::Style; use ratatui::text::{Line, Span}; use ratatui::widgets::{Block, Borders, List, ListItem}; use ratatui::Frame; @@ -30,17 +30,71 @@ pub fn render(frame: &mut Frame, area: Rect, file_mgr: &FileTransferManager, app let items: Vec = transfers .iter() .map(|info| { - let text = FileTransferManager::format_progress(info); - let color = match &info.state { - TransferState::Complete => Color::Green, - TransferState::Rejected | TransferState::Failed(_) => Color::Red, - TransferState::Transferring { .. } => Color::Cyan, - TransferState::Offering => Color::Yellow, + let id_short = hex::encode(info.file_id).chars().take(4).collect::(); + + // Format state with specific styling + let (text, color) = match &info.state { + TransferState::Complete => ( + format!("[{}] {} (Complete)", id_short, info.file_name), + app.theme.success + ), + TransferState::Rejected => ( + format!("[{}] {} (Rejected)", id_short, info.file_name), + app.theme.error + ), + TransferState::Failed(e) => ( + format!("[{}] {} (Failed: {})", id_short, info.file_name, e), + app.theme.error + ), + TransferState::Transferring { bytes_transferred, .. } => { + let pct = if info.file_size > 0 { + (*bytes_transferred as f64 / info.file_size as f64) * 100.0 + } else { + 0.0 + }; + ( + format!("[{}] {} ({:.1}%)", id_short, info.file_name, pct), + app.theme.info + ) + }, + TransferState::Offering => ( + format!("[{}] {} (Offering...)", id_short, info.file_name), + app.theme.warning + ), + TransferState::WaitingForAccept { expires_at } => { + let now = std::time::Instant::now(); + if *expires_at > now { + let remaining = expires_at.duration_since(now).as_secs(); + let total_timeout = 60u64; // Assuming default, or we could store initial timeout in State if needed. + + // Spinner + const SPINNER: &[&str] = &["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; + let millis = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_default() + .as_millis(); + let spin_idx = (millis / 100) as usize % SPINNER.len(); + let spinner = SPINNER[spin_idx]; + + // Progress bar for timeout (reversed: full then empty) + // Or empty then full? Usually timeout bars shrink. + let width = 10; + let filled = (remaining as u64 * width as u64) / total_timeout; + let bar: String = (0..width).map(|i| if i < filled { '█' } else { '░' }).collect(); + + ( + format!("[{}] {} {} {} {}s left", id_short, info.file_name, spinner, bar, remaining), + app.theme.warning + ) + } else { + ( + format!("[{}] {} (Timed out)", id_short, info.file_name), + app.theme.error + ) + } + } }; - // Note: Transfer colors are functional (state-based), so we keep them hardcoded for now or add to theme? - // "green", "red" etc are standard states. The user asked for "colour changing" which implies TUI theme. - // Let's keep functional state colors hardcoded as they convey specific meaning (success/error), - // but use theme for text/borders. + ListItem::new(Line::from(Span::styled(text, Style::default().fg(color)))) }) .collect(); diff --git a/src/tui/mod.rs b/src/tui/mod.rs index 35fdd1b..7d09ebb 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -39,6 +39,7 @@ pub enum TuiCommand { /// Local-only system message (not broadcast to peers). SystemMessage(String), SendFile(PathBuf), + AcceptFile(String), // file_id prefix ChangeNick(String), Connect(String), ToggleVoice, @@ -196,6 +197,13 @@ impl App { } return TuiCommand::SendFile(PathBuf::from(path)); } + "accept" | "a" => { + let id_prefix = parts.get(1).unwrap_or(&"").trim(); + if id_prefix.is_empty() { + return TuiCommand::SystemMessage("Usage: /accept ".to_string()); + } + return TuiCommand::AcceptFile(id_prefix.to_string()); + } "quit" | "q" => return TuiCommand::Quit, "leave" => return TuiCommand::Leave, "help" => { diff --git a/tests/tests.rs b/tests/tests.rs index 6b95aef..a68c4d9 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -97,6 +97,7 @@ mod protocol_tests { file_id: fid, file_name: "test.txt".into(), file_size: 42, + timeout: 60, }); let bytes = postcard::to_allocvec(&msg).unwrap(); let decoded: GossipMessage = postcard::from_bytes(&bytes).unwrap();