1use anyhow::{Result, bail};
2use vbare::{
3 Bytes, Converter, DecodeError, DecodeErrorKind, Encode, EncodeError, Message, Sink, Versioned,
4};
5
6use crate::generated::{v1, v2, v3, v4};
7
8pub enum ToClient {
9 V1(v1::ToClient),
10 V2(v2::ToClient),
11 V3(v3::ToClient),
12 V4(v4::ToClient),
13}
14
15impl Versioned for ToClient {
16 const LATEST: u16 = 4;
17
18 type Latest = v4::ToClient;
19
20 fn wrap_latest(latest: Self::Latest) -> Self {
21 Self::V4(latest)
22 }
23
24 fn unwrap_latest(self) -> Result<Self::Latest> {
25 match self {
26 Self::V4(data) => Ok(data),
27 _ => bail!("version not latest"),
28 }
29 }
30
31 fn decode_version(version: u16, payload: Bytes) -> std::result::Result<Self, DecodeError> {
32 match version {
33 1 => Ok(Self::V1(Message::decode(payload)?)),
34 2 => Ok(Self::V2(Message::decode(payload)?)),
35 3 => Ok(Self::V3(Message::decode(payload)?)),
36 4 => Ok(Self::V4(Message::decode(payload)?)),
37 _ => Err(unsupported_version(format!(
38 "invalid client protocol version: {version}"
39 ))),
40 }
41 }
42
43 fn encode_version<S: Sink>(
44 &self,
45 version: u16,
46 out: &mut S,
47 ) -> std::result::Result<(), EncodeError> {
48 match (self, version) {
49 (Self::V1(data), 1) => {
50 data.encode(out);
51 Ok(())
52 }
53 (Self::V2(data), 2) => {
54 data.encode(out);
55 Ok(())
56 }
57 (Self::V3(data), 3) => {
58 data.encode(out);
59 Ok(())
60 }
61 (Self::V4(data), 4) => {
62 data.encode(out);
63 Ok(())
64 }
65 (_, version) => Err(EncodeError::UnsupportedVersion(version)),
66 }
67 }
68
69 const UPGRADES: &'static [Converter<Self>] = &[Self::v1_to_v2, Self::v2_to_v3, Self::v3_to_v4];
70
71 const DOWNGRADES: &'static [Converter<Self>] =
72 &[Self::v4_to_v3, Self::v3_to_v2, Self::v2_to_v1];
73}
74
75impl ToClient {
76 fn v1_to_v2(self) -> Result<Self> {
77 let Self::V1(data) = self else {
78 bail!("expected client protocol v1 ToClient")
79 };
80
81 let body = match data.body {
82 v1::ToClientBody::Init(init) => v2::ToClientBody::Init(v2::Init {
83 actor_id: init.actor_id,
84 connection_id: init.connection_id,
85 }),
86 v1::ToClientBody::Error(error) => v2::ToClientBody::Error(v2::Error {
87 group: error.group,
88 code: error.code,
89 message: error.message,
90 metadata: error.metadata,
91 action_id: error.action_id,
92 }),
93 v1::ToClientBody::ActionResponse(response) => {
94 v2::ToClientBody::ActionResponse(v2::ActionResponse {
95 id: response.id,
96 output: response.output,
97 })
98 }
99 v1::ToClientBody::Event(event) => v2::ToClientBody::Event(v2::Event {
100 name: event.name,
101 args: event.args,
102 }),
103 };
104
105 Ok(Self::V2(v2::ToClient { body }))
106 }
107
108 fn v2_to_v3(self) -> Result<Self> {
109 let Self::V2(data) = self else {
110 bail!("expected client protocol v2 ToClient")
111 };
112 Ok(Self::V3(data.into()))
113 }
114
115 fn v3_to_v4(self) -> Result<Self> {
116 let Self::V3(data) = self else {
117 bail!("expected client protocol v3 ToClient")
118 };
119
120 let body = match data.body {
121 v3::ToClientBody::Init(init) => v4::ToClientBody::Init(v4::Init {
122 actor_id: init.actor_id,
123 connection_id: init.connection_id,
124 }),
125 v3::ToClientBody::Error(error) => v4::ToClientBody::Error(v4::Error {
126 group: error.group,
127 code: error.code,
128 message: error.message,
129 metadata: error.metadata,
130 action_id: error.action_id,
131 actor: None,
132 }),
133 v3::ToClientBody::ActionResponse(response) => {
134 v4::ToClientBody::ActionResponse(v4::ActionResponse {
135 id: response.id,
136 output: response.output,
137 })
138 }
139 v3::ToClientBody::Event(event) => v4::ToClientBody::Event(v4::Event {
140 name: event.name,
141 args: event.args,
142 }),
143 };
144
145 Ok(Self::V4(v4::ToClient { body }))
146 }
147
148 fn v4_to_v3(self) -> Result<Self> {
149 let Self::V4(data) = self else {
150 bail!("expected client protocol v4 ToClient")
151 };
152
153 let body = match data.body {
154 v4::ToClientBody::Init(init) => v3::ToClientBody::Init(v3::Init {
155 actor_id: init.actor_id,
156 connection_id: init.connection_id,
157 }),
158 v4::ToClientBody::Error(error) => v3::ToClientBody::Error(v3::Error {
159 group: error.group,
160 code: error.code,
161 message: error.message,
162 metadata: error.metadata,
163 action_id: error.action_id,
164 }),
165 v4::ToClientBody::ActionResponse(response) => {
166 v3::ToClientBody::ActionResponse(v3::ActionResponse {
167 id: response.id,
168 output: response.output,
169 })
170 }
171 v4::ToClientBody::Event(event) => v3::ToClientBody::Event(v3::Event {
172 name: event.name,
173 args: event.args,
174 }),
175 };
176
177 Ok(Self::V3(v3::ToClient { body }))
178 }
179
180 fn v3_to_v2(self) -> Result<Self> {
181 let Self::V3(data) = self else {
182 bail!("expected client protocol v3 ToClient")
183 };
184 Ok(Self::V2(data.into()))
185 }
186
187 fn v2_to_v1(self) -> Result<Self> {
188 let Self::V2(data) = self else {
189 bail!("expected client protocol v2 ToClient")
190 };
191
192 let body = match data.body {
193 v2::ToClientBody::Init(init) => v1::ToClientBody::Init(v1::Init {
194 actor_id: init.actor_id,
195 connection_id: init.connection_id,
196 connection_token: String::new().into(),
197 }),
198 v2::ToClientBody::Error(error) => v1::ToClientBody::Error(v1::Error {
199 group: error.group,
200 code: error.code,
201 message: error.message,
202 metadata: error.metadata,
203 action_id: error.action_id,
204 }),
205 v2::ToClientBody::ActionResponse(response) => {
206 v1::ToClientBody::ActionResponse(v1::ActionResponse {
207 id: response.id,
208 output: response.output,
209 })
210 }
211 v2::ToClientBody::Event(event) => v1::ToClientBody::Event(v1::Event {
212 name: event.name,
213 args: event.args,
214 }),
215 };
216
217 Ok(Self::V1(v1::ToClient { body }))
218 }
219}
220
221macro_rules! impl_same_fields_pair {
222 ($left:ident, $right:ident, $ty:ident { $($field:ident),+ $(,)? }) => {
223 impl From<$left::$ty> for $right::$ty {
224 fn from(value: $left::$ty) -> Self {
225 Self {
226 $($field: value.$field),+
227 }
228 }
229 }
230
231 impl From<$right::$ty> for $left::$ty {
232 fn from(value: $right::$ty) -> Self {
233 Self {
234 $($field: value.$field),+
235 }
236 }
237 }
238 };
239}
240
241macro_rules! impl_to_server_pair {
242 ($left:ident, $right:ident) => {
243 impl From<$left::ToServerBody> for $right::ToServerBody {
244 fn from(value: $left::ToServerBody) -> Self {
245 match value {
246 $left::ToServerBody::ActionRequest(request) => {
247 Self::ActionRequest(request.into())
248 }
249 $left::ToServerBody::SubscriptionRequest(request) => {
250 Self::SubscriptionRequest(request.into())
251 }
252 }
253 }
254 }
255
256 impl From<$right::ToServerBody> for $left::ToServerBody {
257 fn from(value: $right::ToServerBody) -> Self {
258 match value {
259 $right::ToServerBody::ActionRequest(request) => {
260 Self::ActionRequest(request.into())
261 }
262 $right::ToServerBody::SubscriptionRequest(request) => {
263 Self::SubscriptionRequest(request.into())
264 }
265 }
266 }
267 }
268
269 impl From<$left::ToServer> for $right::ToServer {
270 fn from(value: $left::ToServer) -> Self {
271 Self {
272 body: value.body.into(),
273 }
274 }
275 }
276
277 impl From<$right::ToServer> for $left::ToServer {
278 fn from(value: $right::ToServer) -> Self {
279 Self {
280 body: value.body.into(),
281 }
282 }
283 }
284 };
285}
286
287macro_rules! impl_common_pair {
288 ($left:ident, $right:ident) => {
289 impl_same_fields_pair!($left, $right, ActionRequest { id, name, args });
290 impl_same_fields_pair!(
291 $left,
292 $right,
293 SubscriptionRequest {
294 event_name,
295 subscribe,
296 }
297 );
298 impl_to_server_pair!($left, $right);
299 impl_same_fields_pair!($left, $right, HttpActionRequest { args });
300 impl_same_fields_pair!($left, $right, HttpActionResponse { output });
301 impl_same_fields_pair!($left, $right, HttpResolveResponse { actor_id });
302 };
303}
304
305macro_rules! impl_to_client_v2_v3_pair {
306 () => {
307 impl_same_fields_pair!(
308 v2,
309 v3,
310 Init {
311 actor_id,
312 connection_id,
313 }
314 );
315 impl_same_fields_pair!(
316 v2,
317 v3,
318 Error {
319 group,
320 code,
321 message,
322 metadata,
323 action_id,
324 }
325 );
326 impl_same_fields_pair!(v2, v3, ActionResponse { id, output });
327 impl_same_fields_pair!(v2, v3, Event { name, args });
328
329 impl From<v2::ToClientBody> for v3::ToClientBody {
330 fn from(value: v2::ToClientBody) -> Self {
331 match value {
332 v2::ToClientBody::Init(init) => Self::Init(init.into()),
333 v2::ToClientBody::Error(error) => Self::Error(error.into()),
334 v2::ToClientBody::ActionResponse(response) => {
335 Self::ActionResponse(response.into())
336 }
337 v2::ToClientBody::Event(event) => Self::Event(event.into()),
338 }
339 }
340 }
341
342 impl From<v3::ToClientBody> for v2::ToClientBody {
343 fn from(value: v3::ToClientBody) -> Self {
344 match value {
345 v3::ToClientBody::Init(init) => Self::Init(init.into()),
346 v3::ToClientBody::Error(error) => Self::Error(error.into()),
347 v3::ToClientBody::ActionResponse(response) => {
348 Self::ActionResponse(response.into())
349 }
350 v3::ToClientBody::Event(event) => Self::Event(event.into()),
351 }
352 }
353 }
354
355 impl From<v2::ToClient> for v3::ToClient {
356 fn from(value: v2::ToClient) -> Self {
357 Self {
358 body: value.body.into(),
359 }
360 }
361 }
362
363 impl From<v3::ToClient> for v2::ToClient {
364 fn from(value: v3::ToClient) -> Self {
365 Self {
366 body: value.body.into(),
367 }
368 }
369 }
370 };
371}
372
373impl_common_pair!(v1, v2);
374impl_common_pair!(v2, v3);
375impl_common_pair!(v3, v4);
376impl_to_client_v2_v3_pair!();
377impl_same_fields_pair!(
378 v1,
379 v2,
380 HttpResponseError {
381 group,
382 code,
383 message,
384 metadata,
385 }
386);
387impl_same_fields_pair!(
388 v2,
389 v3,
390 HttpResponseError {
391 group,
392 code,
393 message,
394 metadata,
395 }
396);
397impl_same_fields_pair!(
398 v3,
399 v4,
400 HttpQueueSendRequest {
401 body,
402 name,
403 wait,
404 timeout,
405 }
406);
407impl_same_fields_pair!(v3, v4, HttpQueueSendResponse { status, response });
408
409macro_rules! impl_versioned_manual {
410 ($name:ident, $latest_ty:path, $v1_ty:path, $v2_ty:path, $v3_ty:path, $v4_ty:path) => {
411 pub enum $name {
412 V1($v1_ty),
413 V2($v2_ty),
414 V3($v3_ty),
415 V4($v4_ty),
416 }
417
418 impl Versioned for $name {
419 const LATEST: u16 = 4;
420
421 type Latest = $latest_ty;
422
423 fn wrap_latest(latest: Self::Latest) -> Self {
424 Self::V4(latest)
425 }
426
427 fn unwrap_latest(self) -> Result<Self::Latest> {
428 match self {
429 Self::V4(data) => Ok(data),
430 _ => bail!("version not latest"),
431 }
432 }
433
434 fn decode_version(
435 version: u16,
436 payload: Bytes,
437 ) -> std::result::Result<Self, DecodeError> {
438 match version {
439 1 => Ok(Self::V1(Message::decode(payload)?)),
440 2 => Ok(Self::V2(Message::decode(payload)?)),
441 3 => Ok(Self::V3(Message::decode(payload)?)),
442 4 => Ok(Self::V4(Message::decode(payload)?)),
443 _ => Err(unsupported_version(format!(
444 "invalid client protocol version for {}: {version}",
445 stringify!($name)
446 ))),
447 }
448 }
449
450 fn encode_version<S: Sink>(
451 &self,
452 version: u16,
453 out: &mut S,
454 ) -> std::result::Result<(), EncodeError> {
455 match (self, version) {
456 (Self::V1(data), 1) => {
457 data.encode(out);
458 Ok(())
459 }
460 (Self::V2(data), 2) => {
461 data.encode(out);
462 Ok(())
463 }
464 (Self::V3(data), 3) => {
465 data.encode(out);
466 Ok(())
467 }
468 (Self::V4(data), 4) => {
469 data.encode(out);
470 Ok(())
471 }
472 (_, version) => Err(EncodeError::UnsupportedVersion(version)),
473 }
474 }
475
476 const UPGRADES: &'static [Converter<Self>] =
477 &[Self::v1_to_v2, Self::v2_to_v3, Self::v3_to_v4];
478
479 const DOWNGRADES: &'static [Converter<Self>] =
480 &[Self::v4_to_v3, Self::v3_to_v2, Self::v2_to_v1];
481 }
482
483 impl $name {
484 fn v1_to_v2(self) -> Result<Self> {
485 let Self::V1(data) = self else {
486 bail!("expected client protocol v1 {}", stringify!($name))
487 };
488 Ok(Self::V2(data.into()))
489 }
490
491 fn v2_to_v3(self) -> Result<Self> {
492 let Self::V2(data) = self else {
493 bail!("expected client protocol v2 {}", stringify!($name))
494 };
495 Ok(Self::V3(data.into()))
496 }
497
498 fn v3_to_v4(self) -> Result<Self> {
499 let Self::V3(data) = self else {
500 bail!("expected client protocol v3 {}", stringify!($name))
501 };
502 Ok(Self::V4(data.into()))
503 }
504
505 fn v4_to_v3(self) -> Result<Self> {
506 let Self::V4(data) = self else {
507 bail!("expected client protocol v4 {}", stringify!($name))
508 };
509 Ok(Self::V3(data.into()))
510 }
511
512 fn v3_to_v2(self) -> Result<Self> {
513 let Self::V3(data) = self else {
514 bail!("expected client protocol v3 {}", stringify!($name))
515 };
516 Ok(Self::V2(data.into()))
517 }
518
519 fn v2_to_v1(self) -> Result<Self> {
520 let Self::V2(data) = self else {
521 bail!("expected client protocol v2 {}", stringify!($name))
522 };
523 Ok(Self::V1(data.into()))
524 }
525 }
526 };
527}
528
529macro_rules! impl_versioned_v3_only {
530 ($name:ident, $latest_ty:path) => {
531 pub enum $name {
532 V3(v3::$name),
533 V4($latest_ty),
534 }
535
536 impl Versioned for $name {
537 const LATEST: u16 = 4;
538
539 type Latest = $latest_ty;
540
541 fn wrap_latest(latest: Self::Latest) -> Self {
542 Self::V4(latest)
543 }
544
545 fn unwrap_latest(self) -> Result<Self::Latest> {
546 match self {
547 Self::V4(data) => Ok(data),
548 _ => bail!("version not latest"),
549 }
550 }
551
552 fn decode_version(
553 version: u16,
554 payload: Bytes,
555 ) -> std::result::Result<Self, DecodeError> {
556 match version {
557 3 => Ok(Self::V3(Message::decode(payload)?)),
558 4 => Ok(Self::V4(Message::decode(payload)?)),
559 _ => Err(unsupported_version(format!(
560 "{} only exists in client protocol v3, got {version}",
561 stringify!($name)
562 ))),
563 }
564 }
565
566 fn encode_version<S: Sink>(
567 &self,
568 version: u16,
569 out: &mut S,
570 ) -> std::result::Result<(), EncodeError> {
571 match (self, version) {
572 (Self::V3(data), 3) => {
573 data.encode(out);
574 Ok(())
575 }
576 (Self::V4(data), 4) => {
577 data.encode(out);
578 Ok(())
579 }
580 (_, version) => Err(EncodeError::UnsupportedVersion(version)),
581 }
582 }
583
584 const UPGRADES: &'static [Converter<Self>] = &[Ok, Ok, Self::v3_to_v4];
585
586 const DOWNGRADES: &'static [Converter<Self>] = &[Self::v4_to_v3, Ok, Ok];
587 }
588
589 impl $name {
590 fn v3_to_v4(self) -> Result<Self> {
591 let Self::V3(data) = self else {
592 bail!("expected client protocol v3 {}", stringify!($name))
593 };
594 Ok(Self::V4(data.into()))
595 }
596
597 fn v4_to_v3(self) -> Result<Self> {
598 let Self::V4(data) = self else {
599 bail!("expected client protocol v4 {}", stringify!($name))
600 };
601 Ok(Self::V3(data.into()))
602 }
603 }
604 };
605}
606
607impl_versioned_manual!(
608 ToServer,
609 v4::ToServer,
610 v1::ToServer,
611 v2::ToServer,
612 v3::ToServer,
613 v4::ToServer
614);
615impl_versioned_manual!(
616 HttpActionRequest,
617 v4::HttpActionRequest,
618 v1::HttpActionRequest,
619 v2::HttpActionRequest,
620 v3::HttpActionRequest,
621 v4::HttpActionRequest
622);
623impl_versioned_manual!(
624 HttpActionResponse,
625 v4::HttpActionResponse,
626 v1::HttpActionResponse,
627 v2::HttpActionResponse,
628 v3::HttpActionResponse,
629 v4::HttpActionResponse
630);
631impl_versioned_manual!(
632 HttpResolveResponse,
633 v4::HttpResolveResponse,
634 v1::HttpResolveResponse,
635 v2::HttpResolveResponse,
636 v3::HttpResolveResponse,
637 v4::HttpResolveResponse
638);
639impl_versioned_v3_only!(HttpQueueSendRequest, v4::HttpQueueSendRequest);
640impl_versioned_v3_only!(HttpQueueSendResponse, v4::HttpQueueSendResponse);
641
642pub enum HttpResponseError {
643 V1(v1::HttpResponseError),
644 V2(v2::HttpResponseError),
645 V3(v3::HttpResponseError),
646 V4(v4::HttpResponseError),
647}
648
649impl Versioned for HttpResponseError {
650 const LATEST: u16 = 4;
651
652 type Latest = v4::HttpResponseError;
653
654 fn wrap_latest(latest: Self::Latest) -> Self {
655 Self::V4(latest)
656 }
657
658 fn unwrap_latest(self) -> Result<Self::Latest> {
659 match self {
660 Self::V4(data) => Ok(data),
661 _ => bail!("version not latest"),
662 }
663 }
664
665 fn decode_version(version: u16, payload: Bytes) -> std::result::Result<Self, DecodeError> {
666 match version {
667 1 => Ok(Self::V1(Message::decode(payload)?)),
668 2 => Ok(Self::V2(Message::decode(payload)?)),
669 3 => Ok(Self::V3(Message::decode(payload)?)),
670 4 => Ok(Self::V4(Message::decode(payload)?)),
671 _ => Err(unsupported_version(format!(
672 "invalid client protocol version for HttpResponseError: {version}"
673 ))),
674 }
675 }
676
677 fn encode_version<S: Sink>(
678 &self,
679 version: u16,
680 out: &mut S,
681 ) -> std::result::Result<(), EncodeError> {
682 match (self, version) {
683 (Self::V1(data), 1) => {
684 data.encode(out);
685 Ok(())
686 }
687 (Self::V2(data), 2) => {
688 data.encode(out);
689 Ok(())
690 }
691 (Self::V3(data), 3) => {
692 data.encode(out);
693 Ok(())
694 }
695 (Self::V4(data), 4) => {
696 data.encode(out);
697 Ok(())
698 }
699 (_, version) => return Err(EncodeError::UnsupportedVersion(version)),
700 }
701 }
702
703 const UPGRADES: &'static [Converter<Self>] = &[Self::v1_to_v2, Self::v2_to_v3, Self::v3_to_v4];
704
705 const DOWNGRADES: &'static [Converter<Self>] =
706 &[Self::v4_to_v3, Self::v3_to_v2, Self::v2_to_v1];
707}
708
709impl HttpResponseError {
710 fn v1_to_v2(self) -> Result<Self> {
711 let Self::V1(data) = self else {
712 bail!("expected client protocol v1 HttpResponseError")
713 };
714 Ok(Self::V2(data.into()))
715 }
716
717 fn v2_to_v3(self) -> Result<Self> {
718 let Self::V2(data) = self else {
719 bail!("expected client protocol v2 HttpResponseError")
720 };
721 Ok(Self::V3(data.into()))
722 }
723
724 fn v3_to_v4(self) -> Result<Self> {
725 let Self::V3(data) = self else {
726 bail!("expected client protocol v3 HttpResponseError")
727 };
728 Ok(Self::V4(v4::HttpResponseError {
729 group: data.group,
730 code: data.code,
731 message: data.message,
732 metadata: data.metadata,
733 actor: None,
734 }))
735 }
736
737 fn v4_to_v3(self) -> Result<Self> {
738 let Self::V4(data) = self else {
739 bail!("expected client protocol v4 HttpResponseError")
740 };
741 Ok(Self::V3(v3::HttpResponseError {
742 group: data.group,
743 code: data.code,
744 message: data.message,
745 metadata: data.metadata,
746 }))
747 }
748
749 fn v3_to_v2(self) -> Result<Self> {
750 let Self::V3(data) = self else {
751 bail!("expected client protocol v3 HttpResponseError")
752 };
753 Ok(Self::V2(data.into()))
754 }
755
756 fn v2_to_v1(self) -> Result<Self> {
757 let Self::V2(data) = self else {
758 bail!("expected client protocol v2 HttpResponseError")
759 };
760 Ok(Self::V1(data.into()))
761 }
762}
763
764fn unsupported_version(detail: String) -> DecodeError {
766 DecodeError::with_detail(DecodeErrorKind::UnsupportedVersion, 0, detail)
767}