arch: split ConfigRepository, extract polling, consolidate conversions, decouple protocol
- Value↔JSON: From impls on domain Value behind `json` feature, delete 4 duplicate converters - ConfigRepository split into ConfigRepository (12), UserRepository (3), WidgetStateCache (2) - polling orchestration moved from bootstrap to application::polling_service - WidgetRenderer in client-domain owns scroll/cache, both clients use it - network loop consolidated into client-application::run_connection_loop - protocol crate drops domain dep, Wire↔Domain conversions move to adapters
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use domain::{
|
||||
ConfigRepository, DataSource, DataSourceId, Layout, LayoutPreset, LayoutPresetId, ThemeConfig,
|
||||
User, WidgetConfig, WidgetId, WidgetState,
|
||||
User, UserRepository, WidgetConfig, WidgetId, WidgetState, WidgetStateCache,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::RwLock;
|
||||
@@ -177,6 +177,10 @@ impl ConfigRepository for MemoryConfigStore {
|
||||
guard.remove(&id);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl UserRepository for MemoryConfigStore {
|
||||
type Error = MemoryConfigError;
|
||||
|
||||
async fn get_user_by_username(&self, username: &str) -> Result<Option<User>, Self::Error> {
|
||||
let guard = self
|
||||
@@ -203,6 +207,10 @@ impl ConfigRepository for MemoryConfigStore {
|
||||
.map_err(|_| MemoryConfigError::LockPoisoned)?;
|
||||
Ok(guard.len() as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetStateCache for MemoryConfigStore {
|
||||
type Error = MemoryConfigError;
|
||||
|
||||
async fn save_widget_states(
|
||||
&self,
|
||||
|
||||
@@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
domain.workspace = true
|
||||
domain = { workspace = true, features = ["json"] }
|
||||
sqlx.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::SqliteConfigStore;
|
||||
use crate::error::SqliteConfigError;
|
||||
use domain::{
|
||||
ConfigRepository, DataSource, DataSourceId, Layout, LayoutPreset, LayoutPresetId, ThemeConfig,
|
||||
User, WidgetConfig, WidgetId, WidgetState,
|
||||
User, UserRepository, WidgetConfig, WidgetId, WidgetState, WidgetStateCache,
|
||||
};
|
||||
|
||||
impl ConfigRepository for SqliteConfigStore {
|
||||
@@ -79,6 +79,10 @@ impl ConfigRepository for SqliteConfigStore {
|
||||
async fn save_theme(&self, theme: &ThemeConfig) -> Result<(), Self::Error> {
|
||||
self.save_theme_impl(theme).await
|
||||
}
|
||||
}
|
||||
|
||||
impl UserRepository for SqliteConfigStore {
|
||||
type Error = SqliteConfigError;
|
||||
|
||||
async fn get_user_by_username(&self, username: &str) -> Result<Option<User>, Self::Error> {
|
||||
self.get_user_by_username_impl(username).await
|
||||
@@ -91,6 +95,10 @@ impl ConfigRepository for SqliteConfigStore {
|
||||
async fn count_users(&self) -> Result<u32, Self::Error> {
|
||||
self.count_users_impl().await
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetStateCache for SqliteConfigStore {
|
||||
type Error = SqliteConfigError;
|
||||
|
||||
async fn save_widget_states(
|
||||
&self,
|
||||
|
||||
@@ -44,56 +44,17 @@ impl SqliteConfigStore {
|
||||
}
|
||||
}
|
||||
|
||||
fn domain_value_to_json(v: &Value) -> serde_json::Value {
|
||||
match v {
|
||||
Value::Null => serde_json::Value::Null,
|
||||
Value::Bool(b) => serde_json::Value::Bool(*b),
|
||||
Value::Number(n) => serde_json::json!(n),
|
||||
Value::String(s) => serde_json::Value::String(s.clone()),
|
||||
Value::Array(arr) => {
|
||||
serde_json::Value::Array(arr.iter().map(domain_value_to_json).collect())
|
||||
}
|
||||
Value::Object(map) => {
|
||||
let obj: serde_json::Map<String, serde_json::Value> = map
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), domain_value_to_json(v)))
|
||||
.collect();
|
||||
serde_json::Value::Object(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn json_value_to_domain(v: &serde_json::Value) -> Value {
|
||||
match v {
|
||||
serde_json::Value::Null => Value::Null,
|
||||
serde_json::Value::Bool(b) => Value::Bool(*b),
|
||||
serde_json::Value::Number(n) => Value::Number(n.as_f64().unwrap_or(0.0)),
|
||||
serde_json::Value::String(s) => Value::String(s.clone()),
|
||||
serde_json::Value::Array(arr) => {
|
||||
Value::Array(arr.iter().map(json_value_to_domain).collect())
|
||||
}
|
||||
serde_json::Value::Object(map) => Value::Object(
|
||||
map.iter()
|
||||
.map(|(k, v)| (k.clone(), json_value_to_domain(v)))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn domain_state_to_json(state: &WidgetState) -> Result<String, serde_json::Error> {
|
||||
let data: serde_json::Map<String, serde_json::Value> = state
|
||||
.data
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), domain_value_to_json(v)))
|
||||
.map(|(k, v)| (k.clone(), v.into()))
|
||||
.collect();
|
||||
serde_json::to_string(&data)
|
||||
}
|
||||
|
||||
fn json_to_domain_state(json: &str) -> Result<WidgetState, serde_json::Error> {
|
||||
let map: serde_json::Map<String, serde_json::Value> = serde_json::from_str(json)?;
|
||||
let data: BTreeMap<String, Value> = map
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), json_value_to_domain(v)))
|
||||
.collect();
|
||||
let data: BTreeMap<String, Value> = map.into_iter().map(|(k, v)| (k, v.into())).collect();
|
||||
Ok(WidgetState { data, error: None })
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use config_sqlite::SqliteConfigStore;
|
||||
use domain::{
|
||||
AlignItems, ConfigRepository, ContainerNode, DataSource, DataSourceConfig, DataSourceType,
|
||||
Direction, DisplayHint, DisplayHintKind, JustifyContent, KeyMapping, Layout, LayoutChild,
|
||||
LayoutNode, LayoutPreset, Sizing, WidgetConfig,
|
||||
LayoutNode, LayoutPreset, Sizing, UserRepository, WidgetConfig, WidgetStateCache,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
domain.workspace = true
|
||||
domain = { workspace = true, features = ["json"] }
|
||||
application.workspace = true
|
||||
api-types.workspace = true
|
||||
axum.workspace = true
|
||||
|
||||
@@ -4,7 +4,7 @@ mod routes;
|
||||
use axum::Router;
|
||||
use domain::{
|
||||
AuthPort, BroadcastPort, ClientRegistry, ConfigRepository, EventPublisher, PasswordHashPort,
|
||||
WidgetStateReader,
|
||||
UserRepository, WidgetStateCache, WidgetStateReader,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use tower_http::cors::CorsLayer;
|
||||
@@ -38,8 +38,9 @@ impl<C, E, W, B, R, A, H> Clone for AppState<C, E, W, B, R, A, H> {
|
||||
|
||||
pub fn router<C, E, W, B, R, A, H>(state: AppState<C, E, W, B, R, A, H>) -> Router
|
||||
where
|
||||
C: ConfigRepository + Send + Sync + 'static,
|
||||
C::Error: std::fmt::Debug + Send,
|
||||
C: ConfigRepository + UserRepository + WidgetStateCache + Send + Sync + 'static,
|
||||
<C as ConfigRepository>::Error: std::fmt::Debug + Send,
|
||||
<C as UserRepository>::Error: std::fmt::Debug + Send,
|
||||
E: EventPublisher + Send + Sync + 'static,
|
||||
E::Error: std::fmt::Debug + Send,
|
||||
W: WidgetStateReader + Send + Sync + 'static,
|
||||
@@ -69,8 +70,9 @@ pub async fn serve<C, E, W, B, R, A, H>(
|
||||
state: AppState<C, E, W, B, R, A, H>,
|
||||
) -> Result<(), std::io::Error>
|
||||
where
|
||||
C: ConfigRepository + Send + Sync + 'static,
|
||||
C::Error: std::fmt::Debug + Send,
|
||||
C: ConfigRepository + UserRepository + WidgetStateCache + Send + Sync + 'static,
|
||||
<C as ConfigRepository>::Error: std::fmt::Debug + Send,
|
||||
<C as UserRepository>::Error: std::fmt::Debug + Send,
|
||||
E: EventPublisher + Send + Sync + 'static,
|
||||
E::Error: std::fmt::Debug + Send,
|
||||
W: WidgetStateReader + Send + Sync + 'static,
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::AppState;
|
||||
use axum::extract::State;
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::Json;
|
||||
use domain::{AuthPort, ConfigRepository, PasswordHashPort};
|
||||
use domain::{AuthPort, PasswordHashPort, UserRepository};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
type S<C, E, W, B, R, A, H> = State<AppState<C, E, W, B, R, A, H>>;
|
||||
@@ -28,7 +28,7 @@ pub async fn login<C, E, W, B, R, A, H>(
|
||||
Json(body): Json<LoginRequest>,
|
||||
) -> Result<Json<LoginResponse>, (StatusCode, String)>
|
||||
where
|
||||
C: ConfigRepository,
|
||||
C: UserRepository,
|
||||
C::Error: std::fmt::Debug,
|
||||
A: AuthPort,
|
||||
H: PasswordHashPort,
|
||||
@@ -51,7 +51,7 @@ pub async fn register<C, E, W, B, R, A, H>(
|
||||
Json(body): Json<LoginRequest>,
|
||||
) -> Result<StatusCode, (StatusCode, String)>
|
||||
where
|
||||
C: ConfigRepository,
|
||||
C: UserRepository,
|
||||
C::Error: std::fmt::Debug,
|
||||
H: PasswordHashPort,
|
||||
{
|
||||
@@ -71,7 +71,7 @@ pub async fn auth_status<C, E, W, B, R, A, H>(
|
||||
State(state): S<C, E, W, B, R, A, H>,
|
||||
) -> Result<Json<StatusResponse>, StatusCode>
|
||||
where
|
||||
C: ConfigRepository,
|
||||
C: UserRepository,
|
||||
C::Error: std::fmt::Debug,
|
||||
{
|
||||
let count = state
|
||||
|
||||
@@ -12,13 +12,14 @@ use axum::Router;
|
||||
use axum::routing::{get, post};
|
||||
use domain::{
|
||||
AuthPort, BroadcastPort, ClientRegistry, ConfigRepository, EventPublisher, PasswordHashPort,
|
||||
WidgetStateReader,
|
||||
UserRepository, WidgetStateCache, WidgetStateReader,
|
||||
};
|
||||
|
||||
pub fn api_routes<C, E, W, B, R, A, H>() -> Router<AppState<C, E, W, B, R, A, H>>
|
||||
where
|
||||
C: ConfigRepository + Send + Sync + 'static,
|
||||
C::Error: std::fmt::Debug + Send,
|
||||
C: ConfigRepository + UserRepository + WidgetStateCache + Send + Sync + 'static,
|
||||
<C as ConfigRepository>::Error: std::fmt::Debug + Send,
|
||||
<C as UserRepository>::Error: std::fmt::Debug + Send,
|
||||
E: EventPublisher + Send + Sync + 'static,
|
||||
E::Error: std::fmt::Debug + Send,
|
||||
W: WidgetStateReader + Send + Sync + 'static,
|
||||
|
||||
@@ -31,7 +31,7 @@ where
|
||||
));
|
||||
}
|
||||
|
||||
let data = json_to_domain_value(body);
|
||||
let data: domain::Value = body.into();
|
||||
|
||||
state
|
||||
.events
|
||||
@@ -41,22 +41,3 @@ where
|
||||
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
||||
fn json_to_domain_value(json: serde_json::Value) -> domain::Value {
|
||||
match json {
|
||||
serde_json::Value::Null => domain::Value::Null,
|
||||
serde_json::Value::Bool(b) => domain::Value::Bool(b),
|
||||
serde_json::Value::Number(n) => domain::Value::Number(n.as_f64().unwrap_or(0.0)),
|
||||
serde_json::Value::String(s) => domain::Value::String(s),
|
||||
serde_json::Value::Array(arr) => {
|
||||
domain::Value::Array(arr.into_iter().map(json_to_domain_value).collect())
|
||||
}
|
||||
serde_json::Value::Object(obj) => {
|
||||
let map = obj
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, json_to_domain_value(v)))
|
||||
.collect();
|
||||
domain::Value::Object(map)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,32 +126,10 @@ where
|
||||
{
|
||||
match state.widget_states.get_widget_state(id).await {
|
||||
Some(ws) => {
|
||||
let map: serde_json::Map<String, serde_json::Value> = ws
|
||||
.data
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), domain_value_to_json(v)))
|
||||
.collect();
|
||||
let map: serde_json::Map<String, serde_json::Value> =
|
||||
ws.data.iter().map(|(k, v)| (k.clone(), v.into())).collect();
|
||||
Ok(Json(serde_json::Value::Object(map)))
|
||||
}
|
||||
None => Err(StatusCode::NOT_FOUND),
|
||||
}
|
||||
}
|
||||
|
||||
fn domain_value_to_json(v: &domain::Value) -> serde_json::Value {
|
||||
match v {
|
||||
domain::Value::Null => serde_json::Value::Null,
|
||||
domain::Value::Bool(b) => serde_json::Value::Bool(*b),
|
||||
domain::Value::Number(n) => serde_json::json!(n),
|
||||
domain::Value::String(s) => serde_json::Value::String(s.clone()),
|
||||
domain::Value::Array(arr) => {
|
||||
serde_json::Value::Array(arr.iter().map(domain_value_to_json).collect())
|
||||
}
|
||||
domain::Value::Object(obj) => {
|
||||
let map = obj
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), domain_value_to_json(v)))
|
||||
.collect();
|
||||
serde_json::Value::Object(map)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
domain.workspace = true
|
||||
domain = { workspace = true, features = ["json"] }
|
||||
reqwest.workspace = true
|
||||
serde_json.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
@@ -28,21 +28,6 @@ impl HttpJsonAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
fn json_to_value(json: serde_json::Value) -> Value {
|
||||
match json {
|
||||
serde_json::Value::Null => Value::Null,
|
||||
serde_json::Value::Bool(b) => Value::Bool(b),
|
||||
serde_json::Value::Number(n) => Value::Number(n.as_f64().unwrap_or(0.0)),
|
||||
serde_json::Value::String(s) => Value::String(s),
|
||||
serde_json::Value::Array(arr) => Value::Array(arr.into_iter().map(json_to_value).collect()),
|
||||
serde_json::Value::Object(map) => Value::Object(
|
||||
map.into_iter()
|
||||
.map(|(k, v)| (k, json_to_value(v)))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
impl DataSourcePort for HttpJsonAdapter {
|
||||
type Error = HttpJsonError;
|
||||
|
||||
@@ -70,6 +55,6 @@ impl DataSourcePort for HttpJsonAdapter {
|
||||
let resp = req.send().await.map_err(HttpJsonError::Request)?;
|
||||
let json: serde_json::Value = resp.json().await.map_err(HttpJsonError::Request)?;
|
||||
|
||||
Ok(json_to_value(json))
|
||||
Ok(json.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::conversions::{display_hint_to_wire, layout_to_wire, widget_state_to_wire};
|
||||
use crate::error::TcpServerError;
|
||||
use domain::{BroadcastPort, DisplayHint, Layout, ThemeConfig, WidgetId, WidgetState};
|
||||
use protocol::{ServerMessage, WidgetDescriptor, WireColor, WireLayoutNode, WireTheme, encode};
|
||||
use protocol::{ServerMessage, WidgetDescriptor, WireColor, WireTheme, encode};
|
||||
use tokio::sync::broadcast;
|
||||
|
||||
pub struct TcpBroadcaster {
|
||||
@@ -31,13 +32,13 @@ impl BroadcastPort for TcpBroadcaster {
|
||||
layout: &Layout,
|
||||
widgets: &[(WidgetId, DisplayHint, WidgetState)],
|
||||
) -> Result<(), Self::Error> {
|
||||
let wire_layout: WireLayoutNode = (&layout.root).into();
|
||||
let wire_layout = layout_to_wire(&layout.root);
|
||||
let wire_widgets: Vec<WidgetDescriptor> = widgets
|
||||
.iter()
|
||||
.map(|(id, hint, state)| WidgetDescriptor {
|
||||
id: *id,
|
||||
display_hint: hint.into(),
|
||||
state: state.into(),
|
||||
display_hint: display_hint_to_wire(hint),
|
||||
state: widget_state_to_wire(state),
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -58,8 +59,8 @@ impl BroadcastPort for TcpBroadcaster {
|
||||
.iter()
|
||||
.map(|(id, hint, state)| WidgetDescriptor {
|
||||
id: *id,
|
||||
display_hint: hint.into(),
|
||||
state: state.into(),
|
||||
display_hint: display_hint_to_wire(hint),
|
||||
state: widget_state_to_wire(state),
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
103
crates/adapters/tcp-server/src/conversions.rs
Normal file
103
crates/adapters/tcp-server/src/conversions.rs
Normal file
@@ -0,0 +1,103 @@
|
||||
use domain::value_objects::{
|
||||
AlignItems, Direction, DisplayHint, DisplayHintKind, HAlign, JustifyContent, LayoutNode,
|
||||
Sizing, VAlign, Value, WidgetError, WidgetState,
|
||||
};
|
||||
use protocol::{
|
||||
WireAlignItems, WireContainerNode, WireDirection, WireDisplayHint, WireDisplayHintKind,
|
||||
WireHAlign, WireJustifyContent, WireKeyValue, WireLayoutChild, WireLayoutNode, WireSizing,
|
||||
WireVAlign, WireValue, WireWidgetError, WireWidgetState,
|
||||
};
|
||||
|
||||
pub fn value_to_wire(v: &Value) -> WireValue {
|
||||
match v {
|
||||
Value::Null => WireValue::Null,
|
||||
Value::Bool(b) => WireValue::Bool(*b),
|
||||
Value::Number(n) => WireValue::Number(*n),
|
||||
Value::String(s) => WireValue::String(s.clone()),
|
||||
Value::Array(arr) => WireValue::Array(arr.iter().map(value_to_wire).collect()),
|
||||
Value::Object(map) => WireValue::Object(
|
||||
map.iter()
|
||||
.map(|(k, v)| (k.clone(), value_to_wire(v)))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn widget_error_to_wire(e: &WidgetError) -> WireWidgetError {
|
||||
match e {
|
||||
WidgetError::SourceUnavailable => WireWidgetError::SourceUnavailable,
|
||||
WidgetError::ExtractionFailed => WireWidgetError::ExtractionFailed,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn widget_state_to_wire(s: &WidgetState) -> WireWidgetState {
|
||||
WireWidgetState {
|
||||
data: s
|
||||
.data
|
||||
.iter()
|
||||
.map(|(k, v)| WireKeyValue {
|
||||
key: k.clone(),
|
||||
value: value_to_wire(v),
|
||||
})
|
||||
.collect(),
|
||||
error: s.error.as_ref().map(widget_error_to_wire),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display_hint_to_wire(h: &DisplayHint) -> WireDisplayHint {
|
||||
WireDisplayHint {
|
||||
kind: match h.kind {
|
||||
DisplayHintKind::IconValue => WireDisplayHintKind::IconValue,
|
||||
DisplayHintKind::TextBlock => WireDisplayHintKind::TextBlock,
|
||||
DisplayHintKind::KeyValue => WireDisplayHintKind::KeyValue,
|
||||
},
|
||||
h_align: match h.h_align {
|
||||
HAlign::Left => WireHAlign::Left,
|
||||
HAlign::Center => WireHAlign::Center,
|
||||
HAlign::Right => WireHAlign::Right,
|
||||
},
|
||||
v_align: match h.v_align {
|
||||
VAlign::Top => WireVAlign::Top,
|
||||
VAlign::Middle => WireVAlign::Middle,
|
||||
VAlign::Bottom => WireVAlign::Bottom,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn layout_to_wire(n: &LayoutNode) -> WireLayoutNode {
|
||||
match n {
|
||||
LayoutNode::Leaf(id) => WireLayoutNode::Leaf(*id),
|
||||
LayoutNode::Container(c) => WireLayoutNode::Container(WireContainerNode {
|
||||
direction: match c.direction {
|
||||
Direction::Row => WireDirection::Row,
|
||||
Direction::Column => WireDirection::Column,
|
||||
},
|
||||
gap: c.gap,
|
||||
padding: c.padding,
|
||||
justify_content: match c.justify_content {
|
||||
JustifyContent::Start => WireJustifyContent::Start,
|
||||
JustifyContent::Center => WireJustifyContent::Center,
|
||||
JustifyContent::End => WireJustifyContent::End,
|
||||
JustifyContent::SpaceBetween => WireJustifyContent::SpaceBetween,
|
||||
JustifyContent::SpaceEvenly => WireJustifyContent::SpaceEvenly,
|
||||
},
|
||||
align_items: match c.align_items {
|
||||
AlignItems::Start => WireAlignItems::Start,
|
||||
AlignItems::Center => WireAlignItems::Center,
|
||||
AlignItems::End => WireAlignItems::End,
|
||||
AlignItems::Stretch => WireAlignItems::Stretch,
|
||||
},
|
||||
children: c
|
||||
.children
|
||||
.iter()
|
||||
.map(|ch| WireLayoutChild {
|
||||
sizing: match ch.sizing {
|
||||
Sizing::Fixed(px) => WireSizing::Fixed(px),
|
||||
Sizing::Flex(w) => WireSizing::Flex(w),
|
||||
},
|
||||
node: layout_to_wire(&ch.node),
|
||||
})
|
||||
.collect(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
mod broadcaster;
|
||||
mod client_tracker;
|
||||
mod conversions;
|
||||
mod error;
|
||||
mod event_bus;
|
||||
mod server;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use crate::broadcaster::domain_theme_to_wire;
|
||||
use crate::client_tracker::ClientTracker;
|
||||
use crate::conversions::{display_hint_to_wire, layout_to_wire, widget_state_to_wire};
|
||||
use crate::error::TcpServerError;
|
||||
use domain::{ConfigRepository, WidgetStateReader};
|
||||
use protocol::{ServerMessage, WidgetDescriptor, WireLayoutNode, encode};
|
||||
use protocol::{ServerMessage, WidgetDescriptor, encode};
|
||||
use std::sync::Arc;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::net::TcpListener;
|
||||
@@ -87,14 +88,14 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
let wire_layout: WireLayoutNode = (&layout.root).into();
|
||||
let wire_layout = layout_to_wire(&layout.root);
|
||||
let mut wire_widgets = Vec::new();
|
||||
for w in &widgets {
|
||||
if let Some(s) = widget_states.get_widget_state(w.id).await {
|
||||
wire_widgets.push(WidgetDescriptor {
|
||||
id: w.id,
|
||||
display_hint: (&w.display_hint).into(),
|
||||
state: (&s).into(),
|
||||
display_hint: display_hint_to_wire(&w.display_hint),
|
||||
state: widget_state_to_wire(&s),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user