From 7304b33b7cf0ec9e8c52692fef1f5d6f711f6b08 Mon Sep 17 00:00:00 2001 From: Xory Date: Mon, 17 Nov 2025 23:00:04 +0200 Subject: [PATCH] wip --- README.md | 1 + src/lib.rs | 30 +++++++++++ src/lib/logger.rs | 59 ++++++++++++++++++++ src/main.rs | 134 ++++++++++++++++++++++++++++++++++++---------- test.txt | 115 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 312 insertions(+), 27 deletions(-) create mode 100644 README.md create mode 100644 src/lib/logger.rs create mode 100644 test.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..969e63a --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# skylink diff --git a/src/lib.rs b/src/lib.rs index 5e9d5e0..47f3a30 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,19 @@ +use futures_util::StreamExt; +use futures_util::stream::SplitSink; use serde::{Deserialize, Serialize}; +use std::sync::Arc; +use tokio::{net::TcpStream, sync::Mutex}; +use tokio_tungstenite::tungstenite::protocol::Message; +use tokio_tungstenite::{MaybeTlsStream, WebSocketStream, connect_async}; + +pub const WS_URL: &str = "ws://127.0.0.1:8080"; +pub const LOG_PATH: &str = "test.txt"; + +pub mod lib { + pub mod logger; +} + +pub type WsTx = Arc>, Message>>>>; #[derive(Deserialize, Serialize)] pub enum PayloadType { @@ -26,3 +41,18 @@ pub enum Command<'a> { Dnx { params: DnxParams<'a> }, Screenshot, } + +pub async fn reconnect_websocket(ws: WsTx) { + let mut lock = ws.lock().await; + loop { + if let Ok(connection) = connect_async(WS_URL).await { + let (ws_conn, _) = connection; + let (ws_trx, _) = ws_conn.split(); + *lock = Some(ws_trx); + break; + } + println!("reconnect slp"); + std::thread::sleep(std::time::Duration::from_secs(5)); + println!("reconnect out"); + } +} diff --git a/src/lib/logger.rs b/src/lib/logger.rs new file mode 100644 index 0000000..5d7cc61 --- /dev/null +++ b/src/lib/logger.rs @@ -0,0 +1,59 @@ +use crate::WsTx; +use crate::reconnect_websocket; +use futures_util::SinkExt; +use std::fs::OpenOptions; +use std::io::Write; +use std::time::{SystemTime, UNIX_EPOCH}; +use tokio_tungstenite::tungstenite::protocol::Message; + +#[derive(PartialEq)] +pub enum LogLevel { + Debug, + Info, + Warning, + Error, +} + +pub async fn log(level: LogLevel, path: &str, detail: String) { + if let Ok(mut logfile) = OpenOptions::new() + .write(true) + .append(true) + .create(true) + .open(path) + { + let unix_timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() // fault tolerance is cool but here it'd be overkill + .as_secs(); + + let logfile_string = match level { + LogLevel::Debug => format!("[ {unix_timestamp} ] [ debug ] {detail}\n"), + LogLevel::Info => format!("[ {unix_timestamp} ] [ info ] {detail}\n"), + LogLevel::Warning => format!("[ {unix_timestamp} ] [ Warning ] {detail}\n"), + LogLevel::Error => format!("[ {unix_timestamp} ] [ ERROR ] {detail}\n"), + }; + let ansi_string = match level { + LogLevel::Debug => { + format!("[ \x1B[0;90m{unix_timestamp} \x1B[0m] [ \x1B[0;37mdebug\x1B[0m ] {detail}") + } + LogLevel::Info => { + format!("[ \x1B[0;90m{unix_timestamp} \x1B[0m] [ \x1B[1;92minfo\x1B[0m ] {detail}") + } + LogLevel::Warning => { + format!("[ \x1B[0;90m{unix_timestamp} \x1B[0m] [ \x1B[1;93mWarning\x1B[0m ] {detail}") + } + LogLevel::Error => { + format!("[ \x1B[0;90m{unix_timestamp} \x1B[0m] [ \x1B[1;101;30mERROR\x1B[0m ] {detail}") + } + }; + + println!("{}", ansi_string); + + if let Err(e) = logfile.write(logfile_string.as_bytes()) { + eprintln!( + "Got error {:?} while trying to write to logfile.\n Exiting.", + e + ); + } + } +} diff --git a/src/main.rs b/src/main.rs index ccb265a..73544db 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,49 +1,129 @@ -use futures_util::stream::StreamExt; -use skylink::{Command, DnxParams, PayloadType}; +use futures_util::{SinkExt, stream::StreamExt}; +use skylink::WsTx; +use skylink::lib::logger::{LogLevel, log}; +use skylink::{LOG_PATH, WS_URL}; +use std::sync::Arc; +use tokio::sync::Mutex; +use tokio_tungstenite::tungstenite::protocol::Message; + +// This is the type for the SENDER half of the WebSocket stream. +// It will be the shared state. // Some parts of this function were generated by an LLM. I'm taking note of this in case a // weird barely detectable bug pops up, as LLMs tend to generate. -async fn websocket_handler() { +async fn websocket_handler(ws_tx: WsTx) { use std::time::Duration; use tokio_tungstenite::connect_async; - use tokio_tungstenite::tungstenite::protocol::Message; - let url = "ws://127.0.0.1:8080"; loop { - match connect_async(url).await { - Ok(ws_stream_tuple) => { - println!("[i] Connected via websocket."); // TODO Use logger over println - let (mut ws_stream, _) = ws_stream_tuple; - while let Some(msg) = ws_stream.next().await { - match msg { - Ok(Message::Text(text)) => { - println!("{}", &text); + let connection_result = connect_async(WS_URL).await; + + let ws_stream = match connection_result { + Ok((stream, _)) => { + log( + LogLevel::Info, + LOG_PATH, + "[ws] WebSocket connection established.".to_string(), + ) + .await; + stream + } + Err(e) => { + log( + LogLevel::Warning, + LOG_PATH, + format!("[ws] Failed to connect: {:?}. Retrying in 5s....", e) + ) + .await; + tokio::time::sleep(Duration::from_secs(5)).await; + continue; // Go to the next iteration of the loop to retry. + } + }; + + let (ws_send, mut ws_recv) = ws_stream.split(); + + { + let mut unlocked = ws_tx.lock().await; + *unlocked = Some(ws_send); + } + + while let Some(msg) = ws_recv.next().await { + match msg { + // break is used to trigger reconnect. + Ok(Message::Text(text)) => { + log( + LogLevel::Debug, + LOG_PATH, + format!("[ws] Received text: {}", &text) + ) + .await; + } + Ok(Message::Close(_)) => { + log( + LogLevel::Warning, + LOG_PATH, + format!("[ws] Received close frame, disconnecting.") + ) + .await; + break; + } + Ok(Message::Ping(h)) => { + log( + LogLevel::Debug, + LOG_PATH, + format!("[ws] Received Ping, sending Pong") + ) + .await; + let mut unlocked = ws_tx.lock().await; + dbg!(&ws_tx); + dbg!(&unlocked); + match unlocked.as_mut() { + Some(v) => { + if let Err(e) = v.send(Message::Pong(h)).await { + log(LogLevel::Error, LOG_PATH, format!("[ws] Failed to send Pong: {e}, reconnecting.")).await; + break; + } } - Ok(Message::Close(_)) => { - println!("[i] Disconnected."); + None => { + log(LogLevel::Error, LOG_PATH, format!("[ws] Failed to respond: no sink, reconnecting.")).await; break; } - Err(e) => { - eprintln!("Error receiving message: {:?}", e); - break; - } - _ => { - // Ignore other message types - } } } + Err(e) => { + log( + LogLevel::Error, + LOG_PATH, + format!("[ws] Error receiving message: {:?}.", e), + ) + .await; + break; + } + _ => { /* Ignore other message types */ } } - Err(e) => { - eprintln!("[e] Failed to connect: {:?}", e); // TODO logger > println + { + let mut unlocked_ws_tx = ws_tx.lock().await; + *unlocked_ws_tx = None; } } - println!("[i] Connection lost, reconnecting in 5 seconds..."); - tokio::time::sleep(Duration::from_secs(5)).await; + + log( + LogLevel::Error, + LOG_PATH, + format!("[ws] Connection lost.") + ) + .await; + + // Reconnecting is handled by the loop + // So, we sleep to avoid spamming the server. + std::thread::sleep(std::time::Duration::from_secs(5)); } } #[tokio::main] async fn main() -> anyhow::Result<()> { - websocket_handler().await; + let ws_tx: WsTx = Arc::new(Mutex::new(None)); + let ws_tx_for_handler = Arc::clone(&ws_tx); + websocket_handler(ws_tx_for_handler).await; Ok(()) } diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..20fde6a --- /dev/null +++ b/test.txt @@ -0,0 +1,115 @@ +[ 1763386850 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763386905 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763386929 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763387266 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763387271 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763387276 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763387281 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763387286 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763387291 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763387296 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763387441 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763387446 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763387451 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763387456 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763387461 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763387466 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763387471 ] [ info ] [ws] WebSocket connection established. +[ 1763387471 ] [ debug ] [ws] Received text: the dingaling +[ 1763387491 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763387491 ] [ ERROR ] [ws] Connection lost. +[ 1763387496 ] [ info ] [ws] WebSocket connection established. +[ 1763387496 ] [ debug ] [ws] Received text: the dingaling +[ 1763387516 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763387516 ] [ ERROR ] [ws] Connection lost. +[ 1763387521 ] [ info ] [ws] WebSocket connection established. +[ 1763387521 ] [ debug ] [ws] Received text: the dingaling +[ 1763387541 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763387541 ] [ ERROR ] [ws] Connection lost. +[ 1763387546 ] [ info ] [ws] WebSocket connection established. +[ 1763387546 ] [ debug ] [ws] Received text: the dingaling +[ 1763387566 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763387566 ] [ ERROR ] [ws] Connection lost. +[ 1763387571 ] [ info ] [ws] WebSocket connection established. +[ 1763387571 ] [ debug ] [ws] Received text: the dingaling +[ 1763387591 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763387591 ] [ ERROR ] [ws] Connection lost. +[ 1763387596 ] [ info ] [ws] WebSocket connection established. +[ 1763387596 ] [ debug ] [ws] Received text: the dingaling +[ 1763387616 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763387616 ] [ ERROR ] [ws] Connection lost. +[ 1763387621 ] [ info ] [ws] WebSocket connection established. +[ 1763387621 ] [ debug ] [ws] Received text: the dingaling +[ 1763387641 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763387641 ] [ ERROR ] [ws] Connection lost. +[ 1763387646 ] [ info ] [ws] WebSocket connection established. +[ 1763387646 ] [ debug ] [ws] Received text: the dingaling +[ 1763387666 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763387666 ] [ ERROR ] [ws] Connection lost. +[ 1763387674 ] [ info ] [ws] WebSocket connection established. +[ 1763387674 ] [ debug ] [ws] Received text: the dingaling +[ 1763387694 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763387694 ] [ ERROR ] [ws] Connection lost. +[ 1763387699 ] [ info ] [ws] WebSocket connection established. +[ 1763387699 ] [ debug ] [ws] Received text: the dingaling +[ 1763387728 ] [ info ] [ws] WebSocket connection established. +[ 1763387728 ] [ debug ] [ws] Received text: the dingaling +[ 1763387748 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763387748 ] [ ERROR ] [ws] Connection lost. +[ 1763387832 ] [ info ] [ws] WebSocket connection established. +[ 1763387832 ] [ debug ] [ws] Received text: the dingaling +[ 1763387852 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763387852 ] [ ERROR ] [ws] Sender is none. +[ 1763387980 ] [ info ] [ws] WebSocket connection established. +[ 1763387980 ] [ debug ] [ws] Received text: the dingaling +[ 1763388000 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763388000 ] [ ERROR ] [ws] Sender is none. +[ 1763388000 ] [ ERROR ] [ws] Connection lost. +[ 1763388005 ] [ info ] [ws] WebSocket connection established. +[ 1763388005 ] [ debug ] [ws] Received text: the dingaling +[ 1763388100 ] [ info ] [ws] WebSocket connection established. +[ 1763388100 ] [ debug ] [ws] Received text: the dingaling +[ 1763388120 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763388120 ] [ ERROR ] [ws] Sender is none. +[ 1763388120 ] [ ERROR ] [ws] Connection lost. +[ 1763388125 ] [ info ] [ws] WebSocket connection established. +[ 1763388125 ] [ debug ] [ws] Received text: the dingaling +[ 1763408430 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763408435 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763408440 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763408445 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763408450 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763408455 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763408460 ] [ Warning ] [ws] Failed to connect: Io(Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }). Retrying in 5s.... +[ 1763408465 ] [ info ] [ws] WebSocket connection established. +[ 1763408465 ] [ debug ] [ws] Received text: the dingaling +[ 1763408485 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763408485 ] [ ERROR ] [ws] Sender is none. +[ 1763408485 ] [ ERROR ] [ws] Connection lost. +[ 1763409385 ] [ info ] [ws] WebSocket connection established. +[ 1763409385 ] [ debug ] [ws] Received text: the dingaling +[ 1763409405 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763409405 ] [ ERROR ] [ws] Sender is none. +[ 1763409405 ] [ ERROR ] [ws] Connection lost. +[ 1763411983 ] [ info ] [ws] WebSocket connection established. +[ 1763411983 ] [ debug ] [ws] Received text: the dingaling +[ 1763412003 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763412003 ] [ ERROR ] [ws] Failed to respond: no sink, reconnecting. +[ 1763412003 ] [ ERROR ] [ws] Connection lost. +[ 1763412163 ] [ info ] [ws] WebSocket connection established. +[ 1763412163 ] [ debug ] [ws] Received text: the dingaling +[ 1763412183 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763412183 ] [ ERROR ] [ws] Failed to respond: no sink, reconnecting. +[ 1763412183 ] [ ERROR ] [ws] Connection lost. +[ 1763412188 ] [ info ] [ws] WebSocket connection established. +[ 1763412188 ] [ debug ] [ws] Received text: the dingaling +[ 1763412208 ] [ info ] [ws] WebSocket connection established. +[ 1763412208 ] [ debug ] [ws] Received text: the dingaling +[ 1763412228 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763412228 ] [ ERROR ] [ws] Failed to respond: no sink, reconnecting. +[ 1763412228 ] [ ERROR ] [ws] Connection lost. +[ 1763412249 ] [ info ] [ws] WebSocket connection established. +[ 1763412249 ] [ debug ] [ws] Received text: the dingaling +[ 1763412269 ] [ debug ] [ws] Received Ping, sending Pong +[ 1763412269 ] [ ERROR ] [ws] Failed to respond: no sink, reconnecting. +[ 1763412269 ] [ ERROR ] [ws] Connection lost.