arch: push wire types out of ClientApp, extract event_service, cleanup dead code
- ClientApp stores domain types, RepaintCommand carries DisplayHint + Vec<(String,Value)> - adapters no longer convert Wire→Domain (eliminated duplication in esp32 + desktop) - event_service in application layer handles LayoutChanged/WebhookDataReceived/ThemeChanged - bootstrap event_handler reduced to 10-line dispatcher - polling_service reuses event_service::apply_and_broadcast (deduplicated broadcast pattern) - AppState.config_service() replaces 11 inline ConfigService::new() calls - delete unused poll_interval_secs parameter chain - delete unused StoragePort/ClientConfig (zero implementations)
This commit is contained in:
@@ -4,7 +4,6 @@ pub struct ServerConfig {
|
||||
pub database_url: String,
|
||||
pub tcp_addr: String,
|
||||
pub http_addr: String,
|
||||
pub poll_interval_secs: u64,
|
||||
pub spa_dir: Option<String>,
|
||||
}
|
||||
|
||||
@@ -15,10 +14,6 @@ impl ServerConfig {
|
||||
.unwrap_or_else(|_| "sqlite:kframe.db?mode=rwc".into()),
|
||||
tcp_addr: env::var("KFRAME_TCP_ADDR").unwrap_or_else(|_| "0.0.0.0:2699".into()),
|
||||
http_addr: env::var("KFRAME_HTTP_ADDR").unwrap_or_else(|_| "0.0.0.0:3000".into()),
|
||||
poll_interval_secs: env::var("KFRAME_POLL_INTERVAL_SECS")
|
||||
.ok()
|
||||
.and_then(|v| v.parse().ok())
|
||||
.unwrap_or(5),
|
||||
spa_dir: env::var("KFRAME_SPA_DIR").ok(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use application::DataProjection;
|
||||
use config_sqlite::SqliteConfigStore;
|
||||
use domain::{BroadcastPort, ConfigRepository, DomainEvent};
|
||||
use std::sync::Arc;
|
||||
use tcp_server::{TcpBroadcaster, TcpEventBus};
|
||||
use tracing::{error, info, warn};
|
||||
use tracing::{error, warn};
|
||||
|
||||
pub async fn run(
|
||||
event_bus: Arc<TcpEventBus>,
|
||||
@@ -15,69 +14,10 @@ pub async fn run(
|
||||
|
||||
loop {
|
||||
match rx.recv().await {
|
||||
Ok(DomainEvent::LayoutChanged { layout }) => {
|
||||
let widgets = match config.list_widgets().await {
|
||||
Ok(w) => w,
|
||||
Err(e) => {
|
||||
error!(error = %e, "failed to fetch widgets for screen update");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let mut widget_states = Vec::new();
|
||||
for w in &widgets {
|
||||
if let Some(s) = projection.get_state(w.id).await {
|
||||
widget_states.push((w.id, w.display_hint.clone(), s));
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(e) = broadcaster
|
||||
.push_screen_update(&layout, &widget_states)
|
||||
.await
|
||||
{
|
||||
error!(error = %e, "failed to push screen update");
|
||||
}
|
||||
|
||||
info!("layout changed, pushed screen update to clients");
|
||||
}
|
||||
Ok(DomainEvent::WebhookDataReceived { source_id, data }) => {
|
||||
let widgets = match config.list_widgets().await {
|
||||
Ok(w) => w,
|
||||
Err(e) => {
|
||||
error!(error = %e, "failed to fetch widgets for webhook");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let changed = projection
|
||||
.apply_poll_result(source_id, &data, &widgets)
|
||||
Ok(event) => {
|
||||
application::event_service::handle_event(event, &config, &broadcaster, &projection)
|
||||
.await;
|
||||
|
||||
if !changed.is_empty() {
|
||||
let with_hints: Vec<_> = changed
|
||||
.iter()
|
||||
.filter_map(|(id, state)| {
|
||||
let hint = widgets.iter().find(|w| w.id == *id)?.display_hint.clone();
|
||||
Some((*id, hint, state.clone()))
|
||||
})
|
||||
.collect();
|
||||
if let Err(e) = broadcaster.push_data_update(&with_hints).await {
|
||||
error!(error = %e, "failed to push webhook data update");
|
||||
}
|
||||
info!(
|
||||
source_id,
|
||||
count = changed.len(),
|
||||
"webhook data received, pushed update"
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(DomainEvent::ThemeChanged { theme }) => {
|
||||
if let Err(e) = broadcaster.push_theme_update(&theme).await {
|
||||
error!(error = %e, "failed to push theme update");
|
||||
}
|
||||
info!("theme changed, pushed update to clients");
|
||||
}
|
||||
Ok(_) => {}
|
||||
Err(tokio::sync::broadcast::error::RecvError::Lagged(n)) => {
|
||||
warn!(skipped = n, "event handler lagged, missed events");
|
||||
}
|
||||
|
||||
@@ -90,11 +90,5 @@ async fn main() -> Result<()> {
|
||||
event_handler::run(ev_bus, ev_config, ev_bc, ev_proj).await;
|
||||
});
|
||||
|
||||
polling::run(
|
||||
config_store,
|
||||
broadcaster,
|
||||
projection,
|
||||
cfg.poll_interval_secs,
|
||||
)
|
||||
.await
|
||||
polling::run(config_store, broadcaster, projection).await
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ pub async fn run(
|
||||
config: Arc<SqliteConfigStore>,
|
||||
broadcaster: Arc<TcpBroadcaster>,
|
||||
projection: Arc<DataProjection>,
|
||||
_poll_interval_secs: u64,
|
||||
) -> Result<()> {
|
||||
let adapters = Adapters {
|
||||
http: Arc::new(HttpJsonAdapter::new()),
|
||||
|
||||
Reference in New Issue
Block a user