breaking up backend and tui/webui

This commit is contained in:
mixa
2026-02-11 22:36:44 +03:00
parent 472b615ea4
commit 3962999aeb
14 changed files with 1462 additions and 304 deletions

3
.gitignore vendored
View File

@@ -1 +1,4 @@
target
.*
!.gitignore
*.log

1
Cargo.lock generated
View File

@@ -3377,6 +3377,7 @@ dependencies = [
"crossterm 0.28.1",
"directories",
"futures",
"hex",
"iroh",
"iroh-gossip",
"libspa",

View File

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

View File

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

310
src/app_logic.rs Normal file
View File

@@ -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<bool> {
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::<crate::net::EndpointId>() {
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 <peer_id> 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::<String>()));
} 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);
}
}
}
}

View File

@@ -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<String>,
@@ -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<UiConfig> for Theme {
@@ -189,6 +227,10 @@ impl From<UiConfig> 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),
}
}
}

View File

@@ -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<Mutex<HashMap<FileId, TransferInfo>>>,
pub pending_accepts: Arc<Mutex<HashMap<FileId, tokio::sync::oneshot::Sender<bool>>>>,
#[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 {

View File

@@ -8,3 +8,4 @@ pub mod net;
pub mod protocol;
pub mod tui;
pub mod web;
pub mod app_logic;

View File

@@ -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<CrosstermBackend<io::Stdout>>,
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<NetEvent>,
gossip_rx: &mut mpsc::Receiver<NetEvent>,
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::<crate::net::EndpointId>() {
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 <peer_id> 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

View File

@@ -215,9 +215,14 @@ impl VoiceChat {
data: bytes::Bytes,
broadcast_tx: tokio::sync::broadcast::Sender<WebMediaEvent>
) {
// tracing::info!("Received datagram from {} ({} bytes)", from, data.len());
match postcard::from_bytes::<MediaStreamMessage>(&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<f32> = 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();
}
}

View File

@@ -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.

View File

@@ -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<ListItem> = 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::<String>();
// 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();

View File

@@ -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 <file_id_prefix>".to_string());
}
return TuiCommand::AcceptFile(id_prefix.to_string());
}
"quit" | "q" => return TuiCommand::Quit,
"leave" => return TuiCommand::Leave,
"help" => {

View File

@@ -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();