1use crate::agents::live::wire::{DoAction, Subscription, WireEnvelope};
2use crate::agents::live::{LiveAgent, LiveResponse};
3use crate::widget::wired_bridge::AgentHook;
5use crate::widget::{Context, OnWireEvent, Widget};
6use anyhow::Error;
7use rill_protocol::diff::diff;
8use rill_protocol::flow::core::Flow;
9use rill_protocol::io::client::{ClientReqId, ClientResponse};
10use rill_protocol::io::provider::Path;
11use std::collections::{HashMap, HashSet};
12use yew::{Callback, Properties};
13
14pub trait WiredWidget<M>: Widget<Tag = Option<Path>, Meta = M> {
15 type Flow: Flow;
16
17 fn state_changed(&mut self, _reloaded: bool, _ctx: &mut Context<Self>) {}
18
19 fn state_update(
20 &mut self,
21 _tag: &Path,
22 _event: &<Self::Flow as Flow>::Event,
23 _reloaded: &mut bool,
24 _ctx: &mut Context<Self>,
25 ) {
26 }
27}
28
29#[derive(Properties, Clone, PartialEq)]
30pub struct SingleFlowProps {
31 pub path: Path,
32 #[prop_or_default]
33 pub triggered: Option<Callback<()>>,
34}
35
36impl SingleFlowProps {
37 pub fn notify(&self) {
38 if let Some(callback) = self.triggered.as_ref() {
39 callback.emit(());
40 }
41 }
42}
43
44pub struct SingleFlowMeta<T: WiredWidget<Self>> {
45 state: Option<T::Flow>,
46 wire: Option<Path>,
47}
48
49impl<T> Default for SingleFlowMeta<T>
50where
51 T: WiredWidget<Self>,
52{
53 fn default() -> Self {
54 Self {
55 state: None,
56 wire: None,
57 }
58 }
59}
60
61impl<T> SingleFlowMeta<T>
62where
63 T: WiredWidget<Self>,
64{
65 pub fn state(&self) -> Option<&T::Flow> {
66 self.state.as_ref()
67 }
68
69 }
75
76impl<T> Context<T>
77where
78 T: WiredWidget<SingleFlowMeta<T>>,
79{
80 pub fn do_action(&mut self, action: <T::Flow as Flow>::Action) {
81 if let Some(path) = self.meta().wire.clone() {
82 let do_action = DoAction::<T::Flow>::new(path, action);
83 self.live().wire(None, do_action);
84 } else {
87 log::error!("No path to do action: {:?}", action);
88 }
89 }
90
91 pub fn do_action_of<F: Flow>(&mut self, path: Path, action: F::Action) {
93 let do_action = DoAction::<F>::new(path, action);
94 self.live().wire(None, do_action);
95 }
96
97 pub fn rewire(&mut self, path: Path) {
99 if self.meta().wire.as_ref() != Some(&path) {
101 self.unwire();
102 self.meta_mut().state.take();
103 let wire_task = Subscription::new(path.clone());
104 let new_wire = Some(path);
105 self.meta_mut().wire = new_wire.clone();
106 self.live().wire(new_wire, wire_task);
107 self.redraw();
108 }
109 }
110
111 pub fn unwire(&mut self) {
112 if let Some(path) = self.meta_mut().wire.take() {
113 self.live().unwire(&Some(path));
114 }
115 }
116}
117
118pub struct SingleHook;
127
128impl AgentHook for SingleHook {
129 type Agent = LiveAgent;
130}
131
132impl<T> OnWireEvent<SingleHook> for T
133where
134 T: WiredWidget<SingleFlowMeta<Self>>,
135{
136 fn on_wire(
137 &mut self,
138 tag: &Self::Tag,
139 event: WireEnvelope<ClientReqId, LiveResponse>,
140 ctx: &mut Context<Self>,
141 ) -> Result<(), Error> {
142 match (tag.as_ref(), event.data) {
143 (Some(path), event) => {
144 if let LiveResponse::Forwarded(response) = event {
145 let mut reloaded = false;
146 match response {
147 ClientResponse::State(data) => {
148 let res = T::Flow::unpack_state(&data);
149 match res {
150 Ok(state) => {
151 ctx.meta_mut().state = Some(state);
152 reloaded = true;
153 }
154 Err(err) => {
155 log::error!("Can't unpack the state: {}", err);
156 }
157 }
158 }
159 ClientResponse::Delta(data) => {
160 let res = T::Flow::unpack_event(&data);
161 match res {
162 Ok(event) => {
163 self.state_update(path, &event, &mut reloaded, ctx);
164 if let Some(state) = ctx.meta_mut().state.as_mut() {
165 state.apply(event);
166 }
167 }
168 Err(err) => {
169 log::error!("Can't unpack the delta: {}", err);
170 }
171 }
172 }
173 ClientResponse::Done => {
174 }
176 other => {
177 log::error!("Unexpected message for the single flow: {:?}", other);
178 }
179 }
180 self.state_changed(reloaded, ctx);
181 }
182 }
183 (None, _) => {
184 ctx.redraw();
186 }
187 }
188 Ok(())
189 }
190}
191
192#[derive(Properties, Clone, PartialEq)]
193pub struct MultiFlowProps {
194 pub paths: HashSet<Path>,
195}
196
197pub struct MultiFlowMeta<T: WiredWidget<Self>> {
198 states: HashMap<Path, T::Flow>,
199 wires: HashSet<Path>,
200}
201
202impl<T> Default for MultiFlowMeta<T>
203where
204 T: WiredWidget<Self>,
205{
206 fn default() -> Self {
207 Self {
208 states: HashMap::new(),
209 wires: HashSet::new(),
210 }
211 }
212}
213
214impl<T> MultiFlowMeta<T>
215where
216 T: WiredWidget<Self>,
217{
218 pub fn states(&self) -> &HashMap<Path, T::Flow> {
219 &self.states
220 }
221}
222
223impl<T> Context<T>
224where
225 T: WiredWidget<MultiFlowMeta<T>>,
226{
227 pub fn rewire_many(&mut self, paths: &HashSet<Path>) {
228 let (to_add, to_remove) = diff(&self.meta().wires, paths);
229 for path in to_add {
230 let wire_task = Subscription::new(path.clone());
231 self.live().wire(Some(path.clone()), wire_task);
232 self.meta_mut().wires.insert(path);
233 self.redraw();
235 }
236 for path in to_remove {
237 self.meta_mut().wires.remove(&path);
238 self.meta_mut().states.remove(&path);
239 self.live().unwire(&Some(path));
240 self.redraw();
241 }
242 }
243}
244
245pub struct MultiHook;
246
247impl AgentHook for MultiHook {
248 type Agent = LiveAgent;
249}
250
251impl<T> OnWireEvent<MultiHook> for T
252where
253 T: WiredWidget<MultiFlowMeta<Self>>,
254{
255 fn on_wire(
256 &mut self,
257 tag: &Self::Tag,
258 event: WireEnvelope<ClientReqId, LiveResponse>,
259 ctx: &mut Context<Self>,
260 ) -> Result<(), Error> {
261 match (tag.as_ref(), event.data) {
262 (Some(path), event) => {
263 if let LiveResponse::Forwarded(response) = event {
264 let mut reloaded = false;
265 match response {
266 ClientResponse::State(data) => {
267 let state = T::Flow::unpack_state(&data).unwrap();
268 ctx.meta_mut().states.insert(path.clone(), state);
269 reloaded = true;
270 }
271 ClientResponse::Delta(data) => {
272 let event = T::Flow::unpack_event(&data).unwrap();
274 self.state_update(path, &event, &mut reloaded, ctx);
275 if let Some(state) = ctx.meta_mut().states.get_mut(path) {
276 state.apply(event);
277 }
278 }
279 ClientResponse::Done => {
280 }
282 other => {
283 log::error!("Unexpected message for the multi flow: {:?}", other);
284 }
285 }
286 self.state_changed(reloaded, ctx);
287 }
288 }
289 (None, _) => {
290 ctx.redraw();
292 }
293 }
294 Ok(())
295 }
296}