Update dependencies and enhance WebSocket server logging: Add 'chrono' and 'android_system_properties' to Cargo.lock, improve error handling and logging in websocket_server.rs, and streamline character creation notifications in worker modules for better clarity and maintainability.

This commit is contained in:
Torsten Schulz (local)
2026-01-28 14:21:28 +01:00
parent 2ac474fe0c
commit c9e0781b61
14 changed files with 1174 additions and 1814 deletions

View File

@@ -20,10 +20,8 @@ use tokio_rustls::rustls::{self, ServerConfig};
use tokio_rustls::TlsAcceptor;
use tokio_tungstenite::tungstenite::Message;
use tokio_tungstenite::accept_async;
use rustls_pemfile::{certs, ec_private_keys, pkcs8_private_keys, rsa_private_keys};
use rustls::pki_types::{
CertificateDer, PrivateKeyDer, PrivatePkcs1KeyDer, PrivatePkcs8KeyDer, PrivateSec1KeyDer,
};
use rustls_pemfile::{certs, pkcs8_private_keys, rsa_private_keys};
use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs1KeyDer, PrivatePkcs8KeyDer};
/// Einfacher WebSocket-Server auf Basis von Tokio + tokio-tungstenite.
///
@@ -134,7 +132,7 @@ fn create_tls_acceptor(
let key_file = File::open(key_path)?;
let mut key_reader = BufReader::new(key_file);
// Versuche zuerst PKCS8, dann ggf. RSA-Key, dann SEC1 (EC PRIVATE KEY).
// Versuche zuerst PKCS8, dann ggf. RSA-Key
let mut keys: Vec<PrivateKeyDer<'static>> = pkcs8_private_keys(&mut key_reader)
.map(|res: Result<PrivatePkcs8KeyDer<'static>, _>| res.map(PrivateKeyDer::Pkcs8))
.collect::<Result<_, _>>()?;
@@ -149,16 +147,7 @@ fn create_tls_acceptor(
}
if keys.is_empty() {
// Leser zurücksetzen und SEC1 (EC PRIVATE KEY) versuchen
let key_file = File::open(key_path)?;
let mut key_reader = BufReader::new(key_file);
keys = ec_private_keys(&mut key_reader)
.map(|res: Result<PrivateSec1KeyDer<'static>, _>| res.map(PrivateKeyDer::Sec1))
.collect::<Result<_, _>>()?;
}
if keys.is_empty() {
return Err("Key-Datei enthält keinen privaten Schlüssel (PKCS8, RSA oder SEC1)".into());
return Err("Key-Datei enthält keinen privaten Schlüssel (PKCS8 oder RSA)".into());
}
let private_key = keys.remove(0);
@@ -210,6 +199,7 @@ impl WebSocketServer {
"Starte WebSocket-Server auf Port {} mit SSL (cert: {:?}, key: {:?})",
self.port, self.cert_path, self.key_path
);
// Hinweis: SSL-Unterstützung ist noch nicht implementiert.
} else {
println!("Starte WebSocket-Server auf Port {} (ohne SSL)", self.port);
}
@@ -238,22 +228,15 @@ impl WebSocketServer {
self.cert_path.as_deref(),
self.key_path.as_deref(),
) {
Ok(acc) => {
println!("[WebSocketServer] TLS erfolgreich initialisiert. Server akzeptiert wss:// Verbindungen.");
Some(acc)
}
Ok(acc) => Some(acc),
Err(err) => {
eprintln!(
"[WebSocketServer] TLS-Initialisierung fehlgeschlagen, starte ohne SSL: {err}"
);
eprintln!(
"[WebSocketServer] ACHTUNG: WEBSOCKET_SSL_ENABLED=true, aber TLS ist nicht aktiv. Clients müssen dann ws:// statt wss:// verwenden."
);
None
}
}
} else {
println!("[WebSocketServer] TLS deaktiviert. Server akzeptiert nur ws:// Verbindungen (nicht wss://).");
None
};
@@ -304,76 +287,48 @@ async fn run_accept_loop(
tls_acceptor: Option<TlsAcceptor>,
) {
let listener = match TcpListener::bind(&addr).await {
Ok(l) => {
println!("[WebSocketServer] Erfolgreich gebunden an {}", addr);
l
}
Ok(l) => l,
Err(e) => {
eprintln!("[WebSocketServer] FEHLER: Konnte nicht an {} binden: {}", addr, e);
eprintln!("[WebSocketServer] Mögliche Ursachen: Port bereits belegt, keine Berechtigung, oder Firewall blockiert.");
eprintln!("[WebSocketServer] Fehler beim Binden an {}: {}", addr, e);
running.store(false, Ordering::SeqCst);
return;
}
};
println!("[WebSocketServer] Lauscht auf {} (TLS: {})", addr, tls_acceptor.is_some());
// Heartbeat: Logge regelmäßig, dass der Server läuft
let mut heartbeat_interval = interval(TokioDuration::from_secs(300)); // Alle 5 Minuten
let server_start = std::time::Instant::now();
println!("[WebSocketServer] Lauscht auf {}", addr);
while running.load(Ordering::SeqCst) {
tokio::select! {
// Heartbeat: Logge alle 5 Minuten, dass der Server läuft
_ = heartbeat_interval.tick() => {
let uptime = server_start.elapsed().as_secs();
println!("[WebSocketServer] Heartbeat: Server läuft seit {} Sekunden auf {} (TLS: {})",
uptime, addr, tls_acceptor.is_some());
let (stream, peer) = match listener.accept().await {
Ok(v) => v,
Err(e) => {
eprintln!("[WebSocketServer] accept() fehlgeschlagen: {}", e);
continue;
}
// Neue Verbindung akzeptieren
result = listener.accept() => {
match result {
Ok((stream, peer)) => {
let peer_addr = peer;
println!("[WebSocketServer] Client-Verbindungsversuch von {} (TCP-Verbindung etabliert)", peer_addr);
let rx = tx.subscribe();
let registry_clone = registry.clone();
let ws_log_clone = ws_log.clone();
let tls_acceptor_clone = tls_acceptor.clone();
};
tokio::spawn(async move {
if let Some(acc) = tls_acceptor_clone {
println!("[WebSocketServer] Starte TLS-Handshake für {}...", peer_addr);
match acc.accept(stream).await {
Ok(tls_stream) => {
println!("[WebSocketServer] TLS-Handshake erfolgreich für {}", peer_addr);
handle_connection(tls_stream, peer_addr, rx, registry_clone, ws_log_clone)
.await
}
Err(err) => {
eprintln!(
"[WebSocketServer] TLS-Handshake fehlgeschlagen ({peer_addr}): {err}"
);
eprintln!(
"[WebSocketServer] Mögliche Ursachen: Ungültiges Zertifikat, unsupported Cipher, oder Client verwendet ws:// statt wss://"
);
}
}
} else {
println!("[WebSocketServer] Verarbeite Verbindung von {} ohne TLS (Client sollte ws:// verwenden, nicht wss://)", peer_addr);
handle_connection(stream, peer_addr, rx, registry_clone, ws_log_clone).await;
}
});
let peer_addr = peer;
let rx = tx.subscribe();
let registry_clone = registry.clone();
let ws_log_clone = ws_log.clone();
let tls_acceptor_clone = tls_acceptor.clone();
tokio::spawn(async move {
if let Some(acc) = tls_acceptor_clone {
match acc.accept(stream).await {
Ok(tls_stream) => {
handle_connection(tls_stream, peer_addr, rx, registry_clone, ws_log_clone)
.await
}
Err(e) => {
eprintln!("[WebSocketServer] Fehler beim Akzeptieren einer Verbindung: {}", e);
// Kurz warten, um CPU-Last zu reduzieren bei wiederholten Fehlern
tokio::time::sleep(TokioDuration::from_millis(100)).await;
Err(err) => {
eprintln!(
"[WebSocketServer] TLS-Handshake fehlgeschlagen ({peer_addr}): {err}"
);
}
}
} else {
handle_connection(stream, peer_addr, rx, registry_clone, ws_log_clone).await;
}
}
});
}
}
@@ -386,19 +341,16 @@ async fn handle_connection<S>(
) where
S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{
println!("[WebSocketServer] Versuche WebSocket-Handshake für {}...", peer_addr);
let ws_stream = match accept_async(stream).await {
Ok(ws) => {
println!("[WebSocketServer] WebSocket-Handshake erfolgreich für {} - Verbindung etabliert", peer_addr);
ws
}
Ok(ws) => ws,
Err(e) => {
eprintln!("[WebSocketServer] WebSocket-Handshake fehlgeschlagen ({peer_addr}): {e}");
eprintln!("[WebSocketServer] Mögliche Ursachen: Client sendet kein WebSocket-Request, falscher Upgrade-Header, oder Protokoll-Mismatch");
return;
}
};
println!("[WebSocketServer] Neue Verbindung von {}", peer_addr);
let (mut ws_sender, mut ws_receiver) = ws_stream.split();
// Kanal für Antworten direkt an diesen Client (z.B. getConnections)