rate_ui/agents/live/
wire.rs1use crate::agents::live::{LiveAgent, LiveRequest, LiveResponse, LiveStatus};
2use rill_protocol::flow::core;
3use rill_protocol::io::client::{ClientReqId, ClientRequest, ClientResponse};
4use rill_protocol::io::provider::{FlowControl, Path, RecorderAction, RecorderRequest};
5use std::fmt;
6use yew::worker::{AgentLink, HandlerId};
7
8#[derive(Debug)]
9pub struct WireEnvelope<ID, T> {
10 pub id: ID,
11 pub data: T,
12}
13
14impl<ID, T> WireEnvelope<ID, T> {
15 pub fn new(id: ID, data: T) -> Self {
16 Self { id, data }
17 }
18}
19
20pub trait WireTask: fmt::Debug + 'static {
22 fn on_action(&mut self, action: WireAction, context: WireContext<'_>);
23}
24
25pub enum WireAction {
26 Status(LiveStatus),
28 Incoming(ClientResponse),
29 Interrupted,
30}
31
32pub struct WireContext<'a> {
33 pub who: HandlerId,
34 pub req_id: ClientReqId,
35 pub link: &'a mut AgentLink<LiveAgent>,
36}
37
38impl<'a> WireContext<'a> {
39 fn send_to_server(&mut self, request: ClientRequest) {
40 let input = LiveRequest::Forward(request);
41 let envelope = WireEnvelope::new(self.req_id, input);
42 self.link.send_input(envelope);
43 }
44
45 fn send_to_component(&mut self, response: ClientResponse) {
46 let output = LiveResponse::Forwarded(response);
47 let envelope = WireEnvelope::new(self.req_id, output);
48 self.link.respond(self.who, envelope);
49 }
50
51 fn shutdown(&mut self) {
52 let input = LiveRequest::DetachRuntime;
53 let envelope = WireEnvelope::new(self.req_id, input);
54 self.link.send_input(envelope);
55 }
56}
57
58#[derive(Debug)]
59pub struct Subscription {
60 path: Path,
61 sent: bool,
62 interrupted: bool,
63}
64
65impl Subscription {
66 pub fn new(path: Path) -> Self {
67 Self {
68 path,
69 sent: false,
70 interrupted: false,
71 }
72 }
73}
74
75impl WireTask for Subscription {
76 fn on_action(&mut self, action: WireAction, mut ctx: WireContext<'_>) {
77 match action {
78 WireAction::Status(LiveStatus::Connected) => {}
79 WireAction::Status(LiveStatus::AccessLevel(_)) => {
80 if !self.sent {
81 self.sent = true;
82 if !self.interrupted {
83 let control = FlowControl::StartStream;
84 let request = RecorderRequest::ControlStream(control);
85 let request = ClientRequest {
86 path: self.path.clone(),
87 request,
88 };
89 ctx.send_to_server(request);
90 }
91 }
92 }
93 WireAction::Status(LiveStatus::Disconnected) => {
94 self.sent = false;
95 }
98 WireAction::Incoming(response) => {
99 if !self.interrupted {
100 match &response {
101 ClientResponse::Done => {
102 self.interrupted = true;
103 }
104 ClientResponse::Error(err) => {
105 log::error!("Stream {} failed: {}", self.path, err);
106 }
107 _ => {}
108 }
109 ctx.send_to_component(response);
113 }
114 }
115 WireAction::Interrupted => {
116 if self.sent && !self.interrupted {
117 self.interrupted = true;
118 let control = FlowControl::StopStream;
119 let request = RecorderRequest::ControlStream(control);
120 let request = ClientRequest {
121 path: self.path.clone(),
122 request,
123 };
124 ctx.send_to_server(request);
125 }
127 }
128 }
129 }
130}
131
132#[derive(Debug)]
133pub struct GetDescription {
134 sent: bool,
135 path: Path,
136}
137
138impl GetDescription {
139 pub fn new(path: Path) -> Self {
140 Self { sent: false, path }
141 }
142}
143
144impl WireTask for GetDescription {
145 fn on_action(&mut self, action: WireAction, mut ctx: WireContext<'_>) {
146 match action {
147 WireAction::Status(LiveStatus::Connected) => {}
148 WireAction::Status(LiveStatus::AccessLevel(_)) => {
149 if !self.sent {
150 self.sent = true;
151 let action = RecorderAction::GetFlow;
152 let request = RecorderRequest::Action(action);
153 let request = ClientRequest {
154 path: self.path.clone(),
155 request,
156 };
157 ctx.send_to_server(request);
158 }
159 }
160 WireAction::Status(LiveStatus::Disconnected) => {
161 self.sent = false;
162 ctx.shutdown();
164 }
165 WireAction::Incoming(response) => {
166 ctx.send_to_component(response);
168 ctx.shutdown();
169 }
170 WireAction::Interrupted => {
171 ctx.shutdown();
174 }
175 }
176 }
177}
178
179#[derive(Debug)]
180pub struct DoAction<T: core::Flow> {
181 sent: bool,
182 path: Path,
183 action: T::Action,
184}
185
186impl<T: core::Flow> DoAction<T> {
187 pub fn new(path: Path, action: T::Action) -> Self {
188 Self {
189 sent: false,
190 path,
191 action,
192 }
193 }
194}
195
196impl<T: core::Flow> WireTask for DoAction<T> {
197 fn on_action(&mut self, action: WireAction, mut ctx: WireContext<'_>) {
198 match action {
199 WireAction::Status(LiveStatus::Connected) => {}
200 WireAction::Status(LiveStatus::AccessLevel(_)) => {
201 if !self.sent {
202 self.sent = true;
203 match T::pack_action(&self.action) {
204 Ok(packed_action) => {
205 let action = RecorderAction::DoAction(packed_action);
206 let request = RecorderRequest::Action(action);
207 let request = ClientRequest {
208 path: self.path.clone(),
209 request,
210 };
211 ctx.send_to_server(request);
212 }
213 Err(err) => {
214 log::error!("Can't pack an action: {}", err);
215 }
216 }
217 ctx.shutdown();
218 }
219 }
220 WireAction::Status(LiveStatus::Disconnected) => {
221 ctx.shutdown();
223 }
224 WireAction::Incoming(_response) => {
225 ctx.shutdown();
227 }
228 WireAction::Interrupted => {
229 ctx.shutdown();
232 }
233 }
234 }
235}