refactor adapters into modular file structure

config-sqlite: split into repository/ (per entity) + serialization/ (per type) + error.rs
http-api: split into dto/ (per resource) + routes/ (per resource)
tcp-server: split into broadcaster, event_bus, server, error
rss: split parser from adapter, external tests
media: split error, external tests
This commit is contained in:
2026-06-18 22:57:58 +02:00
parent 366d98a1ae
commit 6e77236936
37 changed files with 1428 additions and 1253 deletions

View File

@@ -1,29 +1,10 @@
pub mod error;
mod serialization;
mod repository;
use std::time::Duration;
use sqlx::{SqlitePool, Row};
use domain::{
ConfigRepository,
DataSource, DataSourceId, DataSourceConfig, DataSourceType,
Layout, LayoutPreset, LayoutPresetId,
WidgetConfig, WidgetId,
};
use serialization as ser;
use sqlx::SqlitePool;
#[derive(Debug)]
pub enum SqliteConfigError {
Sql(sqlx::Error),
Serialization(String),
}
impl std::fmt::Display for SqliteConfigError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SqliteConfigError::Sql(e) => write!(f, "sql: {e}"),
SqliteConfigError::Serialization(e) => write!(f, "serialization: {e}"),
}
}
}
pub use error::SqliteConfigError;
pub struct SqliteConfigStore {
pool: SqlitePool,
@@ -77,186 +58,3 @@ impl SqliteConfigStore {
Ok(())
}
}
impl ConfigRepository for SqliteConfigStore {
type Error = SqliteConfigError;
async fn get_widget(&self, id: WidgetId) -> Result<Option<WidgetConfig>, Self::Error> {
let row = sqlx::query("SELECT * FROM widgets WHERE id = ?")
.bind(id as i64)
.fetch_optional(&self.pool)
.await
.map_err(SqliteConfigError::Sql)?;
match row {
None => Ok(None),
Some(row) => Ok(Some(ser::widget_from_row(&row)?)),
}
}
async fn list_widgets(&self) -> Result<Vec<WidgetConfig>, Self::Error> {
let rows = sqlx::query("SELECT * FROM widgets")
.fetch_all(&self.pool)
.await
.map_err(SqliteConfigError::Sql)?;
rows.iter().map(|r| ser::widget_from_row(r)).collect()
}
async fn save_widget(&self, config: &WidgetConfig) -> Result<(), Self::Error> {
let mappings_json = ser::mappings_to_json(&config.mappings)?;
let hint_str = ser::display_hint_to_str(&config.display_hint);
sqlx::query(
"INSERT OR REPLACE INTO widgets (id, name, display_hint, data_source_id, mappings, max_data_size)
VALUES (?, ?, ?, ?, ?, ?)"
)
.bind(config.id as i64)
.bind(&config.name)
.bind(hint_str)
.bind(config.data_source_id as i64)
.bind(&mappings_json)
.bind(config.max_data_size as i64)
.execute(&self.pool)
.await
.map_err(SqliteConfigError::Sql)?;
Ok(())
}
async fn delete_widget(&self, id: WidgetId) -> Result<(), Self::Error> {
sqlx::query("DELETE FROM widgets WHERE id = ?")
.bind(id as i64)
.execute(&self.pool)
.await
.map_err(SqliteConfigError::Sql)?;
Ok(())
}
async fn get_data_source(&self, id: DataSourceId) -> Result<Option<DataSource>, Self::Error> {
let row = sqlx::query("SELECT * FROM data_sources WHERE id = ?")
.bind(id as i64)
.fetch_optional(&self.pool)
.await
.map_err(SqliteConfigError::Sql)?;
match row {
None => Ok(None),
Some(row) => Ok(Some(ser::data_source_from_row(&row)?)),
}
}
async fn list_data_sources(&self) -> Result<Vec<DataSource>, Self::Error> {
let rows = sqlx::query("SELECT * FROM data_sources")
.fetch_all(&self.pool)
.await
.map_err(SqliteConfigError::Sql)?;
rows.iter().map(|r| ser::data_source_from_row(r)).collect()
}
async fn save_data_source(&self, source: &DataSource) -> Result<(), Self::Error> {
let config_json = ser::data_source_config_to_json(&source.config)?;
let type_str = ser::data_source_type_to_str(&source.source_type);
sqlx::query(
"INSERT OR REPLACE INTO data_sources (id, name, source_type, poll_interval_secs, config)
VALUES (?, ?, ?, ?, ?)"
)
.bind(source.id as i64)
.bind(&source.name)
.bind(type_str)
.bind(source.poll_interval.as_secs() as i64)
.bind(&config_json)
.execute(&self.pool)
.await
.map_err(SqliteConfigError::Sql)?;
Ok(())
}
async fn delete_data_source(&self, id: DataSourceId) -> Result<(), Self::Error> {
sqlx::query("DELETE FROM data_sources WHERE id = ?")
.bind(id as i64)
.execute(&self.pool)
.await
.map_err(SqliteConfigError::Sql)?;
Ok(())
}
async fn get_layout(&self) -> Result<Option<Layout>, Self::Error> {
let row = sqlx::query("SELECT data FROM layout WHERE id = 1")
.fetch_optional(&self.pool)
.await
.map_err(SqliteConfigError::Sql)?;
match row {
None => Ok(None),
Some(row) => {
let json: String = row.get("data");
Ok(Some(ser::layout_from_json(&json)?))
}
}
}
async fn save_layout(&self, layout: &Layout) -> Result<(), Self::Error> {
let json = ser::layout_to_json(layout)?;
sqlx::query(
"INSERT OR REPLACE INTO layout (id, data) VALUES (1, ?)"
)
.bind(&json)
.execute(&self.pool)
.await
.map_err(SqliteConfigError::Sql)?;
Ok(())
}
async fn get_preset(&self, id: LayoutPresetId) -> Result<Option<LayoutPreset>, Self::Error> {
let row = sqlx::query("SELECT * FROM presets WHERE id = ?")
.bind(id as i64)
.fetch_optional(&self.pool)
.await
.map_err(SqliteConfigError::Sql)?;
match row {
None => Ok(None),
Some(row) => Ok(Some(ser::preset_from_row(&row)?)),
}
}
async fn list_presets(&self) -> Result<Vec<LayoutPreset>, Self::Error> {
let rows = sqlx::query("SELECT * FROM presets")
.fetch_all(&self.pool)
.await
.map_err(SqliteConfigError::Sql)?;
rows.iter().map(|r| ser::preset_from_row(r)).collect()
}
async fn save_preset(&self, preset: &LayoutPreset) -> Result<(), Self::Error> {
let layout_json = ser::layout_to_json(&preset.layout)?;
sqlx::query(
"INSERT OR REPLACE INTO presets (id, name, layout_data) VALUES (?, ?, ?)"
)
.bind(preset.id as i64)
.bind(&preset.name)
.bind(&layout_json)
.execute(&self.pool)
.await
.map_err(SqliteConfigError::Sql)?;
Ok(())
}
async fn delete_preset(&self, id: LayoutPresetId) -> Result<(), Self::Error> {
sqlx::query("DELETE FROM presets WHERE id = ?")
.bind(id as i64)
.execute(&self.pool)
.await
.map_err(SqliteConfigError::Sql)?;
Ok(())
}
}