From 9dcc56fa89e1ec4b6a0fd13f286778769b89afb4 Mon Sep 17 00:00:00 2001 From: Greg Holland <30577851+horned-sphere@users.noreply.github.com> Date: Tue, 23 Apr 2024 16:51:19 +0100 Subject: [PATCH 01/27] Improved with/transform item combinators. --- example_apps/tutorial_app/src/unit_agent.rs | 4 +- .../src/agent_lifecycle/utility/mod.rs | 41 +++++- server/swimos_agent/src/item.rs | 59 +++++++- server/swimos_agent/src/lanes/map/mod.rs | 126 +++++++++++++---- server/swimos_agent/src/lanes/map/tests.rs | 6 +- server/swimos_agent/src/lanes/value/mod.rs | 123 ++++++++++++++++ server/swimos_agent/src/map_storage/mod.rs | 23 ++- server/swimos_agent/src/stores/map/mod.rs | 123 ++++++++++++---- server/swimos_agent/src/stores/map/tests.rs | 6 +- server/swimos_agent/src/stores/value/mod.rs | 131 ++++++++++++++++++ 10 files changed, 564 insertions(+), 78 deletions(-) diff --git a/example_apps/tutorial_app/src/unit_agent.rs b/example_apps/tutorial_app/src/unit_agent.rs index 60c7da427..a4c124e2c 100644 --- a/example_apps/tutorial_app/src/unit_agent.rs +++ b/example_apps/tutorial_app/src/unit_agent.rs @@ -153,8 +153,8 @@ fn update_histogram( item: HistoryItem, ) -> impl EventHandler { let bucket = bucket_of(&item.timestamp); - context.with_entry(UnitAgent::HISTOGRAM, bucket, |maybe| { - let mut counter = maybe.unwrap_or_default(); + context.transform_entry(UnitAgent::HISTOGRAM, bucket, |maybe| { + let mut counter = maybe.copied().unwrap_or_default(); counter.count += rand::thread_rng().gen_range(0..20); Some(counter) }) diff --git a/server/swimos_agent/src/agent_lifecycle/utility/mod.rs b/server/swimos_agent/src/agent_lifecycle/utility/mod.rs index d8940d827..fbc0a8a19 100644 --- a/server/swimos_agent/src/agent_lifecycle/utility/mod.rs +++ b/server/swimos_agent/src/agent_lifecycle/utility/mod.rs @@ -43,7 +43,7 @@ use crate::event_handler::{ }; use crate::event_handler::{GetAgentUri, HandlerAction, SideEffect}; use crate::item::{ - MapLikeItem, MutableMapLikeItem, MutableValueLikeItem, TransformableMapLikeItem, ValueLikeItem, + MapLikeItem, MutableMapLikeItem, MutableValueLikeItem, ValueLikeItem }; use crate::lanes::command::{CommandLane, DoCommand}; use crate::lanes::demand::{Cue, DemandLane}; @@ -184,6 +184,34 @@ impl HandlerContext { Item::set_handler::(lane, value) } + pub fn transform_value<'a, Item, T, F>( + &self, + projection: fn(&Agent) -> &Item, + f: F, + ) -> impl HandlerAction + Send + 'a + where + Agent: 'static, + Item: MutableValueLikeItem + 'static, + T: 'static, + F: FnOnce(&T) -> T + Send + 'a, + { + Item::transform_handler::(projection, f) + } + + pub fn with_value<'a, Item, T, F, U>( + &self, + projection: fn(&Agent) -> &Item, + f: F, + ) -> impl HandlerAction + Send + 'a + where + Agent: 'static, + Item: ValueLikeItem + 'static, + T: 'static, + F: FnOnce(&T) -> U + Send + 'a, + { + Item::with_value_handler::(projection, f) + } + /// Create an event handler that will update an entry in a map lane or store of the agent. /// /// #Arguments @@ -210,7 +238,7 @@ impl HandlerContext { /// * `lane` - Projection to the map lane. /// * `key - The key to update. /// * `f` - A function to apple to the entry in the map. - pub fn with_entry<'a, Item, K, V, F>( + pub fn transform_entry<'a, Item, K, V, F>( &self, lane: fn(&Agent) -> &Item, key: K, @@ -218,12 +246,12 @@ impl HandlerContext { ) -> impl HandlerAction + Send + 'a where Agent: 'static, - Item: TransformableMapLikeItem + 'static, + Item: MutableMapLikeItem + 'static, K: Send + Clone + Eq + Hash + 'static, - V: Clone + 'static, - F: FnOnce(Option) -> Option + Send + 'a, + V: 'static, + F: FnOnce(Option<&V>) -> Option + Send + 'a, { - Item::with_handler::(lane, key, f) + Item::transform_entry_handler::(lane, key, f) } /// Create an event handler that will remove an entry from a map lane or store of the agent. @@ -705,6 +733,7 @@ impl HandlerContext { pub fn stop(&self) -> impl EventHandler + Send + 'static { HandlerActionExt::::discard(Stop) } + } pub struct JoinValueContext { diff --git a/server/swimos_agent/src/item.rs b/server/swimos_agent/src/item.rs index 80d49c361..c2387cf9f 100644 --- a/server/swimos_agent/src/item.rs +++ b/server/swimos_agent/src/item.rs @@ -51,9 +51,28 @@ pub trait MapLikeItem { C: 'static; fn get_handler(projection: fn(&C) -> &Self, key: K) -> Self::GetHandler; + fn get_map_handler(projection: fn(&C) -> &Self) -> Self::GetMapHandler; } +pub trait InspectableMapLikeItem { + type WithEntryHandler<'a, C, F, U>: HandlerAction + Send + 'a + where + Self: 'static, + C: 'a, + F: FnOnce(Option<&V>) -> U + Send + 'a; + + fn with_entry_handler<'a, C, F, U>( + projection: fn(&C) -> &Self, + key: K, + f: F, + ) -> Self::WithEntryHandler<'a, C, F, U> + where + Self: 'static, + C: 'a, + F: FnOnce(Option<&V>) -> U + Send + 'a; +} + pub trait MutableMapLikeItem { type UpdateHandler: EventHandler + Send + 'static where @@ -72,24 +91,22 @@ pub trait MutableMapLikeItem { ) -> Self::UpdateHandler; fn remove_handler(projection: fn(&C) -> &Self, key: K) -> Self::RemoveHandler; fn clear_handler(projection: fn(&C) -> &Self) -> Self::ClearHandler; -} -pub trait TransformableMapLikeItem { - type WithEntryHandler<'a, C, F>: EventHandler + Send + 'a + type TransformEntryHandler<'a, C, F>: EventHandler + Send + 'a where Self: 'static, C: 'a, - F: FnOnce(Option) -> Option + Send + 'a; + F: FnOnce(Option<&V>) -> Option + Send + 'a; - fn with_handler<'a, C, F>( + fn transform_entry_handler<'a, C, F>( projection: fn(&C) -> &Self, key: K, f: F, - ) -> Self::WithEntryHandler<'a, C, F> + ) -> Self::TransformEntryHandler<'a, C, F> where Self: 'static, C: 'a, - F: FnOnce(Option) -> Option + Send + 'a; + F: FnOnce(Option<&V>) -> Option + Send + 'a; } pub trait ValueLikeItem { @@ -97,7 +114,21 @@ pub trait ValueLikeItem { where C: 'static; + type WithValueHandler<'a, C, F, U>: HandlerAction + Send + 'a + where + Self: 'static, + C: 'a, + F: FnOnce(&T) -> U + Send + 'a; + fn get_handler(projection: fn(&C) -> &Self) -> Self::GetHandler; + + fn with_value_handler<'a, Item, C, F, U>( + projection: fn(&C) -> &Self, + f: F, + ) -> Self::WithValueHandler<'a, C, F, U> + where + C: 'a, + F: FnOnce(&T) -> U + Send + 'a; } pub trait MutableValueLikeItem { @@ -105,5 +136,19 @@ pub trait MutableValueLikeItem { where C: 'static; + type TransformValueHandler<'a, C, F>: EventHandler + Send + 'a + where + Self: 'static, + C: 'a, + F: FnOnce(&T) -> T + Send + 'a; + fn set_handler(projection: fn(&C) -> &Self, value: T) -> Self::SetHandler; + + fn transform_handler<'a, Item, C, F>( + projection: fn(&C) -> &Self, + f: F, + ) -> Self::TransformValueHandler<'a, C, F> + where + C: 'a, + F: FnOnce(&T) -> T + Send + 'a; } diff --git a/server/swimos_agent/src/lanes/map/mod.rs b/server/swimos_agent/src/lanes/map/mod.rs index e52760492..2e9589ca1 100644 --- a/server/swimos_agent/src/lanes/map/mod.rs +++ b/server/swimos_agent/src/lanes/map/mod.rs @@ -34,7 +34,7 @@ use crate::{ ActionContext, AndThen, EventHandlerError, HandlerAction, HandlerActionExt, HandlerTrans, Modification, StepResult, }, - item::{AgentItem, MapItem, MapLikeItem, MutableMapLikeItem, TransformableMapLikeItem}, + item::{AgentItem, InspectableMapLikeItem, MapItem, MapLikeItem, MutableMapLikeItem}, map_storage::{MapStoreInner, WithEntryResult}, meta::AgentMetadata, }; @@ -104,12 +104,11 @@ where } /// Transform the value associated with a key. - pub fn with_entry(&self, key: K, f: F) -> WithEntryResult + pub fn transform_entry(&self, key: K, f: F) -> WithEntryResult where - V: Clone, - F: FnOnce(Option) -> Option, + F: FnOnce(Option<&V>) -> Option, { - self.inner.borrow_mut().with_entry(key, f) + self.inner.borrow_mut().transform_entry(key, f) } /// Remove and entry from the map. @@ -147,6 +146,20 @@ where } } +impl MapLane +where + K: Eq + Hash, +{ + + pub fn with_entry(&self, key: K, f: F) -> U + where + F: FnOnce(Option<&V>) -> U, + { + self.inner.borrow().with_entry(key, f) + } + +} + const INFALLIBLE_SER: &str = "Serializing lane responses to recon should be infallible."; impl LaneItem for MapLane @@ -381,6 +394,46 @@ where } } +pub struct MapLaneWithEntry { + projection: for<'a> fn(&'a C) -> &'a MapLane, + key_and_f: Option<(K, F)>, +} + +impl MapLaneWithEntry { + pub fn new(projection: for<'a> fn(&'a C) -> &'a MapLane, key: K, f: F) -> Self { + MapLaneWithEntry { + projection, + key_and_f: Some((key, f)), + } + } +} + +impl HandlerAction for MapLaneWithEntry +where + K: Eq + Hash, + F: FnOnce(Option<&V>) -> U, +{ + type Completion = U; + + fn step( + &mut self, + _action_context: &mut ActionContext, + _meta: AgentMetadata, + context: &C, + ) -> StepResult { + let MapLaneWithEntry { + projection, + key_and_f, + } = self; + if let Some((key, f)) = key_and_f.take() { + let lane = projection(context); + StepResult::done(lane.with_entry(key, f)) + } else { + StepResult::after_done() + } + } +} + /// An [`EventHandler`] that will request a sync from the lane. pub struct MapLaneSync { projection: for<'a> fn(&'a C) -> &'a MapLane, @@ -529,25 +582,24 @@ where } /// An [`EventHandler`] that will alter an entry in the map. -pub struct MapLaneWithEntry { +pub struct MapLaneTransformEntry { projection: for<'a> fn(&'a C) -> &'a MapLane, key_and_f: Option<(K, F)>, } -impl MapLaneWithEntry { +impl MapLaneTransformEntry { pub fn new(projection: for<'a> fn(&'a C) -> &'a MapLane, key: K, f: F) -> Self { - MapLaneWithEntry { + MapLaneTransformEntry { projection, key_and_f: Some((key, f)), } } } -impl HandlerAction for MapLaneWithEntry +impl HandlerAction for MapLaneTransformEntry where K: Clone + Eq + Hash, - V: Clone, - F: FnOnce(Option) -> Option, + F: FnOnce(Option<&V>) -> Option, { type Completion = (); @@ -557,13 +609,13 @@ where _meta: AgentMetadata, context: &C, ) -> StepResult { - let MapLaneWithEntry { + let MapLaneTransformEntry { projection, key_and_f, } = self; if let Some((key, f)) = key_and_f.take() { let lane = projection(context); - if matches!(lane.with_entry(key, f), WithEntryResult::NoChange) { + if matches!(lane.transform_entry(key, f), WithEntryResult::NoChange) { StepResult::done(()) } else { StepResult::Complete { @@ -599,6 +651,30 @@ where } } +impl InspectableMapLikeItem for MapLane +where + K: Eq + Hash + Send + 'static, + V: 'static, +{ + type WithEntryHandler<'a, C, F, U> = MapLaneWithEntry + where + Self: 'static, + C: 'a, + F: FnOnce(Option<&V>) -> U + Send + 'a; + + fn with_entry_handler<'a, C, F, U>( + projection: fn(&C) -> &Self, + key: K, + f: F, + ) -> Self::WithEntryHandler<'a, C, F, U> + where + Self: 'static, + C: 'a, + F: FnOnce(Option<&V>) -> U + Send + 'a { + MapLaneWithEntry::new(projection, key, f) + } +} + impl MutableMapLikeItem for MapLane where K: Clone + Eq + Hash + Send + 'static, @@ -631,29 +707,23 @@ where fn clear_handler(projection: fn(&C) -> &Self) -> Self::ClearHandler { MapLaneClear::new(projection) } -} - -impl TransformableMapLikeItem for MapLane -where - K: Clone + Eq + Hash + Send + 'static, - V: Clone + Send + 'static, -{ - type WithEntryHandler<'a, C, F> = MapLaneWithEntry + + type TransformEntryHandler<'a, C, F> = MapLaneTransformEntry where Self: 'static, C: 'a, - F: FnOnce(Option) -> Option + Send + 'a; - - fn with_handler<'a, C, F>( + F: FnOnce(Option<&V>) -> Option + Send + 'a; + + fn transform_entry_handler<'a, C, F>( projection: fn(&C) -> &Self, key: K, f: F, - ) -> Self::WithEntryHandler<'a, C, F> + ) -> Self::TransformEntryHandler<'a, C, F> where Self: 'static, C: 'a, - F: FnOnce(Option) -> Option + Send + 'a, - { - MapLaneWithEntry::new(projection, key, f) + F: FnOnce(Option<&V>) -> Option + Send + 'a { + MapLaneTransformEntry::new(projection, key, f) } + } diff --git a/server/swimos_agent/src/lanes/map/tests.rs b/server/swimos_agent/src/lanes/map/tests.rs index 40821c904..f7a048646 100644 --- a/server/swimos_agent/src/lanes/map/tests.rs +++ b/server/swimos_agent/src/lanes/map/tests.rs @@ -38,7 +38,7 @@ use crate::{ lanes::{ map::{ MapLane, MapLaneClear, MapLaneEvent, MapLaneGet, MapLaneGetMap, MapLaneRemove, - MapLaneSync, MapLaneUpdate, MapLaneWithEntry, + MapLaneSync, MapLaneUpdate, MapLaneTransformEntry, }, LaneItem, }, @@ -748,7 +748,7 @@ fn map_lane_with_event_handler_update() { let meta = make_meta(&uri, &route_params); let agent = TestAgent::with_init(); - let mut handler = MapLaneWithEntry::new(TestAgent::LANE, K1, |maybe: Option| { + let mut handler = MapLaneTransformEntry::new(TestAgent::LANE, K1, |maybe: Option<&Text>| { maybe.map(|v| Text::from(v.as_str().to_uppercase())) }); @@ -787,7 +787,7 @@ fn map_lane_with_event_handler_remove() { let meta = make_meta(&uri, &route_params); let agent = TestAgent::with_init(); - let mut handler = MapLaneWithEntry::new(TestAgent::LANE, K1, |_: Option| None); + let mut handler = MapLaneTransformEntry::new(TestAgent::LANE, K1, |_: Option<&Text>| None); let result = handler.step( &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), diff --git a/server/swimos_agent/src/lanes/value/mod.rs b/server/swimos_agent/src/lanes/value/mod.rs index 6377f1bee..0c4944ace 100644 --- a/server/swimos_agent/src/lanes/value/mod.rs +++ b/server/swimos_agent/src/lanes/value/mod.rs @@ -77,6 +77,21 @@ impl ValueLane { let ValueLane { sync_queue, .. } = self; sync_queue.borrow_mut().push_back(id); } + + /// Replace the contents of the lane. + pub fn replace(&self, f: F) + where + F: FnOnce(&T) -> T, + { + self.store.replace(f); + } + + pub(crate) fn with(&self, f: F) -> U + where + F: FnOnce(&T) -> U, + { + self.store.with(f) + } } impl AgentItem for ValueLane { @@ -257,6 +272,40 @@ impl HandlerAction for ValueLaneSync { } } +pub struct ValueLaneWithValue { + projection: for<'a> fn(&'a C) -> &'a ValueLane, + f: Option, +} + +impl ValueLaneWithValue { + + pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueLane, + f: F) -> Self { + ValueLaneWithValue { projection, f: Some(f) } + } +} + +impl HandlerAction for ValueLaneWithValue +where + F: FnOnce(&T) -> U, +{ + type Completion = U; + + fn step( + &mut self, + _action_context: &mut ActionContext, + _meta: AgentMetadata, + context: &C, + ) -> StepResult { + if let Some(f) = self.f.take() { + let lane = (self.projection)(context); + StepResult::done(lane.with(f)) + } else { + StepResult::after_done() + } + } +} + impl HandlerTrans for ProjTransform> { type Out = ValueLaneSet; @@ -286,9 +335,26 @@ where where C: 'static; + type WithValueHandler<'a, C, F, U> = ValueLaneWithValue + where + Self: 'static, + C: 'a, + F: FnOnce(&T) -> U + Send + 'a; + fn get_handler(projection: fn(&C) -> &Self) -> Self::GetHandler { ValueLaneGet::new(projection) } + + fn with_value_handler<'a, Item, C, F, U>( + projection: fn(&C) -> &Self, + f: F, + ) -> Self::WithValueHandler<'a, C, F, U> + where + C: 'a, + F: FnOnce(&T) -> U + Send + 'a, + { + ValueLaneWithValue::new(projection, f) + } } impl MutableValueLikeItem for ValueLane @@ -302,4 +368,61 @@ where fn set_handler(projection: fn(&C) -> &Self, value: T) -> Self::SetHandler { ValueLaneSet::new(projection, value) } + + type TransformValueHandler<'a, C, F> = ValueLaneTransformValue + where + Self: 'static, + C: 'a, + F: FnOnce(&T) -> T + Send + 'a; + + fn transform_handler<'a, Item, C, F>( + projection: fn(&C) -> &Self, + f: F, + ) -> Self::TransformValueHandler<'a, C, F> + where + C: 'a, + F: FnOnce(&T) -> T + Send + 'a, + { + ValueLaneTransformValue::new(projection, f) + } +} + +/// An [`EventHandler`] that will transform the value of a value lane. +pub struct ValueLaneTransformValue { + projection: for<'a> fn(&'a C) -> &'a ValueLane, + f: Option, +} + +impl ValueLaneTransformValue { + pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueLane, f: F) -> Self { + ValueLaneTransformValue { + projection, + f: Some(f), + } + } +} + +impl HandlerAction for ValueLaneTransformValue +where + F: FnOnce(&T) -> T, +{ + type Completion = (); + + fn step( + &mut self, + _action_context: &mut ActionContext, + _meta: AgentMetadata, + context: &C, + ) -> StepResult { + if let Some(f) = self.f.take() { + let lane = (self.projection)(context); + lane.replace(f); + StepResult::Complete { + modified_item: Some(Modification::of(lane.id())), + result: (), + } + } else { + StepResult::after_done() + } + } } diff --git a/server/swimos_agent/src/map_storage/mod.rs b/server/swimos_agent/src/map_storage/mod.rs index d5800bb1d..8f97f6198 100644 --- a/server/swimos_agent/src/map_storage/mod.rs +++ b/server/swimos_agent/src/map_storage/mod.rs @@ -78,10 +78,9 @@ where queue.push(MapOperation::Update { key, value: () }); } - pub fn with_entry(&mut self, key: K, f: F) -> WithEntryResult + pub fn transform_entry(&mut self, key: K, f: F) -> WithEntryResult where - V: Clone, - F: FnOnce(Option) -> Option, + F: FnOnce(Option<&V>) -> Option, { let MapStoreInner { content, @@ -89,7 +88,7 @@ where queue, } = self; match content.remove(&key) { - Some(v) => match f(Some(v.clone())) { + Some(v) => match f(Some(&v)) { Some(v2) => { content.insert(key.clone(), v2); *previous = Some(MapLaneEvent::Update(key.clone(), Some(v))); @@ -174,3 +173,19 @@ where queue.pop(content) } } + +impl MapStoreInner +where + K: Eq + Hash, +{ + pub fn with_entry(&self, key: K, f: F) -> U + where + F: FnOnce(Option<&V>) -> U, + { + let MapStoreInner { + content, + .. + } = self; + f(content.get(&key)) + } +} diff --git a/server/swimos_agent/src/stores/map/mod.rs b/server/swimos_agent/src/stores/map/mod.rs index c7cba11af..8ea5d8687 100644 --- a/server/swimos_agent/src/stores/map/mod.rs +++ b/server/swimos_agent/src/stores/map/mod.rs @@ -25,7 +25,7 @@ use tokio_util::codec::Encoder; use crate::agent_model::WriteResult; use crate::event_handler::{ActionContext, HandlerAction, Modification, StepResult}; use crate::event_queue::EventQueue; -use crate::item::{AgentItem, MapItem, MapLikeItem, MutableMapLikeItem, TransformableMapLikeItem}; +use crate::item::{AgentItem, InspectableMapLikeItem, MapItem, MapLikeItem, MutableMapLikeItem}; use crate::map_storage::{MapStoreInner, WithEntryResult}; use crate::meta::AgentMetadata; @@ -91,14 +91,14 @@ where } /// Transform the value associated with a key. - pub fn with_entry(&self, key: K, f: F) -> WithEntryResult + pub fn transform_entry(&self, key: K, f: F) -> WithEntryResult where - V: Clone, - F: FnOnce(Option) -> Option, + F: FnOnce(Option<&V>) -> Option, { - self.inner.borrow_mut().with_entry(key, f) + self.inner.borrow_mut().transform_entry(key, f) } + /// Remove an entry from the map. pub fn remove(&self, key: &K) { self.inner.borrow_mut().remove(key) @@ -128,6 +128,20 @@ where } } +impl MapStore +where + K: Eq + Hash, +{ + + pub fn with_entry(&self, key: K, f: F) -> U + where + F: FnOnce(Option<&V>) -> U, + { + self.inner.borrow().with_entry(key, f) + } + +} + const INFALLIBLE_SER: &str = "Serializing store responses to recon should be infallible."; impl StoreItem for MapStore @@ -363,25 +377,24 @@ where } /// An [`EventHandler`] that will alter an entry in the map. -pub struct MapStoreWithEntry { +pub struct MapStoreTransformEntry { projection: for<'a> fn(&'a C) -> &'a MapStore, key_and_f: Option<(K, F)>, } -impl MapStoreWithEntry { +impl MapStoreTransformEntry { pub fn new(projection: for<'a> fn(&'a C) -> &'a MapStore, key: K, f: F) -> Self { - MapStoreWithEntry { + MapStoreTransformEntry { projection, key_and_f: Some((key, f)), } } } -impl HandlerAction for MapStoreWithEntry +impl HandlerAction for MapStoreTransformEntry where K: Clone + Eq + Hash, - V: Clone, - F: FnOnce(Option) -> Option, + F: FnOnce(Option<&V>) -> Option, { type Completion = (); @@ -391,13 +404,13 @@ where _meta: AgentMetadata, context: &C, ) -> StepResult { - let MapStoreWithEntry { + let MapStoreTransformEntry { projection, key_and_f, } = self; if let Some((key, f)) = key_and_f.take() { let store = projection(context); - if matches!(store.with_entry(key, f), WithEntryResult::NoChange) { + if matches!(store.transform_entry(key, f), WithEntryResult::NoChange) { StepResult::done(()) } else { StepResult::Complete { @@ -411,6 +424,46 @@ where } } +pub struct MapStoreWithEntry { + projection: for<'a> fn(&'a C) -> &'a MapStore, + key_and_f: Option<(K, F)>, +} + +impl MapStoreWithEntry { + pub fn new(projection: for<'a> fn(&'a C) -> &'a MapStore, key: K, f: F) -> Self { + MapStoreWithEntry { + projection, + key_and_f: Some((key, f)), + } + } +} + +impl HandlerAction for MapStoreWithEntry +where + K: Eq + Hash, + F: FnOnce(Option<&V>) -> U, +{ + type Completion = U; + + fn step( + &mut self, + _action_context: &mut ActionContext, + _meta: AgentMetadata, + context: &C, + ) -> StepResult { + let MapStoreWithEntry { + projection, + key_and_f, + } = self; + if let Some((key, f)) = key_and_f.take() { + let store = projection(context); + StepResult::done(store.with_entry(key, f)) + } else { + StepResult::after_done() + } + } +} + impl MapLikeItem for MapStore where K: Clone + Eq + Hash + Send + 'static, @@ -431,6 +484,31 @@ where fn get_map_handler(projection: fn(&C) -> &Self) -> Self::GetMapHandler { MapStoreGetMap::new(projection) } + +} + +impl InspectableMapLikeItem for MapStore +where + K: Eq + Hash + Send + 'static, + V: 'static, +{ + type WithEntryHandler<'a, C, F, U> = MapStoreWithEntry + where + Self: 'static, + C: 'a, + F: FnOnce(Option<&V>) -> U + Send + 'a; + + fn with_entry_handler<'a, C, F, U>( + projection: fn(&C) -> &Self, + key: K, + f: F, + ) -> Self::WithEntryHandler<'a, C, F, U> + where + Self: 'static, + C: 'a, + F: FnOnce(Option<&V>) -> U + Send + 'a { + MapStoreWithEntry::new(projection, key, f) + } } impl MutableMapLikeItem for MapStore @@ -465,29 +543,24 @@ where fn clear_handler(projection: fn(&C) -> &Self) -> Self::ClearHandler { MapStoreClear::new(projection) } -} -impl TransformableMapLikeItem for MapStore -where - K: Clone + Eq + Hash + Send + 'static, - V: Clone + Send + 'static, -{ - type WithEntryHandler<'a, C, F> = MapStoreWithEntry + type TransformEntryHandler<'a, C, F> = MapStoreTransformEntry where Self: 'static, C: 'a, - F: FnOnce(Option) -> Option + Send + 'a; + F: FnOnce(Option<&V>) -> Option + Send + 'a; - fn with_handler<'a, C, F>( + fn transform_entry_handler<'a, C, F>( projection: fn(&C) -> &Self, key: K, f: F, - ) -> Self::WithEntryHandler<'a, C, F> + ) -> Self::TransformEntryHandler<'a, C, F> where Self: 'static, C: 'a, - F: FnOnce(Option) -> Option + Send + 'a, + F: FnOnce(Option<&V>) -> Option + Send + 'a, { - MapStoreWithEntry::new(projection, key, f) + MapStoreTransformEntry::new(projection, key, f) } + } diff --git a/server/swimos_agent/src/stores/map/tests.rs b/server/swimos_agent/src/stores/map/tests.rs index 6bde6a8c4..78a39bf4c 100644 --- a/server/swimos_agent/src/stores/map/tests.rs +++ b/server/swimos_agent/src/stores/map/tests.rs @@ -37,7 +37,7 @@ use crate::{ stores::{ map::{ MapStoreClear, MapStoreGet, MapStoreGetMap, MapStoreRemove, MapStoreUpdate, - MapStoreWithEntry, + MapStoreTransformEntry, }, MapStore, StoreItem, }, @@ -577,7 +577,7 @@ fn map_store_with_event_handler_update() { let meta = make_meta(&uri, &route_params); let agent = TestAgent::with_init(); - let mut handler = MapStoreWithEntry::new(TestAgent::STORE, K1, |maybe: Option| { + let mut handler = MapStoreTransformEntry::new(TestAgent::STORE, K1, |maybe: Option<&Text>| { maybe.map(|v| Text::from(v.as_str().to_uppercase())) }); @@ -616,7 +616,7 @@ fn map_lane_with_event_handler_remove() { let meta = make_meta(&uri, &route_params); let agent = TestAgent::with_init(); - let mut handler = MapStoreWithEntry::new(TestAgent::STORE, K1, |_: Option| None); + let mut handler = MapStoreTransformEntry::new(TestAgent::STORE, K1, |_: Option<&Text>| None); let result = handler.step( &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), diff --git a/server/swimos_agent/src/stores/value/mod.rs b/server/swimos_agent/src/stores/value/mod.rs index 05182b79e..3a9d345de 100644 --- a/server/swimos_agent/src/stores/value/mod.rs +++ b/server/swimos_agent/src/stores/value/mod.rs @@ -120,6 +120,29 @@ impl ValueStore { false } } + + pub(crate) fn replace(&self, f: F) + where + F: FnOnce(&T) -> T, + { + let ValueStore { inner, dirty, .. } = self; + let mut guard = inner.borrow_mut(); + let Inner { content, previous } = &mut *guard; + let new_value = f(content); + let prev = std::mem::replace(content, new_value); + *previous = Some(prev); + dirty.replace(true); + } + + pub(crate) fn with(&self, f: F) -> U + where + F: FnOnce(&T) -> U, + { + let ValueStore { inner, .. } = self; + let guard = inner.borrow(); + let Inner { content, .. } = &*guard; + f(content) + } } impl AgentItem for ValueStore { @@ -247,6 +270,80 @@ impl HandlerAction for ValueStoreSet { } } +/// An [`EventHandler`] that will transform the value of a value store. +pub struct ValueStoreTransformValue { + projection: for<'a> fn(&'a C) -> &'a ValueStore, + f: Option, +} + +impl ValueStoreTransformValue { + pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueStore, f: F) -> Self { + ValueStoreTransformValue { + projection, + f: Some(f), + } + } +} + +impl HandlerAction for ValueStoreTransformValue +where + F: FnOnce(&T) -> T, +{ + type Completion = (); + + fn step( + &mut self, + _action_context: &mut ActionContext, + _meta: AgentMetadata, + context: &C, + ) -> StepResult { + if let Some(f) = self.f.take() { + let store = (self.projection)(context); + store.replace(f); + StepResult::Complete { + modified_item: Some(Modification::of(store.id())), + result: (), + } + } else { + StepResult::after_done() + } + } +} + +pub struct ValueStoreWithValue { + projection: for<'a> fn(&'a C) -> &'a ValueStore, + f: Option, +} + +impl ValueStoreWithValue { + + pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueStore, + f: F) -> Self { + ValueStoreWithValue { projection, f: Some(f) } + } +} + +impl HandlerAction for ValueStoreWithValue +where + F: FnOnce(&T) -> U, +{ + type Completion = U; + + fn step( + &mut self, + _action_context: &mut ActionContext, + _meta: AgentMetadata, + context: &C, + ) -> StepResult { + if let Some(f) = self.f.take() { + let store = (self.projection)(context); + StepResult::done(store.with(f)) + } else { + StepResult::after_done() + } + } +} + impl ValueLikeItem for ValueStore where T: Clone + Send + 'static, @@ -255,9 +352,26 @@ where where C: 'static; + type WithValueHandler<'a, C, F, U> = ValueStoreWithValue + where + Self: 'static, + C: 'a, + F: FnOnce(&T) -> U + Send + 'a; + fn get_handler(projection: fn(&C) -> &Self) -> Self::GetHandler { ValueStoreGet::new(projection) } + + fn with_value_handler<'a, Item, C, F, U>( + projection: fn(&C) -> &Self, + f: F, + ) -> Self::WithValueHandler<'a, C, F, U> + where + C: 'a, + F: FnOnce(&T) -> U + Send + 'a, + { + ValueStoreWithValue::new(projection, f) + } } impl MutableValueLikeItem for ValueStore @@ -268,7 +382,24 @@ where where C: 'static; + type TransformValueHandler<'a, C, F> = ValueStoreTransformValue + where + Self: 'static, + C: 'a, + F: FnOnce(&T) -> T + Send + 'a; + fn set_handler(projection: fn(&C) -> &Self, value: T) -> Self::SetHandler { ValueStoreSet::new(projection, value) } + + fn transform_handler<'a, Item, C, F>( + projection: fn(&C) -> &Self, + f: F, + ) -> Self::TransformValueHandler<'a, C, F> + where + C: 'a, + F: FnOnce(&T) -> T + Send + 'a, + { + ValueStoreTransformValue::new(projection, f) + } } From 599b9f5c145123ede549d9c9c29bbcfc3ccf69f5 Mon Sep 17 00:00:00 2001 From: Greg Holland <30577851+horned-sphere@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:13:27 +0100 Subject: [PATCH 02/27] Changed with_value combinator to allow borrowing. --- .../src/agent_lifecycle/utility/mod.rs | 10 +++--- server/swimos_agent/src/item.rs | 16 +++++---- server/swimos_agent/src/lanes/value/mod.rs | 33 ++++++++++------- server/swimos_agent/src/stores/value/mod.rs | 35 +++++++++++-------- 4 files changed, 57 insertions(+), 37 deletions(-) diff --git a/server/swimos_agent/src/agent_lifecycle/utility/mod.rs b/server/swimos_agent/src/agent_lifecycle/utility/mod.rs index fbc0a8a19..942c114f3 100644 --- a/server/swimos_agent/src/agent_lifecycle/utility/mod.rs +++ b/server/swimos_agent/src/agent_lifecycle/utility/mod.rs @@ -13,6 +13,7 @@ // limitations under the License. use std::any::Any; +use std::borrow::Borrow; use std::fmt::Debug; use std::hash::Hash; use std::time::Duration; @@ -198,7 +199,7 @@ impl HandlerContext { Item::transform_handler::(projection, f) } - pub fn with_value<'a, Item, T, F, U>( + pub fn with_value<'a, Item, T, F, B, U>( &self, projection: fn(&Agent) -> &Item, f: F, @@ -206,10 +207,11 @@ impl HandlerContext { where Agent: 'static, Item: ValueLikeItem + 'static, - T: 'static, - F: FnOnce(&T) -> U + Send + 'a, + T: Borrow, + B: 'static, + F: FnOnce(&B) -> U + Send + 'a, { - Item::with_value_handler::(projection, f) + Item::with_value_handler::(projection, f) } /// Create an event handler that will update an entry in a map lane or store of the agent. diff --git a/server/swimos_agent/src/item.rs b/server/swimos_agent/src/item.rs index c2387cf9f..b3d4be781 100644 --- a/server/swimos_agent/src/item.rs +++ b/server/swimos_agent/src/item.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::HashMap; +use std::{borrow::Borrow, collections::HashMap}; use crate::{ event_handler::{EventHandler, HandlerAction}, @@ -114,21 +114,25 @@ pub trait ValueLikeItem { where C: 'static; - type WithValueHandler<'a, C, F, U>: HandlerAction + Send + 'a + type WithValueHandler<'a, C, F, B, U>: HandlerAction + Send + 'a where Self: 'static, C: 'a, - F: FnOnce(&T) -> U + Send + 'a; + T: Borrow, + B: 'static, + F: FnOnce(&B) -> U + Send + 'a; fn get_handler(projection: fn(&C) -> &Self) -> Self::GetHandler; - fn with_value_handler<'a, Item, C, F, U>( + fn with_value_handler<'a, Item, C, F, B, U>( projection: fn(&C) -> &Self, f: F, - ) -> Self::WithValueHandler<'a, C, F, U> + ) -> Self::WithValueHandler<'a, C, F, B, U> where C: 'a, - F: FnOnce(&T) -> U + Send + 'a; + T: Borrow, + B: 'static, + F: FnOnce(&B) -> U + Send + 'a; } pub trait MutableValueLikeItem { diff --git a/server/swimos_agent/src/lanes/value/mod.rs b/server/swimos_agent/src/lanes/value/mod.rs index 0c4944ace..b0977f7e3 100644 --- a/server/swimos_agent/src/lanes/value/mod.rs +++ b/server/swimos_agent/src/lanes/value/mod.rs @@ -17,7 +17,7 @@ pub mod lifecycle; #[cfg(test)] mod tests; -use std::{cell::RefCell, collections::VecDeque}; +use std::{borrow::Borrow, cell::RefCell, collections::VecDeque, marker::PhantomData}; use bytes::BytesMut; use static_assertions::assert_impl_all; @@ -86,9 +86,10 @@ impl ValueLane { self.store.replace(f); } - pub(crate) fn with(&self, f: F) -> U + pub(crate) fn with(&self, f: F) -> U where - F: FnOnce(&T) -> U, + T: Borrow, + F: FnOnce(&B) -> U, { self.store.with(f) } @@ -272,22 +273,24 @@ impl HandlerAction for ValueLaneSync { } } -pub struct ValueLaneWithValue { +pub struct ValueLaneWithValue { projection: for<'a> fn(&'a C) -> &'a ValueLane, f: Option, + _type: PhantomData, } -impl ValueLaneWithValue { +impl ValueLaneWithValue { pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueLane, f: F) -> Self { - ValueLaneWithValue { projection, f: Some(f) } + ValueLaneWithValue { projection, f: Some(f), _type: PhantomData } } } -impl HandlerAction for ValueLaneWithValue +impl HandlerAction for ValueLaneWithValue where - F: FnOnce(&T) -> U, + T: Borrow, + F: FnOnce(&B) -> U, { type Completion = U; @@ -335,23 +338,27 @@ where where C: 'static; - type WithValueHandler<'a, C, F, U> = ValueLaneWithValue + type WithValueHandler<'a, C, F, B, U> = ValueLaneWithValue where Self: 'static, C: 'a, - F: FnOnce(&T) -> U + Send + 'a; + T: Borrow, + B: 'static, + F: FnOnce(&B) -> U + Send + 'a; fn get_handler(projection: fn(&C) -> &Self) -> Self::GetHandler { ValueLaneGet::new(projection) } - fn with_value_handler<'a, Item, C, F, U>( + fn with_value_handler<'a, Item, C, F, B, U>( projection: fn(&C) -> &Self, f: F, - ) -> Self::WithValueHandler<'a, C, F, U> + ) -> Self::WithValueHandler<'a, C, F, B, U> where C: 'a, - F: FnOnce(&T) -> U + Send + 'a, + T: Borrow, + B: 'static, + F: FnOnce(&B) -> U + Send + 'a, { ValueLaneWithValue::new(projection, f) } diff --git a/server/swimos_agent/src/stores/value/mod.rs b/server/swimos_agent/src/stores/value/mod.rs index 3a9d345de..abfc65e36 100644 --- a/server/swimos_agent/src/stores/value/mod.rs +++ b/server/swimos_agent/src/stores/value/mod.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::cell::{Cell, RefCell}; +use std::{borrow::Borrow, cell::{Cell, RefCell}, marker::PhantomData}; use bytes::BytesMut; use static_assertions::assert_impl_all; @@ -134,14 +134,15 @@ impl ValueStore { dirty.replace(true); } - pub(crate) fn with(&self, f: F) -> U + pub(crate) fn with(&self, f: F) -> U where - F: FnOnce(&T) -> U, + T: Borrow, + F: FnOnce(&B) -> U, { let ValueStore { inner, .. } = self; let guard = inner.borrow(); let Inner { content, .. } = &*guard; - f(content) + f(content.borrow()) } } @@ -310,22 +311,24 @@ where } } -pub struct ValueStoreWithValue { +pub struct ValueStoreWithValue { projection: for<'a> fn(&'a C) -> &'a ValueStore, f: Option, + _type: PhantomData, } -impl ValueStoreWithValue { +impl ValueStoreWithValue { pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueStore, f: F) -> Self { - ValueStoreWithValue { projection, f: Some(f) } + ValueStoreWithValue { projection, f: Some(f), _type: PhantomData } } } -impl HandlerAction for ValueStoreWithValue +impl HandlerAction for ValueStoreWithValue where - F: FnOnce(&T) -> U, + T: Borrow, + F: FnOnce(&B) -> U, { type Completion = U; @@ -352,23 +355,27 @@ where where C: 'static; - type WithValueHandler<'a, C, F, U> = ValueStoreWithValue + type WithValueHandler<'a, C, F, B, U> = ValueStoreWithValue where Self: 'static, C: 'a, - F: FnOnce(&T) -> U + Send + 'a; + T: Borrow, + B: 'static, + F: FnOnce(&B) -> U + Send + 'a; fn get_handler(projection: fn(&C) -> &Self) -> Self::GetHandler { ValueStoreGet::new(projection) } - fn with_value_handler<'a, Item, C, F, U>( + fn with_value_handler<'a, Item, C, F, B, U>( projection: fn(&C) -> &Self, f: F, - ) -> Self::WithValueHandler<'a, C, F, U> + ) -> Self::WithValueHandler<'a, C, F, B, U> where C: 'a, - F: FnOnce(&T) -> U + Send + 'a, + T: Borrow, + B: 'static, + F: FnOnce(&B) -> U + Send + 'a, { ValueStoreWithValue::new(projection, f) } From 9db2c37a3ecb977773708205360d5213742fc850 Mon Sep 17 00:00:00 2001 From: Greg Holland <30577851+horned-sphere@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:13:47 +0100 Subject: [PATCH 03/27] Switched map lane tests to use strings. --- server/swimos_agent/src/lanes/map/tests.rs | 117 ++++++++++----------- 1 file changed, 58 insertions(+), 59 deletions(-) diff --git a/server/swimos_agent/src/lanes/map/tests.rs b/server/swimos_agent/src/lanes/map/tests.rs index f7a048646..d554a140d 100644 --- a/server/swimos_agent/src/lanes/map/tests.rs +++ b/server/swimos_agent/src/lanes/map/tests.rs @@ -23,7 +23,6 @@ use swimos_api::{ map::MapOperation, }, }; -use swimos_model::Text; use swimos_recon::parser::{parse_recognize, Span}; use swimos_utilities::routing::route_uri::RouteUri; use tokio_util::codec::Decoder; @@ -58,10 +57,10 @@ const V1: &str = "first"; const V2: &str = "second"; const V3: &str = "third"; -fn init() -> HashMap { +fn init() -> HashMap { [(K1, V1), (K2, V2), (K3, V3)] .into_iter() - .map(|(k, v)| (k, Text::new(v))) + .map(|(k, v)| (k, v.to_owned())) .collect() } @@ -78,7 +77,7 @@ fn get_from_map_lane() { let lane = MapLane::new(ID, init()); let value = lane.get(&K1, |v| v.cloned()); - assert_eq!(value, Some(Text::new(V1))); + assert_eq!(value.as_deref(), Some(V1)); let value = lane.get(&ABSENT, |v| v.cloned()); assert!(value.is_none()); @@ -96,23 +95,23 @@ fn get_map_lane() { fn update_map_lane() { let lane = MapLane::new(ID, init()); - lane.update(K2, Text::new("altered")); + lane.update(K2, "altered".to_owned()); lane.get_map(|m| { assert_eq!(m.len(), 3); - assert_eq!(m.get(&K1), Some(&Text::new(V1))); - assert_eq!(m.get(&K2), Some(&Text::new("altered"))); - assert_eq!(m.get(&K3), Some(&Text::new(V3))); + assert_eq!(m.get(&K1).as_deref(), Some(V1)); + assert_eq!(m.get(&K2).as_deref(), Some("altered")); + assert_eq!(m.get(&K3).as_deref(), Some(V3)); }); - lane.update(ABSENT, Text::new("added")); + lane.update(ABSENT, "added".to_owned()); lane.get_map(|m| { assert_eq!(m.len(), 4); - assert_eq!(m.get(&K1), Some(&Text::new(V1))); - assert_eq!(m.get(&K2), Some(&Text::new("altered"))); - assert_eq!(m.get(&K3), Some(&Text::new(V3))); - assert_eq!(m.get(&ABSENT), Some(&Text::new("added"))); + assert_eq!(m.get(&K1).as_deref(), Some(V1)); + assert_eq!(m.get(&K2).as_deref(), Some("altered")); + assert_eq!(m.get(&K3).as_deref(), Some(V3)); + assert_eq!(m.get(&ABSENT).as_deref(), Some("added")); }); } @@ -124,8 +123,8 @@ fn remove_from_map_lane() { lane.get_map(|m| { assert_eq!(m.len(), 2); - assert_eq!(m.get(&K1), Some(&Text::new(V1))); - assert_eq!(m.get(&K3), Some(&Text::new(V3))); + assert_eq!(m.get(&K1).as_deref(), Some(V1)); + assert_eq!(m.get(&K3).as_deref(), Some(V3)); }); } @@ -154,7 +153,7 @@ fn write_to_buffer_no_data() { fn write_to_buffer_one_update() { let lane = MapLane::new(ID, init()); - lane.update(K2, Text::new("altered")); + lane.update(K2, "altered".to_owned()); let mut buffer = BytesMut::new(); @@ -238,11 +237,11 @@ fn write_to_buffer_clear() { #[derive(Debug)] struct Operations { - events: Vec>, - sync: HashMap>>, + events: Vec>, + sync: HashMap>>, } -fn consume_events(lane: &MapLane) -> Operations { +fn consume_events(lane: &MapLane) -> Operations { let mut events = vec![]; let mut sync_pending = HashMap::new(); let mut sync = HashMap::new(); @@ -289,14 +288,14 @@ fn consume_events(lane: &MapLane) -> Operations { Operations { events, sync } } -fn interpret(op: MapOperation) -> MapOperation { +fn interpret(op: MapOperation) -> MapOperation { match op { MapOperation::Update { key, value } => { let key_str = std::str::from_utf8(key.as_ref()).expect("Bad key bytes."); let val_str = std::str::from_utf8(value.as_ref()).expect("Bad value bytes."); let key = parse_recognize::(Span::new(key_str), false).expect("Bad key recon."); let value = - parse_recognize::(Span::new(val_str), false).expect("Bad value recon."); + parse_recognize::(Span::new(val_str), false).expect("Bad value recon."); MapOperation::Update { key, value } } MapOperation::Remove { key } => { @@ -312,9 +311,9 @@ fn interpret(op: MapOperation) -> MapOperation { fn write_multiple_events_to_buffer() { let lane = MapLane::new(ID, init()); - lane.update(ABSENT, Text::new("added")); + lane.update(ABSENT, "added".to_owned()); lane.remove(&K1); - lane.update(K3, Text::new("altered")); + lane.update(K3, "altered".to_owned()); let Operations { events, sync } = consume_events(&lane); @@ -323,12 +322,12 @@ fn write_multiple_events_to_buffer() { let expected = vec![ MapOperation::Update { key: ABSENT, - value: Text::new("added"), + value: "added".to_owned(), }, MapOperation::Remove { key: K1 }, MapOperation::Update { key: K3, - value: Text::new("altered"), + value: "altered".to_owned(), }, ]; assert_eq!(events, expected); @@ -338,9 +337,9 @@ fn write_multiple_events_to_buffer() { fn updates_to_one_key_overwrite() { let lane = MapLane::new(ID, init()); - lane.update(ABSENT, Text::new("added")); - lane.update(K3, Text::new("altered")); - lane.update(ABSENT, Text::new("changed")); + lane.update(ABSENT, "added".to_owned()); + lane.update(K3, "altered".to_string()); + lane.update(ABSENT, "changed".to_owned()); let Operations { events, sync } = consume_events(&lane); @@ -349,11 +348,11 @@ fn updates_to_one_key_overwrite() { let expected = vec![ MapOperation::Update { key: ABSENT, - value: Text::new("changed"), + value: "changed".to_owned(), }, MapOperation::Update { key: K3, - value: Text::new("altered"), + value: "altered".to_owned(), }, ]; assert_eq!(events, expected); @@ -363,9 +362,9 @@ fn updates_to_one_key_overwrite() { fn clear_resets_event_queue() { let lane = MapLane::new(ID, init()); - lane.update(ABSENT, Text::new("added")); + lane.update(ABSENT, "added".to_owned()); lane.remove(&K1); - lane.update(K3, Text::new("altered")); + lane.update(K3, "altered".to_owned()); lane.clear(); let Operations { events, sync } = consume_events(&lane); @@ -379,7 +378,7 @@ fn clear_resets_event_queue() { const SYNC_ID1: Uuid = Uuid::from_u128(8578393934); const SYNC_ID2: Uuid = Uuid::from_u128(2847474); -fn to_updates(sync_messages: &Vec>) -> HashMap { +fn to_updates(sync_messages: &[MapOperation]) -> HashMap { let mut map = HashMap::new(); for op in sync_messages { match op { @@ -407,7 +406,7 @@ fn sync_lane_state() { let expected: HashMap<_, _> = [(K1, V1), (K2, V2), (K3, V3)] .into_iter() - .map(|(k, v)| (k, Text::new(v))) + .map(|(k, v)| (k, v.to_owned())) .collect(); assert_eq!(sync_map, expected); } @@ -428,7 +427,7 @@ fn sync_twice_lane_state() { let expected: HashMap<_, _> = [(K1, V1), (K2, V2), (K3, V3)] .into_iter() - .map(|(k, v)| (k, Text::new(v))) + .map(|(k, v)| (k, v.to_owned())) .collect(); assert_eq!(sync_map1, expected); assert_eq!(sync_map2, expected); @@ -439,13 +438,13 @@ fn sync_lane_state_and_event() { let lane = MapLane::new(ID, init()); lane.sync(SYNC_ID1); - lane.update(ABSENT, Text::new("added")); + lane.update(ABSENT, "added".to_owned()); let Operations { events, sync } = consume_events(&lane); let expected_events = vec![MapOperation::Update { key: ABSENT, - value: Text::new("added"), + value: "added".to_owned(), }]; assert_eq!(events, expected_events); @@ -455,7 +454,7 @@ fn sync_lane_state_and_event() { let expected_sync: HashMap<_, _> = [(K1, V1), (K2, V2), (K3, V3)] .into_iter() - .map(|(k, v)| (k, Text::new(v))) + .map(|(k, v)| (k, v.to_owned())) .collect(); assert_eq!(sync_map, expected_sync); } @@ -475,7 +474,7 @@ fn make_meta<'a>( } struct TestAgent { - lane: MapLane, + lane: MapLane, } const LANE_ID: u64 = 9; @@ -492,7 +491,7 @@ impl TestAgent { fn with_init() -> Self { let init: HashMap<_, _> = [(K1, V1), (K2, V2), (K3, V3)] .into_iter() - .map(|(k, v)| (k, Text::new(v))) + .map(|(k, v)| (k, v.to_owned())) .collect(); TestAgent { @@ -502,7 +501,7 @@ impl TestAgent { } impl TestAgent { - pub const LANE: fn(&TestAgent) -> &MapLane = |agent| &agent.lane; + pub const LANE: fn(&TestAgent) -> &MapLane = |agent| &agent.lane; } fn check_result( @@ -547,7 +546,7 @@ fn map_lane_update_event_handler() { let meta = make_meta(&uri, &route_params); let agent = TestAgent::default(); - let mut handler = MapLaneUpdate::new(TestAgent::LANE, K1, Text::new(V1)); + let mut handler = MapLaneUpdate::new(TestAgent::LANE, K1, V1.to_owned()); let result = handler.step( &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), @@ -558,7 +557,7 @@ fn map_lane_update_event_handler() { agent.lane.get_map(|map| { assert_eq!(map.len(), 1); - assert_eq!(map.get(&K1), Some(&Text::new(V1))); + assert_eq!(map.get(&K1).as_deref(), Some(V1)); }); let result = handler.step( @@ -590,8 +589,8 @@ fn map_lane_remove_event_handler() { agent.lane.get_map(|map| { assert_eq!(map.len(), 2); - assert_eq!(map.get(&K2), Some(&Text::new(V2))); - assert_eq!(map.get(&K3), Some(&Text::new(V3))); + assert_eq!(map.get(&K2).as_deref(), Some(V2)); + assert_eq!(map.get(&K3).as_deref(), Some(V3)); }); let result = handler.step( @@ -650,7 +649,7 @@ fn map_lane_get_event_handler() { meta, &agent, ); - check_result(result, false, false, Some(Some(Text::new(V1)))); + check_result(result, false, false, Some(Some(V1.to_owned()))); let mut handler = MapLaneGet::new(TestAgent::LANE, ABSENT); @@ -736,20 +735,20 @@ fn map_lane_sync_event_handler() { let expected: HashMap<_, _> = [(K1, V1), (K2, V2), (K3, V3)] .into_iter() - .map(|(k, v)| (k, Text::new(v))) + .map(|(k, v)| (k, v.to_owned())) .collect(); assert_eq!(sync_map, expected); } #[test] -fn map_lane_with_event_handler_update() { +fn map_lane_transform_entry_handler_update() { let uri = make_uri(); let route_params = HashMap::new(); let meta = make_meta(&uri, &route_params); let agent = TestAgent::with_init(); - let mut handler = MapLaneTransformEntry::new(TestAgent::LANE, K1, |maybe: Option<&Text>| { - maybe.map(|v| Text::from(v.as_str().to_uppercase())) + let mut handler = MapLaneTransformEntry::new(TestAgent::LANE, K1, |maybe: Option<&String>| { + maybe.map(|v| v.to_uppercase()) }); let result = handler.step( @@ -761,9 +760,9 @@ fn map_lane_with_event_handler_update() { agent.lane.get_map(|map| { assert_eq!(map.len(), 3); - assert_eq!(map.get(&K1), Some(&Text::from(V1.to_uppercase()))); - assert_eq!(map.get(&K2), Some(&Text::new(V2))); - assert_eq!(map.get(&K3), Some(&Text::new(V3))); + assert_eq!(map.get(&K1), Some(&V1.to_uppercase())); + assert_eq!(map.get(&K2).as_deref(), Some(V2)); + assert_eq!(map.get(&K3).as_deref(), Some(V3)); }); let result = handler.step( @@ -777,17 +776,17 @@ fn map_lane_with_event_handler_update() { )); let event = agent.lane.read_with_prev(|event, _| event); - assert_eq!(event, Some(MapLaneEvent::Update(K1, Some(Text::new(V1))))); + assert_eq!(event, Some(MapLaneEvent::Update(K1, Some(V1.to_owned())))); } #[test] -fn map_lane_with_event_handler_remove() { +fn map_lane_transform_entry_handler_remove() { let uri = make_uri(); let route_params = HashMap::new(); let meta = make_meta(&uri, &route_params); let agent = TestAgent::with_init(); - let mut handler = MapLaneTransformEntry::new(TestAgent::LANE, K1, |_: Option<&Text>| None); + let mut handler = MapLaneTransformEntry::new(TestAgent::LANE, K1, |_: Option<&String>| None); let result = handler.step( &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), @@ -798,8 +797,8 @@ fn map_lane_with_event_handler_remove() { agent.lane.get_map(|map| { assert_eq!(map.len(), 2); - assert_eq!(map.get(&K2), Some(&Text::new(V2))); - assert_eq!(map.get(&K3), Some(&Text::new(V3))); + assert_eq!(map.get(&K2).as_deref(), Some(V2)); + assert_eq!(map.get(&K3).as_deref(), Some(V3)); }); let result = handler.step( @@ -813,5 +812,5 @@ fn map_lane_with_event_handler_remove() { )); let event = agent.lane.read_with_prev(|event, _| event); - assert_eq!(event, Some(MapLaneEvent::Remove(K1, Text::new(V1)))); + assert_eq!(event, Some(MapLaneEvent::Remove(K1, V1.to_owned()))); } From 1ccd772e6299b2ab19daf69a293a99587f73e441 Mon Sep 17 00:00:00 2001 From: Greg Holland <30577851+horned-sphere@users.noreply.github.com> Date: Wed, 24 Apr 2024 14:18:24 +0100 Subject: [PATCH 04/27] Tests for with_value combinators. --- .../src/agent_lifecycle/utility/mod.rs | 5 +- server/swimos_agent/src/item.rs | 17 +---- server/swimos_agent/src/lanes/map/tests.rs | 34 +++++----- server/swimos_agent/src/lanes/value/mod.rs | 66 ++----------------- server/swimos_agent/src/lanes/value/tests.rs | 50 ++++++++++++-- server/swimos_agent/src/stores/value/mod.rs | 66 ++----------------- server/swimos_agent/src/stores/value/tests.rs | 49 ++++++++++++-- 7 files changed, 125 insertions(+), 162 deletions(-) diff --git a/server/swimos_agent/src/agent_lifecycle/utility/mod.rs b/server/swimos_agent/src/agent_lifecycle/utility/mod.rs index 942c114f3..fdff08c6a 100644 --- a/server/swimos_agent/src/agent_lifecycle/utility/mod.rs +++ b/server/swimos_agent/src/agent_lifecycle/utility/mod.rs @@ -192,11 +192,12 @@ impl HandlerContext { ) -> impl HandlerAction + Send + 'a where Agent: 'static, - Item: MutableValueLikeItem + 'static, + Item: ValueLikeItem + MutableValueLikeItem + 'static, T: 'static, F: FnOnce(&T) -> T + Send + 'a, { - Item::transform_handler::(projection, f) + Item::with_value_handler::(projection, f) + .and_then(move |v| Item::set_handler(projection, v)) } pub fn with_value<'a, Item, T, F, B, U>( diff --git a/server/swimos_agent/src/item.rs b/server/swimos_agent/src/item.rs index b3d4be781..01797b2e0 100644 --- a/server/swimos_agent/src/item.rs +++ b/server/swimos_agent/src/item.rs @@ -119,7 +119,7 @@ pub trait ValueLikeItem { Self: 'static, C: 'a, T: Borrow, - B: 'static, + B: ?Sized + 'static, F: FnOnce(&B) -> U + Send + 'a; fn get_handler(projection: fn(&C) -> &Self) -> Self::GetHandler; @@ -131,7 +131,7 @@ pub trait ValueLikeItem { where C: 'a, T: Borrow, - B: 'static, + B: ?Sized + 'static, F: FnOnce(&B) -> U + Send + 'a; } @@ -140,19 +140,6 @@ pub trait MutableValueLikeItem { where C: 'static; - type TransformValueHandler<'a, C, F>: EventHandler + Send + 'a - where - Self: 'static, - C: 'a, - F: FnOnce(&T) -> T + Send + 'a; - fn set_handler(projection: fn(&C) -> &Self, value: T) -> Self::SetHandler; - fn transform_handler<'a, Item, C, F>( - projection: fn(&C) -> &Self, - f: F, - ) -> Self::TransformValueHandler<'a, C, F> - where - C: 'a, - F: FnOnce(&T) -> T + Send + 'a; } diff --git a/server/swimos_agent/src/lanes/map/tests.rs b/server/swimos_agent/src/lanes/map/tests.rs index d554a140d..9980220f2 100644 --- a/server/swimos_agent/src/lanes/map/tests.rs +++ b/server/swimos_agent/src/lanes/map/tests.rs @@ -99,19 +99,19 @@ fn update_map_lane() { lane.get_map(|m| { assert_eq!(m.len(), 3); - assert_eq!(m.get(&K1).as_deref(), Some(V1)); - assert_eq!(m.get(&K2).as_deref(), Some("altered")); - assert_eq!(m.get(&K3).as_deref(), Some(V3)); + assert_eq!(m.get(&K1).map(String::as_str), Some(V1)); + assert_eq!(m.get(&K2).map(String::as_str), Some("altered")); + assert_eq!(m.get(&K3).map(String::as_str), Some(V3)); }); lane.update(ABSENT, "added".to_owned()); lane.get_map(|m| { assert_eq!(m.len(), 4); - assert_eq!(m.get(&K1).as_deref(), Some(V1)); - assert_eq!(m.get(&K2).as_deref(), Some("altered")); - assert_eq!(m.get(&K3).as_deref(), Some(V3)); - assert_eq!(m.get(&ABSENT).as_deref(), Some("added")); + assert_eq!(m.get(&K1).map(String::as_str), Some(V1)); + assert_eq!(m.get(&K2).map(String::as_str), Some("altered")); + assert_eq!(m.get(&K3).map(String::as_str), Some(V3)); + assert_eq!(m.get(&ABSENT).map(String::as_str), Some("added")); }); } @@ -123,8 +123,8 @@ fn remove_from_map_lane() { lane.get_map(|m| { assert_eq!(m.len(), 2); - assert_eq!(m.get(&K1).as_deref(), Some(V1)); - assert_eq!(m.get(&K3).as_deref(), Some(V3)); + assert_eq!(m.get(&K1).map(String::as_str), Some(V1)); + assert_eq!(m.get(&K3).map(String::as_str), Some(V3)); }); } @@ -288,7 +288,7 @@ fn consume_events(lane: &MapLane) -> Operations { Operations { events, sync } } -fn interpret(op: MapOperation) -> MapOperation { +fn interpret(op: MapOperation) -> MapOperation { match op { MapOperation::Update { key, value } => { let key_str = std::str::from_utf8(key.as_ref()).expect("Bad key bytes."); @@ -557,7 +557,7 @@ fn map_lane_update_event_handler() { agent.lane.get_map(|map| { assert_eq!(map.len(), 1); - assert_eq!(map.get(&K1).as_deref(), Some(V1)); + assert_eq!(map.get(&K1).map(String::as_str), Some(V1)); }); let result = handler.step( @@ -589,8 +589,8 @@ fn map_lane_remove_event_handler() { agent.lane.get_map(|map| { assert_eq!(map.len(), 2); - assert_eq!(map.get(&K2).as_deref(), Some(V2)); - assert_eq!(map.get(&K3).as_deref(), Some(V3)); + assert_eq!(map.get(&K2).map(String::as_str), Some(V2)); + assert_eq!(map.get(&K3).map(String::as_str), Some(V3)); }); let result = handler.step( @@ -761,8 +761,8 @@ fn map_lane_transform_entry_handler_update() { agent.lane.get_map(|map| { assert_eq!(map.len(), 3); assert_eq!(map.get(&K1), Some(&V1.to_uppercase())); - assert_eq!(map.get(&K2).as_deref(), Some(V2)); - assert_eq!(map.get(&K3).as_deref(), Some(V3)); + assert_eq!(map.get(&K2).map(String::as_str), Some(V2)); + assert_eq!(map.get(&K3).map(String::as_str), Some(V3)); }); let result = handler.step( @@ -797,8 +797,8 @@ fn map_lane_transform_entry_handler_remove() { agent.lane.get_map(|map| { assert_eq!(map.len(), 2); - assert_eq!(map.get(&K2).as_deref(), Some(V2)); - assert_eq!(map.get(&K3).as_deref(), Some(V3)); + assert_eq!(map.get(&K2).map(String::as_str), Some(V2)); + assert_eq!(map.get(&K3).map(String::as_str), Some(V3)); }); let result = handler.step( diff --git a/server/swimos_agent/src/lanes/value/mod.rs b/server/swimos_agent/src/lanes/value/mod.rs index b0977f7e3..9512f7264 100644 --- a/server/swimos_agent/src/lanes/value/mod.rs +++ b/server/swimos_agent/src/lanes/value/mod.rs @@ -88,6 +88,7 @@ impl ValueLane { pub(crate) fn with(&self, f: F) -> U where + B: ?Sized, T: Borrow, F: FnOnce(&B) -> U, { @@ -273,13 +274,13 @@ impl HandlerAction for ValueLaneSync { } } -pub struct ValueLaneWithValue { +pub struct ValueLaneWithValue { projection: for<'a> fn(&'a C) -> &'a ValueLane, f: Option, _type: PhantomData, } -impl ValueLaneWithValue { +impl ValueLaneWithValue { pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueLane, f: F) -> Self { @@ -289,6 +290,7 @@ impl ValueLaneWithValue { impl HandlerAction for ValueLaneWithValue where + B: ?Sized, T: Borrow, F: FnOnce(&B) -> U, { @@ -343,7 +345,7 @@ where Self: 'static, C: 'a, T: Borrow, - B: 'static, + B: ?Sized + 'static, F: FnOnce(&B) -> U + Send + 'a; fn get_handler(projection: fn(&C) -> &Self) -> Self::GetHandler { @@ -357,7 +359,7 @@ where where C: 'a, T: Borrow, - B: 'static, + B: ?Sized + 'static, F: FnOnce(&B) -> U + Send + 'a, { ValueLaneWithValue::new(projection, f) @@ -376,60 +378,4 @@ where ValueLaneSet::new(projection, value) } - type TransformValueHandler<'a, C, F> = ValueLaneTransformValue - where - Self: 'static, - C: 'a, - F: FnOnce(&T) -> T + Send + 'a; - - fn transform_handler<'a, Item, C, F>( - projection: fn(&C) -> &Self, - f: F, - ) -> Self::TransformValueHandler<'a, C, F> - where - C: 'a, - F: FnOnce(&T) -> T + Send + 'a, - { - ValueLaneTransformValue::new(projection, f) - } -} - -/// An [`EventHandler`] that will transform the value of a value lane. -pub struct ValueLaneTransformValue { - projection: for<'a> fn(&'a C) -> &'a ValueLane, - f: Option, -} - -impl ValueLaneTransformValue { - pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueLane, f: F) -> Self { - ValueLaneTransformValue { - projection, - f: Some(f), - } - } -} - -impl HandlerAction for ValueLaneTransformValue -where - F: FnOnce(&T) -> T, -{ - type Completion = (); - - fn step( - &mut self, - _action_context: &mut ActionContext, - _meta: AgentMetadata, - context: &C, - ) -> StepResult { - if let Some(f) = self.f.take() { - let lane = (self.projection)(context); - lane.replace(f); - StepResult::Complete { - modified_item: Some(Modification::of(lane.id())), - result: (), - } - } else { - StepResult::after_done() - } - } } diff --git a/server/swimos_agent/src/lanes/value/tests.rs b/server/swimos_agent/src/lanes/value/tests.rs index 7a9a7509d..e23f54714 100644 --- a/server/swimos_agent/src/lanes/value/tests.rs +++ b/server/swimos_agent/src/lanes/value/tests.rs @@ -30,7 +30,7 @@ use crate::{ }, item::ValueItem, lanes::{ - value::{ValueLaneGet, ValueLaneSync}, + value::{ValueLaneGet, ValueLaneSync, ValueLaneWithValue}, LaneItem, }, meta::AgentMetadata, @@ -277,23 +277,28 @@ fn make_meta<'a>( struct TestAgent { lane: ValueLane, + str_lane: ValueLane, } const LANE_ID: u64 = 9; +const STR_LANE_ID: u64 = 73; impl Default for TestAgent { fn default() -> Self { Self { lane: ValueLane::new(LANE_ID, 0), + str_lane: ValueLane::new(STR_LANE_ID, "hello".to_string()) } } } impl TestAgent { const LANE: fn(&TestAgent) -> &ValueLane = |agent| &agent.lane; + const STR_LANE: fn(&TestAgent) -> &ValueLane = |agent| &agent.str_lane; } -fn check_result( +fn check_result_for( + lane_id: u64, result: StepResult, written: bool, trigger_handler: bool, @@ -301,9 +306,9 @@ fn check_result( ) { let expected_mod = if written { if trigger_handler { - Some(Modification::of(LANE_ID)) + Some(Modification::of(lane_id)) } else { - Some(Modification::no_trigger(LANE_ID)) + Some(Modification::no_trigger(lane_id)) } } else { None @@ -328,6 +333,15 @@ fn check_result( } } +fn check_result( + result: StepResult, + written: bool, + trigger_handler: bool, + complete: Option, +) { + check_result_for(LANE_ID, result, written, trigger_handler, complete) +} + #[test] fn value_lane_set_event_handler() { let uri = make_uri(); @@ -438,3 +452,31 @@ fn value_lane_sync_event_handler() { } } } + +#[test] +fn value_lane_with_value_event_handler() { + let uri = make_uri(); + let route_params = HashMap::new(); + let meta = make_meta(&uri, &route_params); + let agent = TestAgent::default(); + + let mut handler = ValueLaneWithValue::new(TestAgent::STR_LANE, |s: &str| s.len()); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + check_result_for(STR_LANE_ID, result, false, false, Some(5)); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + assert!(matches!( + result, + StepResult::Fail(EventHandlerError::SteppedAfterComplete) + )); + +} diff --git a/server/swimos_agent/src/stores/value/mod.rs b/server/swimos_agent/src/stores/value/mod.rs index abfc65e36..8a38e7460 100644 --- a/server/swimos_agent/src/stores/value/mod.rs +++ b/server/swimos_agent/src/stores/value/mod.rs @@ -136,6 +136,7 @@ impl ValueStore { pub(crate) fn with(&self, f: F) -> U where + B: ?Sized, T: Borrow, F: FnOnce(&B) -> U, { @@ -271,53 +272,13 @@ impl HandlerAction for ValueStoreSet { } } -/// An [`EventHandler`] that will transform the value of a value store. -pub struct ValueStoreTransformValue { - projection: for<'a> fn(&'a C) -> &'a ValueStore, - f: Option, -} - -impl ValueStoreTransformValue { - pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueStore, f: F) -> Self { - ValueStoreTransformValue { - projection, - f: Some(f), - } - } -} - -impl HandlerAction for ValueStoreTransformValue -where - F: FnOnce(&T) -> T, -{ - type Completion = (); - - fn step( - &mut self, - _action_context: &mut ActionContext, - _meta: AgentMetadata, - context: &C, - ) -> StepResult { - if let Some(f) = self.f.take() { - let store = (self.projection)(context); - store.replace(f); - StepResult::Complete { - modified_item: Some(Modification::of(store.id())), - result: (), - } - } else { - StepResult::after_done() - } - } -} - -pub struct ValueStoreWithValue { +pub struct ValueStoreWithValue { projection: for<'a> fn(&'a C) -> &'a ValueStore, f: Option, _type: PhantomData, } -impl ValueStoreWithValue { +impl ValueStoreWithValue { pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueStore, f: F) -> Self { @@ -328,6 +289,7 @@ impl ValueStoreWithValue { impl HandlerAction for ValueStoreWithValue where T: Borrow, + B: ?Sized, F: FnOnce(&B) -> U, { type Completion = U; @@ -360,7 +322,7 @@ where Self: 'static, C: 'a, T: Borrow, - B: 'static, + B: ?Sized + 'static, F: FnOnce(&B) -> U + Send + 'a; fn get_handler(projection: fn(&C) -> &Self) -> Self::GetHandler { @@ -374,7 +336,7 @@ where where C: 'a, T: Borrow, - B: 'static, + B: ?Sized + 'static, F: FnOnce(&B) -> U + Send + 'a, { ValueStoreWithValue::new(projection, f) @@ -389,24 +351,8 @@ where where C: 'static; - type TransformValueHandler<'a, C, F> = ValueStoreTransformValue - where - Self: 'static, - C: 'a, - F: FnOnce(&T) -> T + Send + 'a; - fn set_handler(projection: fn(&C) -> &Self, value: T) -> Self::SetHandler { ValueStoreSet::new(projection, value) } - fn transform_handler<'a, Item, C, F>( - projection: fn(&C) -> &Self, - f: F, - ) -> Self::TransformValueHandler<'a, C, F> - where - C: 'a, - F: FnOnce(&T) -> T + Send + 'a, - { - ValueStoreTransformValue::new(projection, f) - } } diff --git a/server/swimos_agent/src/stores/value/tests.rs b/server/swimos_agent/src/stores/value/tests.rs index cba140b56..594b1fc09 100644 --- a/server/swimos_agent/src/stores/value/tests.rs +++ b/server/swimos_agent/src/stores/value/tests.rs @@ -26,7 +26,7 @@ use crate::{ event_handler::{EventHandlerError, HandlerAction, Modification, StepResult}, meta::AgentMetadata, stores::{ - value::{ValueStore, ValueStoreGet, ValueStoreSet}, + value::{ValueStore, ValueStoreGet, ValueStoreSet, ValueStoreWithValue}, StoreItem, }, test_context::dummy_context, @@ -116,23 +116,28 @@ fn make_meta<'a>( struct TestAgent { store: ValueStore, + str_store: ValueStore, } const STORE_ID: u64 = 9; +const STR_STORE_ID: u64 = 3; impl Default for TestAgent { fn default() -> Self { Self { store: ValueStore::new(STORE_ID, 0), + str_store: ValueStore::new(STR_STORE_ID, "world".to_owned()) } } } impl TestAgent { const STORE: fn(&TestAgent) -> &ValueStore = |agent| &agent.store; + const STR_STORE: fn(&TestAgent) -> &ValueStore = |agent| &agent.str_store; } -fn check_result( +fn check_result_for( + store_id: u64, result: StepResult, written: bool, trigger_handler: bool, @@ -140,9 +145,9 @@ fn check_result( ) { let expected_mod = if written { if trigger_handler { - Some(Modification::of(STORE_ID)) + Some(Modification::of(store_id)) } else { - Some(Modification::no_trigger(STORE_ID)) + Some(Modification::no_trigger(store_id)) } } else { None @@ -167,6 +172,15 @@ fn check_result( } } +fn check_result( + result: StepResult, + written: bool, + trigger_handler: bool, + complete: Option, +) { + check_result_for(STORE_ID, result, written, trigger_handler, complete) +} + #[test] fn value_store_set_event_handler() { let uri = make_uri(); @@ -223,3 +237,30 @@ fn value_store_get_event_handler() { StepResult::Fail(EventHandlerError::SteppedAfterComplete) )); } + +#[test] +fn value_store_with_value_event_handler() { + let uri = make_uri(); + let route_params = HashMap::new(); + let meta = make_meta(&uri, &route_params); + let agent = TestAgent::default(); + + let mut handler = ValueStoreWithValue::new(TestAgent::STR_STORE, |s: &str| s.len()); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + check_result(result, false, false, Some(5)); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + assert!(matches!( + result, + StepResult::Fail(EventHandlerError::SteppedAfterComplete) + )); +} From 34b887bb8c2a1582b22c23d3ead4d765a81202de Mon Sep 17 00:00:00 2001 From: Greg Holland <30577851+horned-sphere@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:05:57 +0100 Subject: [PATCH 05/27] Allowed with_entry combinators to borrow values properly. --- server/swimos_agent/src/item.rs | 14 +++++---- server/swimos_agent/src/lanes/map/mod.rs | 33 ++++++++++++++------- server/swimos_agent/src/map_storage/mod.rs | 8 +++-- server/swimos_agent/src/stores/map/mod.rs | 34 +++++++++++++++------- 4 files changed, 59 insertions(+), 30 deletions(-) diff --git a/server/swimos_agent/src/item.rs b/server/swimos_agent/src/item.rs index 01797b2e0..beafa0bdc 100644 --- a/server/swimos_agent/src/item.rs +++ b/server/swimos_agent/src/item.rs @@ -56,21 +56,25 @@ pub trait MapLikeItem { } pub trait InspectableMapLikeItem { - type WithEntryHandler<'a, C, F, U>: HandlerAction + Send + 'a + type WithEntryHandler<'a, C, F, B, U>: HandlerAction + Send + 'a where Self: 'static, C: 'a, - F: FnOnce(Option<&V>) -> U + Send + 'a; + B: ?Sized + 'static, + V: Borrow, + F: FnOnce(Option<&B>) -> U + Send + 'a; - fn with_entry_handler<'a, C, F, U>( + fn with_entry_handler<'a, C, F, B, U>( projection: fn(&C) -> &Self, key: K, f: F, - ) -> Self::WithEntryHandler<'a, C, F, U> + ) -> Self::WithEntryHandler<'a, C, F, B, U> where Self: 'static, C: 'a, - F: FnOnce(Option<&V>) -> U + Send + 'a; + B: ?Sized + 'static, + V: Borrow, + F: FnOnce(Option<&B>) -> U + Send + 'a; } pub trait MutableMapLikeItem { diff --git a/server/swimos_agent/src/lanes/map/mod.rs b/server/swimos_agent/src/lanes/map/mod.rs index 2e9589ca1..a31cc756e 100644 --- a/server/swimos_agent/src/lanes/map/mod.rs +++ b/server/swimos_agent/src/lanes/map/mod.rs @@ -151,9 +151,11 @@ where K: Eq + Hash, { - pub fn with_entry(&self, key: K, f: F) -> U + pub fn with_entry(&self, key: K, f: F) -> U where - F: FnOnce(Option<&V>) -> U, + B: ?Sized, + V: Borrow, + F: FnOnce(Option<&B>) -> U, { self.inner.borrow().with_entry(key, f) } @@ -394,24 +396,28 @@ where } } -pub struct MapLaneWithEntry { +pub struct MapLaneWithEntry { projection: for<'a> fn(&'a C) -> &'a MapLane, key_and_f: Option<(K, F)>, + _type: PhantomData, } -impl MapLaneWithEntry { +impl MapLaneWithEntry { pub fn new(projection: for<'a> fn(&'a C) -> &'a MapLane, key: K, f: F) -> Self { MapLaneWithEntry { projection, key_and_f: Some((key, f)), + _type: PhantomData, } } } -impl HandlerAction for MapLaneWithEntry +impl HandlerAction for MapLaneWithEntry where K: Eq + Hash, - F: FnOnce(Option<&V>) -> U, + B: ?Sized, + V: Borrow, + F: FnOnce(Option<&B>) -> U, { type Completion = U; @@ -424,6 +430,7 @@ where let MapLaneWithEntry { projection, key_and_f, + .. } = self; if let Some((key, f)) = key_and_f.take() { let lane = projection(context); @@ -656,21 +663,25 @@ where K: Eq + Hash + Send + 'static, V: 'static, { - type WithEntryHandler<'a, C, F, U> = MapLaneWithEntry + type WithEntryHandler<'a, C, F, B, U> = MapLaneWithEntry where Self: 'static, C: 'a, - F: FnOnce(Option<&V>) -> U + Send + 'a; + B: ?Sized +'static, + V: Borrow, + F: FnOnce(Option<&B>) -> U + Send + 'a; - fn with_entry_handler<'a, C, F, U>( + fn with_entry_handler<'a, C, F, B, U>( projection: fn(&C) -> &Self, key: K, f: F, - ) -> Self::WithEntryHandler<'a, C, F, U> + ) -> Self::WithEntryHandler<'a, C, F, B, U> where Self: 'static, C: 'a, - F: FnOnce(Option<&V>) -> U + Send + 'a { + B: ?Sized +'static, + V: Borrow, + F: FnOnce(Option<&B>) -> U + Send + 'a { MapLaneWithEntry::new(projection, key, f) } } diff --git a/server/swimos_agent/src/map_storage/mod.rs b/server/swimos_agent/src/map_storage/mod.rs index 8f97f6198..7b24a8f02 100644 --- a/server/swimos_agent/src/map_storage/mod.rs +++ b/server/swimos_agent/src/map_storage/mod.rs @@ -178,14 +178,16 @@ impl MapStoreInner where K: Eq + Hash, { - pub fn with_entry(&self, key: K, f: F) -> U + pub fn with_entry(&self, key: K, f: F) -> U where - F: FnOnce(Option<&V>) -> U, + B: ?Sized, + V: Borrow, + F: FnOnce(Option<&B>) -> U, { let MapStoreInner { content, .. } = self; - f(content.get(&key)) + f(content.get(&key).map(Borrow::borrow)) } } diff --git a/server/swimos_agent/src/stores/map/mod.rs b/server/swimos_agent/src/stores/map/mod.rs index 8ea5d8687..e5edc91c8 100644 --- a/server/swimos_agent/src/stores/map/mod.rs +++ b/server/swimos_agent/src/stores/map/mod.rs @@ -14,6 +14,7 @@ use std::borrow::Borrow; use std::hash::Hash; +use std::marker::PhantomData; use std::{cell::RefCell, collections::HashMap}; use bytes::BytesMut; @@ -133,9 +134,11 @@ where K: Eq + Hash, { - pub fn with_entry(&self, key: K, f: F) -> U + pub fn with_entry(&self, key: K, f: F) -> U where - F: FnOnce(Option<&V>) -> U, + B: ?Sized, + V: Borrow, + F: FnOnce(Option<&B>) -> U, { self.inner.borrow().with_entry(key, f) } @@ -424,24 +427,28 @@ where } } -pub struct MapStoreWithEntry { +pub struct MapStoreWithEntry { projection: for<'a> fn(&'a C) -> &'a MapStore, key_and_f: Option<(K, F)>, + _type: PhantomData, } -impl MapStoreWithEntry { +impl MapStoreWithEntry { pub fn new(projection: for<'a> fn(&'a C) -> &'a MapStore, key: K, f: F) -> Self { MapStoreWithEntry { projection, key_and_f: Some((key, f)), + _type: PhantomData, } } } -impl HandlerAction for MapStoreWithEntry +impl HandlerAction for MapStoreWithEntry where K: Eq + Hash, - F: FnOnce(Option<&V>) -> U, + B: ?Sized, + V: Borrow, + F: FnOnce(Option<&B>) -> U, { type Completion = U; @@ -454,6 +461,7 @@ where let MapStoreWithEntry { projection, key_and_f, + .. } = self; if let Some((key, f)) = key_and_f.take() { let store = projection(context); @@ -492,21 +500,25 @@ where K: Eq + Hash + Send + 'static, V: 'static, { - type WithEntryHandler<'a, C, F, U> = MapStoreWithEntry + type WithEntryHandler<'a, C, F, B, U> = MapStoreWithEntry where Self: 'static, C: 'a, - F: FnOnce(Option<&V>) -> U + Send + 'a; + B: ?Sized +'static, + V: Borrow, + F: FnOnce(Option<&B>) -> U + Send + 'a; - fn with_entry_handler<'a, C, F, U>( + fn with_entry_handler<'a, C, F, B, U>( projection: fn(&C) -> &Self, key: K, f: F, - ) -> Self::WithEntryHandler<'a, C, F, U> + ) -> Self::WithEntryHandler<'a, C, F, B, U> where Self: 'static, C: 'a, - F: FnOnce(Option<&V>) -> U + Send + 'a { + B: ?Sized +'static, + V: Borrow, + F: FnOnce(Option<&B>) -> U + Send + 'a { MapStoreWithEntry::new(projection, key, f) } } From 5d59e84c0cb0ecf17c3eefc67dd448567ca245f6 Mon Sep 17 00:00:00 2001 From: Greg Holland <30577851+horned-sphere@users.noreply.github.com> Date: Wed, 24 Apr 2024 16:55:30 +0100 Subject: [PATCH 06/27] Tests for with entry combinators. --- server/swimos_agent/src/lanes/map/tests.rs | 36 ++++++++++++++++++++ server/swimos_agent/src/stores/map/tests.rs | 37 +++++++++++++++++++-- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/server/swimos_agent/src/lanes/map/tests.rs b/server/swimos_agent/src/lanes/map/tests.rs index 9980220f2..bb22515bb 100644 --- a/server/swimos_agent/src/lanes/map/tests.rs +++ b/server/swimos_agent/src/lanes/map/tests.rs @@ -45,6 +45,8 @@ use crate::{ test_context::dummy_context, }; +use super::MapLaneWithEntry; + const ID: u64 = 74; const K1: i32 = 5; @@ -814,3 +816,37 @@ fn map_lane_transform_entry_handler_remove() { let event = agent.lane.read_with_prev(|event, _| event); assert_eq!(event, Some(MapLaneEvent::Remove(K1, V1.to_owned()))); } + +#[test] +fn map_lane_with_entry_handler_absent() { + let uri = make_uri(); + let route_params = HashMap::new(); + let meta = make_meta(&uri, &route_params); + let agent = TestAgent::with_init(); + + let mut handler = MapLaneWithEntry::new(TestAgent::LANE, ABSENT, |maybe_v: Option<&str>| maybe_v.map(str::to_owned)); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + check_result(result, false, false, Some(None)); +} + +#[test] +fn map_lane_with_entry_handler_present() { + let uri = make_uri(); + let route_params = HashMap::new(); + let meta = make_meta(&uri, &route_params); + let agent = TestAgent::with_init(); + + let mut handler = MapLaneWithEntry::new(TestAgent::LANE, K1, |maybe_v: Option<&str>| maybe_v.map(str::to_owned)); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + check_result(result, false, false, Some(Some(V1.to_owned()))); +} \ No newline at end of file diff --git a/server/swimos_agent/src/stores/map/tests.rs b/server/swimos_agent/src/stores/map/tests.rs index 78a39bf4c..707596778 100644 --- a/server/swimos_agent/src/stores/map/tests.rs +++ b/server/swimos_agent/src/stores/map/tests.rs @@ -36,8 +36,7 @@ use crate::{ meta::AgentMetadata, stores::{ map::{ - MapStoreClear, MapStoreGet, MapStoreGetMap, MapStoreRemove, MapStoreUpdate, - MapStoreTransformEntry, + MapStoreClear, MapStoreGet, MapStoreGetMap, MapStoreRemove, MapStoreTransformEntry, MapStoreUpdate, MapStoreWithEntry }, MapStore, StoreItem, }, @@ -644,3 +643,37 @@ fn map_lane_with_event_handler_remove() { let event = agent.store.read_with_prev(|event, _| event); assert_eq!(event, Some(MapLaneEvent::Remove(K1, Text::new(V1)))); } + +#[test] +fn map_lane_with_entry_handler_absent() { + let uri = make_uri(); + let route_params = HashMap::new(); + let meta = make_meta(&uri, &route_params); + let agent = TestAgent::with_init(); + + let mut handler = MapStoreWithEntry::new(TestAgent::STORE, ABSENT, |maybe_v: Option<&str>| maybe_v.map(str::to_owned)); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + check_result(result, false, false, Some(None)); +} + +#[test] +fn map_lane_with_entry_handler_present() { + let uri = make_uri(); + let route_params = HashMap::new(); + let meta = make_meta(&uri, &route_params); + let agent = TestAgent::with_init(); + + let mut handler = MapStoreWithEntry::new(TestAgent::STORE, K1, |maybe_v: Option<&str>| maybe_v.map(str::to_owned)); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + check_result(result, false, false, Some(Some(V1.to_owned()))); +} From 9ac881e1b1729bbe5c2d3ebd8da3c33b6c36adec Mon Sep 17 00:00:00 2001 From: Greg Holland <30577851+horned-sphere@users.noreply.github.com> Date: Thu, 25 Apr 2024 14:37:23 +0100 Subject: [PATCH 07/27] Added with_entry combinator for JoinValueLane. --- .../src/agent_lifecycle/utility/mod.rs | 111 ++++++++++++------ .../swimos_agent/src/lanes/join/value/mod.rs | 78 +++++++++++- .../src/lanes/join/value/tests.rs | 48 +++++++- server/swimos_agent/src/lanes/map/mod.rs | 6 +- server/swimos_agent/src/map_storage/mod.rs | 28 ++--- server/swimos_agent/src/stores/map/mod.rs | 19 +-- 6 files changed, 222 insertions(+), 68 deletions(-) diff --git a/server/swimos_agent/src/agent_lifecycle/utility/mod.rs b/server/swimos_agent/src/agent_lifecycle/utility/mod.rs index fdff08c6a..3bc3fa94e 100644 --- a/server/swimos_agent/src/agent_lifecycle/utility/mod.rs +++ b/server/swimos_agent/src/agent_lifecycle/utility/mod.rs @@ -44,7 +44,7 @@ use crate::event_handler::{ }; use crate::event_handler::{GetAgentUri, HandlerAction, SideEffect}; use crate::item::{ - MapLikeItem, MutableMapLikeItem, MutableValueLikeItem, ValueLikeItem + InspectableMapLikeItem, MapLikeItem, MutableMapLikeItem, MutableValueLikeItem, ValueLikeItem }; use crate::lanes::command::{CommandLane, DoCommand}; use crate::lanes::demand::{Cue, DemandLane}; @@ -156,38 +156,43 @@ impl HandlerContext { /// Create an event handler that will get the value of a value lane store of the agent. /// /// #Arguments - /// * `lane` - Projection to the value lane. + /// * `item` - Projection to the value lane or store. pub fn get_value( &self, - lane: fn(&Agent) -> &Item, + item: fn(&Agent) -> &Item, ) -> impl HandlerAction + Send + 'static where Item: ValueLikeItem, T: Clone + Send + 'static, { - Item::get_handler::(lane) + Item::get_handler::(item) } - /// Create an event handler that will set a new value into value lane or store of the agent. + /// Create an event handler that will set a new value into a value lane or store of the agent. /// /// #Arguments - /// * `lane` - Projection to the value lane. + /// * `item` - Projection to the value lane or store. /// * `value` - The value to set. pub fn set_value( &self, - lane: fn(&Agent) -> &Item, + item: fn(&Agent) -> &Item, value: T, ) -> impl HandlerAction + Send + 'static where Item: MutableValueLikeItem, T: Send + 'static, { - Item::set_handler::(lane, value) + Item::set_handler::(item, value) } + /// Create an event handler that will transform the value of a value lane or store of the agent. + /// + /// #Arguments + /// * `item` - Projection to the value lane or store. + /// * `f` - A closure that produces a new value from a reference to the existing value. pub fn transform_value<'a, Item, T, F>( &self, - projection: fn(&Agent) -> &Item, + item: fn(&Agent) -> &Item, f: F, ) -> impl HandlerAction + Send + 'a where @@ -196,13 +201,19 @@ impl HandlerContext { T: 'static, F: FnOnce(&T) -> T + Send + 'a, { - Item::with_value_handler::(projection, f) - .and_then(move |v| Item::set_handler(projection, v)) + Item::with_value_handler::(item, f) + .and_then(move |v| Item::set_handler(item, v)) } + /// Create an event handler that will inspect the value of a value lane or store and generate a result from it. + /// This differs from using [`Self::get_value`] in that it does not require a clone to be made of the existing value. + /// + /// #Arguments + /// * `item` - Projection to the value lane or store. + /// * `f` - A closure that produces a value from a reference to the current value of the item. pub fn with_value<'a, Item, T, F, B, U>( &self, - projection: fn(&Agent) -> &Item, + item: fn(&Agent) -> &Item, f: F, ) -> impl HandlerAction + Send + 'a where @@ -212,18 +223,18 @@ impl HandlerContext { B: 'static, F: FnOnce(&B) -> U + Send + 'a, { - Item::with_value_handler::(projection, f) + Item::with_value_handler::(item, f) } /// Create an event handler that will update an entry in a map lane or store of the agent. /// /// #Arguments - /// * `lane` - Projection to the map lane. + /// * `item` - Projection to the map lane or store. /// * `key - The key to update. /// * `value` - The new value. pub fn update( &self, - lane: fn(&Agent) -> &Item, + item: fn(&Agent) -> &Item, key: K, value: V, ) -> impl HandlerAction + Send + 'static @@ -232,18 +243,46 @@ impl HandlerContext { K: Send + Clone + Eq + Hash + 'static, V: Send + 'static, { - Item::update_handler::(lane, key, value) + Item::update_handler::(item, key, value) } - /// Create an event handler that will transform the value in an entry of a map lane or store of the agent. + /// Create an event handler that will inspect an entry in the map and produce a new value from it. + /// This differs from using [`Self::get_entry`] in that it does not require that a clone be made of the existing value. /// /// #Arguments - /// * `lane` - Projection to the map lane. + /// * `item` - Projection to the map lane or store. /// * `key - The key to update. /// * `f` - A function to apple to the entry in the map. + pub fn with_entry<'a, Item, K, V, F, B, U>( + &self, + item: fn(&Agent) -> &Item, + key: K, + f: F + ) -> impl HandlerAction + Send + 'a + where + Agent: 'static, + Item: InspectableMapLikeItem + 'static, + K: Send + Clone + Eq + Hash + 'static, + V: Borrow + 'static, + B: ?Sized + 'static, + F: FnOnce(Option<&B>) -> U + Send + 'a, + { + Item::with_entry_handler::(item, key, f) + } + + + /// Create an event handler that will transform the value in an entry of a map lane or store of the agent. + /// If map contains an entry with that key, it will be updated (or removed) based on the result of the calling + /// the closure on it. If the map does not contain an entry with that key, the closure will be called with [`None`] + /// and an entry will be inserted if it returns a value. + /// + /// #Arguments + /// * `item` - Projection to the map lane. + /// * `key - The key to update. + /// * `f` - A closure to apply to the entry in the map to produce the replacement. pub fn transform_entry<'a, Item, K, V, F>( &self, - lane: fn(&Agent) -> &Item, + item: fn(&Agent) -> &Item, key: K, f: F, ) -> impl HandlerAction + Send + 'a @@ -254,17 +293,17 @@ impl HandlerContext { V: 'static, F: FnOnce(Option<&V>) -> Option + Send + 'a, { - Item::transform_entry_handler::(lane, key, f) + Item::transform_entry_handler::(item, key, f) } /// Create an event handler that will remove an entry from a map lane or store of the agent. /// /// #Arguments - /// * `lane` - Projection to the map lane. + /// * `item` - Projection to the map lane or store. /// * `key - The key to remove. pub fn remove( &self, - lane: fn(&Agent) -> &Item, + item: fn(&Agent) -> &Item, key: K, ) -> impl HandlerAction + Send + 'static where @@ -272,33 +311,33 @@ impl HandlerContext { K: Send + Clone + Eq + Hash + 'static, V: Send + 'static, { - Item::remove_handler::(lane, key) + Item::remove_handler::(item, key) } /// Create an event handler that will clear a map lane or store of the agent. /// /// #Arguments - /// * `lane` - Projection to the map lane. + /// * `item` - Projection to the map lane or store. pub fn clear( &self, - lane: fn(&Agent) -> &Item, + item: fn(&Agent) -> &Item, ) -> impl HandlerAction + Send + 'static where Item: MutableMapLikeItem, K: Send + Clone + Eq + Hash + 'static, V: Send + 'static, { - Item::clear_handler::(lane) + Item::clear_handler::(item) } /// Create an event handler that replaces the entire contents of a map lane or store. /// /// #Arguments - /// * `lane` - Projection to the map lane. + /// * `item` - Projection to the map lane or store. /// * `entries` - The new entries for the lane. pub fn replace_map( &self, - lane: fn(&Agent) -> &Item, + item: fn(&Agent) -> &Item, entries: I, ) -> impl HandlerAction + Send + 'static where @@ -311,19 +350,19 @@ impl HandlerContext { let context = *self; let insertions = entries .into_iter() - .map(move |(k, v)| context.update(lane, k, v)); - self.clear(lane).followed_by(Sequentially::new(insertions)) + .map(move |(k, v)| context.update(item, k, v)); + self.clear(item).followed_by(Sequentially::new(insertions)) } /// Create an event handler that will attempt to get an entry from a map-like item of the agent. /// This includes map lanes and stores and join lanes. /// /// #Arguments - /// * `lane` - Projection to the map lane. + /// * `item` - Projection to the map-like item. /// * `key - The key to fetch. pub fn get_entry( &self, - lane: fn(&Agent) -> &Item, + item: fn(&Agent) -> &Item, key: K, ) -> impl HandlerAction> + Send + 'static where @@ -331,24 +370,24 @@ impl HandlerContext { K: Send + Clone + Eq + Hash + 'static, V: Send + Clone + 'static, { - Item::get_handler::(lane, key) + Item::get_handler::(item, key) } /// Create an event handler that will attempt to get the entire contents of a map-like item of the /// agent. This includes map lanes and stores and join lanes. /// /// #Arguments - /// * `lane` - Projection to the map lane. + /// * `item` - Projection to the map-like item. pub fn get_map( &self, - lane: fn(&Agent) -> &Item, + item: fn(&Agent) -> &Item, ) -> impl HandlerAction> + Send + 'static where Item: MapLikeItem, K: Send + Clone + Eq + Hash + 'static, V: Send + Clone + 'static, { - Item::get_map_handler::(lane) + Item::get_map_handler::(item) } /// Create an event handler that will send a command to a command lane of the agent. diff --git a/server/swimos_agent/src/lanes/join/value/mod.rs b/server/swimos_agent/src/lanes/join/value/mod.rs index af524d655..285ff62ef 100644 --- a/server/swimos_agent/src/lanes/join/value/mod.rs +++ b/server/swimos_agent/src/lanes/join/value/mod.rs @@ -16,6 +16,7 @@ use std::any::{Any, TypeId}; use std::borrow::Borrow; use std::collections::hash_map::Entry; use std::hash::Hash; +use std::marker::PhantomData; use std::{cell::RefCell, collections::HashMap}; use bytes::BytesMut; @@ -28,7 +29,7 @@ use uuid::Uuid; use crate::agent_model::downlink::OpenEventDownlinkAction; use crate::config::SimpleDownlinkConfig; use crate::event_handler::{EventHandler, EventHandlerError, Modification}; -use crate::item::MapLikeItem; +use crate::item::{InspectableMapLikeItem, MapLikeItem}; use crate::{ agent_model::WriteResult, event_handler::{ActionContext, HandlerAction, StepResult}, @@ -427,6 +428,53 @@ impl JoinValueAddDownlink { } } + +pub struct JoinValueLaneWithEntry { + projection: for<'a> fn(&'a C) -> &'a JoinValueLane, + key: K, + f: Option, + _type: PhantomData, +} + +impl JoinValueLaneWithEntry { + + pub fn new(projection: for<'a> fn(&'a C) -> &'a JoinValueLane, + key: K, f: F) -> Self { + JoinValueLaneWithEntry { + projection, + key, + f: Some(f), + _type: PhantomData, + } + } +} + +impl<'a, C, K, V, F, B, U> HandlerAction for JoinValueLaneWithEntry +where + K: Eq + Hash + 'static, + C: 'a, + B: ?Sized + 'static, + V: Borrow, + F: FnOnce(Option<&B>) -> U + Send + 'a, +{ + type Completion = U; + + fn step( + &mut self, + _action_context: &mut ActionContext, + _meta: AgentMetadata, + context: &C, + ) -> StepResult { + if let Some(f) = self.f.take() { + let item = (self.projection)(context); + StepResult::done(item.inner.with_entry(&self.key, f)) + } else { + StepResult::after_done() + } + } +} + + impl MapLikeItem for JoinValueLane where K: Clone + Eq + Hash + Send + 'static, @@ -448,3 +496,31 @@ where JoinValueLaneGetMap::new(projection) } } + +impl InspectableMapLikeItem for JoinValueLane +where + K: Clone + Eq + Hash + Send + 'static, + V: Send + 'static, +{ + type WithEntryHandler<'a, C, F, B, U> = JoinValueLaneWithEntry + where + Self: 'static, + C: 'a, + B: ?Sized + 'static, + V: Borrow, + F: FnOnce(Option<&B>) -> U + Send + 'a; + + fn with_entry_handler<'a, C, F, B, U>( + projection: fn(&C) -> &Self, + key: K, + f: F, + ) -> Self::WithEntryHandler<'a, C, F, B, U> + where + Self: 'static, + C: 'a, + B: ?Sized + 'static, + V: Borrow, + F: FnOnce(Option<&B>) -> U + Send + 'a { + JoinValueLaneWithEntry::new(projection, key, f) + } +} \ No newline at end of file diff --git a/server/swimos_agent/src/lanes/join/value/tests.rs b/server/swimos_agent/src/lanes/join/value/tests.rs index 56f8b0667..127ed374b 100644 --- a/server/swimos_agent/src/lanes/join/value/tests.rs +++ b/server/swimos_agent/src/lanes/join/value/tests.rs @@ -36,7 +36,7 @@ use crate::{ join::test_util::{TestDlContextInner, TestDownlinkContext}, join_value::{ default_lifecycle::DefaultJoinValueLifecycle, AddDownlinkAction, JoinValueLaneGet, - JoinValueLaneGetMap, + JoinValueLaneGetMap, JoinValueLaneWithEntry, }, }, meta::AgentMetadata, @@ -188,6 +188,52 @@ fn join_value_lane_get_event_handler() { )); } +#[test] +fn join_value_lane_with_entry_event_handler() { + let uri = make_uri(); + let route_params = HashMap::new(); + let meta = make_meta(&uri, &route_params); + let agent = TestAgent::with_init(); + + let mut handler = JoinValueLaneWithEntry::new(TestAgent::LANE, K1, |v: Option<&str>| v.map(str::to_owned)); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + check_result(result, false, false, Some(Some(V1.to_string()))); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + assert!(matches!( + result, + StepResult::Fail(EventHandlerError::SteppedAfterComplete) + )); + + let mut handler = JoinValueLaneWithEntry::new(TestAgent::LANE, ABSENT, |v: Option<&str>| v.map(str::to_owned)); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + check_result(result, false, false, Some(None)); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + assert!(matches!( + result, + StepResult::Fail(EventHandlerError::SteppedAfterComplete) + )); +} + #[test] fn join_value_lane_get_map_event_handler() { let uri = make_uri(); diff --git a/server/swimos_agent/src/lanes/map/mod.rs b/server/swimos_agent/src/lanes/map/mod.rs index a31cc756e..5f51ae330 100644 --- a/server/swimos_agent/src/lanes/map/mod.rs +++ b/server/swimos_agent/src/lanes/map/mod.rs @@ -128,7 +128,7 @@ where Q: Hash + Eq, F: FnOnce(Option<&V>) -> R, { - self.inner.borrow().get(key, f) + self.inner.borrow().with_entry(key, f) } /// Read the complete state of the map. @@ -151,7 +151,7 @@ where K: Eq + Hash, { - pub fn with_entry(&self, key: K, f: F) -> U + pub fn with_entry(&self, key: &K, f: F) -> U where B: ?Sized, V: Borrow, @@ -434,7 +434,7 @@ where } = self; if let Some((key, f)) = key_and_f.take() { let lane = projection(context); - StepResult::done(lane.with_entry(key, f)) + StepResult::done(lane.with_entry(&key, f)) } else { StepResult::after_done() } diff --git a/server/swimos_agent/src/map_storage/mod.rs b/server/swimos_agent/src/map_storage/mod.rs index 7b24a8f02..9c5f20337 100644 --- a/server/swimos_agent/src/map_storage/mod.rs +++ b/server/swimos_agent/src/map_storage/mod.rs @@ -136,16 +136,6 @@ where queue.push(MapOperation::Clear); } - pub fn get(&self, key: &B, f: F) -> R - where - K: Borrow, - B: Hash + Eq, - F: FnOnce(Option<&V>) -> R, - { - let MapStoreInner { content, .. } = self; - f(content.get(key)) - } - pub fn get_map(&self, f: F) -> R where F: FnOnce(&HashMap) -> R, @@ -178,16 +168,16 @@ impl MapStoreInner where K: Eq + Hash, { - pub fn with_entry(&self, key: K, f: F) -> U + pub fn with_entry(&self, key: &B1, f: F) -> R where - B: ?Sized, - V: Borrow, - F: FnOnce(Option<&B>) -> U, + B1: ?Sized, + B2: ?Sized, + K: Borrow, + V: Borrow, + B1: Hash + Eq, + F: FnOnce(Option<&B2>) -> R, { - let MapStoreInner { - content, - .. - } = self; - f(content.get(&key).map(Borrow::borrow)) + let MapStoreInner { content, .. } = self; + f(content.get(key).map(Borrow::borrow)) } } diff --git a/server/swimos_agent/src/stores/map/mod.rs b/server/swimos_agent/src/stores/map/mod.rs index e5edc91c8..a8a4d4e28 100644 --- a/server/swimos_agent/src/stores/map/mod.rs +++ b/server/swimos_agent/src/stores/map/mod.rs @@ -113,11 +113,11 @@ where /// Read a value from the map, if it exists. pub fn get(&self, key: &Q, f: F) -> R where - K: Borrow, - Q: Hash + Eq, + K: Borrow + Eq + Hash, + Q: Eq + Hash, F: FnOnce(Option<&V>) -> R, { - self.inner.borrow().get(key, f) + self.inner.borrow().with_entry(key, f) } /// Read the complete state of the map. @@ -134,11 +134,14 @@ where K: Eq + Hash, { - pub fn with_entry(&self, key: K, f: F) -> U + pub fn with_entry(&self, key: &B1, f: F) -> U where - B: ?Sized, - V: Borrow, - F: FnOnce(Option<&B>) -> U, + B1: ?Sized, + B2: ?Sized, + K: Borrow, + B1: Eq + Hash, + V: Borrow, + F: FnOnce(Option<&B2>) -> U, { self.inner.borrow().with_entry(key, f) } @@ -465,7 +468,7 @@ where } = self; if let Some((key, f)) = key_and_f.take() { let store = projection(context); - StepResult::done(store.with_entry(key, f)) + StepResult::done(store.with_entry(&key, f)) } else { StepResult::after_done() } From dc0bbe7ad7e178e5e3ebdb53deab0ee1a1ad90ce Mon Sep 17 00:00:00 2001 From: Greg Holland <30577851+horned-sphere@users.noreply.github.com> Date: Thu, 25 Apr 2024 15:11:14 +0100 Subject: [PATCH 08/27] Added with_entry combinator for JoinMapLane. --- server/swimos_agent/src/lanes/join/map/mod.rs | 78 ++++++++++++++++++- .../swimos_agent/src/lanes/join/map/tests.rs | 48 +++++++++++- .../swimos_agent/src/lanes/join/value/mod.rs | 1 - 3 files changed, 123 insertions(+), 4 deletions(-) diff --git a/server/swimos_agent/src/lanes/join/map/mod.rs b/server/swimos_agent/src/lanes/join/map/mod.rs index 8aef5145f..a876f7867 100644 --- a/server/swimos_agent/src/lanes/join/map/mod.rs +++ b/server/swimos_agent/src/lanes/join/map/mod.rs @@ -17,7 +17,7 @@ use std::{ borrow::Borrow, cell::RefCell, collections::{hash_map::Entry, BTreeSet, HashMap, HashSet}, - hash::Hash, + hash::Hash, marker::PhantomData, }; use bytes::BytesMut; @@ -32,7 +32,7 @@ use crate::{ event_handler::{ ActionContext, EventHandler, EventHandlerError, HandlerAction, Modification, StepResult, }, - item::{AgentItem, MapItem, MapLikeItem}, + item::{AgentItem, InspectableMapLikeItem, MapItem, MapLikeItem}, lanes::{ join_map::default_lifecycle::DefaultJoinMapLifecycle, map::MapLaneEvent, LaneItem, MapLane, }, @@ -666,6 +666,51 @@ where } } +pub struct JoinMapLaneWithEntry { + projection: for<'a> fn(&'a C) -> &'a JoinMapLane, + key: K, + f: Option, + _type: PhantomData, +} + +impl JoinMapLaneWithEntry { + + pub fn new(projection: for<'a> fn(&'a C) -> &'a JoinMapLane, + key: K, f: F) -> Self { + JoinMapLaneWithEntry { + projection, + key, + f: Some(f), + _type: PhantomData, + } + } +} + +impl<'a, C, L, K, V, F, B, U> HandlerAction for JoinMapLaneWithEntry +where + K: Eq + Hash + 'static, + C: 'a, + B: ?Sized + 'static, + V: Borrow, + F: FnOnce(Option<&B>) -> U + Send + 'a, +{ + type Completion = U; + + fn step( + &mut self, + _action_context: &mut ActionContext, + _meta: AgentMetadata, + context: &C, + ) -> StepResult { + if let Some(f) = self.f.take() { + let item = (self.projection)(context); + StepResult::done(item.inner.with_entry(&self.key, f)) + } else { + StepResult::after_done() + } + } +} + impl MapLikeItem for JoinMapLane where L: Send + 'static, @@ -688,3 +733,32 @@ where JoinMapLaneGetMap::new(projection) } } + +impl InspectableMapLikeItem for JoinMapLane +where + L: Send + 'static, + K: Clone + Eq + Hash + Send + 'static, + V: Send + 'static, +{ + type WithEntryHandler<'a, C, F, B, U> = JoinMapLaneWithEntry + where + Self: 'static, + C: 'a, + B: ?Sized + 'static, + V: Borrow, + F: FnOnce(Option<&B>) -> U + Send + 'a; + + fn with_entry_handler<'a, C, F, B, U>( + projection: fn(&C) -> &Self, + key: K, + f: F, + ) -> Self::WithEntryHandler<'a, C, F, B, U> + where + Self: 'static, + C: 'a, + B: ?Sized + 'static, + V: Borrow, + F: FnOnce(Option<&B>) -> U + Send + 'a { + JoinMapLaneWithEntry::new(projection, key, f) + } +} \ No newline at end of file diff --git a/server/swimos_agent/src/lanes/join/map/tests.rs b/server/swimos_agent/src/lanes/join/map/tests.rs index c47aea5a1..d2d60325d 100644 --- a/server/swimos_agent/src/lanes/join/map/tests.rs +++ b/server/swimos_agent/src/lanes/join/map/tests.rs @@ -31,7 +31,7 @@ use crate::item::AgentItem; use crate::lanes::join::test_util::{TestDlContextInner, TestDownlinkContext}; use crate::lanes::join_map::default_lifecycle::DefaultJoinMapLifecycle; use crate::lanes::join_map::{ - AddDownlinkAction, JoinMapAddDownlink, JoinMapLaneGet, JoinMapLaneGetMap, + AddDownlinkAction, JoinMapAddDownlink, JoinMapLaneGet, JoinMapLaneGetMap, JoinMapLaneWithEntry, }; use crate::test_context::{dummy_context, run_event_handlers, run_with_futures}; use crate::{event_handler::StepResult, item::MapItem, meta::AgentMetadata}; @@ -324,3 +324,49 @@ async fn open_downlink_from_registered() { assert_eq!(count.load(Ordering::Relaxed), 1); } + +#[test] +fn join_map_lane_with_entry_event_handler() { + let uri = make_uri(); + let route_params = HashMap::new(); + let meta = make_meta(&uri, &route_params); + let agent = TestAgent::with_init(); + + let mut handler = JoinMapLaneWithEntry::new(TestAgent::LANE, K1, |v: Option<&str>| v.map(str::to_owned)); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + check_result(result, false, false, Some(Some(V1.to_string()))); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + assert!(matches!( + result, + StepResult::Fail(EventHandlerError::SteppedAfterComplete) + )); + + let mut handler = JoinMapLaneWithEntry::new(TestAgent::LANE, ABSENT, |v: Option<&str>| v.map(str::to_owned)); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + check_result(result, false, false, Some(None)); + + let result = handler.step( + &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), + meta, + &agent, + ); + assert!(matches!( + result, + StepResult::Fail(EventHandlerError::SteppedAfterComplete) + )); +} diff --git a/server/swimos_agent/src/lanes/join/value/mod.rs b/server/swimos_agent/src/lanes/join/value/mod.rs index 285ff62ef..4f7432580 100644 --- a/server/swimos_agent/src/lanes/join/value/mod.rs +++ b/server/swimos_agent/src/lanes/join/value/mod.rs @@ -428,7 +428,6 @@ impl JoinValueAddDownlink { } } - pub struct JoinValueLaneWithEntry { projection: for<'a> fn(&'a C) -> &'a JoinValueLane, key: K, From 46f5cd73d6eac81443fdb75b1b11c329e44c0b65 Mon Sep 17 00:00:00 2001 From: Greg Holland <30577851+horned-sphere@users.noreply.github.com> Date: Thu, 25 Apr 2024 15:11:54 +0100 Subject: [PATCH 09/27] Reformatted. --- .../src/agent_lifecycle/utility/mod.rs | 12 +++++------ server/swimos_agent/src/item.rs | 1 - server/swimos_agent/src/lanes/join/map/mod.rs | 12 +++++------ .../swimos_agent/src/lanes/join/map/tests.rs | 7 +++++-- .../swimos_agent/src/lanes/join/value/mod.rs | 10 ++++----- .../src/lanes/join/value/tests.rs | 7 +++++-- server/swimos_agent/src/lanes/map/mod.rs | 19 ++++++++--------- server/swimos_agent/src/lanes/map/tests.rs | 12 +++++++---- server/swimos_agent/src/lanes/value/mod.rs | 15 ++++++------- server/swimos_agent/src/lanes/value/tests.rs | 3 +-- server/swimos_agent/src/stores/map/mod.rs | 12 ++++------- server/swimos_agent/src/stores/map/tests.rs | 11 +++++++--- server/swimos_agent/src/stores/value/mod.rs | 21 ++++++++++++------- server/swimos_agent/src/stores/value/tests.rs | 2 +- 14 files changed, 77 insertions(+), 67 deletions(-) diff --git a/server/swimos_agent/src/agent_lifecycle/utility/mod.rs b/server/swimos_agent/src/agent_lifecycle/utility/mod.rs index 3bc3fa94e..21518edaf 100644 --- a/server/swimos_agent/src/agent_lifecycle/utility/mod.rs +++ b/server/swimos_agent/src/agent_lifecycle/utility/mod.rs @@ -44,7 +44,7 @@ use crate::event_handler::{ }; use crate::event_handler::{GetAgentUri, HandlerAction, SideEffect}; use crate::item::{ - InspectableMapLikeItem, MapLikeItem, MutableMapLikeItem, MutableValueLikeItem, ValueLikeItem + InspectableMapLikeItem, MapLikeItem, MutableMapLikeItem, MutableValueLikeItem, ValueLikeItem, }; use crate::lanes::command::{CommandLane, DoCommand}; use crate::lanes::demand::{Cue, DemandLane}; @@ -186,7 +186,7 @@ impl HandlerContext { } /// Create an event handler that will transform the value of a value lane or store of the agent. - /// + /// /// #Arguments /// * `item` - Projection to the value lane or store. /// * `f` - A closure that produces a new value from a reference to the existing value. @@ -207,7 +207,7 @@ impl HandlerContext { /// Create an event handler that will inspect the value of a value lane or store and generate a result from it. /// This differs from using [`Self::get_value`] in that it does not require a clone to be made of the existing value. - /// + /// /// #Arguments /// * `item` - Projection to the value lane or store. /// * `f` - A closure that produces a value from a reference to the current value of the item. @@ -257,10 +257,10 @@ impl HandlerContext { &self, item: fn(&Agent) -> &Item, key: K, - f: F + f: F, ) -> impl HandlerAction + Send + 'a where - Agent: 'static, + Agent: 'static, Item: InspectableMapLikeItem + 'static, K: Send + Clone + Eq + Hash + 'static, V: Borrow + 'static, @@ -270,7 +270,6 @@ impl HandlerContext { Item::with_entry_handler::(item, key, f) } - /// Create an event handler that will transform the value in an entry of a map lane or store of the agent. /// If map contains an entry with that key, it will be updated (or removed) based on the result of the calling /// the closure on it. If the map does not contain an entry with that key, the closure will be called with [`None`] @@ -775,7 +774,6 @@ impl HandlerContext { pub fn stop(&self) -> impl EventHandler + Send + 'static { HandlerActionExt::::discard(Stop) } - } pub struct JoinValueContext { diff --git a/server/swimos_agent/src/item.rs b/server/swimos_agent/src/item.rs index beafa0bdc..87eb7fb6e 100644 --- a/server/swimos_agent/src/item.rs +++ b/server/swimos_agent/src/item.rs @@ -145,5 +145,4 @@ pub trait MutableValueLikeItem { C: 'static; fn set_handler(projection: fn(&C) -> &Self, value: T) -> Self::SetHandler; - } diff --git a/server/swimos_agent/src/lanes/join/map/mod.rs b/server/swimos_agent/src/lanes/join/map/mod.rs index a876f7867..94417b2a8 100644 --- a/server/swimos_agent/src/lanes/join/map/mod.rs +++ b/server/swimos_agent/src/lanes/join/map/mod.rs @@ -17,7 +17,8 @@ use std::{ borrow::Borrow, cell::RefCell, collections::{hash_map::Entry, BTreeSet, HashMap, HashSet}, - hash::Hash, marker::PhantomData, + hash::Hash, + marker::PhantomData, }; use bytes::BytesMut; @@ -674,9 +675,7 @@ pub struct JoinMapLaneWithEntry { } impl JoinMapLaneWithEntry { - - pub fn new(projection: for<'a> fn(&'a C) -> &'a JoinMapLane, - key: K, f: F) -> Self { + pub fn new(projection: for<'a> fn(&'a C) -> &'a JoinMapLane, key: K, f: F) -> Self { JoinMapLaneWithEntry { projection, key, @@ -758,7 +757,8 @@ where C: 'a, B: ?Sized + 'static, V: Borrow, - F: FnOnce(Option<&B>) -> U + Send + 'a { + F: FnOnce(Option<&B>) -> U + Send + 'a, + { JoinMapLaneWithEntry::new(projection, key, f) } -} \ No newline at end of file +} diff --git a/server/swimos_agent/src/lanes/join/map/tests.rs b/server/swimos_agent/src/lanes/join/map/tests.rs index d2d60325d..f5f297e17 100644 --- a/server/swimos_agent/src/lanes/join/map/tests.rs +++ b/server/swimos_agent/src/lanes/join/map/tests.rs @@ -332,7 +332,8 @@ fn join_map_lane_with_entry_event_handler() { let meta = make_meta(&uri, &route_params); let agent = TestAgent::with_init(); - let mut handler = JoinMapLaneWithEntry::new(TestAgent::LANE, K1, |v: Option<&str>| v.map(str::to_owned)); + let mut handler = + JoinMapLaneWithEntry::new(TestAgent::LANE, K1, |v: Option<&str>| v.map(str::to_owned)); let result = handler.step( &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), @@ -351,7 +352,9 @@ fn join_map_lane_with_entry_event_handler() { StepResult::Fail(EventHandlerError::SteppedAfterComplete) )); - let mut handler = JoinMapLaneWithEntry::new(TestAgent::LANE, ABSENT, |v: Option<&str>| v.map(str::to_owned)); + let mut handler = JoinMapLaneWithEntry::new(TestAgent::LANE, ABSENT, |v: Option<&str>| { + v.map(str::to_owned) + }); let result = handler.step( &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), diff --git a/server/swimos_agent/src/lanes/join/value/mod.rs b/server/swimos_agent/src/lanes/join/value/mod.rs index 4f7432580..41905c761 100644 --- a/server/swimos_agent/src/lanes/join/value/mod.rs +++ b/server/swimos_agent/src/lanes/join/value/mod.rs @@ -436,9 +436,7 @@ pub struct JoinValueLaneWithEntry { } impl JoinValueLaneWithEntry { - - pub fn new(projection: for<'a> fn(&'a C) -> &'a JoinValueLane, - key: K, f: F) -> Self { + pub fn new(projection: for<'a> fn(&'a C) -> &'a JoinValueLane, key: K, f: F) -> Self { JoinValueLaneWithEntry { projection, key, @@ -473,7 +471,6 @@ where } } - impl MapLikeItem for JoinValueLane where K: Clone + Eq + Hash + Send + 'static, @@ -519,7 +516,8 @@ where C: 'a, B: ?Sized + 'static, V: Borrow, - F: FnOnce(Option<&B>) -> U + Send + 'a { + F: FnOnce(Option<&B>) -> U + Send + 'a, + { JoinValueLaneWithEntry::new(projection, key, f) } -} \ No newline at end of file +} diff --git a/server/swimos_agent/src/lanes/join/value/tests.rs b/server/swimos_agent/src/lanes/join/value/tests.rs index 127ed374b..9fc0e4e53 100644 --- a/server/swimos_agent/src/lanes/join/value/tests.rs +++ b/server/swimos_agent/src/lanes/join/value/tests.rs @@ -195,7 +195,8 @@ fn join_value_lane_with_entry_event_handler() { let meta = make_meta(&uri, &route_params); let agent = TestAgent::with_init(); - let mut handler = JoinValueLaneWithEntry::new(TestAgent::LANE, K1, |v: Option<&str>| v.map(str::to_owned)); + let mut handler = + JoinValueLaneWithEntry::new(TestAgent::LANE, K1, |v: Option<&str>| v.map(str::to_owned)); let result = handler.step( &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), @@ -214,7 +215,9 @@ fn join_value_lane_with_entry_event_handler() { StepResult::Fail(EventHandlerError::SteppedAfterComplete) )); - let mut handler = JoinValueLaneWithEntry::new(TestAgent::LANE, ABSENT, |v: Option<&str>| v.map(str::to_owned)); + let mut handler = JoinValueLaneWithEntry::new(TestAgent::LANE, ABSENT, |v: Option<&str>| { + v.map(str::to_owned) + }); let result = handler.step( &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), diff --git a/server/swimos_agent/src/lanes/map/mod.rs b/server/swimos_agent/src/lanes/map/mod.rs index 5f51ae330..267816929 100644 --- a/server/swimos_agent/src/lanes/map/mod.rs +++ b/server/swimos_agent/src/lanes/map/mod.rs @@ -150,7 +150,6 @@ impl MapLane where K: Eq + Hash, { - pub fn with_entry(&self, key: &K, f: F) -> U where B: ?Sized, @@ -159,7 +158,6 @@ where { self.inner.borrow().with_entry(key, f) } - } const INFALLIBLE_SER: &str = "Serializing lane responses to recon should be infallible."; @@ -670,7 +668,7 @@ where B: ?Sized +'static, V: Borrow, F: FnOnce(Option<&B>) -> U + Send + 'a; - + fn with_entry_handler<'a, C, F, B, U>( projection: fn(&C) -> &Self, key: K, @@ -679,9 +677,10 @@ where where Self: 'static, C: 'a, - B: ?Sized +'static, + B: ?Sized + 'static, V: Borrow, - F: FnOnce(Option<&B>) -> U + Send + 'a { + F: FnOnce(Option<&B>) -> U + Send + 'a, + { MapLaneWithEntry::new(projection, key, f) } } @@ -718,13 +717,13 @@ where fn clear_handler(projection: fn(&C) -> &Self) -> Self::ClearHandler { MapLaneClear::new(projection) } - + type TransformEntryHandler<'a, C, F> = MapLaneTransformEntry where Self: 'static, C: 'a, F: FnOnce(Option<&V>) -> Option + Send + 'a; - + fn transform_entry_handler<'a, C, F>( projection: fn(&C) -> &Self, key: K, @@ -733,8 +732,8 @@ where where Self: 'static, C: 'a, - F: FnOnce(Option<&V>) -> Option + Send + 'a { - MapLaneTransformEntry::new(projection, key, f) + F: FnOnce(Option<&V>) -> Option + Send + 'a, + { + MapLaneTransformEntry::new(projection, key, f) } - } diff --git a/server/swimos_agent/src/lanes/map/tests.rs b/server/swimos_agent/src/lanes/map/tests.rs index bb22515bb..27a6b2990 100644 --- a/server/swimos_agent/src/lanes/map/tests.rs +++ b/server/swimos_agent/src/lanes/map/tests.rs @@ -37,7 +37,7 @@ use crate::{ lanes::{ map::{ MapLane, MapLaneClear, MapLaneEvent, MapLaneGet, MapLaneGetMap, MapLaneRemove, - MapLaneSync, MapLaneUpdate, MapLaneTransformEntry, + MapLaneSync, MapLaneTransformEntry, MapLaneUpdate, }, LaneItem, }, @@ -824,7 +824,9 @@ fn map_lane_with_entry_handler_absent() { let meta = make_meta(&uri, &route_params); let agent = TestAgent::with_init(); - let mut handler = MapLaneWithEntry::new(TestAgent::LANE, ABSENT, |maybe_v: Option<&str>| maybe_v.map(str::to_owned)); + let mut handler = MapLaneWithEntry::new(TestAgent::LANE, ABSENT, |maybe_v: Option<&str>| { + maybe_v.map(str::to_owned) + }); let result = handler.step( &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), @@ -841,7 +843,9 @@ fn map_lane_with_entry_handler_present() { let meta = make_meta(&uri, &route_params); let agent = TestAgent::with_init(); - let mut handler = MapLaneWithEntry::new(TestAgent::LANE, K1, |maybe_v: Option<&str>| maybe_v.map(str::to_owned)); + let mut handler = MapLaneWithEntry::new(TestAgent::LANE, K1, |maybe_v: Option<&str>| { + maybe_v.map(str::to_owned) + }); let result = handler.step( &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), @@ -849,4 +853,4 @@ fn map_lane_with_entry_handler_present() { &agent, ); check_result(result, false, false, Some(Some(V1.to_owned()))); -} \ No newline at end of file +} diff --git a/server/swimos_agent/src/lanes/value/mod.rs b/server/swimos_agent/src/lanes/value/mod.rs index 9512f7264..4ecbd4bc0 100644 --- a/server/swimos_agent/src/lanes/value/mod.rs +++ b/server/swimos_agent/src/lanes/value/mod.rs @@ -274,17 +274,19 @@ impl HandlerAction for ValueLaneSync { } } -pub struct ValueLaneWithValue { +pub struct ValueLaneWithValue { projection: for<'a> fn(&'a C) -> &'a ValueLane, f: Option, _type: PhantomData, } -impl ValueLaneWithValue { - - pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueLane, - f: F) -> Self { - ValueLaneWithValue { projection, f: Some(f), _type: PhantomData } +impl ValueLaneWithValue { + pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueLane, f: F) -> Self { + ValueLaneWithValue { + projection, + f: Some(f), + _type: PhantomData, + } } } @@ -377,5 +379,4 @@ where fn set_handler(projection: fn(&C) -> &Self, value: T) -> Self::SetHandler { ValueLaneSet::new(projection, value) } - } diff --git a/server/swimos_agent/src/lanes/value/tests.rs b/server/swimos_agent/src/lanes/value/tests.rs index e23f54714..f722824a6 100644 --- a/server/swimos_agent/src/lanes/value/tests.rs +++ b/server/swimos_agent/src/lanes/value/tests.rs @@ -287,7 +287,7 @@ impl Default for TestAgent { fn default() -> Self { Self { lane: ValueLane::new(LANE_ID, 0), - str_lane: ValueLane::new(STR_LANE_ID, "hello".to_string()) + str_lane: ValueLane::new(STR_LANE_ID, "hello".to_string()), } } } @@ -478,5 +478,4 @@ fn value_lane_with_value_event_handler() { result, StepResult::Fail(EventHandlerError::SteppedAfterComplete) )); - } diff --git a/server/swimos_agent/src/stores/map/mod.rs b/server/swimos_agent/src/stores/map/mod.rs index a8a4d4e28..98c035de4 100644 --- a/server/swimos_agent/src/stores/map/mod.rs +++ b/server/swimos_agent/src/stores/map/mod.rs @@ -99,7 +99,6 @@ where self.inner.borrow_mut().transform_entry(key, f) } - /// Remove an entry from the map. pub fn remove(&self, key: &K) { self.inner.borrow_mut().remove(key) @@ -133,7 +132,6 @@ impl MapStore where K: Eq + Hash, { - pub fn with_entry(&self, key: &B1, f: F) -> U where B1: ?Sized, @@ -145,7 +143,6 @@ where { self.inner.borrow().with_entry(key, f) } - } const INFALLIBLE_SER: &str = "Serializing store responses to recon should be infallible."; @@ -495,7 +492,6 @@ where fn get_map_handler(projection: fn(&C) -> &Self) -> Self::GetMapHandler { MapStoreGetMap::new(projection) } - } impl InspectableMapLikeItem for MapStore @@ -510,7 +506,7 @@ where B: ?Sized +'static, V: Borrow, F: FnOnce(Option<&B>) -> U + Send + 'a; - + fn with_entry_handler<'a, C, F, B, U>( projection: fn(&C) -> &Self, key: K, @@ -519,9 +515,10 @@ where where Self: 'static, C: 'a, - B: ?Sized +'static, + B: ?Sized + 'static, V: Borrow, - F: FnOnce(Option<&B>) -> U + Send + 'a { + F: FnOnce(Option<&B>) -> U + Send + 'a, + { MapStoreWithEntry::new(projection, key, f) } } @@ -577,5 +574,4 @@ where { MapStoreTransformEntry::new(projection, key, f) } - } diff --git a/server/swimos_agent/src/stores/map/tests.rs b/server/swimos_agent/src/stores/map/tests.rs index 707596778..e1a74ba7e 100644 --- a/server/swimos_agent/src/stores/map/tests.rs +++ b/server/swimos_agent/src/stores/map/tests.rs @@ -36,7 +36,8 @@ use crate::{ meta::AgentMetadata, stores::{ map::{ - MapStoreClear, MapStoreGet, MapStoreGetMap, MapStoreRemove, MapStoreTransformEntry, MapStoreUpdate, MapStoreWithEntry + MapStoreClear, MapStoreGet, MapStoreGetMap, MapStoreRemove, MapStoreTransformEntry, + MapStoreUpdate, MapStoreWithEntry, }, MapStore, StoreItem, }, @@ -651,7 +652,9 @@ fn map_lane_with_entry_handler_absent() { let meta = make_meta(&uri, &route_params); let agent = TestAgent::with_init(); - let mut handler = MapStoreWithEntry::new(TestAgent::STORE, ABSENT, |maybe_v: Option<&str>| maybe_v.map(str::to_owned)); + let mut handler = MapStoreWithEntry::new(TestAgent::STORE, ABSENT, |maybe_v: Option<&str>| { + maybe_v.map(str::to_owned) + }); let result = handler.step( &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), @@ -668,7 +671,9 @@ fn map_lane_with_entry_handler_present() { let meta = make_meta(&uri, &route_params); let agent = TestAgent::with_init(); - let mut handler = MapStoreWithEntry::new(TestAgent::STORE, K1, |maybe_v: Option<&str>| maybe_v.map(str::to_owned)); + let mut handler = MapStoreWithEntry::new(TestAgent::STORE, K1, |maybe_v: Option<&str>| { + maybe_v.map(str::to_owned) + }); let result = handler.step( &mut dummy_context(&mut HashMap::new(), &mut BytesMut::new()), diff --git a/server/swimos_agent/src/stores/value/mod.rs b/server/swimos_agent/src/stores/value/mod.rs index 8a38e7460..3516e7d3d 100644 --- a/server/swimos_agent/src/stores/value/mod.rs +++ b/server/swimos_agent/src/stores/value/mod.rs @@ -12,7 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{borrow::Borrow, cell::{Cell, RefCell}, marker::PhantomData}; +use std::{ + borrow::Borrow, + cell::{Cell, RefCell}, + marker::PhantomData, +}; use bytes::BytesMut; use static_assertions::assert_impl_all; @@ -272,17 +276,19 @@ impl HandlerAction for ValueStoreSet { } } -pub struct ValueStoreWithValue { +pub struct ValueStoreWithValue { projection: for<'a> fn(&'a C) -> &'a ValueStore, f: Option, _type: PhantomData, } -impl ValueStoreWithValue { - - pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueStore, - f: F) -> Self { - ValueStoreWithValue { projection, f: Some(f), _type: PhantomData } +impl ValueStoreWithValue { + pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueStore, f: F) -> Self { + ValueStoreWithValue { + projection, + f: Some(f), + _type: PhantomData, + } } } @@ -354,5 +360,4 @@ where fn set_handler(projection: fn(&C) -> &Self, value: T) -> Self::SetHandler { ValueStoreSet::new(projection, value) } - } diff --git a/server/swimos_agent/src/stores/value/tests.rs b/server/swimos_agent/src/stores/value/tests.rs index 594b1fc09..ae2df9dd3 100644 --- a/server/swimos_agent/src/stores/value/tests.rs +++ b/server/swimos_agent/src/stores/value/tests.rs @@ -126,7 +126,7 @@ impl Default for TestAgent { fn default() -> Self { Self { store: ValueStore::new(STORE_ID, 0), - str_store: ValueStore::new(STR_STORE_ID, "world".to_owned()) + str_store: ValueStore::new(STR_STORE_ID, "world".to_owned()), } } } From 5547c0f9e0bfe5110bd139dc796ea139130af74b Mon Sep 17 00:00:00 2001 From: Greg Holland <30577851+horned-sphere@users.noreply.github.com> Date: Thu, 25 Apr 2024 15:30:28 +0100 Subject: [PATCH 10/27] Upgarded RocksDB. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 148b4999a..bf18d82b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,7 +90,7 @@ ratchet = { package = "ratchet_rs", version = "0.4" } ratchet_fixture = "0.4" flate2 = "1.0.22" bitflags = "1.3" -rocksdb = "0.19.0" +rocksdb = "0.22" integer-encoding = "3.0.4" rustls = "0.20" webpki = "0.22" From f5d20885ae916a5a012a074315a4fe300f8d167b Mon Sep 17 00:00:00 2001 From: Greg Holland <30577851+horned-sphere@users.noreply.github.com> Date: Fri, 26 Apr 2024 09:15:01 +0100 Subject: [PATCH 11/27] Added method docs. --- server/swimos_agent/src/lanes/join/map/mod.rs | 6 ++++++ server/swimos_agent/src/lanes/join/value/mod.rs | 6 ++++++ server/swimos_agent/src/lanes/map/mod.rs | 12 +++++++++--- server/swimos_agent/src/lanes/value/mod.rs | 4 ++++ server/swimos_agent/src/map_storage/mod.rs | 12 ++++++------ server/swimos_agent/src/stores/map/mod.rs | 15 ++++++++++++--- server/swimos_agent/src/stores/value/mod.rs | 4 ++++ 7 files changed, 47 insertions(+), 12 deletions(-) diff --git a/server/swimos_agent/src/lanes/join/map/mod.rs b/server/swimos_agent/src/lanes/join/map/mod.rs index 94417b2a8..27da5df38 100644 --- a/server/swimos_agent/src/lanes/join/map/mod.rs +++ b/server/swimos_agent/src/lanes/join/map/mod.rs @@ -667,6 +667,8 @@ where } } +/// A [`HandlerAction`] that will produce a value by applying a closure to a reference to +/// and entry in the lane. pub struct JoinMapLaneWithEntry { projection: for<'a> fn(&'a C) -> &'a JoinMapLane, key: K, @@ -675,6 +677,10 @@ pub struct JoinMapLaneWithEntry { } impl JoinMapLaneWithEntry { + /// #Arguments + /// * `projection` - Projection from the agent context to the lane. + /// * `key` - Key of the entry. + /// * `f` - The closure to apply to the entry. pub fn new(projection: for<'a> fn(&'a C) -> &'a JoinMapLane, key: K, f: F) -> Self { JoinMapLaneWithEntry { projection, diff --git a/server/swimos_agent/src/lanes/join/value/mod.rs b/server/swimos_agent/src/lanes/join/value/mod.rs index 41905c761..ebe657da6 100644 --- a/server/swimos_agent/src/lanes/join/value/mod.rs +++ b/server/swimos_agent/src/lanes/join/value/mod.rs @@ -428,6 +428,8 @@ impl JoinValueAddDownlink { } } +/// A [`HandlerAction`] that will produce a value by applying a closure to a reference to +/// and entry in the lane. pub struct JoinValueLaneWithEntry { projection: for<'a> fn(&'a C) -> &'a JoinValueLane, key: K, @@ -436,6 +438,10 @@ pub struct JoinValueLaneWithEntry { } impl JoinValueLaneWithEntry { + /// #Arguments + /// * `projection` - Projection from the agent context to the lane. + /// * `key` - Key of the entry. + /// * `f` - The closure to apply to the entry. pub fn new(projection: for<'a> fn(&'a C) -> &'a JoinValueLane, key: K, f: F) -> Self { JoinValueLaneWithEntry { projection, diff --git a/server/swimos_agent/src/lanes/map/mod.rs b/server/swimos_agent/src/lanes/map/mod.rs index 267816929..4da46273c 100644 --- a/server/swimos_agent/src/lanes/map/mod.rs +++ b/server/swimos_agent/src/lanes/map/mod.rs @@ -35,7 +35,7 @@ use crate::{ Modification, StepResult, }, item::{AgentItem, InspectableMapLikeItem, MapItem, MapLikeItem, MutableMapLikeItem}, - map_storage::{MapStoreInner, WithEntryResult}, + map_storage::{MapStoreInner, TransformEntryResult}, meta::AgentMetadata, }; @@ -104,7 +104,7 @@ where } /// Transform the value associated with a key. - pub fn transform_entry(&self, key: K, f: F) -> WithEntryResult + pub fn transform_entry(&self, key: K, f: F) -> TransformEntryResult where F: FnOnce(Option<&V>) -> Option, { @@ -394,6 +394,8 @@ where } } +/// A [`HandlerAction`] that will produce a value by applying a closure to a reference to +/// and entry in the lane. pub struct MapLaneWithEntry { projection: for<'a> fn(&'a C) -> &'a MapLane, key_and_f: Option<(K, F)>, @@ -401,6 +403,10 @@ pub struct MapLaneWithEntry { } impl MapLaneWithEntry { + /// #Arguments + /// * `projection` - Projection from the agent context to the lane. + /// * `key` - Key of the entry. + /// * `f` - The closure to apply to the entry. pub fn new(projection: for<'a> fn(&'a C) -> &'a MapLane, key: K, f: F) -> Self { MapLaneWithEntry { projection, @@ -620,7 +626,7 @@ where } = self; if let Some((key, f)) = key_and_f.take() { let lane = projection(context); - if matches!(lane.transform_entry(key, f), WithEntryResult::NoChange) { + if matches!(lane.transform_entry(key, f), TransformEntryResult::NoChange) { StepResult::done(()) } else { StepResult::Complete { diff --git a/server/swimos_agent/src/lanes/value/mod.rs b/server/swimos_agent/src/lanes/value/mod.rs index 4ecbd4bc0..f2a5f3a80 100644 --- a/server/swimos_agent/src/lanes/value/mod.rs +++ b/server/swimos_agent/src/lanes/value/mod.rs @@ -274,6 +274,7 @@ impl HandlerAction for ValueLaneSync { } } +/// An [`HandlerAction`] that will produce a value from a reference to the contents of the lane. pub struct ValueLaneWithValue { projection: for<'a> fn(&'a C) -> &'a ValueLane, f: Option, @@ -281,6 +282,9 @@ pub struct ValueLaneWithValue { } impl ValueLaneWithValue { + /// #Arguments + /// * `projection` - Projection from the agent context to the lane. + /// * `f` - Closure to apply to the value of the lane. pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueLane, f: F) -> Self { ValueLaneWithValue { projection, diff --git a/server/swimos_agent/src/map_storage/mod.rs b/server/swimos_agent/src/map_storage/mod.rs index 9c5f20337..899050312 100644 --- a/server/swimos_agent/src/map_storage/mod.rs +++ b/server/swimos_agent/src/map_storage/mod.rs @@ -52,7 +52,7 @@ impl MapStoreInner { } } -pub enum WithEntryResult { +pub enum TransformEntryResult { NoChange, Update, Remove, @@ -78,7 +78,7 @@ where queue.push(MapOperation::Update { key, value: () }); } - pub fn transform_entry(&mut self, key: K, f: F) -> WithEntryResult + pub fn transform_entry(&mut self, key: K, f: F) -> TransformEntryResult where F: FnOnce(Option<&V>) -> Option, { @@ -93,12 +93,12 @@ where content.insert(key.clone(), v2); *previous = Some(MapLaneEvent::Update(key.clone(), Some(v))); queue.push(MapOperation::Update { key, value: () }); - WithEntryResult::Update + TransformEntryResult::Update } _ => { *previous = Some(MapLaneEvent::Remove(key.clone(), v)); queue.push(MapOperation::Remove { key: key.clone() }); - WithEntryResult::Remove + TransformEntryResult::Remove } }, _ => match f(None) { @@ -106,9 +106,9 @@ where content.insert(key.clone(), v2); *previous = Some(MapLaneEvent::Update(key.clone(), None)); queue.push(MapOperation::Update { key, value: () }); - WithEntryResult::Update + TransformEntryResult::Update } - _ => WithEntryResult::NoChange, + _ => TransformEntryResult::NoChange, }, } } diff --git a/server/swimos_agent/src/stores/map/mod.rs b/server/swimos_agent/src/stores/map/mod.rs index 98c035de4..19a817e73 100644 --- a/server/swimos_agent/src/stores/map/mod.rs +++ b/server/swimos_agent/src/stores/map/mod.rs @@ -27,7 +27,7 @@ use crate::agent_model::WriteResult; use crate::event_handler::{ActionContext, HandlerAction, Modification, StepResult}; use crate::event_queue::EventQueue; use crate::item::{AgentItem, InspectableMapLikeItem, MapItem, MapLikeItem, MutableMapLikeItem}; -use crate::map_storage::{MapStoreInner, WithEntryResult}; +use crate::map_storage::{MapStoreInner, TransformEntryResult}; use crate::meta::AgentMetadata; use super::StoreItem; @@ -92,7 +92,7 @@ where } /// Transform the value associated with a key. - pub fn transform_entry(&self, key: K, f: F) -> WithEntryResult + pub fn transform_entry(&self, key: K, f: F) -> TransformEntryResult where F: FnOnce(Option<&V>) -> Option, { @@ -413,7 +413,10 @@ where } = self; if let Some((key, f)) = key_and_f.take() { let store = projection(context); - if matches!(store.transform_entry(key, f), WithEntryResult::NoChange) { + if matches!( + store.transform_entry(key, f), + TransformEntryResult::NoChange + ) { StepResult::done(()) } else { StepResult::Complete { @@ -427,6 +430,8 @@ where } } +/// A [`HandlerAction`] that will produce a value by applying a closure to a reference to +/// and entry in the store. pub struct MapStoreWithEntry { projection: for<'a> fn(&'a C) -> &'a MapStore, key_and_f: Option<(K, F)>, @@ -434,6 +439,10 @@ pub struct MapStoreWithEntry { } impl MapStoreWithEntry { + /// #Arguments + /// * `projection` - Projection from the agent context to the store. + /// * `key` - Key of the entry. + /// * `f` - The closure to apply to the entry. pub fn new(projection: for<'a> fn(&'a C) -> &'a MapStore, key: K, f: F) -> Self { MapStoreWithEntry { projection, diff --git a/server/swimos_agent/src/stores/value/mod.rs b/server/swimos_agent/src/stores/value/mod.rs index 3516e7d3d..33d5ada03 100644 --- a/server/swimos_agent/src/stores/value/mod.rs +++ b/server/swimos_agent/src/stores/value/mod.rs @@ -276,6 +276,7 @@ impl HandlerAction for ValueStoreSet { } } +/// An [`HandlerAction`] that will produce a value from a reference to the contents of the store. pub struct ValueStoreWithValue { projection: for<'a> fn(&'a C) -> &'a ValueStore, f: Option, @@ -283,6 +284,9 @@ pub struct ValueStoreWithValue { } impl ValueStoreWithValue { + /// #Arguments + /// * `projection` - Projection from the agent context to the store. + /// * `f` - Closure to apply to the value of the store. pub fn new(projection: for<'a> fn(&'a C) -> &'a ValueStore, f: F) -> Self { ValueStoreWithValue { projection, From e86940a68666fef799bfe51d81129ee028ec6194 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 10:07:08 +0000 Subject: [PATCH 12/27] Update axum requirement from 0.6.20 to 0.7.5 Updates the requirements on [axum](https://github.com/tokio-rs/axum) to permit the latest version. - [Release notes](https://github.com/tokio-rs/axum/releases) - [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/axum/compare/axum-v0.6.20...axum-v0.6.20) --- updated-dependencies: - dependency-name: axum dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 712a0e3f0..d20d41364 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -122,7 +122,7 @@ duration-str = "0.11.2" quick-xml = "0.33.0" csv = "1.2" serde-xml-rs = "0.6" -axum = "0.6.20" +axum = "0.7.5" hyper-staticfile = "0.9" httparse = "1.8" sha-1 = "0.10.1" From c99b83f6b45608407fd31481603b73e7cf7d7a58 Mon Sep 17 00:00:00 2001 From: SirCipher Date: Mon, 24 Jun 2024 16:38:30 +0100 Subject: [PATCH 13/27] Adds missing client-side crypto provider init --- runtime/swimos_remote/src/tls/config/mod.rs | 16 ++++------------ runtime/swimos_remote/src/tls/net/client.rs | 4 +++- runtime/swimos_remote/src/tls/net/tests.rs | 10 +++------- server/swimos_server_app/Cargo.toml | 5 +++-- .../swimos_server_app/src/server/builder/mod.rs | 8 ++++++-- 5 files changed, 19 insertions(+), 24 deletions(-) diff --git a/runtime/swimos_remote/src/tls/config/mod.rs b/runtime/swimos_remote/src/tls/config/mod.rs index be97c9564..d58b68404 100644 --- a/runtime/swimos_remote/src/tls/config/mod.rs +++ b/runtime/swimos_remote/src/tls/config/mod.rs @@ -87,8 +87,7 @@ pub struct ServerConfig { /// `SSLKEYLOGFILE` environment variable, and writes keys into it. While this may be enabled, /// if `SSLKEYLOGFILE` is not set, it will do nothing. pub enable_log_file: bool, - /// Process-wide [`CryptoProvider`] that must already have been installed as the default - /// provider. + /// [`CryptoProvider`] to use when building the [`rustls::ServerConfig`]. pub provider: Arc, } @@ -107,22 +106,15 @@ impl ServerConfig { pub struct ClientConfig { pub use_webpki_roots: bool, pub custom_roots: Vec, + pub provider: Arc, } impl ClientConfig { - pub fn new(custom_roots: Vec) -> Self { + pub fn new(custom_roots: Vec, provider: Arc) -> Self { ClientConfig { use_webpki_roots: true, custom_roots, - } - } -} - -impl Default for ClientConfig { - fn default() -> Self { - Self { - use_webpki_roots: true, - custom_roots: vec![], + provider, } } } diff --git a/runtime/swimos_remote/src/tls/net/client.rs b/runtime/swimos_remote/src/tls/net/client.rs index 8159211f4..8bc9555c6 100644 --- a/runtime/swimos_remote/src/tls/net/client.rs +++ b/runtime/swimos_remote/src/tls/net/client.rs @@ -47,6 +47,7 @@ impl RustlsClientNetworking { let ClientConfig { use_webpki_roots, custom_roots, + provider, } = config; let mut root_store = RootCertStore::empty(); if use_webpki_roots { @@ -59,7 +60,8 @@ impl RustlsClientNetworking { } } - let config = rustls::ClientConfig::builder() + let config = rustls::ClientConfig::builder_with_provider(provider) + .with_safe_default_protocol_versions()? .with_root_certificates(root_store) .with_no_client_auth(); diff --git a/runtime/swimos_remote/src/tls/net/tests.rs b/runtime/swimos_remote/src/tls/net/tests.rs index 453c8ca8f..811745992 100644 --- a/runtime/swimos_remote/src/tls/net/tests.rs +++ b/runtime/swimos_remote/src/tls/net/tests.rs @@ -17,6 +17,7 @@ use std::{net::SocketAddr, path::PathBuf, sync::Arc, time::Duration}; use crate::dns::Resolver; use crate::net::{ClientConnections, ConnectionError, Listener, ListenerError, Scheme}; use futures::{future::join, StreamExt}; +use rustls::crypto::aws_lc_rs; use crate::tls::{ CertChain, CertificateFile, ClientConfig, PrivateKey, RustlsClientNetworking, @@ -46,18 +47,12 @@ fn make_server_config() -> ServerConfig { CertificateFile::der(ca_cert), ]); - let provider = rustls::crypto::aws_lc_rs::default_provider(); - provider - .clone() - .install_default() - .expect("Crypto Provider has already been initialised elsewhere."); - let key = PrivateKey::der(server_key); ServerConfig { chain, key, enable_log_file: false, - provider: Arc::new(provider), + provider: Arc::new(aws_lc_rs::default_provider()), } } @@ -67,6 +62,7 @@ fn make_client_config() -> ClientConfig { ClientConfig { use_webpki_roots: true, custom_roots: vec![CertificateFile::der(ca_cert)], + provider: Arc::new(aws_lc_rs::default_provider()), } } diff --git a/server/swimos_server_app/Cargo.toml b/server/swimos_server_app/Cargo.toml index 6d0fb66f6..57cd650a3 100644 --- a/server/swimos_server_app/Cargo.toml +++ b/server/swimos_server_app/Cargo.toml @@ -17,7 +17,7 @@ swimos_runtime = { path = "../../runtime/swimos_runtime" } swimos_messages = { path = "../../runtime/swimos_messages" } swimos_http = { path = "../../runtime/swimos_http" } swimos_introspection = { path = "../swimos_introspection" } -swimos_remote = { path = "../../runtime/swimos_remote", features = ["tls"]} +swimos_remote = { path = "../../runtime/swimos_remote", features = ["tls"] } bytes = { workspace = true } tokio = { workspace = true, features = ["rt"] } tokio-util = { workspace = true, features = ["codec"] } @@ -30,11 +30,12 @@ uuid = { workspace = true } thiserror = { workspace = true } rand = { workspace = true } url = { workspace = true } -swimos_rocks_store = { path = "../../runtime/swimos_rocks_store", optional = true} +swimos_rocks_store = { path = "../../runtime/swimos_rocks_store", optional = true } parking_lot = { workspace = true } hyper = { workspace = true, features = ["server", "runtime", "tcp", "http1", "backports"] } pin-project = { workspace = true } percent-encoding = { workspace = true } +rustls = { workspace = true } [dev-dependencies] swimos_recon = { path = "../../api/formats/swimos_recon" } diff --git a/server/swimos_server_app/src/server/builder/mod.rs b/server/swimos_server_app/src/server/builder/mod.rs index 22d0753a4..f75bcfd9a 100644 --- a/server/swimos_server_app/src/server/builder/mod.rs +++ b/server/swimos_server_app/src/server/builder/mod.rs @@ -21,6 +21,7 @@ use ratchet::{ deflate::{DeflateConfig, DeflateExtProvider}, NoExtProvider, WebSocketStream, }; +use rustls::crypto::aws_lc_rs; use swimos_api::{ agent::Agent, error::StoreError, @@ -188,8 +189,11 @@ impl ServerBuilder { let networking = RustlsNetworking::new_tls(client, server); Ok(with_store(bind_to, routes, networking, config)?) } else { - let client = - RustlsClientNetworking::try_from_config(resolver.clone(), ClientConfig::default())?; + let provider = Arc::new(aws_lc_rs::default_provider()); + let client = RustlsClientNetworking::try_from_config( + resolver.clone(), + ClientConfig::new(Default::default(), provider), + )?; let server = TokioPlainTextNetworking::new(resolver); let networking = RustlsNetworking::new_plain_text(client, server); Ok(with_store(bind_to, routes, networking, config)?) From 88752d8496fe3df413b0d5fdb077f3de6edc80c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 10:07:08 +0000 Subject: [PATCH 14/27] Update axum requirement from 0.6.20 to 0.7.5 Updates the requirements on [axum](https://github.com/tokio-rs/axum) to permit the latest version. - [Release notes](https://github.com/tokio-rs/axum/releases) - [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/axum/compare/axum-v0.6.20...axum-v0.6.20) --- updated-dependencies: - dependency-name: axum dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 712a0e3f0..d20d41364 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -122,7 +122,7 @@ duration-str = "0.11.2" quick-xml = "0.33.0" csv = "1.2" serde-xml-rs = "0.6" -axum = "0.6.20" +axum = "0.7.5" hyper-staticfile = "0.9" httparse = "1.8" sha-1 = "0.10.1" From b9767e59d906990c446b0bbdb162001356e89e06 Mon Sep 17 00:00:00 2001 From: SirCipher Date: Mon, 24 Jun 2024 16:41:59 +0100 Subject: [PATCH 15/27] Updates to new Axum API --- example_apps/transit/Cargo.toml | 1 + example_apps/transit/src/bin/ui.rs | 24 ++++++++++++++++-------- example_apps/transit/src/main.rs | 23 +++++++++++++++-------- example_apps/transit/src/ui.rs | 8 +++----- 4 files changed, 35 insertions(+), 21 deletions(-) diff --git a/example_apps/transit/Cargo.toml b/example_apps/transit/Cargo.toml index 0c9b1ce92..1877e435e 100644 --- a/example_apps/transit/Cargo.toml +++ b/example_apps/transit/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } swimos_form = { path = "../../api/swimos_form" } +swimos_utilities = { path = "../../swimos_utilities", features = ["trigger"] } tokio = { workspace = true, features = ["rt-multi-thread", "macros", "sync", "io-util", "fs"] } tokio-stream = { workspace = true, features = ["io-util"] } tokio-util = { workspace = true, features = ["io"] } diff --git a/example_apps/transit/src/bin/ui.rs b/example_apps/transit/src/bin/ui.rs index c07688ade..f9d656856 100644 --- a/example_apps/transit/src/bin/ui.rs +++ b/example_apps/transit/src/bin/ui.rs @@ -12,11 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{error::Error, pin::pin, sync::Arc, time::Duration}; +use std::future::IntoFuture; +use std::{error::Error, pin::pin, time::Duration}; use clap::Parser; use futures::future::{select, Either}; -use tokio::sync::Notify; +use tokio::net::TcpListener; + +use swimos_utilities::trigger::trigger; use transit::ui::ui_server_router; const SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(1); @@ -32,19 +35,24 @@ async fn ui_server( shutdown_timeout: Duration, ) -> Result<(), Box> { let app = ui_server_router(port); - let server = axum::Server::try_bind(&"0.0.0.0:0".parse()?)?.serve(app.into_make_service()); - let ui_addr = server.local_addr(); + let (stop_tx, stop_rx) = trigger(); + + let listener = TcpListener::bind("0.0.0.0:0").await?; + let ui_addr = listener.local_addr()?; println!("UI bound to: {}", ui_addr); - let stop_tx = Arc::new(Notify::new()); - let stop_rx = stop_tx.clone(); - let server_task = pin!(server.with_graceful_shutdown(stop_rx.notified())); + + let server = + axum::serve(listener, app.into_make_service()).with_graceful_shutdown(async move { + let _r = stop_rx.await; + }); + let server_task = pin!(server.into_future()); let shutdown_notified = pin!(async move { let _ = tokio::signal::ctrl_c().await; }); match select(server_task, shutdown_notified).await { Either::Left((result, _)) => result?, Either::Right((_, server)) => { - stop_tx.notify_one(); + assert!(stop_tx.trigger()); tokio::time::timeout(shutdown_timeout, server).await??; } } diff --git a/example_apps/transit/src/main.rs b/example_apps/transit/src/main.rs index 7baa73301..466ee7ef4 100644 --- a/example_apps/transit/src/main.rs +++ b/example_apps/transit/src/main.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::future::IntoFuture; use std::{error::Error, net::SocketAddr, pin::pin, sync::Arc, time::Duration}; use clap::Parser; @@ -22,6 +23,8 @@ use swimos::{ route::RouteUri, server::{Server, ServerBuilder}, }; +use swimos_utilities::trigger::trigger; +use tokio::net::TcpListener; use tokio::sync::{oneshot, Notify}; use tracing_subscriber::filter::LevelFilter; use transit::start_agencies_and_wait; @@ -74,20 +77,24 @@ async fn ui_server( ) -> Result<(), Box> { if let Ok(addr) = swim_addr_rx.await { let app = ui_server_router(addr.port()); + let bind_to: SocketAddr = format!("0.0.0.0:{}", port.unwrap_or_default()).parse()?; + let (stop_tx, stop_rx) = trigger(); - let bind_to = format!("0.0.0.0:{}", port.unwrap_or_default()).parse()?; - - let server = axum::Server::try_bind(&bind_to)?.serve(app.into_make_service()); - let ui_addr = server.local_addr(); + let listener = TcpListener::bind(bind_to).await?; + let ui_addr = listener.local_addr()?; println!("UI bound to: {}", ui_addr); - let stop_tx = Arc::new(Notify::new()); - let stop_rx = stop_tx.clone(); - let server_task = pin!(server.with_graceful_shutdown(stop_rx.notified())); + + let server = + axum::serve(listener, app.into_make_service()).with_graceful_shutdown(async move { + let _ = stop_rx.await; + }); + + let server_task = pin!(server.into_future()); let shutdown_notified = pin!(shutdown_signal.notified()); match select(server_task, shutdown_notified).await { Either::Left((result, _)) => result?, Either::Right((_, server)) => { - stop_tx.notify_one(); + assert!(stop_tx.trigger()); tokio::time::timeout(shutdown_timeout, server).await??; } } diff --git a/example_apps/transit/src/ui.rs b/example_apps/transit/src/ui.rs index 3ff9ebee6..323fb206f 100644 --- a/example_apps/transit/src/ui.rs +++ b/example_apps/transit/src/ui.rs @@ -12,11 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +use axum::body::Body; use axum::http::{header, HeaderValue}; -use axum::{ - body::StreamBody, extract::State, http::StatusCode, response::IntoResponse, routing::get, - Router, -}; +use axum::{extract::State, http::StatusCode, response::IntoResponse, routing::get, Router}; use futures::{TryFutureExt, TryStreamExt}; use tokio::fs::File; use tokio::io::{AsyncBufReadExt, BufReader}; @@ -102,7 +100,7 @@ async fn load_file(path: &str) -> impl IntoResponse { .await { let headers = [(header::CONTENT_LENGTH, HeaderValue::from(len))]; - Ok((headers, StreamBody::new(ReaderStream::new(file)))) + Ok((headers, Body::from_stream(ReaderStream::new(file)))) } else { Err((StatusCode::NOT_FOUND, format!("File not found: {}", target))) } From 6082bc7450c3280f93b865fe2c3bbf6fdb5b3e9d Mon Sep 17 00:00:00 2001 From: SirCipher Date: Wed, 26 Jun 2024 11:24:12 +0100 Subject: [PATCH 16/27] Resolves PR comments --- client/swimos_client/Cargo.toml | 5 +- client/swimos_client/src/lib.rs | 119 ++++++++++++------ runtime/swimos_remote/Cargo.toml | 2 + runtime/swimos_remote/src/tls/config/mod.rs | 12 +- runtime/swimos_remote/src/tls/mod.rs | 37 ++++++ runtime/swimos_remote/src/tls/net/client.rs | 5 +- runtime/swimos_remote/src/tls/net/server.rs | 11 +- runtime/swimos_remote/src/tls/net/tests.rs | 10 +- server/swimos_server_app/Cargo.toml | 4 +- .../src/server/builder/mod.rs | 66 +++++++++- swimos/Cargo.toml | 4 +- 11 files changed, 201 insertions(+), 74 deletions(-) diff --git a/client/swimos_client/Cargo.toml b/client/swimos_client/Cargo.toml index bf9e0e1cf..9053e2e6d 100644 --- a/client/swimos_client/Cargo.toml +++ b/client/swimos_client/Cargo.toml @@ -5,9 +5,10 @@ edition = "2021" [features] default = [] -tls = ["swimos_remote/tls"] deflate = ["runtime/deflate"] trust_dns = ["swimos_runtime/trust_dns"] +ring_provider = ["swimos_remote/ring_provider"] +aws_lc_rs_provider = ["swimos_remote/aws_lc_rs_provider"] [dependencies] runtime = { path = "../runtime" } @@ -25,4 +26,4 @@ tokio = { workspace = true, features = ["sync"] } futures = { workspace = true } futures-util = { workspace = true } tracing = { workspace = true } - +rustls = { workspace = true } diff --git a/client/swimos_client/src/lib.rs b/client/swimos_client/src/lib.rs index fc7ef4693..fa5fe1c36 100644 --- a/client/swimos_client/src/lib.rs +++ b/client/swimos_client/src/lib.rs @@ -12,101 +12,138 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[cfg(not(feature = "deflate"))] -use ratchet::NoExtProvider; -use ratchet::WebSocketStream; -use std::marker::PhantomData; -use std::num::NonZeroUsize; -use swimos_remote::websocket::RatchetClient; +use std::{marker::PhantomData, num::NonZeroUsize, sync::Arc}; use futures_util::future::BoxFuture; -#[cfg(feature = "deflate")] -use ratchet::deflate::{DeflateConfig, DeflateExtProvider}; +use ratchet::{ + deflate::{DeflateConfig, DeflateExtProvider}, + WebSocketStream, +}; +use rustls::crypto::CryptoProvider; +use tokio::{sync::mpsc, sync::mpsc::error::SendError, sync::oneshot::error::RecvError}; +pub use url::Url; + use runtime::{ start_runtime, ClientConfig, DownlinkRuntimeError, RawHandle, Transport, WebSocketConfig, }; pub use runtime::{CommandError, Commander, RemotePath}; -use std::sync::Arc; pub use swimos_client_api::DownlinkConfig; -pub use swimos_downlink::lifecycle::{ - BasicEventDownlinkLifecycle, BasicMapDownlinkLifecycle, BasicValueDownlinkLifecycle, - EventDownlinkLifecycle, MapDownlinkLifecycle, ValueDownlinkLifecycle, +pub use swimos_downlink::{ + lifecycle::BasicEventDownlinkLifecycle, lifecycle::BasicMapDownlinkLifecycle, + lifecycle::BasicValueDownlinkLifecycle, lifecycle::EventDownlinkLifecycle, + lifecycle::MapDownlinkLifecycle, lifecycle::ValueDownlinkLifecycle, }; use swimos_downlink::{ ChannelError, DownlinkTask, EventDownlinkModel, MapDownlinkHandle, MapDownlinkModel, MapKey, MapValue, NotYetSyncedError, ValueDownlinkModel, ValueDownlinkSet, }; use swimos_form::Form; -use swimos_remote::dns::Resolver; -use swimos_remote::plain::TokioPlainTextNetworking; -#[cfg(feature = "tls")] -use swimos_remote::tls::{ClientConfig as TlsConfig, RustlsClientNetworking, TlsError}; -use swimos_remote::ClientConnections; +pub use swimos_remote::tls::ClientConfig as TlsConfig; +use swimos_remote::tls::TlsError; +use swimos_remote::{ + dns::Resolver, + plain::TokioPlainTextNetworking, + tls::{CryptoProviderConfig, RustlsClientNetworking}, + websocket::RatchetClient, + ClientConnections, +}; use swimos_runtime::downlink::{DownlinkOptions, DownlinkRuntimeConfig}; -use swimos_utilities::trigger; -use swimos_utilities::trigger::promise; -use tokio::sync::mpsc; -use tokio::sync::mpsc::error::SendError; -use tokio::sync::oneshot::error::RecvError; -pub use url::Url; +use swimos_utilities::{trigger, trigger::promise}; pub type DownlinkOperationResult = Result; -#[derive(Debug, Default)] +#[derive(Default)] pub struct SwimClientBuilder { - config: ClientConfig, + client_config: ClientConfig, } impl SwimClientBuilder { - pub fn new(config: ClientConfig) -> SwimClientBuilder { - SwimClientBuilder { config } + pub fn new(client_config: ClientConfig) -> SwimClientBuilder { + SwimClientBuilder { client_config } } /// Sets the websocket configuration. pub fn set_websocket_config(mut self, to: WebSocketConfig) -> SwimClientBuilder { - self.config.websocket = to; + self.client_config.websocket = to; self } /// Size of the buffers to communicate with the socket. pub fn set_remote_buffer_size(mut self, to: NonZeroUsize) -> SwimClientBuilder { - self.config.remote_buffer_size = to; + self.client_config.remote_buffer_size = to; self } /// Sets the buffer size between the runtime and transport tasks. pub fn set_transport_buffer_size(mut self, to: NonZeroUsize) -> SwimClientBuilder { - self.config.transport_buffer_size = to; + self.client_config.transport_buffer_size = to; self } /// Sets the deflate extension configuration for WebSocket connections. #[cfg(feature = "deflate")] pub fn set_deflate_config(mut self, to: DeflateConfig) -> SwimClientBuilder { - self.config.websocket.deflate_config = Some(to); + self.client_config.websocket.deflate_config = Some(to); self } + /// Enables TLS support. + pub fn set_tls_config(self, tls_config: TlsConfig) -> SwimClientTlsBuilder { + SwimClientTlsBuilder { + client_config: self.client_config, + tls_config, + crypto_provider: Default::default(), + } + } + /// Builds the client. pub async fn build(self) -> (SwimClient, BoxFuture<'static, ()>) { - let SwimClientBuilder { config } = self; + let SwimClientBuilder { client_config } = self; open_client( - config, + client_config, TokioPlainTextNetworking::new(Arc::new(Resolver::new().await)), ) .await } +} + +pub struct SwimClientTlsBuilder { + client_config: ClientConfig, + tls_config: TlsConfig, + crypto_provider: CryptoProviderConfig, +} + +impl SwimClientTlsBuilder { + /// Uses the process-default [`CryptoProvider`] for any TLS connections. + /// + /// This is only used if the TLS configuration has been set. + pub fn with_default_crypto_provider(mut self) -> Self { + self.crypto_provider = CryptoProviderConfig::ProcessDefault; + self + } + + /// Uses the provided [`CryptoProvider`] for any TLS connections. + /// + /// This is only used if the TLS configuration has been set. + pub fn with_crypto_provider(mut self, provider: Arc) -> Self { + self.crypto_provider = CryptoProviderConfig::Provided(provider); + self + } /// Builds the client using the provided TLS configuration. - #[cfg(feature = "tls")] - pub async fn build_tls( - self, - tls_config: TlsConfig, - ) -> Result<(SwimClient, BoxFuture<'static, ()>), TlsError> { - let SwimClientBuilder { config } = self; + pub async fn build(self) -> Result<(SwimClient, BoxFuture<'static, ()>), TlsError> { + let SwimClientTlsBuilder { + client_config, + tls_config, + crypto_provider, + } = self; Ok(open_client( - config, - RustlsClientNetworking::try_from_config(Arc::new(Resolver::new().await), tls_config)?, + client_config, + RustlsClientNetworking::build( + Arc::new(Resolver::new().await), + tls_config, + crypto_provider.build(), + )?, ) .await) } diff --git a/runtime/swimos_remote/Cargo.toml b/runtime/swimos_remote/Cargo.toml index 6d86dc8c6..2f61417f8 100644 --- a/runtime/swimos_remote/Cargo.toml +++ b/runtime/swimos_remote/Cargo.toml @@ -7,6 +7,8 @@ edition = "2021" [features] default = [] tls = ["rustls", "webpki", "webpki-roots", "tokio-rustls", "rustls-pemfile"] +ring_provider = [] +aws_lc_rs_provider = [] [dependencies] ratchet = { workspace = true, features = ["deflate", "split"] } diff --git a/runtime/swimos_remote/src/tls/config/mod.rs b/runtime/swimos_remote/src/tls/config/mod.rs index d58b68404..533f860df 100644 --- a/runtime/swimos_remote/src/tls/config/mod.rs +++ b/runtime/swimos_remote/src/tls/config/mod.rs @@ -12,9 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use rustls::crypto::CryptoProvider; -use std::sync::Arc; - /// Supported certificate formats for TLS connections. pub enum CertFormat { Pem, @@ -87,17 +84,14 @@ pub struct ServerConfig { /// `SSLKEYLOGFILE` environment variable, and writes keys into it. While this may be enabled, /// if `SSLKEYLOGFILE` is not set, it will do nothing. pub enable_log_file: bool, - /// [`CryptoProvider`] to use when building the [`rustls::ServerConfig`]. - pub provider: Arc, } impl ServerConfig { - pub fn new(chain: CertChain, key: PrivateKey, provider: Arc) -> Self { + pub fn new(chain: CertChain, key: PrivateKey) -> Self { ServerConfig { chain, key, enable_log_file: false, - provider, } } } @@ -106,15 +100,13 @@ impl ServerConfig { pub struct ClientConfig { pub use_webpki_roots: bool, pub custom_roots: Vec, - pub provider: Arc, } impl ClientConfig { - pub fn new(custom_roots: Vec, provider: Arc) -> Self { + pub fn new(custom_roots: Vec) -> Self { ClientConfig { use_webpki_roots: true, custom_roots, - provider, } } } diff --git a/runtime/swimos_remote/src/tls/mod.rs b/runtime/swimos_remote/src/tls/mod.rs index bdab55daf..5018c5c58 100644 --- a/runtime/swimos_remote/src/tls/mod.rs +++ b/runtime/swimos_remote/src/tls/mod.rs @@ -23,3 +23,40 @@ pub use config::{ pub use errors::TlsError; pub use maybe::MaybeTlsStream; pub use net::{RustlsClientNetworking, RustlsListener, RustlsNetworking, RustlsServerNetworking}; +use rustls::crypto::CryptoProvider; +use std::sync::Arc; + +#[derive(Default)] +pub enum CryptoProviderConfig { + ProcessDefault, + #[default] + FromFeatureFlags, + Provided(Arc), +} + +impl CryptoProviderConfig { + pub fn build(self) -> Arc { + match self { + CryptoProviderConfig::ProcessDefault => CryptoProvider::get_default() + .expect("No default cryptographic provider specified") + .clone(), + CryptoProviderConfig::FromFeatureFlags => { + #[cfg(all(feature = "ring_provider", not(feature = "aws_lc_rs_provider")))] + { + return Arc::new(rustls::crypto::ring::default_provider()); + } + + #[cfg(all(feature = "aws_lc_rs_provider", not(feature = "ring_provider")))] + { + return Arc::new(rustls::crypto::aws_lc_rs::default_provider()); + } + + #[allow(unreachable_code)] + { + panic!("Ambiguous cryptographic provider feature flags specified. Only \"ring_provider\" or \"aws_lc_rs_provider\" may be specified") + } + } + CryptoProviderConfig::Provided(provider) => provider, + } + } +} diff --git a/runtime/swimos_remote/src/tls/net/client.rs b/runtime/swimos_remote/src/tls/net/client.rs index 8bc9555c6..180541950 100644 --- a/runtime/swimos_remote/src/tls/net/client.rs +++ b/runtime/swimos_remote/src/tls/net/client.rs @@ -15,6 +15,7 @@ use std::{net::SocketAddr, sync::Arc}; use futures::{future::BoxFuture, FutureExt}; +use rustls::crypto::CryptoProvider; use rustls::pki_types::ServerName; use rustls::RootCertStore; @@ -40,14 +41,14 @@ impl RustlsClientNetworking { } } - pub fn try_from_config( + pub fn build( resolver: Arc, config: ClientConfig, + provider: Arc, ) -> Result { let ClientConfig { use_webpki_roots, custom_roots, - provider, } = config; let mut root_store = RootCertStore::empty(); if use_webpki_roots { diff --git a/runtime/swimos_remote/src/tls/net/server.rs b/runtime/swimos_remote/src/tls/net/server.rs index 25905d28b..06a172c68 100644 --- a/runtime/swimos_remote/src/tls/net/server.rs +++ b/runtime/swimos_remote/src/tls/net/server.rs @@ -22,6 +22,7 @@ use futures::{ stream::{unfold, BoxStream, FuturesUnordered}, Future, FutureExt, Stream, StreamExt, TryStreamExt, }; +use rustls::crypto::CryptoProvider; use rustls::pki_types::PrivateKeyDer; use rustls::KeyLogFile; use rustls_pemfile::Item; @@ -64,17 +65,15 @@ impl RustlsServerNetworking { pub fn new(acceptor: TlsAcceptor) -> Self { RustlsServerNetworking { acceptor } } -} - -impl TryFrom for RustlsServerNetworking { - type Error = TlsError; - fn try_from(config: ServerConfig) -> Result { + pub fn build( + config: ServerConfig, + provider: Arc, + ) -> Result { let ServerConfig { chain: CertChain(certs), key, enable_log_file, - provider, } = config; let mut chain = vec![]; diff --git a/runtime/swimos_remote/src/tls/net/tests.rs b/runtime/swimos_remote/src/tls/net/tests.rs index 811745992..ecf47e14c 100644 --- a/runtime/swimos_remote/src/tls/net/tests.rs +++ b/runtime/swimos_remote/src/tls/net/tests.rs @@ -52,7 +52,6 @@ fn make_server_config() -> ServerConfig { chain, key, enable_log_file: false, - provider: Arc::new(aws_lc_rs::default_provider()), } } @@ -62,17 +61,18 @@ fn make_client_config() -> ClientConfig { ClientConfig { use_webpki_roots: true, custom_roots: vec![CertificateFile::der(ca_cert)], - provider: Arc::new(aws_lc_rs::default_provider()), } } #[tokio::test] async fn perform_handshake() { - let server_net = - RustlsServerNetworking::try_from(make_server_config()).expect("Invalid server config."); - let client_net = RustlsClientNetworking::try_from_config( + let crypto_provider = Arc::new(aws_lc_rs::default_provider()); + let server_net = RustlsServerNetworking::build(make_server_config(), crypto_provider.clone()) + .expect("Invalid server config."); + let client_net = RustlsClientNetworking::build( Arc::new(Resolver::new().await), make_client_config(), + crypto_provider, ) .expect("Invalid client config."); diff --git a/server/swimos_server_app/Cargo.toml b/server/swimos_server_app/Cargo.toml index 57cd650a3..24da9d4d7 100644 --- a/server/swimos_server_app/Cargo.toml +++ b/server/swimos_server_app/Cargo.toml @@ -5,9 +5,11 @@ authors = ["Swim Inc. developers info@swim.ai"] edition = "2021" [features] -default = [] +default = ["aws_lc_rs_provider"] rocks_store = ["swimos_rocks_store"] trust_dns = ["swimos_runtime/trust_dns"] +ring_provider = ["swimos_remote/ring_provider"] +aws_lc_rs_provider = ["swimos_remote/aws_lc_rs_provider"] [dependencies] futures = { workspace = true } diff --git a/server/swimos_server_app/src/server/builder/mod.rs b/server/swimos_server_app/src/server/builder/mod.rs index f75bcfd9a..1a04ecd36 100644 --- a/server/swimos_server_app/src/server/builder/mod.rs +++ b/server/swimos_server_app/src/server/builder/mod.rs @@ -21,7 +21,8 @@ use ratchet::{ deflate::{DeflateConfig, DeflateExtProvider}, NoExtProvider, WebSocketStream, }; -use rustls::crypto::aws_lc_rs; +use rustls::crypto::CryptoProvider; + use swimos_api::{ agent::Agent, error::StoreError, @@ -49,6 +50,41 @@ use super::{ BoxServer, }; +#[derive(Default)] +enum CryptoProviderConfig { + ProcessDefault, + #[default] + FromFeatureFlags, + Provided(Arc), +} + +impl CryptoProviderConfig { + fn build(self) -> Arc { + match self { + CryptoProviderConfig::ProcessDefault => CryptoProvider::get_default() + .expect("No default cryptographic provider specified") + .clone(), + CryptoProviderConfig::FromFeatureFlags => { + #[cfg(all(feature = "ring_provider", not(feature = "aws_lc_rs_provider")))] + { + return Arc::new(rustls::crypto::ring::default_provider()); + } + + #[cfg(all(feature = "aws_lc_rs_provider", not(feature = "ring_provider")))] + { + return Arc::new(rustls::crypto::aws_lc_rs::default_provider()); + } + + #[allow(unreachable_code)] + { + panic!("Ambiguous cryptographic provider feature flags specified. Only \"ring_provider\" or \"aws_lc_rs_provider\" may be specified") + } + } + CryptoProviderConfig::Provided(provider) => provider, + } + } +} + /// Builder for a swimos server that will listen on a socket and run a suite of agents. pub struct ServerBuilder { bind_to: SocketAddr, @@ -58,6 +94,7 @@ pub struct ServerBuilder { config: SwimServerConfig, store_options: StoreConfig, introspection: Option, + crypto_provider: CryptoProviderConfig, } #[non_exhaustive] @@ -85,6 +122,7 @@ impl ServerBuilder { config: Default::default(), store_options: Default::default(), introspection: Default::default(), + crypto_provider: CryptoProviderConfig::default(), } } @@ -160,6 +198,18 @@ impl ServerBuilder { self } + /// Uses the process-default [`CryptoProvider`] for any TLS connections. + pub fn with_default_crypto_provider(mut self) -> Self { + self.crypto_provider = CryptoProviderConfig::ProcessDefault; + self + } + + /// Uses the provided [`CryptoProvider`] for any TLS connections. + pub fn with_crypto_provider(mut self, provider: Arc) -> Self { + self.crypto_provider = CryptoProviderConfig::Provided(provider); + self + } + /// Attempt to make a server instance. This will fail if the routes specified for the /// agents are ambiguous. pub async fn build(self) -> Result { @@ -171,6 +221,7 @@ impl ServerBuilder { config, store_options, introspection, + crypto_provider, } = self; let routes = plane.build()?; if introspection.is_some() { @@ -183,16 +234,19 @@ impl ServerBuilder { deflate, introspection, }; + let crypto_provider = crypto_provider.build(); + if let Some(tls_conf) = tls_config { - let client = RustlsClientNetworking::try_from_config(resolver, tls_conf.client)?; - let server = RustlsServerNetworking::try_from(tls_conf.server)?; + let client = + RustlsClientNetworking::build(resolver, tls_conf.client, crypto_provider.clone())?; + let server = RustlsServerNetworking::build(tls_conf.server, crypto_provider)?; let networking = RustlsNetworking::new_tls(client, server); Ok(with_store(bind_to, routes, networking, config)?) } else { - let provider = Arc::new(aws_lc_rs::default_provider()); - let client = RustlsClientNetworking::try_from_config( + let client = RustlsClientNetworking::build( resolver.clone(), - ClientConfig::new(Default::default(), provider), + ClientConfig::new(Default::default()), + crypto_provider, )?; let server = TokioPlainTextNetworking::new(resolver); let networking = RustlsNetworking::new_plain_text(client, server); diff --git a/swimos/Cargo.toml b/swimos/Cargo.toml index bae39e33d..ea610f3d7 100644 --- a/swimos/Cargo.toml +++ b/swimos/Cargo.toml @@ -5,11 +5,13 @@ authors = ["Swim Inc. developers info@swim.ai"] edition = "2021" [features] -default = ["agent"] +default = ["agent", "aws_lc_rs_provider"] all = ["server", "agent", "json"] server = ["dep:swimos_server_app"] agent = ["dep:swimos_agent", "dep:swimos_agent_derive"] json = ["agent", "swimos_agent/json"] +ring_provider = ["swimos_server_app/ring_provider"] +aws_lc_rs_provider = ["swimos_server_app/aws_lc_rs_provider"] [dependencies] swimos_utilities = { path = "../swimos_utilities", features = ["io", "text"] } From 93d6b94eca154628262f26eca4586b81c7723ebb Mon Sep 17 00:00:00 2001 From: SirCipher Date: Wed, 26 Jun 2024 11:25:12 +0100 Subject: [PATCH 17/27] Removes incorrect comment --- client/swimos_client/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/swimos_client/src/lib.rs b/client/swimos_client/src/lib.rs index fa5fe1c36..b0d3d79a8 100644 --- a/client/swimos_client/src/lib.rs +++ b/client/swimos_client/src/lib.rs @@ -123,8 +123,6 @@ impl SwimClientTlsBuilder { } /// Uses the provided [`CryptoProvider`] for any TLS connections. - /// - /// This is only used if the TLS configuration has been set. pub fn with_crypto_provider(mut self, provider: Arc) -> Self { self.crypto_provider = CryptoProviderConfig::Provided(provider); self From 3d66798244da23399a3011a5a0ab8ac5e81b5dd4 Mon Sep 17 00:00:00 2001 From: SirCipher Date: Wed, 26 Jun 2024 11:26:27 +0100 Subject: [PATCH 18/27] Removes duplicate crypto provider config --- .../src/server/builder/mod.rs | 38 +------------------ 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/server/swimos_server_app/src/server/builder/mod.rs b/server/swimos_server_app/src/server/builder/mod.rs index 1a04ecd36..34fa515ce 100644 --- a/server/swimos_server_app/src/server/builder/mod.rs +++ b/server/swimos_server_app/src/server/builder/mod.rs @@ -31,7 +31,8 @@ use swimos_api::{ use swimos_remote::dns::Resolver; use swimos_remote::plain::TokioPlainTextNetworking; use swimos_remote::tls::{ - ClientConfig, RustlsClientNetworking, RustlsNetworking, RustlsServerNetworking, TlsConfig, + ClientConfig, CryptoProviderConfig, RustlsClientNetworking, RustlsNetworking, + RustlsServerNetworking, TlsConfig, }; use swimos_remote::ExternalConnections; use swimos_utilities::routing::RoutePattern; @@ -50,41 +51,6 @@ use super::{ BoxServer, }; -#[derive(Default)] -enum CryptoProviderConfig { - ProcessDefault, - #[default] - FromFeatureFlags, - Provided(Arc), -} - -impl CryptoProviderConfig { - fn build(self) -> Arc { - match self { - CryptoProviderConfig::ProcessDefault => CryptoProvider::get_default() - .expect("No default cryptographic provider specified") - .clone(), - CryptoProviderConfig::FromFeatureFlags => { - #[cfg(all(feature = "ring_provider", not(feature = "aws_lc_rs_provider")))] - { - return Arc::new(rustls::crypto::ring::default_provider()); - } - - #[cfg(all(feature = "aws_lc_rs_provider", not(feature = "ring_provider")))] - { - return Arc::new(rustls::crypto::aws_lc_rs::default_provider()); - } - - #[allow(unreachable_code)] - { - panic!("Ambiguous cryptographic provider feature flags specified. Only \"ring_provider\" or \"aws_lc_rs_provider\" may be specified") - } - } - CryptoProviderConfig::Provided(provider) => provider, - } - } -} - /// Builder for a swimos server that will listen on a socket and run a suite of agents. pub struct ServerBuilder { bind_to: SocketAddr, From 585bdf81fe75cd21c23b3d93c1651fc43bc6fcc6 Mon Sep 17 00:00:00 2001 From: Greg Holland <30577851+horned-sphere@users.noreply.github.com> Date: Wed, 26 Jun 2024 12:14:04 +0100 Subject: [PATCH 19/27] Reformatted. --- server/swimos_agent/src/agent_lifecycle/utility/mod.rs | 3 ++- server/swimos_agent/src/lanes/join/map/tests.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/server/swimos_agent/src/agent_lifecycle/utility/mod.rs b/server/swimos_agent/src/agent_lifecycle/utility/mod.rs index da215b8b9..a3c30cac5 100644 --- a/server/swimos_agent/src/agent_lifecycle/utility/mod.rs +++ b/server/swimos_agent/src/agent_lifecycle/utility/mod.rs @@ -42,7 +42,8 @@ use crate::event_handler::{ }; use crate::event_handler::{GetAgentUri, HandlerAction, SideEffect}; use crate::item::{ - InspectableMapLikeItem, JoinLikeItem, MapLikeItem, MutableMapLikeItem, MutableValueLikeItem, ValueLikeItem + InspectableMapLikeItem, JoinLikeItem, MapLikeItem, MutableMapLikeItem, MutableValueLikeItem, + ValueLikeItem, }; use crate::lanes::command::{CommandLane, DoCommand}; use crate::lanes::demand::{Cue, DemandLane}; diff --git a/server/swimos_agent/src/lanes/join/map/tests.rs b/server/swimos_agent/src/lanes/join/map/tests.rs index 160e83380..27e1bffb7 100644 --- a/server/swimos_agent/src/lanes/join/map/tests.rs +++ b/server/swimos_agent/src/lanes/join/map/tests.rs @@ -33,7 +33,8 @@ use crate::item::AgentItem; use crate::lanes::join::test_util::{TestDlContextInner, TestDownlinkContext}; use crate::lanes::join_map::default_lifecycle::DefaultJoinMapLifecycle; use crate::lanes::join_map::{ - AddDownlinkAction, JoinMapAddDownlink, JoinMapLaneGet, JoinMapLaneGetMap, JoinMapLaneWithEntry, JoinMapRemoveDownlink, + AddDownlinkAction, JoinMapAddDownlink, JoinMapLaneGet, JoinMapLaneGetMap, JoinMapLaneWithEntry, + JoinMapRemoveDownlink, }; use crate::test_context::{dummy_context, run_event_handlers, run_with_futures}; use crate::{event_handler::StepResult, item::MapItem, meta::AgentMetadata}; From 89fb1d3c5ab6f5e23f7e2566ebbe72534a988921 Mon Sep 17 00:00:00 2001 From: Greg Holland <30577851+horned-sphere@users.noreply.github.com> Date: Wed, 26 Jun 2024 12:28:29 +0100 Subject: [PATCH 20/27] Fixed doc comment. --- server/swimos_agent/src/lanes/map/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/swimos_agent/src/lanes/map/mod.rs b/server/swimos_agent/src/lanes/map/mod.rs index 82bafca6d..a6dd9ac62 100644 --- a/server/swimos_agent/src/lanes/map/mod.rs +++ b/server/swimos_agent/src/lanes/map/mod.rs @@ -591,7 +591,7 @@ where decode.and_then(ProjTransform::new(projection)) } -/// An [`EventHandler`] that will alter an entry in the map. +/// An (event handler)[`crate::event_handler::EventHandler`] that will alter an entry in the map. pub struct MapLaneTransformEntry { projection: for<'a> fn(&'a C) -> &'a MapLane, key_and_f: Option<(K, F)>, From 41624be5c42004b49e3c7e2c0159bcffd4550ae3 Mon Sep 17 00:00:00 2001 From: SirCipher Date: Wed, 26 Jun 2024 14:54:23 +0100 Subject: [PATCH 21/27] Changes crypto provider configuration build failure to return an error instead of panic --- client/swimos_client/src/lib.rs | 2 +- runtime/swimos_remote/src/tls/errors.rs | 2 ++ runtime/swimos_remote/src/tls/mod.rs | 14 +++++++++----- server/swimos_server_app/src/server/builder/mod.rs | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/client/swimos_client/src/lib.rs b/client/swimos_client/src/lib.rs index b0d3d79a8..bc78cbdde 100644 --- a/client/swimos_client/src/lib.rs +++ b/client/swimos_client/src/lib.rs @@ -140,7 +140,7 @@ impl SwimClientTlsBuilder { RustlsClientNetworking::build( Arc::new(Resolver::new().await), tls_config, - crypto_provider.build(), + crypto_provider.try_build()?, )?, ) .await) diff --git a/runtime/swimos_remote/src/tls/errors.rs b/runtime/swimos_remote/src/tls/errors.rs index 03d12ae0a..a8e3b20a4 100644 --- a/runtime/swimos_remote/src/tls/errors.rs +++ b/runtime/swimos_remote/src/tls/errors.rs @@ -32,4 +32,6 @@ pub enum TlsError { /// Performing the TLS handshake failed. #[error("TLS handshake failed: {0}")] HandshakeFailed(std::io::Error), + #[error("Invalid cryptographic provider configured: {0}")] + InvalidCryptoProvider(String), } diff --git a/runtime/swimos_remote/src/tls/mod.rs b/runtime/swimos_remote/src/tls/mod.rs index 5018c5c58..14030ca87 100644 --- a/runtime/swimos_remote/src/tls/mod.rs +++ b/runtime/swimos_remote/src/tls/mod.rs @@ -35,11 +35,15 @@ pub enum CryptoProviderConfig { } impl CryptoProviderConfig { - pub fn build(self) -> Arc { + pub fn try_build(self) -> Result, TlsError> { match self { CryptoProviderConfig::ProcessDefault => CryptoProvider::get_default() - .expect("No default cryptographic provider specified") - .clone(), + .ok_or_else(|| { + TlsError::InvalidCryptoProvider( + "No default cryptographic provider specified".to_string(), + ) + }) + .cloned(), CryptoProviderConfig::FromFeatureFlags => { #[cfg(all(feature = "ring_provider", not(feature = "aws_lc_rs_provider")))] { @@ -53,10 +57,10 @@ impl CryptoProviderConfig { #[allow(unreachable_code)] { - panic!("Ambiguous cryptographic provider feature flags specified. Only \"ring_provider\" or \"aws_lc_rs_provider\" may be specified") + Err(TlsError::InvalidCryptoProvider("Ambiguous cryptographic provider feature flags specified. Only \"ring_provider\" or \"aws_lc_rs_provider\" may be specified".to_string())) } } - CryptoProviderConfig::Provided(provider) => provider, + CryptoProviderConfig::Provided(provider) => Ok(provider), } } } diff --git a/server/swimos_server_app/src/server/builder/mod.rs b/server/swimos_server_app/src/server/builder/mod.rs index 34fa515ce..cbf9b3da9 100644 --- a/server/swimos_server_app/src/server/builder/mod.rs +++ b/server/swimos_server_app/src/server/builder/mod.rs @@ -200,7 +200,7 @@ impl ServerBuilder { deflate, introspection, }; - let crypto_provider = crypto_provider.build(); + let crypto_provider = crypto_provider.try_build()?; if let Some(tls_conf) = tls_config { let client = From 005eda081d3351c86d59f6ef8693fafd23ab12f1 Mon Sep 17 00:00:00 2001 From: Greg Holland <30577851+horned-sphere@users.noreply.github.com> Date: Wed, 26 Jun 2024 15:14:18 +0100 Subject: [PATCH 22/27] Fixed typo. --- server/swimos_agent/src/agent_lifecycle/utility/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/swimos_agent/src/agent_lifecycle/utility/mod.rs b/server/swimos_agent/src/agent_lifecycle/utility/mod.rs index 3916936f4..aec999a17 100644 --- a/server/swimos_agent/src/agent_lifecycle/utility/mod.rs +++ b/server/swimos_agent/src/agent_lifecycle/utility/mod.rs @@ -274,7 +274,7 @@ impl HandlerContext { } /// Create an event handler that will transform the value in an entry of a map lane or store of the agent. - /// If map contains an entry with that key, it will be updated (or removed) based on the result of the calling + /// If the map contains an entry with that key, it will be updated (or removed) based on the result of the calling /// the closure on it. If the map does not contain an entry with that key, the closure will be called with [`None`] /// and an entry will be inserted if it returns a value. /// From 6b3b67ba85e7825d187e7cb54b3a0bb6a56cf4a3 Mon Sep 17 00:00:00 2001 From: SirCipher Date: Wed, 26 Jun 2024 15:19:44 +0100 Subject: [PATCH 23/27] Tidies up crates --- .tarpaulin.toml | 2 +- Cargo.toml | 8 +- api/swimos_form_derive/Cargo.toml | 2 +- api/swimos_form_derive/src/modifiers.rs | 10 +- .../src/structural/model/enumeration/mod.rs | 4 +- .../src/structural/model/field/mod.rs | 14 +- .../src/structural/model/record/mod.rs | 8 +- .../src/structural/read/mod.rs | 2 +- .../src/structural/write/mod.rs | 2 +- api/swimos_form_derive/src/tag/mod.rs | 6 +- client/fixture/Cargo.toml | 18 - client/fixture/src/lib.rs | 440 ----------------- client/runtime/Cargo.toml | 36 -- client/runtime/src/lib.rs | 81 ---- client/swimos_client/Cargo.toml | 28 -- example_apps/aggregations/Cargo.toml | 1 + example_apps/command_lane/Cargo.toml | 1 + example_apps/console/Cargo.toml | 1 + example_apps/console/console_views/Cargo.toml | 1 + example_apps/demand_lane/Cargo.toml | 1 + example_apps/demand_map_lane/Cargo.toml | 1 + .../devguide/2_2/example_client/Cargo.toml | 3 +- .../devguide/2_2/example_server/Cargo.toml | 1 + .../devguide/2_3/example_client/Cargo.toml | 3 +- .../devguide/2_3/example_server/Cargo.toml | 1 + example_apps/event_downlink/Cargo.toml | 1 + example_apps/example_util/Cargo.toml | 1 + example_apps/http_lane/Cargo.toml | 1 + example_apps/join_map/Cargo.toml | 1 + example_apps/join_value/Cargo.toml | 1 + example_apps/local_downlink/Cargo.toml | 1 + example_apps/map_downlink/Cargo.toml | 1 + example_apps/map_lane/Cargo.toml | 1 + example_apps/map_lane_persistence/Cargo.toml | 1 + example_apps/map_store/Cargo.toml | 1 + example_apps/map_store_persistence/Cargo.toml | 1 + example_apps/supply_lane/Cargo.toml | 1 + example_apps/time_series/Cargo.toml | 1 + example_apps/transit/Cargo.toml | 1 + example_apps/transit/transit-model/Cargo.toml | 1 + example_apps/tutorial_app/Cargo.toml | 1 + .../tutorial_app/generator/Cargo.toml | 3 +- .../tutorial_app/generator/src/main.rs | 3 +- example_apps/tutorial_app/model/Cargo.toml | 1 + example_apps/value_downlink/Cargo.toml | 1 + example_apps/value_lane/Cargo.toml | 1 + .../value_lane_persistence/Cargo.toml | 1 + example_apps/value_store/Cargo.toml | 1 + .../value_store_persistence/Cargo.toml | 1 + server/swimos_agent_derive/Cargo.toml | 2 +- .../src/lane_model_derive/attributes/mod.rs | 2 +- .../src/lane_model_derive/model.rs | 4 +- server/swimos_agent_derive/src/lib.rs | 2 +- swimos_client/Cargo.toml | 34 ++ .../mod.rs => swimos_client/src/commander.rs | 0 .../runtime => swimos_client}/src/error.rs | 9 - .../src/lib.rs | 95 +++- .../runtime => swimos_client}/src/models.rs | 0 .../runtime => swimos_client}/src/pending.rs | 0 .../runtime => swimos_client}/src/runtime.rs | 0 .../runtime => swimos_client}/src/tests.rs | 455 +++++++++++++++++- .../src/transport.rs | 0 .../Cargo.toml | 2 +- .../src/attributes/mod.rs | 0 .../src/form.rs | 0 .../src/generics.rs | 0 .../src/label.rs | 0 .../src/lib.rs | 0 .../src/names/mod.rs | 0 .../src/utilities.rs | 0 70 files changed, 617 insertions(+), 691 deletions(-) delete mode 100644 client/fixture/Cargo.toml delete mode 100644 client/fixture/src/lib.rs delete mode 100644 client/runtime/Cargo.toml delete mode 100644 client/runtime/src/lib.rs delete mode 100644 client/swimos_client/Cargo.toml create mode 100644 swimos_client/Cargo.toml rename client/runtime/src/commander/mod.rs => swimos_client/src/commander.rs (100%) rename {client/runtime => swimos_client}/src/error.rs (93%) rename {client/swimos_client => swimos_client}/src/lib.rs (89%) rename {client/runtime => swimos_client}/src/models.rs (100%) rename {client/runtime => swimos_client}/src/pending.rs (100%) rename {client/runtime => swimos_client}/src/runtime.rs (100%) rename {client/runtime => swimos_client}/src/tests.rs (64%) rename {client/runtime => swimos_client}/src/transport.rs (100%) rename {macro_utilities => swimos_macro_utilities}/Cargo.toml (92%) rename {macro_utilities => swimos_macro_utilities}/src/attributes/mod.rs (100%) rename {macro_utilities => swimos_macro_utilities}/src/form.rs (100%) rename {macro_utilities => swimos_macro_utilities}/src/generics.rs (100%) rename {macro_utilities => swimos_macro_utilities}/src/label.rs (100%) rename {macro_utilities => swimos_macro_utilities}/src/lib.rs (100%) rename {macro_utilities => swimos_macro_utilities}/src/names/mod.rs (100%) rename {macro_utilities => swimos_macro_utilities}/src/utilities.rs (100%) diff --git a/.tarpaulin.toml b/.tarpaulin.toml index 904e5d5f2..0e215b7b4 100644 --- a/.tarpaulin.toml +++ b/.tarpaulin.toml @@ -31,7 +31,7 @@ exclude = [ "time_series", "swimos_form_derive", "swimos_agent_derive", - "macro_utilities", + "swimos_macro_utilities", "example_client_2_2", "example_server_2_2", "example_client_2_3", diff --git a/Cargo.toml b/Cargo.toml index fc2b171e2..5c7b51356 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [workspace] resolver = "2" members = [ - "client/*", + "swimos_client", "swimos", "api/swimos_*", "api/formats/swimos_*", - "macro_utilities", + "swimos_macro_utilities", "runtime/swimos_*", "swimos_utilities", "swimos_utilities/swimos_*", @@ -44,10 +44,6 @@ members = [ "example_apps/devguide/2_3/*", ] -exclude = [ - "cookbook" -] - [profile.release] opt-level = 3 diff --git a/api/swimos_form_derive/Cargo.toml b/api/swimos_form_derive/Cargo.toml index 9c64ab52b..e88a410b5 100644 --- a/api/swimos_form_derive/Cargo.toml +++ b/api/swimos_form_derive/Cargo.toml @@ -11,7 +11,7 @@ proc-macro = true [dependencies] either = { workspace = true } swimos_utilities = { path = "../../swimos_utilities", features = ["errors", "text"] } -macro_utilities = { path = "../../macro_utilities" } +swimos_macro_utilities = { path = "../../swimos_macro_utilities" } proc-macro2 = { workspace = true } syn = { workspace = true, features = ["full"] } quote = { workspace = true } diff --git a/api/swimos_form_derive/src/modifiers.rs b/api/swimos_form_derive/src/modifiers.rs index b9f32c0c8..3fa3d2d62 100644 --- a/api/swimos_form_derive/src/modifiers.rs +++ b/api/swimos_form_derive/src/modifiers.rs @@ -14,13 +14,15 @@ use crate::structural::model::field::FieldSelector; use crate::SynValidation; -use macro_utilities::attr_names::{CONV_NAME, FIELDS_NAME, NEWTYPE_PATH, SCHEMA_NAME, TAG_NAME}; -use macro_utilities::attributes::{IgnoreConsumer, NestedMetaConsumer}; -use macro_utilities::{ +use quote::ToTokens; +use swimos_macro_utilities::attr_names::{ + CONV_NAME, FIELDS_NAME, NEWTYPE_PATH, SCHEMA_NAME, TAG_NAME, +}; +use swimos_macro_utilities::attributes::{IgnoreConsumer, NestedMetaConsumer}; +use swimos_macro_utilities::{ CaseConvention, NameTransform, NameTransformConsumer, Symbol, Transformation, TypeLevelNameTransform, TypeLevelNameTransformConsumer, }; -use quote::ToTokens; use swimos_utilities::errors::Errors; use swimos_utilities::errors::{Validation, ValidationItExt}; diff --git a/api/swimos_form_derive/src/structural/model/enumeration/mod.rs b/api/swimos_form_derive/src/structural/model/enumeration/mod.rs index 1165a27c3..003b36514 100644 --- a/api/swimos_form_derive/src/structural/model/enumeration/mod.rs +++ b/api/swimos_form_derive/src/structural/model/enumeration/mod.rs @@ -16,10 +16,10 @@ use crate::modifiers::{combine_enum_trans_parts, EnumPartConsumer, StructTransfo use crate::structural::model::record::{SegregatedStructModel, StructDef, StructModel}; use crate::structural::model::ValidateFrom; use crate::SynValidation; -use macro_utilities::attr_names::FORM_NAME; -use macro_utilities::attributes::consume_attributes; use quote::ToTokens; use std::collections::HashSet; +use swimos_macro_utilities::attr_names::FORM_NAME; +use swimos_macro_utilities::attributes::consume_attributes; use swimos_utilities::errors::Errors; use swimos_utilities::errors::{Validation, ValidationItExt}; use syn::{Attribute, DataEnum, Ident}; diff --git a/api/swimos_form_derive/src/structural/model/field/mod.rs b/api/swimos_form_derive/src/structural/model/field/mod.rs index 4977d987f..4490af7f5 100644 --- a/api/swimos_form_derive/src/structural/model/field/mod.rs +++ b/api/swimos_form_derive/src/structural/model/field/mod.rs @@ -13,16 +13,18 @@ // limitations under the License. use crate::SynValidation; -use macro_utilities::attr_names::{ - ATTR_PATH, BODY_PATH, CONV_NAME, FORM_PATH, HEADER_BODY_PATH, HEADER_PATH, NAME_NAME, - SCHEMA_NAME, SKIP_PATH, SLOT_PATH, TAG_PATH, -}; -use macro_utilities::attributes::NestedMetaConsumer; -use macro_utilities::{FieldKind, NameTransform, NameTransformConsumer, Symbol, Transformation}; use proc_macro2::TokenStream; use quote::{ToTokens, TokenStreamExt}; use std::borrow::Cow; use std::ops::Add; +use swimos_macro_utilities::attr_names::{ + ATTR_PATH, BODY_PATH, CONV_NAME, FORM_PATH, HEADER_BODY_PATH, HEADER_PATH, NAME_NAME, + SCHEMA_NAME, SKIP_PATH, SLOT_PATH, TAG_PATH, +}; +use swimos_macro_utilities::attributes::NestedMetaConsumer; +use swimos_macro_utilities::{ + FieldKind, NameTransform, NameTransformConsumer, Symbol, Transformation, +}; use swimos_utilities::errors::Validation; use syn::{Field, Ident, Meta, NestedMeta, Type}; diff --git a/api/swimos_form_derive/src/structural/model/record/mod.rs b/api/swimos_form_derive/src/structural/model/record/mod.rs index 089d4f5b6..5d55e63f4 100644 --- a/api/swimos_form_derive/src/structural/model/record/mod.rs +++ b/api/swimos_form_derive/src/structural/model/record/mod.rs @@ -22,14 +22,14 @@ use crate::structural::model::field::{ }; use crate::structural::model::StructLike; use crate::SynValidation; -use macro_utilities::attr_names::FORM_NAME; -use macro_utilities::attributes::consume_attributes; -use macro_utilities::CompoundTypeKind; -use macro_utilities::FieldKind; use proc_macro2::TokenStream; use quote::ToTokens; use std::collections::HashSet; use std::ops::Add; +use swimos_macro_utilities::attr_names::FORM_NAME; +use swimos_macro_utilities::attributes::consume_attributes; +use swimos_macro_utilities::CompoundTypeKind; +use swimos_macro_utilities::FieldKind; use swimos_utilities::errors::Errors; use swimos_utilities::errors::{validate2, Validation, ValidationItExt}; use swimos_utilities::format::comma_sep; diff --git a/api/swimos_form_derive/src/structural/read/mod.rs b/api/swimos_form_derive/src/structural/read/mod.rs index 3ed0e930c..c586db1fe 100644 --- a/api/swimos_form_derive/src/structural/read/mod.rs +++ b/api/swimos_form_derive/src/structural/read/mod.rs @@ -19,7 +19,7 @@ use proc_macro2::{Span, TokenStream}; use quote::ToTokens; use syn::{Generics, TypeGenerics}; -use macro_utilities::{CompoundTypeKind, FieldKind}; +use swimos_macro_utilities::{CompoundTypeKind, FieldKind}; use crate::quote::TokenStreamExt; use crate::structural::model::enumeration::SegregatedEnumModel; diff --git a/api/swimos_form_derive/src/structural/write/mod.rs b/api/swimos_form_derive/src/structural/write/mod.rs index f42c350f8..57a706548 100644 --- a/api/swimos_form_derive/src/structural/write/mod.rs +++ b/api/swimos_form_derive/src/structural/write/mod.rs @@ -19,9 +19,9 @@ use crate::structural::model::field::{ }; use crate::structural::model::record::{SegregatedStructModel, StructModel}; use either::Either; -use macro_utilities::CompoundTypeKind; use proc_macro2::TokenStream; use quote::ToTokens; +use swimos_macro_utilities::CompoundTypeKind; use syn::{Generics, Pat, Path}; /// Implements the StructuralWritable trait for either of [`SegregatedStructModel`] or diff --git a/api/swimos_form_derive/src/tag/mod.rs b/api/swimos_form_derive/src/tag/mod.rs index 91021f7d7..303f443a7 100644 --- a/api/swimos_form_derive/src/tag/mod.rs +++ b/api/swimos_form_derive/src/tag/mod.rs @@ -13,12 +13,12 @@ // limitations under the License. use crate::quote::TokenStreamExt; -use macro_utilities::attr_names::{CONV_NAME, FORM_NAME, TAG_NAME}; -use macro_utilities::attributes::consume_attributes; -use macro_utilities::{combine_name_transform, NameTransform, NameTransformConsumer}; use proc_macro2::TokenStream; use quote::ToTokens; use std::fmt::{Display, Formatter}; +use swimos_macro_utilities::attr_names::{CONV_NAME, FORM_NAME, TAG_NAME}; +use swimos_macro_utilities::attributes::consume_attributes; +use swimos_macro_utilities::{combine_name_transform, NameTransform, NameTransformConsumer}; use swimos_utilities::errors::Errors; use swimos_utilities::errors::{Validation, ValidationItExt}; diff --git a/client/fixture/Cargo.toml b/client/fixture/Cargo.toml deleted file mode 100644 index d381a464e..000000000 --- a/client/fixture/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "fixture" -version = "0.1.0" -edition = "2021" - -[dependencies] -swimos_remote = { path = "../../runtime/swimos_remote" } -swimos_messages = { path = "../../runtime/swimos_messages" } -swimos_api = { path = "../../api/swimos_api" } -ratchet = { features = ["deflate", "split"], workspace = true } -swimos_recon = { path = "../../api/formats/swimos_recon" } -swimos_model = { path = "../../api/swimos_model" } -swimos_form = { path = "../../api/swimos_form" } -tokio-util = { workspace = true, features = ["codec"] } -futures = { workspace = true } -futures-util = { workspace = true } -bytes = { workspace = true } -tokio = { workspace = true, features = ["io-util"] } diff --git a/client/fixture/src/lib.rs b/client/fixture/src/lib.rs deleted file mode 100644 index 038612422..000000000 --- a/client/fixture/src/lib.rs +++ /dev/null @@ -1,440 +0,0 @@ -use bytes::BytesMut; -use futures_util::future::{ready, BoxFuture}; -use futures_util::stream::BoxStream; -use futures_util::{FutureExt, StreamExt}; -use ratchet::{ - ExtensionProvider, Message, NegotiatedExtension, NoExt, PayloadType, Role, WebSocket, - WebSocketConfig, WebSocketStream, -}; -use std::borrow::BorrowMut; -use std::collections::HashMap; -use std::io; -use std::io::ErrorKind; -use std::net::SocketAddr; -use std::ops::DerefMut; -use std::sync::Arc; -use swimos_form::Form; -use swimos_messages::remote_protocol::FindNode; -use swimos_model::{Text, Value}; -use swimos_recon::parser::parse_recognize; -use swimos_recon::print_recon; -use swimos_remote::dns::{BoxDnsResolver, DnsResolver}; -use swimos_remote::websocket::{RatchetError, WebsocketClient, WebsocketServer, WsOpenFuture}; -use swimos_remote::{ - ClientConnections, ConnectionError, ConnectionResult, Listener, ListenerError, Scheme, -}; -use tokio::io::{AsyncRead, AsyncWrite, DuplexStream}; -use tokio::sync::mpsc; -use tokio::sync::Mutex; - -#[derive(Debug)] -struct Inner { - addrs: HashMap<(String, u16), SocketAddr>, - sockets: HashMap, -} - -impl Inner { - fn new(resolver: R, sockets: S) -> Inner - where - R: IntoIterator, - S: IntoIterator, - { - Inner { - addrs: HashMap::from_iter(resolver), - sockets: HashMap::from_iter(sockets), - } - } -} - -#[derive(Debug, Clone)] -pub struct MockClientConnections { - inner: Arc>, -} - -impl MockClientConnections { - pub fn new(resolver: R, sockets: S) -> MockClientConnections - where - R: IntoIterator, - S: IntoIterator, - { - MockClientConnections { - inner: Arc::new(Mutex::new(Inner::new(resolver, sockets))), - } - } -} - -impl ClientConnections for MockClientConnections { - type ClientSocket = DuplexStream; - - fn try_open( - &self, - _scheme: Scheme, - _host: Option<&str>, - addr: SocketAddr, - ) -> BoxFuture<'_, ConnectionResult> { - async move { - self.inner - .lock() - .await - .sockets - .remove(&addr) - .ok_or_else(|| ConnectionError::ConnectionFailed(ErrorKind::NotFound.into())) - } - .boxed() - } - - fn dns_resolver(&self) -> BoxDnsResolver { - Box::new(self.clone()) - } - - fn lookup( - &self, - host: String, - port: u16, - ) -> BoxFuture<'static, std::io::Result>> { - self.resolve(host, port).boxed() - } -} - -impl DnsResolver for MockClientConnections { - type ResolveFuture = BoxFuture<'static, io::Result>>; - - fn resolve(&self, host: String, port: u16) -> Self::ResolveFuture { - let inner = self.inner.clone(); - async move { - match inner.lock().await.addrs.get(&(host, port)) { - Some(sock) => Ok(vec![*sock]), - None => Err(io::ErrorKind::NotFound.into()), - } - } - .boxed() - } -} - -pub enum WsAction { - Open, - Fail(Box RatchetError + Send + Sync + 'static>), -} - -impl WsAction { - pub fn fail(with: F) -> WsAction - where - F: Fn() -> RatchetError + Send + Sync + 'static, - { - WsAction::Fail(Box::new(with)) - } -} - -pub struct MockWs { - states: HashMap, -} - -impl MockWs { - pub fn new(states: S) -> MockWs - where - S: IntoIterator, - { - MockWs { - states: HashMap::from_iter(states), - } - } -} - -impl WebsocketClient for MockWs { - fn open_connection<'a, Sock, Provider>( - &self, - socket: Sock, - _provider: &'a Provider, - addr: String, - ) -> WsOpenFuture<'a, Sock, Provider::Extension, RatchetError> - where - Sock: WebSocketStream + Send, - Provider: ExtensionProvider + Send + Sync + 'static, - Provider::Extension: Send + Sync + 'static, - { - let result = match self.states.get(&addr) { - Some(WsAction::Open) => Ok(WebSocket::from_upgraded( - WebSocketConfig::default(), - socket, - NegotiatedExtension::from(None), - BytesMut::default(), - Role::Client, - )), - Some(WsAction::Fail(e)) => Err(e()), - None => Err(ratchet::Error::new(ratchet::ErrorKind::Http).into()), - }; - ready(result).boxed() - } -} - -impl WebsocketServer for MockWs { - type WsStream = - BoxStream<'static, Result<(WebSocket, SocketAddr), ListenerError>>; - - fn wrap_listener( - &self, - _listener: L, - _provider: Provider, - _find: mpsc::Sender, - ) -> Self::WsStream - where - Sock: AsyncRead + AsyncWrite + Unpin + Send + Sync + 'static, - L: Listener + Send + 'static, - Provider: ExtensionProvider + Send + Sync + Unpin + 'static, - Provider::Extension: Send + Sync + Unpin + 'static, - { - futures::stream::pending().boxed() - } -} - -#[derive(Clone, Debug, PartialEq, Form)] - -pub enum Envelope { - #[form(tag = "link")] - Link { - #[form(name = "node")] - node_uri: Text, - #[form(name = "lane")] - lane_uri: Text, - rate: Option, - prio: Option, - #[form(body)] - body: Option, - }, - #[form(tag = "sync")] - Sync { - #[form(name = "node")] - node_uri: Text, - #[form(name = "lane")] - lane_uri: Text, - rate: Option, - prio: Option, - #[form(body)] - body: Option, - }, - #[form(tag = "unlink")] - Unlink { - #[form(name = "node")] - node_uri: Text, - #[form(name = "lane")] - lane_uri: Text, - #[form(body)] - body: Option, - }, - #[form(tag = "command")] - Command { - #[form(name = "node")] - node_uri: Text, - #[form(name = "lane")] - lane_uri: Text, - #[form(body)] - body: Option, - }, - #[form(tag = "linked")] - Linked { - #[form(name = "node")] - node_uri: Text, - #[form(name = "lane")] - lane_uri: Text, - rate: Option, - prio: Option, - #[form(body)] - body: Option, - }, - #[form(tag = "synced")] - Synced { - #[form(name = "node")] - node_uri: Text, - #[form(name = "lane")] - lane_uri: Text, - #[form(body)] - body: Option, - }, - #[form(tag = "unlinked")] - Unlinked { - #[form(name = "node")] - node_uri: Text, - #[form(name = "lane")] - lane_uri: Text, - #[form(body)] - body: Option, - }, - #[form(tag = "event")] - Event { - #[form(name = "node")] - node_uri: Text, - #[form(name = "lane")] - lane_uri: Text, - #[form(body)] - body: Option, - }, -} - -pub struct Lane { - node: String, - lane: String, - server: Arc>, -} - -impl Lane { - pub async fn read(&mut self) -> Envelope { - let Lane { server, .. } = self; - let mut guard = server.lock().await; - let Server { buf, transport } = &mut guard.deref_mut(); - - match transport.read(buf).await.unwrap() { - Message::Text => {} - m => panic!("Unexpected message type: {:?}", m), - } - let read = String::from_utf8(buf.to_vec()).unwrap(); - buf.clear(); - - parse_recognize::(read.as_str(), false).unwrap() - } - - pub async fn write(&mut self, env: Envelope) { - let Lane { server, .. } = self; - let mut guard = server.lock().await; - let Server { transport, .. } = &mut guard.deref_mut(); - - let response = print_recon(&env); - transport - .write(format!("{}", response), PayloadType::Text) - .await - .unwrap(); - } - - pub async fn write_bytes(&mut self, msg: &[u8]) { - let Lane { server, .. } = self; - let mut guard = server.lock().await; - let Server { transport, .. } = &mut guard.deref_mut(); - - transport.write(msg, PayloadType::Text).await.unwrap(); - } - - pub async fn await_link(&mut self) { - match self.read().await { - Envelope::Link { - node_uri, lane_uri, .. - } => { - assert_eq!(node_uri, self.node); - assert_eq!(lane_uri, self.lane); - self.write(Envelope::Linked { - node_uri: node_uri.clone(), - lane_uri: lane_uri.clone(), - rate: None, - prio: None, - body: None, - }) - .await; - } - e => panic!("Unexpected envelope {:?}", e), - } - } - - pub async fn await_sync(&mut self, val: Vec) { - match self.read().await { - Envelope::Sync { - node_uri, lane_uri, .. - } => { - assert_eq!(node_uri, self.node); - assert_eq!(lane_uri, self.lane); - - for v in val { - self.write(Envelope::Event { - node_uri: node_uri.clone(), - lane_uri: lane_uri.clone(), - body: Some(v.as_value()), - }) - .await; - } - - self.write(Envelope::Synced { - node_uri: node_uri.clone(), - lane_uri: lane_uri.clone(), - body: None, - }) - .await; - } - e => panic!("Unexpected envelope {:?}", e), - } - } - - pub async fn await_command(&mut self, expected: i32) { - match self.read().await { - Envelope::Command { - node_uri, - lane_uri, - body: Some(val), - } => { - assert_eq!(node_uri, self.node); - assert_eq!(lane_uri, self.lane); - assert_eq!(val, Value::Int32Value(expected)); - } - e => panic!("Unexpected envelope {:?}", e), - } - } - - pub async fn send_unlinked(&mut self) { - self.write(Envelope::Unlinked { - node_uri: self.node.clone().into(), - lane_uri: self.lane.clone().into(), - body: None, - }) - .await; - } - - pub async fn send_event(&mut self, val: V) { - self.write(Envelope::Event { - node_uri: self.node.clone().into(), - lane_uri: self.lane.clone().into(), - body: Some(val.as_value()), - }) - .await; - } - - pub async fn await_closed(&mut self) { - let Lane { server, .. } = self; - let mut guard = server.lock().await; - let Server { buf, transport } = &mut guard.deref_mut(); - - match transport.borrow_mut().read(buf).await.unwrap() { - Message::Close(_) => {} - m => panic!("Unexpected message type: {:?}", m), - } - } -} - -pub struct Server { - pub buf: BytesMut, - pub transport: WebSocket, -} - -impl Server { - pub fn lane_for(server: Arc>, node: N, lane: L) -> Lane - where - N: ToString, - L: ToString, - { - Lane { - node: node.to_string(), - lane: lane.to_string(), - server, - } - } -} - -impl Server { - pub fn new(transport: DuplexStream) -> Server { - Server { - buf: BytesMut::new(), - transport: WebSocket::from_upgraded( - WebSocketConfig::default(), - transport, - NegotiatedExtension::from(NoExt), - BytesMut::default(), - Role::Server, - ), - } - } -} diff --git a/client/runtime/Cargo.toml b/client/runtime/Cargo.toml deleted file mode 100644 index 75323622c..000000000 --- a/client/runtime/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -name = "runtime" -version = "0.1.0" -edition = "2021" - -[features] -default = [] -deflate = ["ratchet/deflate"] - -[dependencies] -fixture = { path = "../fixture" } -swimos_downlink = { path = "../../swimos_downlink" } -swimos_api = { path = "../../api/swimos_api" } -swimos_client_api = { path = "../../api/swimos_client_api" } -swimos_agent_protocol = { path = "../../api/swimos_agent_protocol" } -swimos_model = { path = "../../api/swimos_model" } -swimos_recon = { path = "../../api/formats/swimos_recon" } -swimos_form = { path = "../../api/swimos_form" } -swimos_utilities = { path = "../../swimos_utilities", features = ["buf_channel", "trigger", "algebra"] } -swimos_runtime = { path = "../../runtime/swimos_runtime" } -swimos_remote = { path = "../../runtime/swimos_remote" } -swimos_messages = { path = "../../runtime/swimos_messages" } -ratchet = { features = ["deflate", "split"], workspace = true } -futures = { workspace = true } -futures-util = { workspace = true } -bytes = { workspace = true } -tokio = { workspace = true, features = ["io-util", "sync"] } -tokio-util = { workspace = true, features = ["codec"] } -url = { workspace = true } -fnv = { workspace = true } -thiserror = { workspace = true } -uuid = { workspace = true } -tracing = { workspace = true } - -[dev-dependencies] -tokio = { workspace = true, features = ["rt-multi-thread", "macros", "test-util"] } diff --git a/client/runtime/src/lib.rs b/client/runtime/src/lib.rs deleted file mode 100644 index a8e009146..000000000 --- a/client/runtime/src/lib.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2015-2024 Swim Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::fmt::Debug; -use std::num::NonZeroUsize; -use std::time::Duration; - -pub use crate::runtime::{start_runtime, RawHandle}; -pub use commander::{CommandError, Commander}; -pub use error::{DownlinkErrorKind, DownlinkRuntimeError, TimeoutElapsed}; -pub use models::RemotePath; -#[cfg(feature = "deflate")] -use ratchet::deflate::DeflateConfig; -pub use swimos_api::agent::DownlinkKind; -pub use swimos_api::error::DownlinkTaskError; -use swimos_utilities::non_zero_usize; -pub use transport::Transport; - -#[cfg(test)] -mod tests; - -mod commander; -mod error; -mod models; -mod pending; -mod runtime; -mod transport; - -const DEFAULT_BUFFER_SIZE: NonZeroUsize = non_zero_usize!(32); -const DEFAULT_CLOSE_TIMEOUT: Duration = Duration::from_secs(5); - -#[derive(Debug)] -pub struct WebSocketConfig { - pub max_message_size: usize, - #[cfg(feature = "deflate")] - pub deflate_config: Option, -} - -impl Default for WebSocketConfig { - fn default() -> Self { - WebSocketConfig { - max_message_size: 64 << 20, - #[cfg(feature = "deflate")] - deflate_config: None, - } - } -} - -#[derive(Debug)] -pub struct ClientConfig { - pub websocket: WebSocketConfig, - pub remote_buffer_size: NonZeroUsize, - pub transport_buffer_size: NonZeroUsize, - pub registration_buffer_size: NonZeroUsize, - pub close_timeout: Duration, - pub interpret_frame_data: bool, -} - -impl Default for ClientConfig { - fn default() -> Self { - ClientConfig { - websocket: WebSocketConfig::default(), - remote_buffer_size: non_zero_usize!(4096), - transport_buffer_size: DEFAULT_BUFFER_SIZE, - registration_buffer_size: DEFAULT_BUFFER_SIZE, - close_timeout: DEFAULT_CLOSE_TIMEOUT, - interpret_frame_data: true, - } - } -} diff --git a/client/swimos_client/Cargo.toml b/client/swimos_client/Cargo.toml deleted file mode 100644 index bf9e0e1cf..000000000 --- a/client/swimos_client/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "swimos_client" -version = "0.1.0" -edition = "2021" - -[features] -default = [] -tls = ["swimos_remote/tls"] -deflate = ["runtime/deflate"] -trust_dns = ["swimos_runtime/trust_dns"] - -[dependencies] -runtime = { path = "../runtime" } -swimos_utilities = { path = "../../swimos_utilities", features = ["trigger"] } -swimos_downlink = { path = "../../swimos_downlink" } -swimos_api = { path = "../../api/swimos_api" } -swimos_client_api = { path = "../../api/swimos_client_api" } -swimos_model = { path = "../../api/swimos_model" } -swimos_form = { path = "../../api/swimos_form" } -swimos_runtime = { path = "../../runtime/swimos_runtime" } -swimos_remote = { path = "../../runtime/swimos_remote" } -ratchet = { workspace = true } -url = { workspace = true } -tokio = { workspace = true, features = ["sync"] } -futures = { workspace = true } -futures-util = { workspace = true } -tracing = { workspace = true } - diff --git a/example_apps/aggregations/Cargo.toml b/example_apps/aggregations/Cargo.toml index dd5067dae..4e18c95ca 100644 --- a/example_apps/aggregations/Cargo.toml +++ b/example_apps/aggregations/Cargo.toml @@ -2,6 +2,7 @@ name = "aggregations" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/command_lane/Cargo.toml b/example_apps/command_lane/Cargo.toml index 4b7a2fb98..883974ce1 100644 --- a/example_apps/command_lane/Cargo.toml +++ b/example_apps/command_lane/Cargo.toml @@ -2,6 +2,7 @@ name = "command-lane" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/console/Cargo.toml b/example_apps/console/Cargo.toml index 00c05f9dc..ef59d962a 100644 --- a/example_apps/console/Cargo.toml +++ b/example_apps/console/Cargo.toml @@ -2,6 +2,7 @@ name = "console" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos_utilities = { path = "../../swimos_utilities", features = ["trigger"] } diff --git a/example_apps/console/console_views/Cargo.toml b/example_apps/console/console_views/Cargo.toml index ecc15e125..426a311a2 100644 --- a/example_apps/console/console_views/Cargo.toml +++ b/example_apps/console/console_views/Cargo.toml @@ -3,6 +3,7 @@ name = "console-views" version = "0.1.0" authors = ["Swim Inc. developers info@swim.ai"] edition = "2021" +publish = false [dependencies] cursive = { workspace = true } diff --git a/example_apps/demand_lane/Cargo.toml b/example_apps/demand_lane/Cargo.toml index 246305942..7a6c4aeb3 100644 --- a/example_apps/demand_lane/Cargo.toml +++ b/example_apps/demand_lane/Cargo.toml @@ -2,6 +2,7 @@ name = "demand-lane" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/demand_map_lane/Cargo.toml b/example_apps/demand_map_lane/Cargo.toml index d1999a0fa..527cd75a0 100644 --- a/example_apps/demand_map_lane/Cargo.toml +++ b/example_apps/demand_map_lane/Cargo.toml @@ -2,6 +2,7 @@ name = "demand-map-lane" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/devguide/2_2/example_client/Cargo.toml b/example_apps/devguide/2_2/example_client/Cargo.toml index 9183041a5..88545ff81 100644 --- a/example_apps/devguide/2_2/example_client/Cargo.toml +++ b/example_apps/devguide/2_2/example_client/Cargo.toml @@ -2,8 +2,9 @@ name = "example_client_2_2" version = "0.1.0" edition = "2021" +publish = false [dependencies] tokio = { workspace = true, features = ["full"] } -swimos_client = { path = "../../../../client/swimos_client" } +swimos_client = { path = "../../../../swimos_client" } swimos_form = { path = "../../../../api/swimos_form" } \ No newline at end of file diff --git a/example_apps/devguide/2_2/example_server/Cargo.toml b/example_apps/devguide/2_2/example_server/Cargo.toml index 0ede66706..3a142eaf9 100644 --- a/example_apps/devguide/2_2/example_server/Cargo.toml +++ b/example_apps/devguide/2_2/example_server/Cargo.toml @@ -2,6 +2,7 @@ name = "example_server_2_2" version = "0.1.0" edition = "2021" +publish = false [dependencies] tokio = { workspace = true, features = ["full"] } diff --git a/example_apps/devguide/2_3/example_client/Cargo.toml b/example_apps/devguide/2_3/example_client/Cargo.toml index 1fa19be12..b5fc51a92 100644 --- a/example_apps/devguide/2_3/example_client/Cargo.toml +++ b/example_apps/devguide/2_3/example_client/Cargo.toml @@ -2,8 +2,9 @@ name = "example_client_2_3" version = "0.1.0" edition = "2021" +publish = false [dependencies] tokio = { workspace = true, features = ["full"] } -swimos_client = { path = "../../../../client/swimos_client" } +swimos_client = { path = "../../../../swimos_client" } swimos_form = { path = "../../../../api/swimos_form" } \ No newline at end of file diff --git a/example_apps/devguide/2_3/example_server/Cargo.toml b/example_apps/devguide/2_3/example_server/Cargo.toml index c3274305d..5a889228e 100644 --- a/example_apps/devguide/2_3/example_server/Cargo.toml +++ b/example_apps/devguide/2_3/example_server/Cargo.toml @@ -2,6 +2,7 @@ name = "example_server_2_3" version = "0.1.0" edition = "2021" +publish = false [dependencies] tokio = { workspace = true, features = ["full"] } diff --git a/example_apps/event_downlink/Cargo.toml b/example_apps/event_downlink/Cargo.toml index ea0e35370..4f702b5ee 100644 --- a/example_apps/event_downlink/Cargo.toml +++ b/example_apps/event_downlink/Cargo.toml @@ -2,6 +2,7 @@ name = "event-downlink" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/example_util/Cargo.toml b/example_apps/example_util/Cargo.toml index 37f1eefc3..c3bbfcd23 100644 --- a/example_apps/example_util/Cargo.toml +++ b/example_apps/example_util/Cargo.toml @@ -2,6 +2,7 @@ name = "example-util" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/http_lane/Cargo.toml b/example_apps/http_lane/Cargo.toml index 42dacd998..687c4b916 100644 --- a/example_apps/http_lane/Cargo.toml +++ b/example_apps/http_lane/Cargo.toml @@ -2,6 +2,7 @@ name = "http-lane" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/join_map/Cargo.toml b/example_apps/join_map/Cargo.toml index 3e23f212b..221912af1 100644 --- a/example_apps/join_map/Cargo.toml +++ b/example_apps/join_map/Cargo.toml @@ -2,6 +2,7 @@ name = "join_map" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/join_value/Cargo.toml b/example_apps/join_value/Cargo.toml index bddb1b93e..197218670 100644 --- a/example_apps/join_value/Cargo.toml +++ b/example_apps/join_value/Cargo.toml @@ -2,6 +2,7 @@ name = "join_value" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/local_downlink/Cargo.toml b/example_apps/local_downlink/Cargo.toml index 567f4511a..aa2af4e60 100644 --- a/example_apps/local_downlink/Cargo.toml +++ b/example_apps/local_downlink/Cargo.toml @@ -2,6 +2,7 @@ name = "local-downlink" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/map_downlink/Cargo.toml b/example_apps/map_downlink/Cargo.toml index 1f845d653..513b7052a 100644 --- a/example_apps/map_downlink/Cargo.toml +++ b/example_apps/map_downlink/Cargo.toml @@ -2,6 +2,7 @@ name = "map-downlink" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/map_lane/Cargo.toml b/example_apps/map_lane/Cargo.toml index a91af92fd..df1ef1ab2 100644 --- a/example_apps/map_lane/Cargo.toml +++ b/example_apps/map_lane/Cargo.toml @@ -2,6 +2,7 @@ name = "map-lane" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/map_lane_persistence/Cargo.toml b/example_apps/map_lane_persistence/Cargo.toml index e7abc1056..c53904990 100644 --- a/example_apps/map_lane_persistence/Cargo.toml +++ b/example_apps/map_lane_persistence/Cargo.toml @@ -2,6 +2,7 @@ name = "map-lane-persistence" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/map_store/Cargo.toml b/example_apps/map_store/Cargo.toml index 69676d9c0..096a4a103 100644 --- a/example_apps/map_store/Cargo.toml +++ b/example_apps/map_store/Cargo.toml @@ -2,6 +2,7 @@ name = "map-store" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/map_store_persistence/Cargo.toml b/example_apps/map_store_persistence/Cargo.toml index 0d6e3b949..c555e3721 100644 --- a/example_apps/map_store_persistence/Cargo.toml +++ b/example_apps/map_store_persistence/Cargo.toml @@ -2,6 +2,7 @@ name = "map-store-persistence" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/supply_lane/Cargo.toml b/example_apps/supply_lane/Cargo.toml index f895668ca..2bfa4708b 100644 --- a/example_apps/supply_lane/Cargo.toml +++ b/example_apps/supply_lane/Cargo.toml @@ -2,6 +2,7 @@ name = "supply-lane" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/time_series/Cargo.toml b/example_apps/time_series/Cargo.toml index 74412eebd..caa7c8bde 100644 --- a/example_apps/time_series/Cargo.toml +++ b/example_apps/time_series/Cargo.toml @@ -2,6 +2,7 @@ name = "time_series" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/transit/Cargo.toml b/example_apps/transit/Cargo.toml index 0c9b1ce92..53062cfab 100644 --- a/example_apps/transit/Cargo.toml +++ b/example_apps/transit/Cargo.toml @@ -2,6 +2,7 @@ name = "transit" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/transit/transit-model/Cargo.toml b/example_apps/transit/transit-model/Cargo.toml index 464e30f32..268d5aa44 100644 --- a/example_apps/transit/transit-model/Cargo.toml +++ b/example_apps/transit/transit-model/Cargo.toml @@ -2,6 +2,7 @@ name = "transit-model" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../../swimos" } diff --git a/example_apps/tutorial_app/Cargo.toml b/example_apps/tutorial_app/Cargo.toml index a9947a2c2..1fac83f94 100644 --- a/example_apps/tutorial_app/Cargo.toml +++ b/example_apps/tutorial_app/Cargo.toml @@ -2,6 +2,7 @@ name = "tutorial-app" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/tutorial_app/generator/Cargo.toml b/example_apps/tutorial_app/generator/Cargo.toml index e0949ffa9..af1ab89d2 100644 --- a/example_apps/tutorial_app/generator/Cargo.toml +++ b/example_apps/tutorial_app/generator/Cargo.toml @@ -2,9 +2,10 @@ name = "tutorial-app-generator" version = "0.1.0" edition = "2021" +publish = false [dependencies] tutorial-app-model = { path = "../model" } tokio = { workspace = true, features = ["rt-multi-thread", "macros", "signal"] } rand = { workspace = true } -swimos_client = { path = "../../../client/swimos_client" } +swimos_client = { path = "../../../swimos_client" } diff --git a/example_apps/tutorial_app/generator/src/main.rs b/example_apps/tutorial_app/generator/src/main.rs index 7d6dd404f..28512a9ff 100644 --- a/example_apps/tutorial_app/generator/src/main.rs +++ b/example_apps/tutorial_app/generator/src/main.rs @@ -15,6 +15,7 @@ use std::{env::args, pin::pin, time::Duration}; use rand::Rng; +use swimos_client::Commander; use tutorial_app_model::Message; const NODE: &str = "/unit/master"; @@ -30,7 +31,7 @@ async fn main() -> Result<(), Box> { .expect("No port provided.") .parse::() .expect("Invalid port."); - let mut commander = swimos_client::Commander::default(); + let mut commander = Commander::default(); let host = format!("ws://localhost:{}", port); let mut rng = rand::thread_rng(); diff --git a/example_apps/tutorial_app/model/Cargo.toml b/example_apps/tutorial_app/model/Cargo.toml index 4465c1b1c..295365812 100644 --- a/example_apps/tutorial_app/model/Cargo.toml +++ b/example_apps/tutorial_app/model/Cargo.toml @@ -2,6 +2,7 @@ name = "tutorial-app-model" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../../swimos" } diff --git a/example_apps/value_downlink/Cargo.toml b/example_apps/value_downlink/Cargo.toml index e4e15dae3..daa3a9ea8 100644 --- a/example_apps/value_downlink/Cargo.toml +++ b/example_apps/value_downlink/Cargo.toml @@ -2,6 +2,7 @@ name = "value-downlink" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/value_lane/Cargo.toml b/example_apps/value_lane/Cargo.toml index 4e1963c3d..54ec072d2 100644 --- a/example_apps/value_lane/Cargo.toml +++ b/example_apps/value_lane/Cargo.toml @@ -2,6 +2,7 @@ name = "value-lane" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/value_lane_persistence/Cargo.toml b/example_apps/value_lane_persistence/Cargo.toml index 059de0d0c..ae07b7eb9 100644 --- a/example_apps/value_lane_persistence/Cargo.toml +++ b/example_apps/value_lane_persistence/Cargo.toml @@ -2,6 +2,7 @@ name = "value-lane-persistence" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/value_store/Cargo.toml b/example_apps/value_store/Cargo.toml index 2ca7d1449..a359d591e 100644 --- a/example_apps/value_store/Cargo.toml +++ b/example_apps/value_store/Cargo.toml @@ -2,6 +2,7 @@ name = "value-store" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/example_apps/value_store_persistence/Cargo.toml b/example_apps/value_store_persistence/Cargo.toml index dd6c0eac0..68cbb90d9 100644 --- a/example_apps/value_store_persistence/Cargo.toml +++ b/example_apps/value_store_persistence/Cargo.toml @@ -2,6 +2,7 @@ name = "value-store-persistence" version = "0.1.0" edition = "2021" +publish = false [dependencies] swimos = { path = "../../swimos", features = ["server", "agent"] } diff --git a/server/swimos_agent_derive/Cargo.toml b/server/swimos_agent_derive/Cargo.toml index 39577763c..3583e39f0 100644 --- a/server/swimos_agent_derive/Cargo.toml +++ b/server/swimos_agent_derive/Cargo.toml @@ -14,7 +14,7 @@ syn = { workspace = true, features = ["full", "extra-traits"] } quote = { workspace = true } swimos_utilities = { path = "../../swimos_utilities", features = ["errors", "text"] } bitflags = { workspace = true } -macro_utilities = { path = "../../macro_utilities" } +swimos_macro_utilities = { path = "../../swimos_macro_utilities" } frunk = { workspace = true } [dev-dependencies] \ No newline at end of file diff --git a/server/swimos_agent_derive/src/lane_model_derive/attributes/mod.rs b/server/swimos_agent_derive/src/lane_model_derive/attributes/mod.rs index a3ee5a256..72930f5c2 100644 --- a/server/swimos_agent_derive/src/lane_model_derive/attributes/mod.rs +++ b/server/swimos_agent_derive/src/lane_model_derive/attributes/mod.rs @@ -13,7 +13,7 @@ // limitations under the License. use frunk::hlist; -use macro_utilities::{ +use swimos_macro_utilities::{ attributes::NestedMetaConsumer, CaseConvention, NameTransform, NameTransformConsumer, Transformation, TypeLevelNameTransformConsumer, }; diff --git a/server/swimos_agent_derive/src/lane_model_derive/model.rs b/server/swimos_agent_derive/src/lane_model_derive/model.rs index dd735f822..7b240f6da 100644 --- a/server/swimos_agent_derive/src/lane_model_derive/model.rs +++ b/server/swimos_agent_derive/src/lane_model_derive/model.rs @@ -13,9 +13,11 @@ // limitations under the License. use bitflags::bitflags; -use macro_utilities::{attributes::consume_attributes, NameTransform, TypeLevelNameTransform}; use proc_macro2::Literal; use std::{collections::HashSet, hash::Hash}; +use swimos_macro_utilities::{ + attributes::consume_attributes, NameTransform, TypeLevelNameTransform, +}; use swimos_utilities::{ errors::{Errors, Validation, ValidationItExt}, format::comma_sep, diff --git a/server/swimos_agent_derive/src/lib.rs b/server/swimos_agent_derive/src/lib.rs index 910fb3b1d..3c15cdfe6 100644 --- a/server/swimos_agent_derive/src/lib.rs +++ b/server/swimos_agent_derive/src/lib.rs @@ -20,7 +20,7 @@ use lane_projections::ProjectionsImpl; use proc_macro::TokenStream; use quote::{quote, ToTokens}; -use macro_utilities::{attributes::consume_attributes, to_compile_errors}; +use swimos_macro_utilities::{attributes::consume_attributes, to_compile_errors}; use swimos_utilities::errors::{Errors, Validation}; use syn::{parse_macro_input, parse_quote, AttributeArgs, DeriveInput, Item}; diff --git a/swimos_client/Cargo.toml b/swimos_client/Cargo.toml new file mode 100644 index 000000000..dc4e4727c --- /dev/null +++ b/swimos_client/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "swimos_client" +version = "0.1.0" +edition = "2021" + +[features] +default = [] +tls = ["swimos_remote/tls"] +deflate = ["ratchet/deflate"] +trust_dns = ["swimos_runtime/trust_dns"] + +[dependencies] +swimos_agent_protocol = { path = "../api/swimos_agent_protocol" } +swimos_recon = { path = "../api/formats/swimos_recon" } +swimos_messages = { path = "../runtime/swimos_messages" } +swimos_utilities = { path = "../swimos_utilities", features = ["trigger"] } +swimos_downlink = { path = "../swimos_downlink" } +swimos_api = { path = "../api/swimos_api" } +swimos_client_api = { path = "../api/swimos_client_api" } +swimos_model = { path = "../api/swimos_model" } +swimos_form = { path = "../api/swimos_form" } +swimos_runtime = { path = "../runtime/swimos_runtime" } +swimos_remote = { path = "../runtime/swimos_remote" } +ratchet = { workspace = true } +url = { workspace = true } +tracing = { workspace = true } +fnv = { workspace = true } +uuid = { workspace = true } +futures = { workspace = true } +futures-util = { workspace = true } +bytes = { workspace = true } +tokio = { workspace = true, features = ["io-util", "sync"] } +tokio-util = { workspace = true, features = ["codec"] } +thiserror = { workspace = true } \ No newline at end of file diff --git a/client/runtime/src/commander/mod.rs b/swimos_client/src/commander.rs similarity index 100% rename from client/runtime/src/commander/mod.rs rename to swimos_client/src/commander.rs diff --git a/client/runtime/src/error.rs b/swimos_client/src/error.rs similarity index 93% rename from client/runtime/src/error.rs rename to swimos_client/src/error.rs index 00da00d71..1b24d8364 100644 --- a/client/runtime/src/error.rs +++ b/swimos_client/src/error.rs @@ -40,9 +40,6 @@ pub enum DownlinkErrorKind { RemoteStopped, Timeout, Terminated, - /// Error propagated from user-code, such as a Java exception cause through the FFI - // todo: this can be removed? - User, } impl Display for DownlinkErrorKind { @@ -66,12 +63,6 @@ impl Display for DownlinkErrorKind { DownlinkErrorKind::Terminated => { write!(f, "Terminated") } - DownlinkErrorKind::User => { - write!( - f, - "Error produced during downlink lifecycle callback invocation" - ) - } } } } diff --git a/client/swimos_client/src/lib.rs b/swimos_client/src/lib.rs similarity index 89% rename from client/swimos_client/src/lib.rs rename to swimos_client/src/lib.rs index c7bf13380..e791c653c 100644 --- a/client/swimos_client/src/lib.rs +++ b/swimos_client/src/lib.rs @@ -12,21 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[cfg(not(feature = "deflate"))] -use ratchet::NoExtProvider; -use ratchet::WebSocketStream; -use std::marker::PhantomData; -use std::num::NonZeroUsize; -use swimos_remote::websocket::RatchetClient; +use std::{marker::PhantomData, num::NonZeroUsize, sync::Arc, time::Duration}; +pub use commander::{CommandError, Commander}; use futures_util::future::BoxFuture; -#[cfg(feature = "deflate")] -use ratchet::deflate::{DeflateConfig, DeflateExtProvider}; -use runtime::{ - start_runtime, ClientConfig, DownlinkRuntimeError, RawHandle, Transport, WebSocketConfig, -}; -pub use runtime::{CommandError, Commander, RemotePath}; -use std::sync::Arc; +use ratchet::{deflate::DeflateConfig, deflate::DeflateExtProvider, WebSocketStream}; pub use swimos_client_api::DownlinkConfig; pub use swimos_downlink::lifecycle::{ BasicEventDownlinkLifecycle, BasicMapDownlinkLifecycle, BasicValueDownlinkLifecycle, @@ -37,21 +27,80 @@ use swimos_downlink::{ MapValue, NotYetSyncedError, ValueDownlinkModel, ValueDownlinkSet, }; use swimos_form::Form; -use swimos_remote::dns::Resolver; -use swimos_remote::plain::TokioPlainTextNetworking; -#[cfg(feature = "tls")] -use swimos_remote::tls::{ClientConfig as TlsConfig, RustlsClientNetworking, TlsError}; -use swimos_remote::ClientConnections; +use swimos_remote::{ + dns::Resolver, + plain::TokioPlainTextNetworking, + tls::{ClientConfig as TlsConfig, RustlsClientNetworking, TlsError}, + websocket::RatchetClient, + ClientConnections, +}; use swimos_runtime::downlink::{DownlinkOptions, DownlinkRuntimeConfig}; -use swimos_utilities::trigger; -use swimos_utilities::trigger::promise; -use tokio::sync::mpsc; -use tokio::sync::mpsc::error::SendError; -use tokio::sync::oneshot::error::RecvError; +use swimos_utilities::{non_zero_usize, trigger, trigger::promise}; +use tokio::{sync::mpsc, sync::mpsc::error::SendError, sync::oneshot::error::RecvError}; pub use url::Url; +pub use crate::models::RemotePath; +use crate::{ + error::DownlinkRuntimeError, + runtime::{start_runtime, RawHandle}, + transport::Transport, +}; + +#[cfg(test)] +mod tests; + +mod commander; +mod error; +mod models; +mod pending; +mod runtime; +mod transport; + pub type DownlinkOperationResult = Result; +const DEFAULT_BUFFER_SIZE: NonZeroUsize = non_zero_usize!(32); +const DEFAULT_CLOSE_TIMEOUT: Duration = Duration::from_secs(5); + +#[derive(Debug)] +pub struct WebSocketConfig { + pub max_message_size: usize, + #[cfg(feature = "deflate")] + pub deflate_config: Option, +} + +impl Default for WebSocketConfig { + fn default() -> Self { + WebSocketConfig { + max_message_size: 64 << 20, + #[cfg(feature = "deflate")] + deflate_config: None, + } + } +} + +#[derive(Debug)] +pub struct ClientConfig { + pub websocket: WebSocketConfig, + pub remote_buffer_size: NonZeroUsize, + pub transport_buffer_size: NonZeroUsize, + pub registration_buffer_size: NonZeroUsize, + pub close_timeout: Duration, + pub interpret_frame_data: bool, +} + +impl Default for ClientConfig { + fn default() -> Self { + ClientConfig { + websocket: WebSocketConfig::default(), + remote_buffer_size: non_zero_usize!(4096), + transport_buffer_size: DEFAULT_BUFFER_SIZE, + registration_buffer_size: DEFAULT_BUFFER_SIZE, + close_timeout: DEFAULT_CLOSE_TIMEOUT, + interpret_frame_data: true, + } + } +} + #[derive(Debug, Default)] pub struct SwimClientBuilder { config: ClientConfig, diff --git a/client/runtime/src/models.rs b/swimos_client/src/models.rs similarity index 100% rename from client/runtime/src/models.rs rename to swimos_client/src/models.rs diff --git a/client/runtime/src/pending.rs b/swimos_client/src/pending.rs similarity index 100% rename from client/runtime/src/pending.rs rename to swimos_client/src/pending.rs diff --git a/client/runtime/src/runtime.rs b/swimos_client/src/runtime.rs similarity index 100% rename from client/runtime/src/runtime.rs rename to swimos_client/src/runtime.rs diff --git a/client/runtime/src/tests.rs b/swimos_client/src/tests.rs similarity index 64% rename from client/runtime/src/tests.rs rename to swimos_client/src/tests.rs index b1665f1a2..2032e81db 100644 --- a/client/runtime/src/tests.rs +++ b/swimos_client/src/tests.rs @@ -12,33 +12,43 @@ // See the License for the specific language governing permissions and // limitations under the License. +use ratchet::NoExtProvider; use std::collections::BTreeMap; use std::fmt::Debug; use std::future::Future; use std::hash::Hash; -use std::net::SocketAddr; -use std::sync::Arc; use std::time::Duration; - -use bytes::BytesMut; -use futures_util::future::BoxFuture; -use futures_util::FutureExt; -use ratchet::{ - Message, NegotiatedExtension, NoExt, NoExtProvider, Role, WebSocket, WebSocketConfig, -}; use swimos_agent_protocol::MapMessage; use swimos_messages::remote_protocol::AttachClient; -use swimos_remote::{Scheme, SchemeHostPort}; +use swimos_remote::SchemeHostPort; use tokio::io::{duplex, AsyncWriteExt}; use tokio::spawn; use tokio::sync::mpsc::unbounded_channel; -use tokio::sync::{mpsc, oneshot, Mutex, Notify}; +use tokio::sync::{oneshot, Notify}; use tokio::task::JoinHandle; use tokio::time::timeout; use tokio_util::codec::Encoder; use uuid::Uuid; -use fixture::{MockClientConnections, MockWs, Server, WsAction}; +use crate::error::{DownlinkErrorKind, DownlinkRuntimeError}; +use crate::models::RemotePath; +use crate::runtime::{start_runtime, RawHandle}; +use crate::transport::{Transport, TransportHandle}; +use bytes::BytesMut; +use futures_util::future::{ready, BoxFuture}; +use futures_util::stream::BoxStream; +use futures_util::{FutureExt, StreamExt}; +use ratchet::{ + ExtensionProvider, Message, NegotiatedExtension, NoExt, PayloadType, Role, WebSocket, + WebSocketConfig, WebSocketStream, +}; +use std::borrow::BorrowMut; +use std::collections::HashMap; +use std::io; +use std::io::ErrorKind; +use std::net::SocketAddr; +use std::ops::DerefMut; +use std::sync::Arc; use swimos_api::{ address::{Address, RelativeAddress}, agent::DownlinkKind, @@ -54,17 +64,426 @@ use swimos_downlink::{ }; use swimos_form::Form; use swimos_messages::protocol::{RawRequestMessageEncoder, RequestMessage}; -use swimos_model::Text; -use swimos_remote::websocket::RatchetError; +use swimos_messages::remote_protocol::FindNode; +use swimos_model::{Text, Value}; +use swimos_recon::parser::parse_recognize; +use swimos_recon::print_recon; +use swimos_remote::dns::{BoxDnsResolver, DnsResolver}; +use swimos_remote::websocket::{RatchetError, WebsocketClient, WebsocketServer, WsOpenFuture}; +use swimos_remote::{ + ClientConnections, ConnectionError, ConnectionResult, Listener, ListenerError, Scheme, +}; use swimos_runtime::downlink::{DownlinkOptions, DownlinkRuntimeConfig}; use swimos_utilities::byte_channel::{byte_channel, ByteReader, ByteWriter}; use swimos_utilities::trigger::{promise, trigger}; use swimos_utilities::{non_zero_usize, trigger}; +use tokio::io::{AsyncRead, AsyncWrite, DuplexStream}; +use tokio::sync::mpsc; +use tokio::sync::Mutex; + +#[derive(Debug)] +struct Inner { + addrs: HashMap<(String, u16), SocketAddr>, + sockets: HashMap, +} -use crate::error::{DownlinkErrorKind, DownlinkRuntimeError}; -use crate::models::RemotePath; -use crate::runtime::{start_runtime, RawHandle}; -use crate::transport::{Transport, TransportHandle}; +impl Inner { + fn new(resolver: R, sockets: S) -> Inner + where + R: IntoIterator, + S: IntoIterator, + { + Inner { + addrs: HashMap::from_iter(resolver), + sockets: HashMap::from_iter(sockets), + } + } +} + +#[derive(Debug, Clone)] +pub struct MockClientConnections { + inner: Arc>, +} + +impl MockClientConnections { + pub fn new(resolver: R, sockets: S) -> MockClientConnections + where + R: IntoIterator, + S: IntoIterator, + { + MockClientConnections { + inner: Arc::new(Mutex::new(Inner::new(resolver, sockets))), + } + } +} + +impl ClientConnections for MockClientConnections { + type ClientSocket = DuplexStream; + + fn try_open( + &self, + _scheme: Scheme, + _host: Option<&str>, + addr: SocketAddr, + ) -> BoxFuture<'_, ConnectionResult> { + async move { + self.inner + .lock() + .await + .sockets + .remove(&addr) + .ok_or_else(|| ConnectionError::ConnectionFailed(ErrorKind::NotFound.into())) + } + .boxed() + } + + fn dns_resolver(&self) -> BoxDnsResolver { + Box::new(self.clone()) + } + + fn lookup( + &self, + host: String, + port: u16, + ) -> BoxFuture<'static, std::io::Result>> { + self.resolve(host, port).boxed() + } +} + +impl DnsResolver for MockClientConnections { + type ResolveFuture = BoxFuture<'static, io::Result>>; + + fn resolve(&self, host: String, port: u16) -> Self::ResolveFuture { + let inner = self.inner.clone(); + async move { + match inner.lock().await.addrs.get(&(host, port)) { + Some(sock) => Ok(vec![*sock]), + None => Err(io::ErrorKind::NotFound.into()), + } + } + .boxed() + } +} + +pub enum WsAction { + Open, + Fail(Box RatchetError + Send + Sync + 'static>), +} + +impl WsAction { + pub fn fail(with: F) -> WsAction + where + F: Fn() -> RatchetError + Send + Sync + 'static, + { + WsAction::Fail(Box::new(with)) + } +} + +pub struct MockWs { + states: HashMap, +} + +impl MockWs { + pub fn new(states: S) -> MockWs + where + S: IntoIterator, + { + MockWs { + states: HashMap::from_iter(states), + } + } +} + +impl WebsocketClient for MockWs { + fn open_connection<'a, Sock, Provider>( + &self, + socket: Sock, + _provider: &'a Provider, + addr: String, + ) -> WsOpenFuture<'a, Sock, Provider::Extension, RatchetError> + where + Sock: WebSocketStream + Send, + Provider: ExtensionProvider + Send + Sync + 'static, + Provider::Extension: Send + Sync + 'static, + { + let result = match self.states.get(&addr) { + Some(WsAction::Open) => Ok(WebSocket::from_upgraded( + WebSocketConfig::default(), + socket, + NegotiatedExtension::from(None), + BytesMut::default(), + Role::Client, + )), + Some(WsAction::Fail(e)) => Err(e()), + None => Err(ratchet::Error::new(ratchet::ErrorKind::Http).into()), + }; + ready(result).boxed() + } +} + +impl WebsocketServer for MockWs { + type WsStream = + BoxStream<'static, Result<(WebSocket, SocketAddr), ListenerError>>; + + fn wrap_listener( + &self, + _listener: L, + _provider: Provider, + _find: mpsc::Sender, + ) -> Self::WsStream + where + Sock: AsyncRead + AsyncWrite + Unpin + Send + Sync + 'static, + L: Listener + Send + 'static, + Provider: ExtensionProvider + Send + Sync + Unpin + 'static, + Provider::Extension: Send + Sync + Unpin + 'static, + { + futures::stream::pending().boxed() + } +} + +#[derive(Clone, Debug, PartialEq, Form)] + +pub enum Envelope { + #[form(tag = "link")] + Link { + #[form(name = "node")] + node_uri: Text, + #[form(name = "lane")] + lane_uri: Text, + rate: Option, + prio: Option, + #[form(body)] + body: Option, + }, + #[form(tag = "sync")] + Sync { + #[form(name = "node")] + node_uri: Text, + #[form(name = "lane")] + lane_uri: Text, + rate: Option, + prio: Option, + #[form(body)] + body: Option, + }, + #[form(tag = "unlink")] + Unlink { + #[form(name = "node")] + node_uri: Text, + #[form(name = "lane")] + lane_uri: Text, + #[form(body)] + body: Option, + }, + #[form(tag = "command")] + Command { + #[form(name = "node")] + node_uri: Text, + #[form(name = "lane")] + lane_uri: Text, + #[form(body)] + body: Option, + }, + #[form(tag = "linked")] + Linked { + #[form(name = "node")] + node_uri: Text, + #[form(name = "lane")] + lane_uri: Text, + rate: Option, + prio: Option, + #[form(body)] + body: Option, + }, + #[form(tag = "synced")] + Synced { + #[form(name = "node")] + node_uri: Text, + #[form(name = "lane")] + lane_uri: Text, + #[form(body)] + body: Option, + }, + #[form(tag = "unlinked")] + Unlinked { + #[form(name = "node")] + node_uri: Text, + #[form(name = "lane")] + lane_uri: Text, + #[form(body)] + body: Option, + }, + #[form(tag = "event")] + Event { + #[form(name = "node")] + node_uri: Text, + #[form(name = "lane")] + lane_uri: Text, + #[form(body)] + body: Option, + }, +} + +pub struct Lane { + node: String, + lane: String, + server: Arc>, +} + +impl Lane { + pub async fn read(&mut self) -> Envelope { + let Lane { server, .. } = self; + let mut guard = server.lock().await; + let Server { buf, transport } = &mut guard.deref_mut(); + + match transport.read(buf).await.unwrap() { + Message::Text => {} + m => panic!("Unexpected message type: {:?}", m), + } + let read = String::from_utf8(buf.to_vec()).unwrap(); + buf.clear(); + + parse_recognize::(read.as_str(), false).unwrap() + } + + pub async fn write(&mut self, env: Envelope) { + let Lane { server, .. } = self; + let mut guard = server.lock().await; + let Server { transport, .. } = &mut guard.deref_mut(); + + let response = print_recon(&env); + transport + .write(format!("{}", response), PayloadType::Text) + .await + .unwrap(); + } + + pub async fn await_link(&mut self) { + match self.read().await { + Envelope::Link { + node_uri, lane_uri, .. + } => { + assert_eq!(node_uri, self.node); + assert_eq!(lane_uri, self.lane); + self.write(Envelope::Linked { + node_uri: node_uri.clone(), + lane_uri: lane_uri.clone(), + rate: None, + prio: None, + body: None, + }) + .await; + } + e => panic!("Unexpected envelope {:?}", e), + } + } + + pub async fn await_sync(&mut self, val: Vec) { + match self.read().await { + Envelope::Sync { + node_uri, lane_uri, .. + } => { + assert_eq!(node_uri, self.node); + assert_eq!(lane_uri, self.lane); + + for v in val { + self.write(Envelope::Event { + node_uri: node_uri.clone(), + lane_uri: lane_uri.clone(), + body: Some(v.as_value()), + }) + .await; + } + + self.write(Envelope::Synced { + node_uri: node_uri.clone(), + lane_uri: lane_uri.clone(), + body: None, + }) + .await; + } + e => panic!("Unexpected envelope {:?}", e), + } + } + + pub async fn await_command(&mut self, expected: i32) { + match self.read().await { + Envelope::Command { + node_uri, + lane_uri, + body: Some(val), + } => { + assert_eq!(node_uri, self.node); + assert_eq!(lane_uri, self.lane); + assert_eq!(val, Value::Int32Value(expected)); + } + e => panic!("Unexpected envelope {:?}", e), + } + } + + pub async fn send_unlinked(&mut self) { + self.write(Envelope::Unlinked { + node_uri: self.node.clone().into(), + lane_uri: self.lane.clone().into(), + body: None, + }) + .await; + } + + pub async fn send_event(&mut self, val: V) { + self.write(Envelope::Event { + node_uri: self.node.clone().into(), + lane_uri: self.lane.clone().into(), + body: Some(val.as_value()), + }) + .await; + } + + pub async fn await_closed(&mut self) { + let Lane { server, .. } = self; + let mut guard = server.lock().await; + let Server { buf, transport } = &mut guard.deref_mut(); + + match transport.borrow_mut().read(buf).await.unwrap() { + Message::Close(_) => {} + m => panic!("Unexpected message type: {:?}", m), + } + } +} + +pub struct Server { + pub buf: BytesMut, + pub transport: WebSocket, +} + +impl Server { + pub fn lane_for(server: Arc>, node: N, lane: L) -> Lane + where + N: ToString, + L: ToString, + { + Lane { + node: node.to_string(), + lane: lane.to_string(), + server, + } + } +} + +impl Server { + pub fn new(transport: DuplexStream) -> Server { + Server { + buf: BytesMut::new(), + transport: WebSocket::from_upgraded( + WebSocketConfig::default(), + transport, + NegotiatedExtension::from(NoExt), + BytesMut::default(), + Role::Server, + ), + } + } +} #[tokio::test] async fn transport_opens_connection_ok() { diff --git a/client/runtime/src/transport.rs b/swimos_client/src/transport.rs similarity index 100% rename from client/runtime/src/transport.rs rename to swimos_client/src/transport.rs diff --git a/macro_utilities/Cargo.toml b/swimos_macro_utilities/Cargo.toml similarity index 92% rename from macro_utilities/Cargo.toml rename to swimos_macro_utilities/Cargo.toml index 9c5e5380c..9faefa1d3 100644 --- a/macro_utilities/Cargo.toml +++ b/swimos_macro_utilities/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "macro_utilities" +name = "swimos_macro_utilities" version = "0.1.0" authors = ["Swim Inc. developers info@swim.ai"] edition = "2021" diff --git a/macro_utilities/src/attributes/mod.rs b/swimos_macro_utilities/src/attributes/mod.rs similarity index 100% rename from macro_utilities/src/attributes/mod.rs rename to swimos_macro_utilities/src/attributes/mod.rs diff --git a/macro_utilities/src/form.rs b/swimos_macro_utilities/src/form.rs similarity index 100% rename from macro_utilities/src/form.rs rename to swimos_macro_utilities/src/form.rs diff --git a/macro_utilities/src/generics.rs b/swimos_macro_utilities/src/generics.rs similarity index 100% rename from macro_utilities/src/generics.rs rename to swimos_macro_utilities/src/generics.rs diff --git a/macro_utilities/src/label.rs b/swimos_macro_utilities/src/label.rs similarity index 100% rename from macro_utilities/src/label.rs rename to swimos_macro_utilities/src/label.rs diff --git a/macro_utilities/src/lib.rs b/swimos_macro_utilities/src/lib.rs similarity index 100% rename from macro_utilities/src/lib.rs rename to swimos_macro_utilities/src/lib.rs diff --git a/macro_utilities/src/names/mod.rs b/swimos_macro_utilities/src/names/mod.rs similarity index 100% rename from macro_utilities/src/names/mod.rs rename to swimos_macro_utilities/src/names/mod.rs diff --git a/macro_utilities/src/utilities.rs b/swimos_macro_utilities/src/utilities.rs similarity index 100% rename from macro_utilities/src/utilities.rs rename to swimos_macro_utilities/src/utilities.rs From 85cc0e5904fbc2ea30435b4760b98f898c2b3517 Mon Sep 17 00:00:00 2001 From: SirCipher Date: Wed, 26 Jun 2024 15:23:41 +0100 Subject: [PATCH 24/27] Tidies up cryptographic provider error messaging --- runtime/swimos_remote/src/tls/errors.rs | 8 ++++++-- runtime/swimos_remote/src/tls/mod.rs | 8 ++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/runtime/swimos_remote/src/tls/errors.rs b/runtime/swimos_remote/src/tls/errors.rs index a8e3b20a4..8de8f33ee 100644 --- a/runtime/swimos_remote/src/tls/errors.rs +++ b/runtime/swimos_remote/src/tls/errors.rs @@ -32,6 +32,10 @@ pub enum TlsError { /// Performing the TLS handshake failed. #[error("TLS handshake failed: {0}")] HandshakeFailed(std::io::Error), - #[error("Invalid cryptographic provider configured: {0}")] - InvalidCryptoProvider(String), + /// User specified that a cryptographic provider had been installed but none was found. + #[error("No default cryptographic provider has been installed")] + NoCryptoProviderInstalled, + /// User specified more than one cryptographic provider feature flag. Only one may be specified. + #[error("Ambiguous cryptographic provider feature flags specified. Only \"ring_provider\" or \"aws_lc_rs_provider\" may be specified")] + InvalidCryptoProvider, } diff --git a/runtime/swimos_remote/src/tls/mod.rs b/runtime/swimos_remote/src/tls/mod.rs index 14030ca87..c3d0064bc 100644 --- a/runtime/swimos_remote/src/tls/mod.rs +++ b/runtime/swimos_remote/src/tls/mod.rs @@ -38,11 +38,7 @@ impl CryptoProviderConfig { pub fn try_build(self) -> Result, TlsError> { match self { CryptoProviderConfig::ProcessDefault => CryptoProvider::get_default() - .ok_or_else(|| { - TlsError::InvalidCryptoProvider( - "No default cryptographic provider specified".to_string(), - ) - }) + .ok_or(TlsError::NoCryptoProviderInstalled) .cloned(), CryptoProviderConfig::FromFeatureFlags => { #[cfg(all(feature = "ring_provider", not(feature = "aws_lc_rs_provider")))] @@ -57,7 +53,7 @@ impl CryptoProviderConfig { #[allow(unreachable_code)] { - Err(TlsError::InvalidCryptoProvider("Ambiguous cryptographic provider feature flags specified. Only \"ring_provider\" or \"aws_lc_rs_provider\" may be specified".to_string())) + Err(TlsError::InvalidCryptoProvider) } } CryptoProviderConfig::Provided(provider) => Ok(provider), From ae29730e35c408feeb25174b4ed25d57cbf79840 Mon Sep 17 00:00:00 2001 From: SirCipher Date: Wed, 26 Jun 2024 15:27:41 +0100 Subject: [PATCH 25/27] Adds missing default client crypto provider feature flag --- client/swimos_client/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/swimos_client/Cargo.toml b/client/swimos_client/Cargo.toml index 9053e2e6d..f5d479216 100644 --- a/client/swimos_client/Cargo.toml +++ b/client/swimos_client/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [features] -default = [] +default = ["aws_lc_rs_provider"] deflate = ["runtime/deflate"] trust_dns = ["swimos_runtime/trust_dns"] ring_provider = ["swimos_remote/ring_provider"] From 45633ccdb181ea0c91caf4dd5d0a5fc1cb551a90 Mon Sep 17 00:00:00 2001 From: SirCipher Date: Wed, 26 Jun 2024 15:39:42 +0100 Subject: [PATCH 26/27] Adds dependency version to local dependencies --- api/formats/swimos_msgpack/Cargo.toml | 4 ++-- api/formats/swimos_recon/Cargo.toml | 6 +++--- api/swimos_agent_protocol/Cargo.toml | 10 +++++----- api/swimos_api/Cargo.toml | 8 ++++---- api/swimos_client_api/Cargo.toml | 10 +++++----- api/swimos_form/Cargo.toml | 6 +++--- api/swimos_form_derive/Cargo.toml | 4 ++-- api/swimos_meta/Cargo.toml | 6 +++--- api/swimos_model/Cargo.toml | 2 +- runtime/swimos_messages/Cargo.toml | 14 +++++++------- runtime/swimos_remote/Cargo.toml | 10 +++++----- runtime/swimos_rocks_store/Cargo.toml | 8 ++++---- runtime/swimos_runtime/Cargo.toml | 18 +++++++++--------- server/swimos_agent/Cargo.toml | 14 +++++++------- server/swimos_agent_derive/Cargo.toml | 4 ++-- server/swimos_server_app/Cargo.toml | 20 ++++++++++---------- swimos/Cargo.toml | 18 +++++++++--------- swimos_client/Cargo.toml | 22 +++++++++++----------- swimos_downlink/Cargo.toml | 14 +++++++------- 19 files changed, 99 insertions(+), 99 deletions(-) diff --git a/api/formats/swimos_msgpack/Cargo.toml b/api/formats/swimos_msgpack/Cargo.toml index eb6c5105f..31fa95693 100644 --- a/api/formats/swimos_msgpack/Cargo.toml +++ b/api/formats/swimos_msgpack/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" [dependencies] base64 = { workspace = true } either = { workspace = true } -swimos_form = { path = "../../swimos_form" } -swimos_model = { path = "../../swimos_model" } +swimos_form = { path = "../../swimos_form", version = "0.1.0" } +swimos_model = { path = "../../swimos_model", version = "0.1.0" } bytes = { workspace = true } byteorder = { workspace = true } rmp = { workspace = true } diff --git a/api/formats/swimos_recon/Cargo.toml b/api/formats/swimos_recon/Cargo.toml index 780747e55..f0f883d9c 100644 --- a/api/formats/swimos_recon/Cargo.toml +++ b/api/formats/swimos_recon/Cargo.toml @@ -10,9 +10,9 @@ default = [] [dependencies] base64 = { workspace = true } either = { workspace = true } -swimos_form = { path = "../../swimos_form" } -swimos_model = { path = "../../swimos_model" } -swimos_utilities = { path = "../../../swimos_utilities", features = ["encoding"] } +swimos_form = { path = "../../swimos_form", version = "0.1.0" } +swimos_model = { path = "../../swimos_model", version = "0.1.0" } +swimos_utilities = { path = "../../../swimos_utilities", features = ["encoding"], version = "0.1.0" } nom = { workspace = true } nom_locate = { workspace = true } num-traits = { workspace = true } diff --git a/api/swimos_agent_protocol/Cargo.toml b/api/swimos_agent_protocol/Cargo.toml index abc7b416b..015cd3413 100644 --- a/api/swimos_agent_protocol/Cargo.toml +++ b/api/swimos_agent_protocol/Cargo.toml @@ -7,10 +7,10 @@ edition = "2021" [dependencies] bytes = { workspace = true } tokio-util = { workspace = true, features = ["codec"] } -swimos_api = { path = "../swimos_api" } -swimos_model = { path = "../swimos_model" } +swimos_api = { path = "../swimos_api", version = "0.1.0" } +swimos_model = { path = "../swimos_model", version = "0.1.0" } uuid = { workspace = true } -swimos_form = { path = "../swimos_form" } -swimos_recon = { path = "../formats/swimos_recon" } +swimos_form = { path = "../swimos_form", version = "0.1.0" } +swimos_recon = { path = "../formats/swimos_recon", version = "0.1.0" } thiserror = { workspace = true } -swimos_utilities = { path = "../../swimos_utilities", features = ["encoding"] } +swimos_utilities = { path = "../../swimos_utilities", features = ["encoding"], version = "0.1.0" } diff --git a/api/swimos_api/Cargo.toml b/api/swimos_api/Cargo.toml index ced907394..452f1e894 100644 --- a/api/swimos_api/Cargo.toml +++ b/api/swimos_api/Cargo.toml @@ -6,10 +6,10 @@ edition = "2021" [dependencies] futures = { workspace = true } -swimos_utilities = { path = "../../swimos_utilities", features = ["io", "errors", "trigger"] } -swimos_model = { path = "../swimos_model" } -swimos_form = { path = "../swimos_form" } -swimos_recon = { path = "../formats/swimos_recon" } +swimos_utilities = { path = "../../swimos_utilities", features = ["io", "errors", "trigger"], version = "0.1.0" } +swimos_model = { path = "../swimos_model", version = "0.1.0" } +swimos_form = { path = "../swimos_form", version = "0.1.0" } +swimos_recon = { path = "../formats/swimos_recon", version = "0.1.0" } thiserror = { workspace = true } bytes = { workspace = true } tokio = { workspace = true } diff --git a/api/swimos_client_api/Cargo.toml b/api/swimos_client_api/Cargo.toml index 376779292..2ebce100b 100644 --- a/api/swimos_client_api/Cargo.toml +++ b/api/swimos_client_api/Cargo.toml @@ -6,11 +6,11 @@ edition = "2021" [dependencies] futures = { workspace = true } -swimos_utilities = { path = "../../swimos_utilities", features = ["io"] } -swimos_model = { path = "../swimos_model" } -swimos_form = { path = "../swimos_form" } -swimos_recon = { path = "../formats/swimos_recon" } -swimos_api = { path = "../swimos_api" } +swimos_utilities = { path = "../../swimos_utilities", features = ["io"], version = "0.1.0" } +swimos_model = { path = "../swimos_model", version = "0.1.0" } +swimos_form = { path = "../swimos_form", version = "0.1.0" } +swimos_recon = { path = "../formats/swimos_recon", version = "0.1.0" } +swimos_api = { path = "../swimos_api", version = "0.1.0" } thiserror = { workspace = true } static_assertions = { workspace = true } diff --git a/api/swimos_form/Cargo.toml b/api/swimos_form/Cargo.toml index 935d0f85e..239a05a05 100644 --- a/api/swimos_form/Cargo.toml +++ b/api/swimos_form/Cargo.toml @@ -5,9 +5,9 @@ authors = ["Swim Inc. developers info@swim.ai"] edition = "2021" [dependencies] -swimos_utilities = { path = "../../swimos_utilities", features = ["text", "future"] } -swimos_form_derive = { path = "../swimos_form_derive" } -swimos_model = { path = "../swimos_model" } +swimos_utilities = { path = "../../swimos_utilities", features = ["text", "future"], version = "0.1.0" } +swimos_form_derive = { path = "../swimos_form_derive", version = "0.1.0" } +swimos_model = { path = "../swimos_model", version = "0.1.0" } chrono = { workspace = true } either = { workspace = true } num-traits = { workspace = true } diff --git a/api/swimos_form_derive/Cargo.toml b/api/swimos_form_derive/Cargo.toml index e88a410b5..d166a7b9c 100644 --- a/api/swimos_form_derive/Cargo.toml +++ b/api/swimos_form_derive/Cargo.toml @@ -10,8 +10,8 @@ proc-macro = true [dependencies] either = { workspace = true } -swimos_utilities = { path = "../../swimos_utilities", features = ["errors", "text"] } -swimos_macro_utilities = { path = "../../swimos_macro_utilities" } +swimos_utilities = { path = "../../swimos_utilities", features = ["errors", "text"], version = "0.1.0" } +swimos_macro_utilities = { path = "../../swimos_macro_utilities", version = "0.1.0" } proc-macro2 = { workspace = true } syn = { workspace = true, features = ["full"] } quote = { workspace = true } diff --git a/api/swimos_meta/Cargo.toml b/api/swimos_meta/Cargo.toml index 1dbdbe485..df919bced 100644 --- a/api/swimos_meta/Cargo.toml +++ b/api/swimos_meta/Cargo.toml @@ -5,6 +5,6 @@ authors = ["Swim Inc. developers info@swim.ai"] edition = "2021" [dependencies] -swimos_model = { path = "../swimos_model" } -swimos_form = { path = "../swimos_form" } -swimos_api = { path = "../swimos_api" } +swimos_model = { path = "../swimos_model", version = "0.1.0" } +swimos_form = { path = "../swimos_form", version = "0.1.0" } +swimos_api = { path = "../swimos_api", version = "0.1.0" } diff --git a/api/swimos_model/Cargo.toml b/api/swimos_model/Cargo.toml index e9051e2e9..0bfc71a45 100644 --- a/api/swimos_model/Cargo.toml +++ b/api/swimos_model/Cargo.toml @@ -11,7 +11,7 @@ either = { workspace = true } num-bigint = { workspace = true } base64 = { workspace = true } http = { workspace = true } -swimos_utilities = { path = "../../swimos_utilities", features = ["text", "encoding"] } +swimos_utilities = { path = "../../swimos_utilities", features = ["text", "encoding"], version = "0.1.0" } num-traits = { workspace = true } thiserror = { workspace = true } diff --git a/runtime/swimos_messages/Cargo.toml b/runtime/swimos_messages/Cargo.toml index ab532b71c..4a225ec2f 100644 --- a/runtime/swimos_messages/Cargo.toml +++ b/runtime/swimos_messages/Cargo.toml @@ -7,13 +7,13 @@ edition = "2021" [dependencies] bytes = { workspace = true } futures = { workspace = true } -tokio = { workspace = true, features = ["sync"]} +tokio = { workspace = true, features = ["sync"] } tokio-util = { workspace = true, features = ["codec"] } -swimos_model = { path = "../../api/swimos_model" } -swimos_api = { path = "../../api/swimos_api" } -swimos_form = { path = "../../api/swimos_form" } -swimos_recon = { path = "../../api/formats/swimos_recon" } -swimos_utilities = { path = "../../swimos_utilities", features = ["algebra"] } +swimos_model = { path = "../../api/swimos_model", version = "0.1.0" } +swimos_api = { path = "../../api/swimos_api", version = "0.1.0" } +swimos_form = { path = "../../api/swimos_form", version = "0.1.0" } +swimos_recon = { path = "../../api/formats/swimos_recon", version = "0.1.0" } +swimos_utilities = { path = "../../swimos_utilities", features = ["algebra"], version = "0.1.0" } thiserror = { workspace = true } uuid = { workspace = true } smallvec = { workspace = true } @@ -21,5 +21,5 @@ smallvec = { workspace = true } [dev-dependencies] tokio = { workspace = true, features = ["macros", "rt"] } uuid = { workspace = true, features = ["v4"] } -swimos_utilities = { path = "../../swimos_utilities", features = ["buf_channel"] } +swimos_utilities = { path = "../../swimos_utilities", features = ["buf_channel"], version = "0.1.0" } rand = { workspace = true } diff --git a/runtime/swimos_remote/Cargo.toml b/runtime/swimos_remote/Cargo.toml index 6d86dc8c6..f4df77f66 100644 --- a/runtime/swimos_remote/Cargo.toml +++ b/runtime/swimos_remote/Cargo.toml @@ -16,11 +16,11 @@ futures = { workspace = true } http = { workspace = true } tokio = { workspace = true, features = ["sync", "macros"] } tokio-util = { workspace = true, features = ["codec"] } -swimos_utilities = { path = "../../swimos_utilities", features = ["io", "buf_channel", "multi_reader"] } -swimos_api = { path = "../../api/swimos_api" } -swimos_model = { path = "../../api/swimos_model" } -swimos_recon = { path = "../../api/formats/swimos_recon" } -swimos_messages = { path = "../swimos_messages" } +swimos_utilities = { path = "../../swimos_utilities", features = ["io", "buf_channel", "multi_reader"], version = "0.1.0" } +swimos_api = { path = "../../api/swimos_api", version = "0.1.0" } +swimos_model = { path = "../../api/swimos_model", version = "0.1.0" } +swimos_recon = { path = "../../api/formats/swimos_recon", version = "0.1.0" } +swimos_messages = { path = "../swimos_messages", version = "0.1.0" } tracing = { workspace = true } thiserror = { workspace = true } tokio-stream = { workspace = true, features = ["sync"] } diff --git a/runtime/swimos_rocks_store/Cargo.toml b/runtime/swimos_rocks_store/Cargo.toml index f391d5a1c..a52f54c8d 100644 --- a/runtime/swimos_rocks_store/Cargo.toml +++ b/runtime/swimos_rocks_store/Cargo.toml @@ -4,12 +4,12 @@ version = "0.1.0" edition = "2021" [dependencies] -swimos_api = { path = "../../api/swimos_api" } -swimos_model = { path = "../../api/swimos_model" } +swimos_api = { path = "../../api/swimos_api", version = "0.1.0" } +swimos_model = { path = "../../api/swimos_model", version = "0.1.0" } rocksdb = { workspace = true } futures = { workspace = true } -swimos_utilities = { path = "../../swimos_utilities", features = ["io", "circular_buffer", "future"] } -swimos_form = { path = "../../api/swimos_form" } +swimos_utilities = { path = "../../swimos_utilities", features = ["io", "circular_buffer", "future"], version = "0.1.0" } +swimos_form = { path = "../../api/swimos_form", version = "0.1.0" } tokio = { workspace = true, features = ["sync"] } futures-util = { workspace = true } bytes = { workspace = true } diff --git a/runtime/swimos_runtime/Cargo.toml b/runtime/swimos_runtime/Cargo.toml index 7e0678c15..eff1ba7a2 100644 --- a/runtime/swimos_runtime/Cargo.toml +++ b/runtime/swimos_runtime/Cargo.toml @@ -18,15 +18,15 @@ futures-util = { workspace = true } http = { workspace = true } tokio = { workspace = true, features = ["sync", "rt", "macros"] } tokio-util = { workspace = true, features = ["codec"] } -swimos_utilities = { path = "../../swimos_utilities", features = ["circular_buffer", "errors", "future", "io", "encoding"] } -swimos_api = { path = "../../api/swimos_api" } -swimos_agent_protocol = { path = "../../api/swimos_agent_protocol" } -swimos_meta = { path = "../../api/swimos_meta" } -swimos_model = { path = "../../api/swimos_model" } -swimos_form = { path = "../../api/swimos_form" } -swimos_recon = { path = "../../api/formats/swimos_recon" } -swimos_messages = { path = "../swimos_messages" } -swimos_remote = { path = "../swimos_remote" } +swimos_utilities = { path = "../../swimos_utilities", features = ["circular_buffer", "errors", "future", "io", "encoding"], version = "0.1.0" } +swimos_api = { path = "../../api/swimos_api", version = "0.1.0" } +swimos_agent_protocol = { path = "../../api/swimos_agent_protocol", version = "0.1.0" } +swimos_meta = { path = "../../api/swimos_meta", version = "0.1.0" } +swimos_model = { path = "../../api/swimos_model", version = "0.1.0" } +swimos_form = { path = "../../api/swimos_form", version = "0.1.0" } +swimos_recon = { path = "../../api/formats/swimos_recon", version = "0.1.0" } +swimos_messages = { path = "../swimos_messages", version = "0.1.0" } +swimos_remote = { path = "../swimos_remote", version = "0.1.0" } tracing = { workspace = true } thiserror = { workspace = true } tokio-stream = { workspace = true, features = ["sync"] } diff --git a/server/swimos_agent/Cargo.toml b/server/swimos_agent/Cargo.toml index c45417178..1a9aaa4a2 100644 --- a/server/swimos_agent/Cargo.toml +++ b/server/swimos_agent/Cargo.toml @@ -10,15 +10,15 @@ json = ["dep:serde", "dep:serde_json"] [dependencies] futures = { workspace = true } -swimos_utilities = { path = "../../swimos_utilities", features = ["io", "trigger", "circular_buffer", "encoding"] } -swimos_model = { path = "../../api/swimos_model" } -swimos_form = { path = "../../api/swimos_form" } -swimos_recon = { path = "../../api/formats/swimos_recon" } +swimos_utilities = { path = "../../swimos_utilities", features = ["io", "trigger", "circular_buffer", "encoding"], version = "0.1.0" } +swimos_model = { path = "../../api/swimos_model", version = "0.1.0" } +swimos_form = { path = "../../api/swimos_form", version = "0.1.0" } +swimos_recon = { path = "../../api/formats/swimos_recon", version = "0.1.0" } bytes = { workspace = true } tokio = { workspace = true, features = ["macros", "time"] } tokio-util = { workspace = true, features = ["codec"] } -swimos_api = { path = "../../api/swimos_api" } -swimos_agent_protocol = { path = "../../api/swimos_agent_protocol" } +swimos_api = { path = "../../api/swimos_api", version = "0.1.0" } +swimos_agent_protocol = { path = "../../api/swimos_agent_protocol", version = "0.1.0" } tokio-stream = { workspace = true } tracing = { workspace = true } frunk = { workspace = true } @@ -35,4 +35,4 @@ serde_json = { workspace = true, optional = true } swimos_recon = { path = "../../api/formats/swimos_recon" } tokio = { workspace = true, features = ["rt", "test-util", "time"] } parking_lot = { workspace = true } -swimos_agent_derive = { path = "../swimos_agent_derive"} +swimos_agent_derive = { path = "../swimos_agent_derive" } diff --git a/server/swimos_agent_derive/Cargo.toml b/server/swimos_agent_derive/Cargo.toml index 3583e39f0..0b69a195f 100644 --- a/server/swimos_agent_derive/Cargo.toml +++ b/server/swimos_agent_derive/Cargo.toml @@ -12,9 +12,9 @@ proc-macro = true proc-macro2 = { workspace = true } syn = { workspace = true, features = ["full", "extra-traits"] } quote = { workspace = true } -swimos_utilities = { path = "../../swimos_utilities", features = ["errors", "text"] } +swimos_utilities = { path = "../../swimos_utilities", features = ["errors", "text"], version = "0.1.0" } bitflags = { workspace = true } -swimos_macro_utilities = { path = "../../swimos_macro_utilities" } +swimos_macro_utilities = { path = "../../swimos_macro_utilities", version = "0.1.0" } frunk = { workspace = true } [dev-dependencies] \ No newline at end of file diff --git a/server/swimos_server_app/Cargo.toml b/server/swimos_server_app/Cargo.toml index 8d788ae21..686ca2111 100644 --- a/server/swimos_server_app/Cargo.toml +++ b/server/swimos_server_app/Cargo.toml @@ -13,25 +13,25 @@ signal = ["tokio/signal"] [dependencies] futures = { workspace = true } ratchet = { workspace = true, features = ["deflate", "split"] } -swimos_utilities = { path = "../../swimos_utilities", features = ["io", "trigger", "text", "time"] } -swimos_runtime = { path = "../../runtime/swimos_runtime" } -swimos_messages = { path = "../../runtime/swimos_messages" } -swimos_http = { path = "../../runtime/swimos_http" } -swimos_introspection = { path = "../swimos_introspection" } -swimos_remote = { path = "../../runtime/swimos_remote", features = ["tls"]} +swimos_utilities = { path = "../../swimos_utilities", features = ["io", "trigger", "text", "time"], version = "0.1.0" } +swimos_runtime = { path = "../../runtime/swimos_runtime", version = "0.1.0" } +swimos_messages = { path = "../../runtime/swimos_messages", version = "0.1.0" } +swimos_http = { path = "../../runtime/swimos_http", version = "0.1.0" } +swimos_introspection = { path = "../swimos_introspection", version = "0.1.0" } +swimos_remote = { path = "../../runtime/swimos_remote", features = ["tls"], version = "0.1.0" } bytes = { workspace = true } tokio = { workspace = true, features = ["rt"] } tokio-util = { workspace = true, features = ["codec"] } -swimos_model = { path = "../../api/swimos_model" } -swimos_api = { path = "../../api/swimos_api" } -swimos_agent_protocol = { path = "../../api/swimos_agent_protocol" } +swimos_model = { path = "../../api/swimos_model", version = "0.1.0" } +swimos_api = { path = "../../api/swimos_api", version = "0.1.0" } +swimos_agent_protocol = { path = "../../api/swimos_agent_protocol", version = "0.1.0" } tokio-stream = { workspace = true } tracing = { workspace = true } uuid = { workspace = true } thiserror = { workspace = true } rand = { workspace = true } url = { workspace = true } -swimos_rocks_store = { path = "../../runtime/swimos_rocks_store", optional = true} +swimos_rocks_store = { path = "../../runtime/swimos_rocks_store", optional = true, version = "0.1.0" } parking_lot = { workspace = true } hyper = { workspace = true, features = ["server", "runtime", "tcp", "http1", "backports"] } pin-project = { workspace = true } diff --git a/swimos/Cargo.toml b/swimos/Cargo.toml index faa948d8e..3173a4220 100644 --- a/swimos/Cargo.toml +++ b/swimos/Cargo.toml @@ -12,15 +12,15 @@ agent = ["dep:swimos_agent", "dep:swimos_agent_derive"] json = ["agent", "swimos_agent/json"] [dependencies] -swimos_utilities = { path = "../swimos_utilities", features = ["io", "text"] } -swimos_api = { path = "../api/swimos_api" } -swimos_model = { path = "../api/swimos_model" } -swimos_recon = { path = "../api/formats/swimos_recon" } -swimos_server_app = { path = "../server/swimos_server_app", optional = true, features = ["signal"]} -swimos_agent = { path = "../server/swimos_agent", optional = true } -swimos_agent_derive = { path = "../server/swimos_agent_derive", optional = true } -swimos_remote = { path = "../runtime/swimos_remote", optional = true} -swimos_form = { path = "../api/swimos_form" } +swimos_utilities = { path = "../swimos_utilities", features = ["io", "text"], version = "0.1.0" } +swimos_api = { path = "../api/swimos_api", version = "0.1.0" } +swimos_model = { path = "../api/swimos_model", version = "0.1.0" } +swimos_recon = { path = "../api/formats/swimos_recon", version = "0.1.0" } +swimos_server_app = { path = "../server/swimos_server_app", optional = true, features = ["signal"], version = "0.1.0" } +swimos_agent = { path = "../server/swimos_agent", optional = true, version = "0.1.0" } +swimos_agent_derive = { path = "../server/swimos_agent_derive", optional = true, version = "0.1.0" } +swimos_remote = { path = "../runtime/swimos_remote", optional = true, version = "0.1.0" } +swimos_form = { path = "../api/swimos_form", version = "0.1.0" } [dev-dependencies] parking_lot = { workspace = true } diff --git a/swimos_client/Cargo.toml b/swimos_client/Cargo.toml index dc4e4727c..9d403e1fc 100644 --- a/swimos_client/Cargo.toml +++ b/swimos_client/Cargo.toml @@ -10,17 +10,17 @@ deflate = ["ratchet/deflate"] trust_dns = ["swimos_runtime/trust_dns"] [dependencies] -swimos_agent_protocol = { path = "../api/swimos_agent_protocol" } -swimos_recon = { path = "../api/formats/swimos_recon" } -swimos_messages = { path = "../runtime/swimos_messages" } -swimos_utilities = { path = "../swimos_utilities", features = ["trigger"] } -swimos_downlink = { path = "../swimos_downlink" } -swimos_api = { path = "../api/swimos_api" } -swimos_client_api = { path = "../api/swimos_client_api" } -swimos_model = { path = "../api/swimos_model" } -swimos_form = { path = "../api/swimos_form" } -swimos_runtime = { path = "../runtime/swimos_runtime" } -swimos_remote = { path = "../runtime/swimos_remote" } +swimos_agent_protocol = { path = "../api/swimos_agent_protocol", version = "0.1.0" } +swimos_recon = { path = "../api/formats/swimos_recon", version = "0.1.0" } +swimos_messages = { path = "../runtime/swimos_messages", version = "0.1.0" } +swimos_utilities = { path = "../swimos_utilities", features = ["trigger"], version = "0.1.0" } +swimos_downlink = { path = "../swimos_downlink", version = "0.1.0" } +swimos_api = { path = "../api/swimos_api", version = "0.1.0" } +swimos_client_api = { path = "../api/swimos_client_api", version = "0.1.0" } +swimos_model = { path = "../api/swimos_model", version = "0.1.0" } +swimos_form = { path = "../api/swimos_form", version = "0.1.0" } +swimos_runtime = { path = "../runtime/swimos_runtime", version = "0.1.0" } +swimos_remote = { path = "../runtime/swimos_remote", version = "0.1.0" } ratchet = { workspace = true } url = { workspace = true } tracing = { workspace = true } diff --git a/swimos_downlink/Cargo.toml b/swimos_downlink/Cargo.toml index 8322df761..f4208fb0d 100644 --- a/swimos_downlink/Cargo.toml +++ b/swimos_downlink/Cargo.toml @@ -6,16 +6,16 @@ edition = "2021" [dependencies] futures = { workspace = true } -swimos_utilities = { path = "../swimos_utilities", features = ["io", "trigger"] } -swimos_model = { path = "../api/swimos_model" } -swimos_form = { path = "../api/swimos_form" } -swimos_recon = { path = "../api/formats/swimos_recon" } +swimos_utilities = { path = "../swimos_utilities", features = ["io", "trigger"], version = "0.1.0" } +swimos_model = { path = "../api/swimos_model", version = "0.1.0" } +swimos_form = { path = "../api/swimos_form", version = "0.1.0" } +swimos_recon = { path = "../api/formats/swimos_recon", version = "0.1.0" } bytes = { workspace = true } tokio = { workspace = true } tokio-util = { workspace = true, features = ["codec"] } -swimos_api = { path = "../api/swimos_api" } -swimos_client_api = { path = "../api/swimos_client_api" } -swimos_agent_protocol = { path = "../api/swimos_agent_protocol" } +swimos_api = { path = "../api/swimos_api", version = "0.1.0" } +swimos_client_api = { path = "../api/swimos_client_api", version = "0.1.0" } +swimos_agent_protocol = { path = "../api/swimos_agent_protocol", version = "0.1.0" } tokio-stream = { workspace = true } tracing = { workspace = true } either = { workspace = true } From 53957a43c665618bc8a9225286b774b7c004ec06 Mon Sep 17 00:00:00 2001 From: SirCipher Date: Wed, 26 Jun 2024 16:00:25 +0100 Subject: [PATCH 27/27] Updates client to new crate structure --- client/swimos_client/Cargo.toml | 0 swimos_client/Cargo.toml | 8 +++++--- swimos_client/src/lib.rs | 24 ++++-------------------- 3 files changed, 9 insertions(+), 23 deletions(-) delete mode 100644 client/swimos_client/Cargo.toml diff --git a/client/swimos_client/Cargo.toml b/client/swimos_client/Cargo.toml deleted file mode 100644 index e69de29bb..000000000 diff --git a/swimos_client/Cargo.toml b/swimos_client/Cargo.toml index 9d403e1fc..324b3bb25 100644 --- a/swimos_client/Cargo.toml +++ b/swimos_client/Cargo.toml @@ -4,10 +4,11 @@ version = "0.1.0" edition = "2021" [features] -default = [] -tls = ["swimos_remote/tls"] +default = ["aws_lc_rs_provider"] deflate = ["ratchet/deflate"] trust_dns = ["swimos_runtime/trust_dns"] +ring_provider = ["swimos_remote/ring_provider"] +aws_lc_rs_provider = ["swimos_remote/aws_lc_rs_provider"] [dependencies] swimos_agent_protocol = { path = "../api/swimos_agent_protocol", version = "0.1.0" } @@ -31,4 +32,5 @@ futures-util = { workspace = true } bytes = { workspace = true } tokio = { workspace = true, features = ["io-util", "sync"] } tokio-util = { workspace = true, features = ["codec"] } -thiserror = { workspace = true } \ No newline at end of file +thiserror = { workspace = true } +rustls = { workspace = true } diff --git a/swimos_client/src/lib.rs b/swimos_client/src/lib.rs index fa6da9203..5ee0352d0 100644 --- a/swimos_client/src/lib.rs +++ b/swimos_client/src/lib.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::time::Duration; use std::{marker::PhantomData, num::NonZeroUsize, sync::Arc}; use futures_util::future::BoxFuture; @@ -20,13 +21,8 @@ use ratchet::{ WebSocketStream, }; use rustls::crypto::CryptoProvider; -use tokio::{sync::mpsc, sync::mpsc::error::SendError, sync::oneshot::error::RecvError}; -pub use url::Url; -use runtime::{ - start_runtime, ClientConfig, DownlinkRuntimeError, RawHandle, Transport, WebSocketConfig, -}; -pub use runtime::{CommandError, Commander, RemotePath}; +pub use commander::{CommandError, Commander}; pub use swimos_client_api::DownlinkConfig; pub use swimos_downlink::{ lifecycle::BasicEventDownlinkLifecycle, lifecycle::BasicMapDownlinkLifecycle, @@ -38,33 +34,22 @@ use swimos_downlink::{ MapValue, NotYetSyncedError, ValueDownlinkModel, ValueDownlinkSet, }; use swimos_form::Form; -pub use swimos_remote::tls::ClientConfig as TlsConfig; -use swimos_remote::tls::TlsError; -use swimos_remote::{ - dns::Resolver, - plain::TokioPlainTextNetworking, - tls::{CryptoProviderConfig, RustlsClientNetworking}, - websocket::RatchetClient, - ClientConnections, -}; use swimos_remote::{ dns::Resolver, plain::TokioPlainTextNetworking, + tls::CryptoProviderConfig, tls::{ClientConfig as TlsConfig, RustlsClientNetworking, TlsError}, websocket::RatchetClient, ClientConnections, }; use swimos_runtime::downlink::{DownlinkOptions, DownlinkRuntimeConfig}; -use swimos_utilities::{trigger, trigger::promise}; use swimos_utilities::{non_zero_usize, trigger, trigger::promise}; use tokio::{sync::mpsc, sync::mpsc::error::SendError, sync::oneshot::error::RecvError}; pub use url::Url; pub use crate::models::RemotePath; use crate::{ - error::DownlinkRuntimeError, - runtime::{start_runtime, RawHandle}, - transport::Transport, + error::DownlinkRuntimeError, runtime::start_runtime, runtime::RawHandle, transport::Transport, }; #[cfg(test)] @@ -79,7 +64,6 @@ mod transport; pub type DownlinkOperationResult = Result; -#[derive(Default)] const DEFAULT_BUFFER_SIZE: NonZeroUsize = non_zero_usize!(32); const DEFAULT_CLOSE_TIMEOUT: Duration = Duration::from_secs(5);