1use std::time::Instant;
4
5use a7n_proto::MachineId;
6use a7n_proto::limits;
7use a7n_proto::v1::{Accept, Ack, Handover, Refuse, RefuseReason, envelope::Body};
8
9use super::{Action, Cursor, Focus, Owner, Session, Take};
10
11impl Focus {
12 pub fn take(&mut self, take: Take, now: Instant) -> Vec<Action> {
14 if take.target == self.own_id {
15 return self.go_home();
16 }
17 if matches!(self.owner, Owner::Taking { .. }) || self.driven.is_some() {
18 return Vec::new();
19 }
20 let Some(route) = self.next_route() else {
21 return self.go_home();
22 };
23 let session = Session { take, route };
24 let action = Self::send(
25 session.take.target,
26 Body::Focus(Self::focus_message(&session, session.take.target, false)),
27 );
28 let previous = match std::mem::replace(&mut self.owner, Owner::Home) {
29 Owner::Driving(previous) => Some(previous),
30 _ => None,
31 };
32 self.owner = Owner::Taking {
33 session,
34 previous,
35 deadline: now + limits::TAKE_TIMEOUT,
36 };
37 vec![action]
38 }
39
40 pub fn on_accept(&mut self, peer: MachineId, accept: &Accept) -> Vec<Action> {
41 if !self.pending_matches(peer, accept.route) {
42 return Vec::new();
43 }
44 let Owner::Taking {
45 session, previous, ..
46 } = std::mem::replace(&mut self.owner, Owner::Home)
47 else {
48 return Vec::new();
49 };
50 let mut actions = Vec::new();
51 if let Some(previous) = previous.filter(|p| p.take.target != peer) {
52 self.let_go(previous.take.target, peer, &mut actions);
53 }
54 self.owner = Owner::Driving(session);
55 actions.push(Action::Cursor(Cursor::Driving(peer)));
56 actions
57 }
58
59 pub fn on_refuse(&mut self, peer: MachineId, refuse: &Refuse) -> Vec<Action> {
60 if !self.pending_matches(peer, refuse.route) {
61 return Vec::new();
62 }
63 match RefuseReason::try_from(refuse.reason) {
64 Ok(RefuseReason::SentHome) => self.go_home(),
66 _ => self.restore_previous(),
67 }
68 }
69
70 fn restore_previous(&mut self) -> Vec<Action> {
71 let Owner::Taking { previous, .. } = std::mem::replace(&mut self.owner, Owner::Home) else {
72 return Vec::new();
73 };
74 let Some(mut previous) = previous else {
75 return vec![Action::Cursor(Cursor::Home)];
76 };
77 let Some(route) = self.next_route() else {
78 self.owner = Owner::Driving(previous);
79 return self.go_home();
80 };
81 previous.route = route;
82 let target = previous.take.target;
83 let action = Self::send(
84 target,
85 Body::Focus(Self::focus_message(&previous, target, true)),
86 );
87 self.owner = Owner::Driving(previous);
88 vec![action, Action::Cursor(Cursor::Driving(target))]
89 }
90
91 pub fn poll(&mut self, now: Instant) -> Vec<Action> {
92 if self.next_deadline().is_some_and(|deadline| now >= deadline) {
93 return self.go_home();
94 }
95 Vec::new()
96 }
97
98 pub fn go_home(&mut self) -> Vec<Action> {
100 let owner = std::mem::replace(&mut self.owner, Owner::Home);
101 let mut actions = Vec::new();
102 match owner {
103 Owner::Home => return actions,
104 Owner::Driving(session) => self.let_go(session.take.target, self.own_id, &mut actions),
105 Owner::Taking {
106 session, previous, ..
107 } => {
108 if let Some(previous) = previous.filter(|p| p.take.target != session.take.target) {
109 self.let_go(previous.take.target, self.own_id, &mut actions);
110 }
111 self.let_go(session.take.target, self.own_id, &mut actions);
112 }
113 }
114 actions.push(Action::Cursor(Cursor::Home));
115 actions
116 }
117
118 pub fn on_handover(
119 &mut self,
120 peer: MachineId,
121 handover: &Handover,
122 now: Instant,
123 ) -> Vec<Action> {
124 let Owner::Driving(session) = &self.owner else {
125 return Vec::new();
126 };
127 if session.take.target != peer || session.route.0 != handover.route {
128 return Vec::new();
129 }
130 let Ok(next) = MachineId::try_from(handover.next.as_slice()) else {
131 return Vec::new();
132 };
133 if !handover.taken_over_by.is_empty() {
134 if next != self.own_id
135 || MachineId::try_from(handover.taken_over_by.as_slice()).is_err()
136 {
137 return Vec::new();
138 }
139 self.owner = Owner::Home;
140 return vec![Action::Cursor(Cursor::Home)];
141 }
142 if self.is_locked() {
143 return Vec::new();
144 }
145 if next == self.own_id {
146 return self.go_home();
147 }
148 if !session.take.reach.contains(&next) {
149 return Vec::new();
150 }
151 let take = Take {
152 target: next,
153 landing: handover.landing.clone(),
154 ..session.take.clone()
155 };
156 self.take(take, now)
157 }
158
159 pub fn on_ack(&mut self, peer: MachineId, ack: &Ack) -> Vec<Action> {
160 self.on_accepts(peer, !ack.locked)
161 }
162
163 pub fn on_accepts(&mut self, peer: MachineId, accepts: bool) -> Vec<Action> {
165 let is_target = match &self.owner {
166 Owner::Home => false,
167 Owner::Driving(session) => session.take.target == peer,
168 Owner::Taking {
169 session, previous, ..
170 } => {
171 session.take.target == peer
172 || previous.as_ref().is_some_and(|p| p.take.target == peer)
173 }
174 };
175 if !accepts && is_target {
176 self.go_home()
177 } else {
178 Vec::new()
179 }
180 }
181
182 pub fn on_link_lost(&mut self, peer: MachineId) -> Vec<Action> {
186 self.accepted.remove(&peer);
187 let mut actions = Vec::new();
188 if self
189 .driven
190 .as_ref()
191 .is_some_and(|driven| driven.owner == peer)
192 {
193 self.end_driven(&mut actions);
194 }
195 let involved = match &self.owner {
196 Owner::Home => false,
197 Owner::Driving(session) => session.take.target == peer,
198 Owner::Taking {
199 session, previous, ..
200 } => {
201 session.take.target == peer
202 || previous.as_ref().is_some_and(|p| p.take.target == peer)
203 }
204 };
205 if involved {
206 actions.extend(self.go_home());
207 actions.retain(|action| !matches!(action, Action::Send { peer: destination, .. } if *destination == peer));
208 }
209 actions
210 }
211
212 fn pending_matches(&self, peer: MachineId, route: u64) -> bool {
213 matches!(&self.owner, Owner::Taking { session, .. } if session.take.target == peer && session.route.0 == route)
214 }
215
216 fn let_go(&mut self, peer: MachineId, target: MachineId, actions: &mut Vec<Action>) {
217 if let Some(route) = self.next_route() {
218 actions.push(Self::send(
219 peer,
220 Body::Focus(a7n_proto::v1::Focus {
221 route: route.0,
222 target: target.as_bytes().to_vec(),
223 ..Default::default()
224 }),
225 ));
226 }
227 }
228}