add SPA config UI, wire media/rss adapters, event-driven layout push

- React SPA: dashboard, data sources CRUD, widgets CRUD, layout builder,
  presets. TanStack Router + Query, shadcn/ui, Vite proxy to :3000
- wire media + rss adapters into polling loop, remove xtb source type
- media adapter: read username/password from headers, proper subsonic auth
- event handler: subscribe to LayoutChanged, push screen update to clients
- fix clippy warnings across workspace (Default impls, collapsible ifs,
  redundant closures, is_none_or, unused imports)
This commit is contained in:
2026-06-19 00:12:42 +02:00
parent 21c08911df
commit 26ebfad3a2
175 changed files with 12338 additions and 801 deletions

View File

@@ -1,8 +1,8 @@
use client_domain::NetworkPort;
use protocol::MAX_FRAME_SIZE;
use std::io::{Read, Write};
use std::net::TcpStream;
use std::time::Duration;
use client_domain::NetworkPort;
use protocol::MAX_FRAME_SIZE;
#[derive(Debug, thiserror::Error)]
pub enum TcpClientError {
@@ -14,13 +14,14 @@ pub enum TcpClientError {
FrameTooLarge(usize),
}
#[derive(Default)]
pub struct StdTcpClient {
stream: Option<TcpStream>,
}
impl StdTcpClient {
pub fn new() -> Self {
Self { stream: None }
Self::default()
}
}
@@ -30,7 +31,9 @@ impl NetworkPort for StdTcpClient {
fn connect(&mut self, addr: &str) -> Result<(), Self::Error> {
let stream = TcpStream::connect(addr).map_err(TcpClientError::Io)?;
stream.set_nonblocking(true).map_err(TcpClientError::Io)?;
stream.set_read_timeout(Some(Duration::from_millis(10))).map_err(TcpClientError::Io)?;
stream
.set_read_timeout(Some(Duration::from_millis(10)))
.map_err(TcpClientError::Io)?;
self.stream = Some(stream);
Ok(())
}
@@ -63,7 +66,9 @@ impl NetworkPort for StdTcpClient {
let mut payload = vec![0u8; len];
stream.set_nonblocking(false).map_err(TcpClientError::Io)?;
stream.read_exact(&mut payload).map_err(TcpClientError::Io)?;
stream
.read_exact(&mut payload)
.map_err(TcpClientError::Io)?;
stream.set_nonblocking(true).map_err(TcpClientError::Io)?;
Ok(Some(payload))