fiberplane_models/
proxies.rs

1use super::data_sources::{DataSource, DataSourceStatus};
2use super::names::{InvalidName, Name};
3use super::providers::Error;
4use crate::blobs::Blob;
5use crate::notebooks::Cell;
6use crate::providers::{ConfigSchema, ProviderConfig, SupportedQueryType};
7use base64uuid::{Base64Uuid, InvalidId};
8#[cfg(feature = "fp-bindgen")]
9use fp_bindgen::prelude::Serializable;
10use serde::{Deserialize, Serialize};
11use std::fmt::{self, Debug, Formatter};
12use std::{convert::TryFrom, str::FromStr};
13use strum_macros::Display;
14use time::OffsetDateTime;
15use typed_builder::TypedBuilder;
16
17#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, TypedBuilder)]
18#[non_exhaustive]
19#[serde(rename_all = "camelCase")]
20pub struct Proxy {
21    pub id: Base64Uuid,
22    pub name: Name,
23    pub status: ProxyStatus,
24    #[builder(default)]
25    pub data_sources: Vec<DataSource>,
26    #[builder(default, setter(into, strip_option))]
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub token: Option<ProxyToken>,
29    #[builder(default, setter(into))]
30    pub description: Option<String>,
31    #[builder(setter(into))]
32    pub created_at: OffsetDateTime,
33    #[builder(setter(into))]
34    pub updated_at: OffsetDateTime,
35}
36
37#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, TypedBuilder)]
38#[cfg_attr(
39    feature = "fp-bindgen",
40    derive(Serializable),
41    fp(rust_module = "fiberplane_models::proxies")
42)]
43#[non_exhaustive]
44#[serde(rename_all = "camelCase")]
45pub struct ProxySummary {
46    pub id: Base64Uuid,
47    pub name: Name,
48    pub status: ProxyStatus,
49}
50
51impl From<Proxy> for ProxySummary {
52    fn from(proxy: Proxy) -> Self {
53        Self {
54            id: proxy.id,
55            name: proxy.name,
56            status: proxy.status,
57        }
58    }
59}
60
61#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy, Display)]
62#[cfg_attr(
63    feature = "fp-bindgen",
64    derive(Serializable),
65    fp(rust_module = "fiberplane_models::proxies")
66)]
67#[non_exhaustive]
68#[serde(rename_all = "snake_case")]
69pub enum ProxyStatus {
70    Connected,
71    Disconnected,
72}
73
74#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, TypedBuilder)]
75#[cfg_attr(
76    feature = "fp-bindgen",
77    derive(Serializable),
78    fp(rust_module = "fiberplane_models::proxies")
79)]
80#[non_exhaustive]
81#[serde(rename_all = "camelCase")]
82pub struct NewProxy {
83    pub name: Name,
84    #[builder(default, setter(into))]
85    pub description: Option<String>,
86}
87
88#[derive(Debug, thiserror::Error, PartialEq, Eq)]
89#[cfg_attr(
90    feature = "fp-bindgen",
91    derive(Serializable),
92    fp(rust_module = "fiberplane_models::proxies")
93)]
94#[non_exhaustive]
95pub enum InvalidProxyToken {
96    #[error("Invalid workspace ID")]
97    InvalidWorkspaceId(#[from] InvalidId),
98    #[error("Invalid proxy name")]
99    InvalidProxyName(#[from] InvalidName),
100    #[error("Missing token")]
101    MissingToken,
102}
103
104/// This represents the auth token that is generated by the API and used
105/// by the proxy to authenticate its websocket connection.
106#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, TypedBuilder)]
107#[cfg_attr(
108    feature = "fp-bindgen",
109    derive(Serializable),
110    fp(rust_module = "fiberplane_models::proxies")
111)]
112#[non_exhaustive]
113#[serde(try_from = "&str", into = "String")]
114pub struct ProxyToken {
115    #[builder(setter(into))]
116    pub workspace_id: Base64Uuid,
117    pub proxy_name: Name,
118    #[builder(setter(into))]
119    pub token: String,
120}
121
122impl Debug for ProxyToken {
123    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
124        f.debug_struct("ProxyToken")
125            .field("workspace_id", &self.workspace_id)
126            .field("proxy_name", &self.proxy_name)
127            .field("token", &"[REDACTED]")
128            .finish()
129    }
130}
131
132impl From<ProxyToken> for String {
133    fn from(token: ProxyToken) -> Self {
134        format!(
135            "{}:{}:{}",
136            token.workspace_id, token.proxy_name, token.token
137        )
138    }
139}
140
141impl FromStr for ProxyToken {
142    type Err = InvalidProxyToken;
143
144    fn from_str(s: &str) -> Result<Self, Self::Err> {
145        let mut parts = s.split(':');
146
147        let workspace_id = parts.next().unwrap_or_default().parse::<Base64Uuid>()?;
148        let proxy_name = Name::new(parts.next().unwrap_or_default())?;
149        let token = parts
150            .next()
151            .ok_or(InvalidProxyToken::MissingToken)?
152            .to_string();
153
154        Ok(ProxyToken {
155            workspace_id,
156            proxy_name,
157            token,
158        })
159    }
160}
161
162impl TryFrom<&str> for ProxyToken {
163    type Error = InvalidProxyToken;
164
165    fn try_from(s: &str) -> Result<Self, Self::Error> {
166        Self::from_str(s)
167    }
168}
169
170#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, TypedBuilder)]
171#[cfg_attr(
172    feature = "fp-bindgen",
173    derive(Serializable),
174    fp(rust_module = "fiberplane_models::proxies")
175)]
176#[non_exhaustive]
177#[serde(rename_all = "camelCase")]
178pub struct CreateCellsApiRequest {
179    pub response: Blob,
180    pub query_type: String,
181}
182
183#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, TypedBuilder)]
184#[cfg_attr(
185    feature = "fp-bindgen",
186    derive(Serializable),
187    fp(rust_module = "fiberplane_models::proxies")
188)]
189#[non_exhaustive]
190#[serde(rename_all = "camelCase")]
191pub struct ExtractDataApiRequest {
192    pub response: Blob,
193    pub mime_type: String,
194    #[serde(default, skip_serializing_if = "Option::is_none")]
195    pub query: Option<String>,
196}
197
198/// Messages sent to the Proxy
199#[derive(Debug, Deserialize, Serialize, TypedBuilder)]
200#[cfg_attr(
201    feature = "fp-bindgen",
202    derive(Serializable),
203    fp(rust_module = "fiberplane_models::proxies")
204)]
205#[non_exhaustive]
206#[serde(rename_all = "camelCase")]
207pub struct ServerMessage {
208    pub op_id: Base64Uuid,
209    pub data_source_name: Name,
210    pub protocol_version: u8,
211    #[serde(flatten)]
212    pub payload: ServerMessagePayload,
213}
214
215impl ServerMessage {
216    pub fn deserialize_msgpack(
217        input: impl AsRef<[u8]>,
218    ) -> Result<ServerMessage, rmp_serde::decode::Error> {
219        rmp_serde::from_slice(input.as_ref())
220    }
221
222    pub fn serialize_msgpack(&self) -> Vec<u8> {
223        rmp_serde::to_vec(&self).expect("MessgePack serialization error")
224    }
225
226    pub fn op_id(&self) -> Option<Base64Uuid> {
227        Some(self.op_id)
228    }
229
230    fn payload_with_header(
231        payload: ServerMessagePayload,
232        data_source_name: Name,
233        protocol_version: u8,
234        op_id: Base64Uuid,
235    ) -> Self {
236        Self {
237            op_id,
238            data_source_name,
239            protocol_version,
240            payload,
241        }
242    }
243
244    pub fn new_invoke_proxy_request(
245        data: Vec<u8>,
246        data_source_name: Name,
247        protocol_version: u8,
248        op_id: Base64Uuid,
249    ) -> Self {
250        Self::payload_with_header(
251            ServerMessagePayload::Invoke(InvokeRequest { data }),
252            data_source_name,
253            protocol_version,
254            op_id,
255        )
256    }
257    pub fn new_create_cells_request(
258        data: Blob,
259        query_type: String,
260        data_source_name: Name,
261        protocol_version: u8,
262        op_id: Base64Uuid,
263    ) -> Self {
264        Self::payload_with_header(
265            ServerMessagePayload::CreateCells(CreateCellsRequest {
266                response: data,
267                query_type,
268            }),
269            data_source_name,
270            protocol_version,
271            op_id,
272        )
273    }
274    pub fn new_extract_data_request(
275        data: Blob,
276        mime_type: String,
277        query: Option<String>,
278        data_source_name: Name,
279        protocol_version: u8,
280        op_id: Base64Uuid,
281    ) -> Self {
282        Self::payload_with_header(
283            ServerMessagePayload::ExtractData(ExtractDataRequest {
284                response: data,
285                mime_type,
286                query,
287            }),
288            data_source_name,
289            protocol_version,
290            op_id,
291        )
292    }
293    pub fn new_get_config_schema_request(
294        data_source_name: Name,
295        protocol_version: u8,
296        op_id: Base64Uuid,
297    ) -> Self {
298        Self::payload_with_header(
299            ServerMessagePayload::GetConfigSchema(GetConfigSchemaRequest {}),
300            data_source_name,
301            protocol_version,
302            op_id,
303        )
304    }
305    pub fn new_get_supported_query_types_request(
306        config: ProviderConfig,
307        data_source_name: Name,
308        protocol_version: u8,
309        op_id: Base64Uuid,
310    ) -> Self {
311        Self::payload_with_header(
312            ServerMessagePayload::GetSupportedQueryTypes(GetSupportedQueryTypesRequest { config }),
313            data_source_name,
314            protocol_version,
315            op_id,
316        )
317    }
318}
319
320/// Messages sent to the Proxy
321#[derive(Debug, Deserialize, Serialize)]
322#[cfg_attr(
323    feature = "fp-bindgen",
324    derive(Serializable),
325    fp(rust_module = "fiberplane_models::proxies")
326)]
327#[non_exhaustive]
328#[serde(tag = "type", rename_all = "camelCase")]
329pub enum ServerMessagePayload {
330    /// A request to call the `invoke` or `invoke2` exported binding
331    #[serde(rename = "invokeProxy")] // Backwards compatibility alias
332    Invoke(InvokeRequest),
333    /// A request to call the `create_cells` exported binding
334    CreateCells(CreateCellsRequest),
335    /// A request to call the `extract_data` exported binding
336    ExtractData(ExtractDataRequest),
337    /// A request to call the `get_config_schema` exported binding
338    GetConfigSchema(GetConfigSchemaRequest),
339    /// A request to call the `get_supported_query_types` exported binding
340    GetSupportedQueryTypes(GetSupportedQueryTypesRequest),
341}
342
343#[derive(Deserialize, Serialize, TypedBuilder)]
344#[cfg_attr(
345    feature = "fp-bindgen",
346    derive(Serializable),
347    fp(rust_module = "fiberplane_models::proxies")
348)]
349#[non_exhaustive]
350#[serde(rename_all = "camelCase")]
351pub struct InvokeRequest {
352    #[serde(with = "serde_bytes")]
353    pub data: Vec<u8>,
354}
355
356impl Debug for InvokeRequest {
357    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
358        f.debug_struct("InvokeRequest")
359            .field("data", &format!("[{} bytes]", self.data.len()))
360            .finish()
361    }
362}
363
364#[derive(Deserialize, Serialize, TypedBuilder)]
365#[cfg_attr(
366    feature = "fp-bindgen",
367    derive(Serializable),
368    fp(rust_module = "fiberplane_models::proxies")
369)]
370#[non_exhaustive]
371#[serde(rename_all = "camelCase")]
372pub struct CreateCellsRequest {
373    pub response: Blob,
374    pub query_type: String,
375}
376
377impl Debug for CreateCellsRequest {
378    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
379        f.debug_struct("CreateCellsRequest")
380            .field("query_type", &self.query_type)
381            .field("response", &format!("[{} bytes]", self.response.data.len()))
382            .finish()
383    }
384}
385
386#[derive(Deserialize, Serialize, TypedBuilder)]
387#[cfg_attr(
388    feature = "fp-bindgen",
389    derive(Serializable),
390    fp(rust_module = "fiberplane_models::proxies")
391)]
392#[non_exhaustive]
393#[serde(rename_all = "camelCase")]
394pub struct ExtractDataRequest {
395    pub response: Blob,
396    pub mime_type: String,
397    #[serde(default, skip_serializing_if = "Option::is_none")]
398    pub query: Option<String>,
399}
400
401impl Debug for ExtractDataRequest {
402    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
403        f.debug_struct("ExtractDataRequest")
404            .field("mime_type", &self.mime_type)
405            .field("query", &self.query)
406            .field("response", &format!("[{} bytes]", self.response.data.len()))
407            .finish()
408    }
409}
410
411#[derive(Deserialize, Serialize)]
412#[cfg_attr(
413    feature = "fp-bindgen",
414    derive(Serializable),
415    fp(rust_module = "fiberplane_models::proxies")
416)]
417#[non_exhaustive]
418#[serde(rename_all = "camelCase")]
419pub struct GetConfigSchemaRequest {}
420
421impl Debug for GetConfigSchemaRequest {
422    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
423        f.debug_struct("ConfigSchemaRequest").finish()
424    }
425}
426
427#[derive(Deserialize, Serialize, Debug, TypedBuilder)]
428#[cfg_attr(
429    feature = "fp-bindgen",
430    derive(Serializable),
431    fp(rust_module = "fiberplane_models::proxies")
432)]
433#[non_exhaustive]
434#[serde(rename_all = "camelCase")]
435pub struct GetSupportedQueryTypesRequest {
436    pub config: ProviderConfig,
437}
438
439/// Messages sent from the Proxy
440#[derive(Debug, Deserialize, Serialize, TypedBuilder)]
441#[cfg_attr(
442    feature = "fp-bindgen",
443    derive(Serializable),
444    fp(rust_module = "fiberplane_models::proxies")
445)]
446#[non_exhaustive]
447#[serde(rename_all = "camelCase")]
448pub struct ProxyMessage {
449    pub op_id: Option<Base64Uuid>,
450    #[serde(flatten)]
451    pub payload: ProxyMessagePayload,
452}
453
454impl ProxyMessage {
455    fn response(payload: ProxyMessagePayload, op_id: Base64Uuid) -> Self {
456        Self {
457            op_id: Some(op_id),
458            payload,
459        }
460    }
461
462    fn notification(payload: ProxyMessagePayload) -> Self {
463        Self {
464            op_id: None,
465            payload,
466        }
467    }
468
469    pub fn new_error_response(error: Error, op_id: Base64Uuid) -> Self {
470        Self::response(ProxyMessagePayload::Error(ErrorMessage { error }), op_id)
471    }
472    pub fn new_invoke_proxy_response(data: Vec<u8>, op_id: Base64Uuid) -> Self {
473        Self::response(
474            ProxyMessagePayload::InvokeProxyResponse(InvokeProxyResponseMessage { data }),
475            op_id,
476        )
477    }
478    pub fn new_create_cells_response(cells: Result<Vec<Cell>, Error>, op_id: Base64Uuid) -> Self {
479        Self::response(
480            ProxyMessagePayload::CreateCellsResponse(CreateCellsResponseMessage { cells }),
481            op_id,
482        )
483    }
484    pub fn new_extract_data_response(data: Result<Blob, Error>, op_id: Base64Uuid) -> Self {
485        Self::response(
486            ProxyMessagePayload::ExtractDataResponse(ExtractDataResponseMessage { data }),
487            op_id,
488        )
489    }
490    pub fn new_config_schema_response(schema: ConfigSchema, op_id: Base64Uuid) -> Self {
491        Self::response(
492            ProxyMessagePayload::GetConfigSchemaResponse(GetConfigSchemaResponseMessage { schema }),
493            op_id,
494        )
495    }
496    pub fn new_supported_query_types_response(
497        queries: Vec<SupportedQueryType>,
498        op_id: Base64Uuid,
499    ) -> Self {
500        Self::response(
501            ProxyMessagePayload::GetSupportedQueryTypesResponse(
502                GetSupportedQueryTypesResponseMessage { queries },
503            ),
504            op_id,
505        )
506    }
507    pub fn new_set_data_sources_notification(data_sources: Vec<UpsertProxyDataSource>) -> Self {
508        Self::notification(ProxyMessagePayload::SetDataSources(SetDataSourcesMessage {
509            data_sources,
510        }))
511    }
512}
513
514/// Messages sent from the Proxy
515#[derive(Debug, Deserialize, Serialize)]
516#[cfg_attr(
517    feature = "fp-bindgen",
518    derive(Serializable),
519    fp(rust_module = "fiberplane_models::proxies")
520)]
521#[non_exhaustive]
522#[serde(tag = "type", rename_all = "camelCase")]
523pub enum ProxyMessagePayload {
524    SetDataSources(SetDataSourcesMessage),
525    InvokeProxyResponse(InvokeProxyResponseMessage),
526    CreateCellsResponse(CreateCellsResponseMessage),
527    ExtractDataResponse(ExtractDataResponseMessage),
528    GetConfigSchemaResponse(GetConfigSchemaResponseMessage),
529    GetSupportedQueryTypesResponse(GetSupportedQueryTypesResponseMessage),
530    Error(ErrorMessage),
531}
532
533impl From<(ErrorMessage, Base64Uuid)> for ProxyMessage {
534    fn from((message, op_id): (ErrorMessage, Base64Uuid)) -> Self {
535        Self::response(ProxyMessagePayload::Error(message), op_id)
536    }
537}
538
539#[derive(Deserialize, Serialize, TypedBuilder)]
540#[cfg_attr(
541    feature = "fp-bindgen",
542    derive(Serializable),
543    fp(rust_module = "fiberplane_models::proxies")
544)]
545#[non_exhaustive]
546#[serde(rename_all = "camelCase")]
547pub struct InvokeProxyResponseMessage {
548    #[serde(with = "serde_bytes")]
549    pub data: Vec<u8>,
550}
551
552impl Debug for InvokeProxyResponseMessage {
553    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
554        f.debug_struct("InvokeProxyResponseMessage")
555            .field("data", &format!("[{} bytes]", self.data.len()))
556            .finish()
557    }
558}
559
560#[derive(Deserialize, Serialize, Debug, TypedBuilder)]
561#[cfg_attr(
562    feature = "fp-bindgen",
563    derive(Serializable),
564    fp(rust_module = "fiberplane_models::proxies")
565)]
566#[non_exhaustive]
567#[serde(rename_all = "camelCase")]
568pub struct ExtractDataResponseMessage {
569    pub data: Result<Blob, Error>,
570}
571
572#[derive(Deserialize, Serialize, Debug, TypedBuilder)]
573#[cfg_attr(
574    feature = "fp-bindgen",
575    derive(Serializable),
576    fp(rust_module = "fiberplane_models::proxies")
577)]
578#[non_exhaustive]
579#[serde(rename_all = "camelCase")]
580pub struct CreateCellsResponseMessage {
581    pub cells: Result<Vec<Cell>, Error>,
582}
583
584#[derive(Deserialize, Serialize, Debug, TypedBuilder)]
585#[cfg_attr(
586    feature = "fp-bindgen",
587    derive(Serializable),
588    fp(rust_module = "fiberplane_models::proxies")
589)]
590#[non_exhaustive]
591#[serde(rename_all = "camelCase")]
592pub struct GetConfigSchemaResponseMessage {
593    pub schema: ConfigSchema,
594}
595
596#[derive(Deserialize, Serialize, Debug, TypedBuilder)]
597#[cfg_attr(
598    feature = "fp-bindgen",
599    derive(Serializable),
600    fp(rust_module = "fiberplane_models::proxies")
601)]
602#[non_exhaustive]
603#[serde(rename_all = "camelCase")]
604pub struct GetSupportedQueryTypesResponseMessage {
605    pub queries: Vec<SupportedQueryType>,
606}
607
608#[derive(Debug, Deserialize, Serialize, TypedBuilder)]
609#[cfg_attr(
610    feature = "fp-bindgen",
611    derive(Serializable),
612    fp(rust_module = "fiberplane_models::proxies")
613)]
614#[non_exhaustive]
615#[serde(rename_all = "camelCase")]
616pub struct ErrorMessage {
617    pub error: Error,
618}
619
620impl ProxyMessage {
621    pub fn deserialize_msgpack(
622        input: impl AsRef<[u8]>,
623    ) -> Result<ProxyMessage, rmp_serde::decode::Error> {
624        rmp_serde::from_slice(input.as_ref())
625    }
626
627    pub fn serialize_msgpack(&self) -> Vec<u8> {
628        rmp_serde::to_vec_named(&self).expect("MessgePack serialization error")
629    }
630
631    pub fn op_id(&self) -> Option<Base64Uuid> {
632        self.op_id
633    }
634}
635
636#[derive(Debug, Deserialize, Serialize, TypedBuilder)]
637#[cfg_attr(
638    feature = "fp-bindgen",
639    derive(Serializable),
640    fp(rust_module = "fiberplane_models::proxies")
641)]
642#[non_exhaustive]
643#[serde(rename_all = "camelCase")]
644pub struct SetDataSourcesMessage {
645    pub data_sources: Vec<UpsertProxyDataSource>,
646}
647
648#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, TypedBuilder)]
649#[cfg_attr(
650    feature = "fp-bindgen",
651    derive(Serializable),
652    fp(rust_module = "fiberplane_models::proxies")
653)]
654#[non_exhaustive]
655#[serde(tag = "type", rename_all = "camelCase")]
656pub struct UpsertProxyDataSource {
657    pub name: Name,
658    #[builder(default, setter(into))]
659    pub description: Option<String>,
660    #[builder(setter(into))]
661    pub provider_type: String,
662    #[builder(default)]
663    #[serde(default)]
664    pub protocol_version: u8,
665    #[serde(flatten)]
666    pub status: DataSourceStatus,
667}
668
669#[cfg(test)]
670mod tests {
671    use super::*;
672    use crate::providers::Error;
673
674    #[test]
675    fn serialization_deserialization() {
676        let data_sources = vec![
677            UpsertProxyDataSource {
678                name: Name::from_static("prometheus-prod"),
679                provider_type: "prometheus".to_string(),
680                protocol_version: 2,
681                description: Some("Production Prometheus".to_string()),
682                status: DataSourceStatus::Connected,
683            },
684            UpsertProxyDataSource {
685                name: Name::from_static("elasticsearch-prod"),
686                provider_type: "elasticsearch".to_string(),
687                protocol_version: 1,
688                description: None,
689                status: DataSourceStatus::Error(Error::NotFound),
690            },
691        ];
692        let message = ProxyMessage::new_set_data_sources_notification(data_sources.clone());
693        let serialized = message.serialize_msgpack();
694        let deserialized = ProxyMessage::deserialize_msgpack(serialized).unwrap();
695        if let ProxyMessage {
696            op_id: None,
697            payload: ProxyMessagePayload::SetDataSources(set_data_sources),
698        } = deserialized
699        {
700            assert_eq!(set_data_sources.data_sources, data_sources)
701        } else {
702            panic!("Unexpected message type");
703        }
704    }
705
706    #[test]
707    fn backwards_compatibility() {
708        // The test checks that an old message can be deserialized into a new one
709        mod old {
710            use crate::names::Name;
711            use base64uuid::Base64Uuid;
712            use serde::{Deserialize, Serialize};
713
714            #[derive(Debug, Deserialize, Serialize)]
715            #[serde(tag = "type", rename_all = "camelCase")]
716            pub enum ServerMessage {
717                InvokeProxy(InvokeProxyMessage),
718            }
719
720            #[derive(Debug, Deserialize, Serialize, Clone)]
721            #[serde(rename_all = "camelCase")]
722            pub struct InvokeProxyMessage {
723                pub op_id: Base64Uuid,
724                pub data_source_name: Name,
725                #[serde(with = "serde_bytes")]
726                pub data: Vec<u8>,
727                pub protocol_version: u8,
728            }
729        }
730
731        let op_id = Base64Uuid::parse_str("34edc58d-f8ec-4c95-bce0-c2ae8800e6ef").unwrap();
732        let data_source_name = Name::from_static("test-name");
733        let data = b"aieu".to_vec();
734        let old_message = old::InvokeProxyMessage {
735            op_id,
736            data_source_name,
737            protocol_version: 12,
738            data,
739        };
740
741        let new_message: ServerMessage = rmp_serde::from_slice(
742            &rmp_serde::to_vec_named(&old::ServerMessage::InvokeProxy(old_message.clone()))
743                .unwrap(),
744        )
745        .unwrap();
746
747        assert_eq!(new_message.op_id, old_message.op_id);
748        assert_eq!(new_message.data_source_name, old_message.data_source_name);
749        assert_eq!(new_message.protocol_version, old_message.protocol_version);
750
751        if let ServerMessagePayload::Invoke(response) = new_message.payload {
752            assert_eq!(response.data, old_message.data)
753        } else {
754            panic!("Wrong variant of ServerMessage deserialized. Expecting Invoke")
755        }
756    }
757}