use anyhow::{Result, bail};
use serde_bare::Uint;
use vbare::OwnedVersionedData;
use crate::generated::{v1, v2, v3, v4, v5, v6};
const WORKFLOW_HISTORY_DROPPED_ERROR: &str = "inspector.workflow_history_dropped";
const QUEUE_DROPPED_ERROR: &str = "inspector.queue_dropped";
const TRACE_DROPPED_ERROR: &str = "inspector.trace_dropped";
const DATABASE_DROPPED_ERROR: &str = "inspector.database_dropped";
const SCHEDULES_DROPPED_ERROR: &str = "inspector.schedules_dropped";
pub enum ToServer {
V1(v1::ToServer),
V2(v2::ToServer),
V3(v3::ToServer),
V4(v4::ToServer),
V5(v5::ToServer),
V6(v6::ToServer),
}
impl OwnedVersionedData for ToServer {
type Latest = v6::ToServer;
fn wrap_latest(latest: Self::Latest) -> Self {
Self::V6(latest)
}
fn unwrap_latest(self) -> Result<Self::Latest> {
match self {
Self::V6(data) => Ok(data),
_ => bail!("version not latest"),
}
}
fn deserialize_version(payload: &[u8], version: u16) -> Result<Self> {
match version {
1 => Ok(Self::V1(serde_bare::from_slice(payload)?)),
2 => Ok(Self::V2(serde_bare::from_slice(payload)?)),
3 => Ok(Self::V3(serde_bare::from_slice(payload)?)),
4 => Ok(Self::V4(serde_bare::from_slice(payload)?)),
5 => Ok(Self::V5(serde_bare::from_slice(payload)?)),
6 => Ok(Self::V6(serde_bare::from_slice(payload)?)),
_ => bail!("invalid inspector protocol version for ToServer: {version}"),
}
}
fn serialize_version(self, version: u16) -> Result<Vec<u8>> {
match (self, version) {
(Self::V1(data), 1) => serde_bare::to_vec(&data).map_err(Into::into),
(Self::V2(data), 2) => serde_bare::to_vec(&data).map_err(Into::into),
(Self::V3(data), 3) => serde_bare::to_vec(&data).map_err(Into::into),
(Self::V4(data), 4) => serde_bare::to_vec(&data).map_err(Into::into),
(Self::V5(data), 5) => serde_bare::to_vec(&data).map_err(Into::into),
(Self::V6(data), 6) => serde_bare::to_vec(&data).map_err(Into::into),
(_, version) => bail!("unexpected inspector protocol version for ToServer: {version}"),
}
}
fn deserialize_converters() -> Vec<impl Fn(Self) -> Result<Self>> {
vec![
Self::v1_to_v2,
Self::v2_to_v3,
Self::v3_to_v4,
Self::v4_to_v5,
Self::v5_to_v6,
]
}
fn serialize_converters() -> Vec<impl Fn(Self) -> Result<Self>> {
vec![
Self::v6_to_v5,
Self::v5_to_v4,
Self::v4_to_v3,
Self::v3_to_v2,
Self::v2_to_v1,
]
}
}
impl ToServer {
fn v1_to_v2(self) -> Result<Self> {
let Self::V1(data) = self else {
bail!("expected inspector protocol v1 ToServer")
};
let body = match data.body {
v1::ToServerBody::PatchStateRequest(req) => {
v2::ToServerBody::PatchStateRequest(req.into())
}
v1::ToServerBody::StateRequest(req) => v2::ToServerBody::StateRequest(req.into()),
v1::ToServerBody::ConnectionsRequest(req) => {
v2::ToServerBody::ConnectionsRequest(req.into())
}
v1::ToServerBody::ActionRequest(req) => v2::ToServerBody::ActionRequest(req.into()),
v1::ToServerBody::RpcsListRequest(req) => v2::ToServerBody::RpcsListRequest(req.into()),
v1::ToServerBody::EventsRequest(_) | v1::ToServerBody::ClearEventsRequest(_) => {
bail!("cannot convert inspector v1 events requests to v2")
}
};
Ok(Self::V2(v2::ToServer { body }))
}
fn v2_to_v3(self) -> Result<Self> {
let Self::V2(data) = self else {
bail!("expected inspector protocol v2 ToServer")
};
Ok(Self::V3(data.into()))
}
fn v3_to_v4(self) -> Result<Self> {
let Self::V3(data) = self else {
bail!("expected inspector protocol v3 ToServer")
};
let body = match data.body {
v3::ToServerBody::PatchStateRequest(req) => {
v4::ToServerBody::PatchStateRequest(req.into())
}
v3::ToServerBody::StateRequest(req) => v4::ToServerBody::StateRequest(req.into()),
v3::ToServerBody::ConnectionsRequest(req) => {
v4::ToServerBody::ConnectionsRequest(req.into())
}
v3::ToServerBody::ActionRequest(req) => v4::ToServerBody::ActionRequest(req.into()),
v3::ToServerBody::RpcsListRequest(req) => v4::ToServerBody::RpcsListRequest(req.into()),
v3::ToServerBody::TraceQueryRequest(req) => {
v4::ToServerBody::TraceQueryRequest(req.into())
}
v3::ToServerBody::QueueRequest(req) => v4::ToServerBody::QueueRequest(req.into()),
v3::ToServerBody::WorkflowHistoryRequest(req) => {
v4::ToServerBody::WorkflowHistoryRequest(req.into())
}
v3::ToServerBody::DatabaseSchemaRequest(req) => {
v4::ToServerBody::DatabaseSchemaRequest(req.into())
}
v3::ToServerBody::DatabaseTableRowsRequest(req) => {
v4::ToServerBody::DatabaseTableRowsRequest(req.into())
}
};
Ok(Self::V4(v4::ToServer { body }))
}
fn v4_to_v5(self) -> Result<Self> {
let Self::V4(data) = self else {
bail!("expected inspector protocol v4 ToServer")
};
Ok(Self::V5(data.into()))
}
fn v5_to_v6(self) -> Result<Self> {
let Self::V5(data) = self else {
bail!("expected inspector protocol v5 ToServer")
};
Ok(Self::V6(data.into()))
}
fn v6_to_v5(self) -> Result<Self> {
let Self::V6(data) = self else {
bail!("expected inspector protocol v6 ToServer")
};
let body = match data.body {
v6::ToServerBody::PatchStateRequest(req) => {
v5::ToServerBody::PatchStateRequest(req.into())
}
v6::ToServerBody::StateRequest(req) => v5::ToServerBody::StateRequest(req.into()),
v6::ToServerBody::ConnectionsRequest(req) => {
v5::ToServerBody::ConnectionsRequest(req.into())
}
v6::ToServerBody::ActionRequest(req) => v5::ToServerBody::ActionRequest(req.into()),
v6::ToServerBody::RpcsListRequest(req) => v5::ToServerBody::RpcsListRequest(req.into()),
v6::ToServerBody::TraceQueryRequest(req) => {
v5::ToServerBody::TraceQueryRequest(req.into())
}
v6::ToServerBody::QueueRequest(req) => v5::ToServerBody::QueueRequest(req.into()),
v6::ToServerBody::WorkflowHistoryRequest(req) => {
v5::ToServerBody::WorkflowHistoryRequest(req.into())
}
v6::ToServerBody::WorkflowReplayRequest(req) => {
v5::ToServerBody::WorkflowReplayRequest(req.into())
}
v6::ToServerBody::DatabaseSchemaRequest(req) => {
v5::ToServerBody::DatabaseSchemaRequest(req.into())
}
v6::ToServerBody::DatabaseTableRowsRequest(req) => {
v5::ToServerBody::DatabaseTableRowsRequest(req.into())
}
v6::ToServerBody::SchedulesRequest(_)
| v6::ToServerBody::ScheduleHistoryRequest(_)
| v6::ToServerBody::ScheduleDeleteRequest(_) => {
bail!("cannot convert inspector v6 schedule requests to v5")
}
};
Ok(Self::V5(v5::ToServer { body }))
}
fn v5_to_v4(self) -> Result<Self> {
let Self::V5(data) = self else {
bail!("expected inspector protocol v5 ToServer")
};
Ok(Self::V4(data.into()))
}
fn v4_to_v3(self) -> Result<Self> {
let Self::V4(data) = self else {
bail!("expected inspector protocol v4 ToServer")
};
let body = match data.body {
v4::ToServerBody::PatchStateRequest(req) => {
v3::ToServerBody::PatchStateRequest(req.into())
}
v4::ToServerBody::StateRequest(req) => v3::ToServerBody::StateRequest(req.into()),
v4::ToServerBody::ConnectionsRequest(req) => {
v3::ToServerBody::ConnectionsRequest(req.into())
}
v4::ToServerBody::ActionRequest(req) => v3::ToServerBody::ActionRequest(req.into()),
v4::ToServerBody::RpcsListRequest(req) => v3::ToServerBody::RpcsListRequest(req.into()),
v4::ToServerBody::TraceQueryRequest(req) => {
v3::ToServerBody::TraceQueryRequest(req.into())
}
v4::ToServerBody::QueueRequest(req) => v3::ToServerBody::QueueRequest(req.into()),
v4::ToServerBody::WorkflowHistoryRequest(req) => {
v3::ToServerBody::WorkflowHistoryRequest(req.into())
}
v4::ToServerBody::WorkflowReplayRequest(_) => {
bail!("cannot convert inspector v4 workflow replay requests to v3")
}
v4::ToServerBody::DatabaseSchemaRequest(req) => {
v3::ToServerBody::DatabaseSchemaRequest(req.into())
}
v4::ToServerBody::DatabaseTableRowsRequest(req) => {
v3::ToServerBody::DatabaseTableRowsRequest(req.into())
}
};
Ok(Self::V3(v3::ToServer { body }))
}
fn v3_to_v2(self) -> Result<Self> {
let Self::V3(data) = self else {
bail!("expected inspector protocol v3 ToServer")
};
let body = match data.body {
v3::ToServerBody::PatchStateRequest(req) => {
v2::ToServerBody::PatchStateRequest(req.into())
}
v3::ToServerBody::StateRequest(req) => v2::ToServerBody::StateRequest(req.into()),
v3::ToServerBody::ConnectionsRequest(req) => {
v2::ToServerBody::ConnectionsRequest(req.into())
}
v3::ToServerBody::ActionRequest(req) => v2::ToServerBody::ActionRequest(req.into()),
v3::ToServerBody::RpcsListRequest(req) => v2::ToServerBody::RpcsListRequest(req.into()),
v3::ToServerBody::TraceQueryRequest(req) => {
v2::ToServerBody::TraceQueryRequest(req.into())
}
v3::ToServerBody::QueueRequest(req) => v2::ToServerBody::QueueRequest(req.into()),
v3::ToServerBody::WorkflowHistoryRequest(req) => {
v2::ToServerBody::WorkflowHistoryRequest(req.into())
}
v3::ToServerBody::DatabaseSchemaRequest(_)
| v3::ToServerBody::DatabaseTableRowsRequest(_) => {
bail!("cannot convert inspector v3 database requests to v2")
}
};
Ok(Self::V2(v2::ToServer { body }))
}
fn v2_to_v1(self) -> Result<Self> {
let Self::V2(data) = self else {
bail!("expected inspector protocol v2 ToServer")
};
let body = match data.body {
v2::ToServerBody::PatchStateRequest(req) => {
v1::ToServerBody::PatchStateRequest(req.into())
}
v2::ToServerBody::StateRequest(req) => v1::ToServerBody::StateRequest(req.into()),
v2::ToServerBody::ConnectionsRequest(req) => {
v1::ToServerBody::ConnectionsRequest(req.into())
}
v2::ToServerBody::ActionRequest(req) => v1::ToServerBody::ActionRequest(req.into()),
v2::ToServerBody::RpcsListRequest(req) => v1::ToServerBody::RpcsListRequest(req.into()),
v2::ToServerBody::TraceQueryRequest(_)
| v2::ToServerBody::QueueRequest(_)
| v2::ToServerBody::WorkflowHistoryRequest(_) => {
bail!("cannot convert inspector v2 queue/trace/workflow requests to v1")
}
};
Ok(Self::V1(v1::ToServer { body }))
}
}
pub enum ToClient {
V1(v1::ToClient),
V2(v2::ToClient),
V3(v3::ToClient),
V4(v4::ToClient),
V5(v5::ToClient),
V6(v6::ToClient),
}
impl OwnedVersionedData for ToClient {
type Latest = v6::ToClient;
fn wrap_latest(latest: Self::Latest) -> Self {
Self::V6(latest)
}
fn unwrap_latest(self) -> Result<Self::Latest> {
match self {
Self::V6(data) => Ok(data),
_ => bail!("version not latest"),
}
}
fn deserialize_version(payload: &[u8], version: u16) -> Result<Self> {
match version {
1 => Ok(Self::V1(serde_bare::from_slice(payload)?)),
2 => Ok(Self::V2(serde_bare::from_slice(payload)?)),
3 => Ok(Self::V3(serde_bare::from_slice(payload)?)),
4 => Ok(Self::V4(serde_bare::from_slice(payload)?)),
5 => Ok(Self::V5(serde_bare::from_slice(payload)?)),
6 => Ok(Self::V6(serde_bare::from_slice(payload)?)),
_ => bail!("invalid inspector protocol version for ToClient: {version}"),
}
}
fn serialize_version(self, version: u16) -> Result<Vec<u8>> {
match (self, version) {
(Self::V1(data), 1) => serde_bare::to_vec(&data).map_err(Into::into),
(Self::V2(data), 2) => serde_bare::to_vec(&data).map_err(Into::into),
(Self::V3(data), 3) => serde_bare::to_vec(&data).map_err(Into::into),
(Self::V4(data), 4) => serde_bare::to_vec(&data).map_err(Into::into),
(Self::V5(data), 5) => serde_bare::to_vec(&data).map_err(Into::into),
(Self::V6(data), 6) => serde_bare::to_vec(&data).map_err(Into::into),
(_, version) => bail!("unexpected inspector protocol version for ToClient: {version}"),
}
}
fn deserialize_converters() -> Vec<impl Fn(Self) -> Result<Self>> {
vec![
Self::v1_to_v2,
Self::v2_to_v3,
Self::v3_to_v4,
Self::v4_to_v5,
Self::v5_to_v6,
]
}
fn serialize_converters() -> Vec<impl Fn(Self) -> Result<Self>> {
vec![
Self::v6_to_v5,
Self::v5_to_v4,
Self::v4_to_v3,
Self::v3_to_v2,
Self::v2_to_v1,
]
}
}
impl ToClient {
fn v1_to_v2(self) -> Result<Self> {
let Self::V1(data) = self else {
bail!("expected inspector protocol v1 ToClient")
};
let body = match data.body {
v1::ToClientBody::StateResponse(resp) => v2::ToClientBody::StateResponse(resp.into()),
v1::ToClientBody::ConnectionsResponse(resp) => {
v2::ToClientBody::ConnectionsResponse(resp.into())
}
v1::ToClientBody::ActionResponse(resp) => v2::ToClientBody::ActionResponse(resp.into()),
v1::ToClientBody::RpcsListResponse(resp) => {
v2::ToClientBody::RpcsListResponse(resp.into())
}
v1::ToClientBody::ConnectionsUpdated(update) => {
v2::ToClientBody::ConnectionsUpdated(update.into())
}
v1::ToClientBody::StateUpdated(update) => v2::ToClientBody::StateUpdated(update.into()),
v1::ToClientBody::Error(error) => v2::ToClientBody::Error(error.into()),
v1::ToClientBody::Init(init) => v2::ToClientBody::Init(v2::Init {
connections: convert_vec(init.connections),
state: init.state,
is_state_enabled: init.is_state_enabled,
rpcs: init.rpcs,
is_database_enabled: init.is_database_enabled,
queue_size: Uint(0),
workflow_history: None,
is_workflow_enabled: false,
}),
v1::ToClientBody::EventsResponse(_) | v1::ToClientBody::EventsUpdated(_) => {
bail!("cannot convert inspector v1 events responses to v2")
}
};
Ok(Self::V2(v2::ToClient { body }))
}
fn v2_to_v3(self) -> Result<Self> {
let Self::V2(data) = self else {
bail!("expected inspector protocol v2 ToClient")
};
Ok(Self::V3(data.into()))
}
fn v3_to_v4(self) -> Result<Self> {
let Self::V3(data) = self else {
bail!("expected inspector protocol v3 ToClient")
};
let body = match data.body {
v3::ToClientBody::StateResponse(resp) => v4::ToClientBody::StateResponse(resp.into()),
v3::ToClientBody::ConnectionsResponse(resp) => {
v4::ToClientBody::ConnectionsResponse(resp.into())
}
v3::ToClientBody::ActionResponse(resp) => v4::ToClientBody::ActionResponse(resp.into()),
v3::ToClientBody::ConnectionsUpdated(update) => {
v4::ToClientBody::ConnectionsUpdated(update.into())
}
v3::ToClientBody::QueueUpdated(update) => v4::ToClientBody::QueueUpdated(update.into()),
v3::ToClientBody::StateUpdated(update) => v4::ToClientBody::StateUpdated(update.into()),
v3::ToClientBody::WorkflowHistoryUpdated(update) => {
v4::ToClientBody::WorkflowHistoryUpdated(update.into())
}
v3::ToClientBody::RpcsListResponse(resp) => {
v4::ToClientBody::RpcsListResponse(resp.into())
}
v3::ToClientBody::TraceQueryResponse(resp) => {
v4::ToClientBody::TraceQueryResponse(resp.into())
}
v3::ToClientBody::QueueResponse(resp) => v4::ToClientBody::QueueResponse(resp.into()),
v3::ToClientBody::WorkflowHistoryResponse(resp) => {
v4::ToClientBody::WorkflowHistoryResponse(resp.into())
}
v3::ToClientBody::Error(error) => v4::ToClientBody::Error(error.into()),
v3::ToClientBody::Init(init) => v4::ToClientBody::Init(init.into()),
v3::ToClientBody::DatabaseSchemaResponse(resp) => {
v4::ToClientBody::DatabaseSchemaResponse(resp.into())
}
v3::ToClientBody::DatabaseTableRowsResponse(resp) => {
v4::ToClientBody::DatabaseTableRowsResponse(resp.into())
}
};
Ok(Self::V4(v4::ToClient { body }))
}
fn v4_to_v5(self) -> Result<Self> {
let Self::V4(data) = self else {
bail!("expected inspector protocol v4 ToClient")
};
let body = match data.body {
v4::ToClientBody::StateResponse(resp) => v5::ToClientBody::StateResponse(resp.into()),
v4::ToClientBody::ConnectionsResponse(resp) => {
v5::ToClientBody::ConnectionsResponse(resp.into())
}
v4::ToClientBody::ActionResponse(resp) => v5::ToClientBody::ActionResponse(resp.into()),
v4::ToClientBody::ConnectionsUpdated(update) => {
v5::ToClientBody::ConnectionsUpdated(update.into())
}
v4::ToClientBody::QueueUpdated(update) => v5::ToClientBody::QueueUpdated(update.into()),
v4::ToClientBody::StateUpdated(update) => v5::ToClientBody::StateUpdated(update.into()),
v4::ToClientBody::WorkflowHistoryUpdated(update) => {
v5::ToClientBody::WorkflowHistoryUpdated(update.into())
}
v4::ToClientBody::RpcsListResponse(resp) => {
v5::ToClientBody::RpcsListResponse(resp.into())
}
v4::ToClientBody::TraceQueryResponse(resp) => {
v5::ToClientBody::TraceQueryResponse(resp.into())
}
v4::ToClientBody::QueueResponse(resp) => v5::ToClientBody::QueueResponse(resp.into()),
v4::ToClientBody::WorkflowHistoryResponse(resp) => {
v5::ToClientBody::WorkflowHistoryResponse(resp.into())
}
v4::ToClientBody::WorkflowReplayResponse(resp) => {
v5::ToClientBody::WorkflowReplayResponse(resp.into())
}
v4::ToClientBody::Error(error) => v5::ToClientBody::Error(error.into()),
v4::ToClientBody::Init(init) => v5::ToClientBody::Init(v5::Init {
connections: convert_vec(init.connections),
state: init.state,
is_state_enabled: init.is_state_enabled,
rpcs: init.rpcs,
is_database_enabled: init.is_database_enabled,
queue_size: init.queue_size,
workflow_history: init.workflow_history,
is_workflow_enabled: init.is_workflow_enabled,
tab_config: Vec::new(),
}),
v4::ToClientBody::DatabaseSchemaResponse(resp) => {
v5::ToClientBody::DatabaseSchemaResponse(resp.into())
}
v4::ToClientBody::DatabaseTableRowsResponse(resp) => {
v5::ToClientBody::DatabaseTableRowsResponse(resp.into())
}
};
Ok(Self::V5(v5::ToClient { body }))
}
fn v5_to_v6(self) -> Result<Self> {
let Self::V5(data) = self else {
bail!("expected inspector protocol v5 ToClient")
};
let body = match data.body {
v5::ToClientBody::StateResponse(resp) => v6::ToClientBody::StateResponse(resp.into()),
v5::ToClientBody::ConnectionsResponse(resp) => {
v6::ToClientBody::ConnectionsResponse(resp.into())
}
v5::ToClientBody::ActionResponse(resp) => v6::ToClientBody::ActionResponse(resp.into()),
v5::ToClientBody::ConnectionsUpdated(update) => {
v6::ToClientBody::ConnectionsUpdated(update.into())
}
v5::ToClientBody::QueueUpdated(update) => v6::ToClientBody::QueueUpdated(update.into()),
v5::ToClientBody::StateUpdated(update) => v6::ToClientBody::StateUpdated(update.into()),
v5::ToClientBody::WorkflowHistoryUpdated(update) => {
v6::ToClientBody::WorkflowHistoryUpdated(update.into())
}
v5::ToClientBody::RpcsListResponse(resp) => {
v6::ToClientBody::RpcsListResponse(resp.into())
}
v5::ToClientBody::TraceQueryResponse(resp) => {
v6::ToClientBody::TraceQueryResponse(resp.into())
}
v5::ToClientBody::QueueResponse(resp) => v6::ToClientBody::QueueResponse(resp.into()),
v5::ToClientBody::WorkflowHistoryResponse(resp) => {
v6::ToClientBody::WorkflowHistoryResponse(resp.into())
}
v5::ToClientBody::WorkflowReplayResponse(resp) => {
v6::ToClientBody::WorkflowReplayResponse(resp.into())
}
v5::ToClientBody::Error(error) => v6::ToClientBody::Error(error.into()),
v5::ToClientBody::Init(init) => v6::ToClientBody::Init(v6::Init {
connections: convert_vec(init.connections),
state: init.state,
is_state_enabled: init.is_state_enabled,
rpcs: init.rpcs,
is_database_enabled: init.is_database_enabled,
queue_size: init.queue_size,
workflow_history: init.workflow_history,
is_workflow_enabled: init.is_workflow_enabled,
tab_config: convert_vec(init.tab_config),
schedules: Vec::new(),
}),
v5::ToClientBody::DatabaseSchemaResponse(resp) => {
v6::ToClientBody::DatabaseSchemaResponse(resp.into())
}
v5::ToClientBody::DatabaseTableRowsResponse(resp) => {
v6::ToClientBody::DatabaseTableRowsResponse(resp.into())
}
};
Ok(Self::V6(v6::ToClient { body }))
}
fn v6_to_v5(self) -> Result<Self> {
let Self::V6(data) = self else {
bail!("expected inspector protocol v6 ToClient")
};
let body = match data.body {
v6::ToClientBody::StateResponse(resp) => v5::ToClientBody::StateResponse(resp.into()),
v6::ToClientBody::ConnectionsResponse(resp) => {
v5::ToClientBody::ConnectionsResponse(resp.into())
}
v6::ToClientBody::ActionResponse(resp) => v5::ToClientBody::ActionResponse(resp.into()),
v6::ToClientBody::ConnectionsUpdated(update) => {
v5::ToClientBody::ConnectionsUpdated(update.into())
}
v6::ToClientBody::QueueUpdated(update) => v5::ToClientBody::QueueUpdated(update.into()),
v6::ToClientBody::StateUpdated(update) => v5::ToClientBody::StateUpdated(update.into()),
v6::ToClientBody::WorkflowHistoryUpdated(update) => {
v5::ToClientBody::WorkflowHistoryUpdated(update.into())
}
v6::ToClientBody::RpcsListResponse(resp) => {
v5::ToClientBody::RpcsListResponse(resp.into())
}
v6::ToClientBody::TraceQueryResponse(resp) => {
v5::ToClientBody::TraceQueryResponse(resp.into())
}
v6::ToClientBody::QueueResponse(resp) => v5::ToClientBody::QueueResponse(resp.into()),
v6::ToClientBody::WorkflowHistoryResponse(resp) => {
v5::ToClientBody::WorkflowHistoryResponse(resp.into())
}
v6::ToClientBody::WorkflowReplayResponse(resp) => {
v5::ToClientBody::WorkflowReplayResponse(resp.into())
}
v6::ToClientBody::Error(error) => v5::ToClientBody::Error(error.into()),
v6::ToClientBody::Init(init) => v5::ToClientBody::Init(v5::Init {
connections: convert_vec(init.connections),
state: init.state,
is_state_enabled: init.is_state_enabled,
rpcs: init.rpcs,
is_database_enabled: init.is_database_enabled,
queue_size: init.queue_size,
workflow_history: init.workflow_history,
is_workflow_enabled: init.is_workflow_enabled,
tab_config: convert_vec(init.tab_config),
}),
v6::ToClientBody::DatabaseSchemaResponse(resp) => {
v5::ToClientBody::DatabaseSchemaResponse(resp.into())
}
v6::ToClientBody::DatabaseTableRowsResponse(resp) => {
v5::ToClientBody::DatabaseTableRowsResponse(resp.into())
}
v6::ToClientBody::SchedulesUpdated(_)
| v6::ToClientBody::SchedulesResponse(_)
| v6::ToClientBody::ScheduleHistoryResponse(_)
| v6::ToClientBody::ScheduleDeleteResponse(_) => v5::ToClientBody::Error(v5::Error {
message: SCHEDULES_DROPPED_ERROR.to_owned(),
}),
};
Ok(Self::V5(v5::ToClient { body }))
}
fn v5_to_v4(self) -> Result<Self> {
let Self::V5(data) = self else {
bail!("expected inspector protocol v5 ToClient")
};
let body = match data.body {
v5::ToClientBody::StateResponse(resp) => v4::ToClientBody::StateResponse(resp.into()),
v5::ToClientBody::ConnectionsResponse(resp) => {
v4::ToClientBody::ConnectionsResponse(resp.into())
}
v5::ToClientBody::ActionResponse(resp) => v4::ToClientBody::ActionResponse(resp.into()),
v5::ToClientBody::ConnectionsUpdated(update) => {
v4::ToClientBody::ConnectionsUpdated(update.into())
}
v5::ToClientBody::QueueUpdated(update) => v4::ToClientBody::QueueUpdated(update.into()),
v5::ToClientBody::StateUpdated(update) => v4::ToClientBody::StateUpdated(update.into()),
v5::ToClientBody::WorkflowHistoryUpdated(update) => {
v4::ToClientBody::WorkflowHistoryUpdated(update.into())
}
v5::ToClientBody::RpcsListResponse(resp) => {
v4::ToClientBody::RpcsListResponse(resp.into())
}
v5::ToClientBody::TraceQueryResponse(resp) => {
v4::ToClientBody::TraceQueryResponse(resp.into())
}
v5::ToClientBody::QueueResponse(resp) => v4::ToClientBody::QueueResponse(resp.into()),
v5::ToClientBody::WorkflowHistoryResponse(resp) => {
v4::ToClientBody::WorkflowHistoryResponse(resp.into())
}
v5::ToClientBody::WorkflowReplayResponse(resp) => {
v4::ToClientBody::WorkflowReplayResponse(resp.into())
}
v5::ToClientBody::Error(error) => v4::ToClientBody::Error(error.into()),
v5::ToClientBody::Init(init) => v4::ToClientBody::Init(v4::Init {
connections: convert_vec(init.connections),
state: init.state,
is_state_enabled: init.is_state_enabled,
rpcs: init.rpcs,
is_database_enabled: init.is_database_enabled,
queue_size: init.queue_size,
workflow_history: init.workflow_history,
is_workflow_enabled: init.is_workflow_enabled,
}),
v5::ToClientBody::DatabaseSchemaResponse(resp) => {
v4::ToClientBody::DatabaseSchemaResponse(resp.into())
}
v5::ToClientBody::DatabaseTableRowsResponse(resp) => {
v4::ToClientBody::DatabaseTableRowsResponse(resp.into())
}
};
Ok(Self::V4(v4::ToClient { body }))
}
fn v4_to_v3(self) -> Result<Self> {
let Self::V4(data) = self else {
bail!("expected inspector protocol v4 ToClient")
};
let body = match data.body {
v4::ToClientBody::StateResponse(resp) => v3::ToClientBody::StateResponse(resp.into()),
v4::ToClientBody::ConnectionsResponse(resp) => {
v3::ToClientBody::ConnectionsResponse(resp.into())
}
v4::ToClientBody::ActionResponse(resp) => v3::ToClientBody::ActionResponse(resp.into()),
v4::ToClientBody::ConnectionsUpdated(update) => {
v3::ToClientBody::ConnectionsUpdated(update.into())
}
v4::ToClientBody::QueueUpdated(update) => v3::ToClientBody::QueueUpdated(update.into()),
v4::ToClientBody::StateUpdated(update) => v3::ToClientBody::StateUpdated(update.into()),
v4::ToClientBody::WorkflowHistoryUpdated(update) => {
v3::ToClientBody::WorkflowHistoryUpdated(update.into())
}
v4::ToClientBody::RpcsListResponse(resp) => {
v3::ToClientBody::RpcsListResponse(resp.into())
}
v4::ToClientBody::TraceQueryResponse(resp) => {
v3::ToClientBody::TraceQueryResponse(resp.into())
}
v4::ToClientBody::QueueResponse(resp) => v3::ToClientBody::QueueResponse(resp.into()),
v4::ToClientBody::WorkflowHistoryResponse(resp) => {
v3::ToClientBody::WorkflowHistoryResponse(resp.into())
}
v4::ToClientBody::WorkflowReplayResponse(_) => {
v3::ToClientBody::Error(dropped_error(WORKFLOW_HISTORY_DROPPED_ERROR).into())
}
v4::ToClientBody::Error(error) => v3::ToClientBody::Error(error.into()),
v4::ToClientBody::Init(init) => v3::ToClientBody::Init(init.into()),
v4::ToClientBody::DatabaseSchemaResponse(resp) => {
v3::ToClientBody::DatabaseSchemaResponse(resp.into())
}
v4::ToClientBody::DatabaseTableRowsResponse(resp) => {
v3::ToClientBody::DatabaseTableRowsResponse(resp.into())
}
};
Ok(Self::V3(v3::ToClient { body }))
}
fn v3_to_v2(self) -> Result<Self> {
let Self::V3(data) = self else {
bail!("expected inspector protocol v3 ToClient")
};
let body = match data.body {
v3::ToClientBody::StateResponse(resp) => v2::ToClientBody::StateResponse(resp.into()),
v3::ToClientBody::ConnectionsResponse(resp) => {
v2::ToClientBody::ConnectionsResponse(resp.into())
}
v3::ToClientBody::ActionResponse(resp) => v2::ToClientBody::ActionResponse(resp.into()),
v3::ToClientBody::ConnectionsUpdated(update) => {
v2::ToClientBody::ConnectionsUpdated(update.into())
}
v3::ToClientBody::QueueUpdated(update) => v2::ToClientBody::QueueUpdated(update.into()),
v3::ToClientBody::StateUpdated(update) => v2::ToClientBody::StateUpdated(update.into()),
v3::ToClientBody::WorkflowHistoryUpdated(update) => {
v2::ToClientBody::WorkflowHistoryUpdated(update.into())
}
v3::ToClientBody::RpcsListResponse(resp) => {
v2::ToClientBody::RpcsListResponse(resp.into())
}
v3::ToClientBody::TraceQueryResponse(resp) => {
v2::ToClientBody::TraceQueryResponse(resp.into())
}
v3::ToClientBody::QueueResponse(resp) => v2::ToClientBody::QueueResponse(resp.into()),
v3::ToClientBody::WorkflowHistoryResponse(resp) => {
v2::ToClientBody::WorkflowHistoryResponse(resp.into())
}
v3::ToClientBody::Error(error) => v2::ToClientBody::Error(error.into()),
v3::ToClientBody::Init(init) => v2::ToClientBody::Init(init.into()),
v3::ToClientBody::DatabaseSchemaResponse(_)
| v3::ToClientBody::DatabaseTableRowsResponse(_) => {
v2::ToClientBody::Error(dropped_error(DATABASE_DROPPED_ERROR))
}
};
Ok(Self::V2(v2::ToClient { body }))
}
fn v2_to_v1(self) -> Result<Self> {
let Self::V2(data) = self else {
bail!("expected inspector protocol v2 ToClient")
};
let body = match data.body {
v2::ToClientBody::StateResponse(resp) => v1::ToClientBody::StateResponse(resp.into()),
v2::ToClientBody::ConnectionsResponse(resp) => {
v1::ToClientBody::ConnectionsResponse(resp.into())
}
v2::ToClientBody::ActionResponse(resp) => v1::ToClientBody::ActionResponse(resp.into()),
v2::ToClientBody::ConnectionsUpdated(update) => {
v1::ToClientBody::ConnectionsUpdated(update.into())
}
v2::ToClientBody::StateUpdated(update) => v1::ToClientBody::StateUpdated(update.into()),
v2::ToClientBody::RpcsListResponse(resp) => {
v1::ToClientBody::RpcsListResponse(resp.into())
}
v2::ToClientBody::Error(error) => v1::ToClientBody::Error(error.into()),
v2::ToClientBody::Init(init) => v1::ToClientBody::Init(v1::Init {
connections: init.connections.into_iter().map(Into::into).collect(),
events: Vec::new(),
state: init.state,
is_state_enabled: init.is_state_enabled,
rpcs: init.rpcs,
is_database_enabled: init.is_database_enabled,
}),
v2::ToClientBody::QueueUpdated(_) | v2::ToClientBody::QueueResponse(_) => {
v1::ToClientBody::Error(dropped_error(QUEUE_DROPPED_ERROR).into())
}
v2::ToClientBody::WorkflowHistoryUpdated(_)
| v2::ToClientBody::WorkflowHistoryResponse(_) => {
v1::ToClientBody::Error(dropped_error(WORKFLOW_HISTORY_DROPPED_ERROR).into())
}
v2::ToClientBody::TraceQueryResponse(_) => {
v1::ToClientBody::Error(dropped_error(TRACE_DROPPED_ERROR).into())
}
};
Ok(Self::V1(v1::ToClient { body }))
}
}
fn convert_vec<From, To>(values: Vec<From>) -> Vec<To>
where
From: Into<To>,
{
values.into_iter().map(Into::into).collect()
}
macro_rules! impl_same_fields_pair {
($left:ident, $right:ident, $ty:ident { $($field:ident),+ $(,)? }) => {
impl From<$left::$ty> for $right::$ty {
fn from(value: $left::$ty) -> Self {
Self {
$($field: value.$field),+
}
}
}
impl From<$right::$ty> for $left::$ty {
fn from(value: $right::$ty) -> Self {
Self {
$($field: value.$field),+
}
}
}
};
}
macro_rules! impl_connection_list_pair {
($left:ident, $right:ident, $ty:ident) => {
impl From<$left::$ty> for $right::$ty {
fn from(value: $left::$ty) -> Self {
Self {
connections: convert_vec(value.connections),
}
}
}
impl From<$right::$ty> for $left::$ty {
fn from(value: $right::$ty) -> Self {
Self {
connections: convert_vec(value.connections),
}
}
}
};
}
macro_rules! impl_connections_response_pair {
($left:ident, $right:ident) => {
impl From<$left::ConnectionsResponse> for $right::ConnectionsResponse {
fn from(value: $left::ConnectionsResponse) -> Self {
Self {
rid: value.rid,
connections: convert_vec(value.connections),
}
}
}
impl From<$right::ConnectionsResponse> for $left::ConnectionsResponse {
fn from(value: $right::ConnectionsResponse) -> Self {
Self {
rid: value.rid,
connections: convert_vec(value.connections),
}
}
}
};
}
macro_rules! impl_queue_status_pair {
($left:ident, $right:ident) => {
impl From<$left::QueueStatus> for $right::QueueStatus {
fn from(value: $left::QueueStatus) -> Self {
Self {
size: value.size,
max_size: value.max_size,
messages: convert_vec(value.messages),
truncated: value.truncated,
}
}
}
impl From<$right::QueueStatus> for $left::QueueStatus {
fn from(value: $right::QueueStatus) -> Self {
Self {
size: value.size,
max_size: value.max_size,
messages: convert_vec(value.messages),
truncated: value.truncated,
}
}
}
};
}
macro_rules! impl_queue_response_pair {
($left:ident, $right:ident) => {
impl From<$left::QueueResponse> for $right::QueueResponse {
fn from(value: $left::QueueResponse) -> Self {
Self {
rid: value.rid,
status: value.status.into(),
}
}
}
impl From<$right::QueueResponse> for $left::QueueResponse {
fn from(value: $right::QueueResponse) -> Self {
Self {
rid: value.rid,
status: value.status.into(),
}
}
}
};
}
macro_rules! impl_init_pair {
($left:ident, $right:ident) => {
impl From<$left::Init> for $right::Init {
fn from(value: $left::Init) -> Self {
Self {
connections: convert_vec(value.connections),
state: value.state,
is_state_enabled: value.is_state_enabled,
rpcs: value.rpcs,
is_database_enabled: value.is_database_enabled,
queue_size: value.queue_size,
workflow_history: value.workflow_history,
is_workflow_enabled: value.is_workflow_enabled,
}
}
}
impl From<$right::Init> for $left::Init {
fn from(value: $right::Init) -> Self {
Self {
connections: convert_vec(value.connections),
state: value.state,
is_state_enabled: value.is_state_enabled,
rpcs: value.rpcs,
is_database_enabled: value.is_database_enabled,
queue_size: value.queue_size,
workflow_history: value.workflow_history,
is_workflow_enabled: value.is_workflow_enabled,
}
}
}
};
}
macro_rules! impl_common_actor_pair {
($left:ident, $right:ident) => {
impl_same_fields_pair!($left, $right, PatchStateRequest { state });
impl_same_fields_pair!($left, $right, ActionRequest { id, name, args });
impl_same_fields_pair!($left, $right, StateRequest { id });
impl_same_fields_pair!($left, $right, ConnectionsRequest { id });
impl_same_fields_pair!($left, $right, RpcsListRequest { id });
impl_same_fields_pair!($left, $right, Connection { id, details });
impl_connections_response_pair!($left, $right);
impl_connection_list_pair!($left, $right, ConnectionsUpdated);
impl_same_fields_pair!(
$left,
$right,
StateResponse {
rid,
state,
is_state_enabled,
}
);
impl_same_fields_pair!($left, $right, ActionResponse { rid, output });
impl_same_fields_pair!($left, $right, StateUpdated { state });
impl_same_fields_pair!($left, $right, RpcsListResponse { rid, rpcs });
impl_same_fields_pair!($left, $right, Error { message });
};
}
macro_rules! impl_queue_workflow_pair {
($left:ident, $right:ident) => {
impl_same_fields_pair!(
$left,
$right,
TraceQueryRequest {
id,
start_ms,
end_ms,
limit,
}
);
impl_same_fields_pair!($left, $right, TraceQueryResponse { rid, payload });
impl_same_fields_pair!($left, $right, QueueRequest { id, limit });
impl_same_fields_pair!(
$left,
$right,
QueueMessageSummary {
id,
name,
created_at_ms,
}
);
impl_queue_status_pair!($left, $right);
impl_queue_response_pair!($left, $right);
impl_same_fields_pair!($left, $right, QueueUpdated { queue_size });
impl_same_fields_pair!($left, $right, WorkflowHistoryRequest { id });
impl_same_fields_pair!(
$left,
$right,
WorkflowHistoryResponse {
rid,
history,
is_workflow_enabled,
}
);
impl_same_fields_pair!($left, $right, WorkflowHistoryUpdated { history });
impl_init_pair!($left, $right);
};
}
macro_rules! impl_database_pair {
($left:ident, $right:ident) => {
impl_same_fields_pair!($left, $right, DatabaseSchemaRequest { id });
impl_same_fields_pair!($left, $right, DatabaseSchemaResponse { rid, schema });
impl_same_fields_pair!(
$left,
$right,
DatabaseTableRowsRequest {
id,
table,
limit,
offset,
}
);
impl_same_fields_pair!($left, $right, DatabaseTableRowsResponse { rid, result });
};
}
impl_common_actor_pair!(v1, v2);
impl_common_actor_pair!(v2, v3);
impl_common_actor_pair!(v3, v4);
impl_common_actor_pair!(v4, v5);
impl_common_actor_pair!(v5, v6);
impl_queue_workflow_pair!(v2, v3);
impl_queue_workflow_pair!(v3, v4);
impl_database_pair!(v3, v4);
impl_database_pair!(v4, v5);
impl_database_pair!(v5, v6);
impl_same_fields_pair!(
v5,
v6,
TabConfigEntry {
id,
label,
icon,
hidden
}
);
impl_same_fields_pair!(
v5,
v6,
TraceQueryRequest {
id,
start_ms,
end_ms,
limit,
}
);
impl_same_fields_pair!(v5, v6, TraceQueryResponse { rid, payload });
impl_same_fields_pair!(v5, v6, QueueRequest { id, limit });
impl_same_fields_pair!(
v5,
v6,
QueueMessageSummary {
id,
name,
created_at_ms,
}
);
impl_queue_status_pair!(v5, v6);
impl_queue_response_pair!(v5, v6);
impl_same_fields_pair!(v5, v6, QueueUpdated { queue_size });
impl_same_fields_pair!(v5, v6, WorkflowHistoryRequest { id });
impl_same_fields_pair!(
v5,
v6,
WorkflowHistoryResponse {
rid,
history,
is_workflow_enabled,
}
);
impl_same_fields_pair!(v5, v6, WorkflowHistoryUpdated { history });
impl_same_fields_pair!(v5, v6, WorkflowReplayRequest { id, entry_id });
impl_same_fields_pair!(
v5,
v6,
WorkflowReplayResponse {
rid,
history,
is_workflow_enabled,
}
);
impl From<v5::ToServerBody> for v6::ToServerBody {
fn from(value: v5::ToServerBody) -> Self {
match value {
v5::ToServerBody::PatchStateRequest(req) => Self::PatchStateRequest(req.into()),
v5::ToServerBody::StateRequest(req) => Self::StateRequest(req.into()),
v5::ToServerBody::ConnectionsRequest(req) => Self::ConnectionsRequest(req.into()),
v5::ToServerBody::ActionRequest(req) => Self::ActionRequest(req.into()),
v5::ToServerBody::RpcsListRequest(req) => Self::RpcsListRequest(req.into()),
v5::ToServerBody::TraceQueryRequest(req) => Self::TraceQueryRequest(req.into()),
v5::ToServerBody::QueueRequest(req) => Self::QueueRequest(req.into()),
v5::ToServerBody::WorkflowHistoryRequest(req) => {
Self::WorkflowHistoryRequest(req.into())
}
v5::ToServerBody::WorkflowReplayRequest(req) => Self::WorkflowReplayRequest(req.into()),
v5::ToServerBody::DatabaseSchemaRequest(req) => Self::DatabaseSchemaRequest(req.into()),
v5::ToServerBody::DatabaseTableRowsRequest(req) => {
Self::DatabaseTableRowsRequest(req.into())
}
}
}
}
impl From<v5::ToServer> for v6::ToServer {
fn from(value: v5::ToServer) -> Self {
Self {
body: value.body.into(),
}
}
}
impl_same_fields_pair!(
v4,
v5,
TraceQueryRequest {
id,
start_ms,
end_ms,
limit,
}
);
impl_same_fields_pair!(v4, v5, TraceQueryResponse { rid, payload });
impl_same_fields_pair!(v4, v5, QueueRequest { id, limit });
impl_same_fields_pair!(
v4,
v5,
QueueMessageSummary {
id,
name,
created_at_ms,
}
);
impl_queue_status_pair!(v4, v5);
impl_queue_response_pair!(v4, v5);
impl_same_fields_pair!(v4, v5, QueueUpdated { queue_size });
impl_same_fields_pair!(v4, v5, WorkflowHistoryRequest { id });
impl_same_fields_pair!(
v4,
v5,
WorkflowHistoryResponse {
rid,
history,
is_workflow_enabled,
}
);
impl_same_fields_pair!(v4, v5, WorkflowHistoryUpdated { history });
impl_same_fields_pair!(v4, v5, WorkflowReplayRequest { id, entry_id });
impl_same_fields_pair!(
v4,
v5,
WorkflowReplayResponse {
rid,
history,
is_workflow_enabled,
}
);
impl From<v4::ToServerBody> for v5::ToServerBody {
fn from(value: v4::ToServerBody) -> Self {
match value {
v4::ToServerBody::PatchStateRequest(req) => Self::PatchStateRequest(req.into()),
v4::ToServerBody::StateRequest(req) => Self::StateRequest(req.into()),
v4::ToServerBody::ConnectionsRequest(req) => Self::ConnectionsRequest(req.into()),
v4::ToServerBody::ActionRequest(req) => Self::ActionRequest(req.into()),
v4::ToServerBody::RpcsListRequest(req) => Self::RpcsListRequest(req.into()),
v4::ToServerBody::TraceQueryRequest(req) => Self::TraceQueryRequest(req.into()),
v4::ToServerBody::QueueRequest(req) => Self::QueueRequest(req.into()),
v4::ToServerBody::WorkflowHistoryRequest(req) => {
Self::WorkflowHistoryRequest(req.into())
}
v4::ToServerBody::WorkflowReplayRequest(req) => Self::WorkflowReplayRequest(req.into()),
v4::ToServerBody::DatabaseSchemaRequest(req) => Self::DatabaseSchemaRequest(req.into()),
v4::ToServerBody::DatabaseTableRowsRequest(req) => {
Self::DatabaseTableRowsRequest(req.into())
}
}
}
}
impl From<v5::ToServerBody> for v4::ToServerBody {
fn from(value: v5::ToServerBody) -> Self {
match value {
v5::ToServerBody::PatchStateRequest(req) => Self::PatchStateRequest(req.into()),
v5::ToServerBody::StateRequest(req) => Self::StateRequest(req.into()),
v5::ToServerBody::ConnectionsRequest(req) => Self::ConnectionsRequest(req.into()),
v5::ToServerBody::ActionRequest(req) => Self::ActionRequest(req.into()),
v5::ToServerBody::RpcsListRequest(req) => Self::RpcsListRequest(req.into()),
v5::ToServerBody::TraceQueryRequest(req) => Self::TraceQueryRequest(req.into()),
v5::ToServerBody::QueueRequest(req) => Self::QueueRequest(req.into()),
v5::ToServerBody::WorkflowHistoryRequest(req) => {
Self::WorkflowHistoryRequest(req.into())
}
v5::ToServerBody::WorkflowReplayRequest(req) => Self::WorkflowReplayRequest(req.into()),
v5::ToServerBody::DatabaseSchemaRequest(req) => Self::DatabaseSchemaRequest(req.into()),
v5::ToServerBody::DatabaseTableRowsRequest(req) => {
Self::DatabaseTableRowsRequest(req.into())
}
}
}
}
impl From<v4::ToServer> for v5::ToServer {
fn from(value: v4::ToServer) -> Self {
Self {
body: value.body.into(),
}
}
}
impl From<v5::ToServer> for v4::ToServer {
fn from(value: v5::ToServer) -> Self {
Self {
body: value.body.into(),
}
}
}
impl From<v2::ToServerBody> for v3::ToServerBody {
fn from(value: v2::ToServerBody) -> Self {
match value {
v2::ToServerBody::PatchStateRequest(req) => Self::PatchStateRequest(req.into()),
v2::ToServerBody::StateRequest(req) => Self::StateRequest(req.into()),
v2::ToServerBody::ConnectionsRequest(req) => Self::ConnectionsRequest(req.into()),
v2::ToServerBody::ActionRequest(req) => Self::ActionRequest(req.into()),
v2::ToServerBody::RpcsListRequest(req) => Self::RpcsListRequest(req.into()),
v2::ToServerBody::TraceQueryRequest(req) => Self::TraceQueryRequest(req.into()),
v2::ToServerBody::QueueRequest(req) => Self::QueueRequest(req.into()),
v2::ToServerBody::WorkflowHistoryRequest(req) => {
Self::WorkflowHistoryRequest(req.into())
}
}
}
}
impl From<v2::ToServer> for v3::ToServer {
fn from(value: v2::ToServer) -> Self {
Self {
body: value.body.into(),
}
}
}
impl From<v2::ToClientBody> for v3::ToClientBody {
fn from(value: v2::ToClientBody) -> Self {
match value {
v2::ToClientBody::StateResponse(resp) => Self::StateResponse(resp.into()),
v2::ToClientBody::ConnectionsResponse(resp) => Self::ConnectionsResponse(resp.into()),
v2::ToClientBody::ActionResponse(resp) => Self::ActionResponse(resp.into()),
v2::ToClientBody::ConnectionsUpdated(update) => Self::ConnectionsUpdated(update.into()),
v2::ToClientBody::QueueUpdated(update) => Self::QueueUpdated(update.into()),
v2::ToClientBody::StateUpdated(update) => Self::StateUpdated(update.into()),
v2::ToClientBody::WorkflowHistoryUpdated(update) => {
Self::WorkflowHistoryUpdated(update.into())
}
v2::ToClientBody::RpcsListResponse(resp) => Self::RpcsListResponse(resp.into()),
v2::ToClientBody::TraceQueryResponse(resp) => Self::TraceQueryResponse(resp.into()),
v2::ToClientBody::QueueResponse(resp) => Self::QueueResponse(resp.into()),
v2::ToClientBody::WorkflowHistoryResponse(resp) => {
Self::WorkflowHistoryResponse(resp.into())
}
v2::ToClientBody::Error(error) => Self::Error(error.into()),
v2::ToClientBody::Init(init) => Self::Init(init.into()),
}
}
}
impl From<v2::ToClient> for v3::ToClient {
fn from(value: v2::ToClient) -> Self {
Self {
body: value.body.into(),
}
}
}
fn dropped_error(message: &str) -> v2::Error {
v2::Error {
message: message.to_owned(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn v3_database_schema_request_keeps_meaning_when_upgrading_to_v4() {
let request = ToServer::V3(v3::ToServer {
body: v3::ToServerBody::DatabaseSchemaRequest(v3::DatabaseSchemaRequest {
id: Uint(7),
}),
});
let ToServer::V4(upgraded) = ToServer::v3_to_v4(request).unwrap() else {
panic!("expected v4 request")
};
assert!(matches!(
upgraded.body,
v4::ToServerBody::DatabaseSchemaRequest(v4::DatabaseSchemaRequest { id }) if id == Uint(7)
));
}
fn v5_init_with_tabs() -> v5::Init {
v5::Init {
connections: Vec::new(),
state: None,
is_state_enabled: false,
rpcs: Vec::new(),
is_database_enabled: false,
queue_size: Uint(0),
workflow_history: None,
is_workflow_enabled: false,
tab_config: vec![v5::TabConfigEntry {
id: "custom".to_owned(),
label: Some("Custom".to_owned()),
icon: Some("star".to_owned()),
hidden: false,
}],
}
}
#[test]
fn v5_init_tab_config_drops_when_downgrading_to_v4() {
let response = ToClient::V5(v5::ToClient {
body: v5::ToClientBody::Init(v5_init_with_tabs()),
});
let ToClient::V4(downgraded) = ToClient::v5_to_v4(response).unwrap() else {
panic!("expected v4 response")
};
assert!(matches!(
downgraded.body,
v4::ToClientBody::Init(v4::Init {
is_workflow_enabled: false,
..
})
));
}
#[test]
fn v4_init_upgrades_to_v5_with_empty_tab_config() {
let response = ToClient::V4(v4::ToClient {
body: v4::ToClientBody::Init(v4::Init {
connections: Vec::new(),
state: None,
is_state_enabled: false,
rpcs: Vec::new(),
is_database_enabled: false,
queue_size: Uint(0),
workflow_history: None,
is_workflow_enabled: false,
}),
});
let ToClient::V5(upgraded) = ToClient::v4_to_v5(response).unwrap() else {
panic!("expected v5 response")
};
let v5::ToClientBody::Init(init) = upgraded.body else {
panic!("expected Init body")
};
assert!(init.tab_config.is_empty());
}
#[test]
fn v5_init_tab_config_round_trips_at_version_5() {
let original = v5_init_with_tabs();
let latest = ToClient::v5_to_v6(ToClient::V5(v5::ToClient {
body: v5::ToClientBody::Init(original.clone()),
}))
.unwrap();
let encoded = latest.serialize_with_embedded_version(5).unwrap();
let decoded =
<ToClient as OwnedVersionedData>::deserialize_with_embedded_version(&encoded).unwrap();
let v6::ToClientBody::Init(init) = decoded.body else {
panic!("expected Init body")
};
assert_eq!(init.tab_config.len(), original.tab_config.len());
assert_eq!(init.tab_config[0].id, original.tab_config[0].id);
assert!(init.schedules.is_empty());
}
#[test]
fn v6_schedule_messages_downgrade_to_structured_error() {
let response = ToClient::V6(v6::ToClient {
body: v6::ToClientBody::SchedulesUpdated(v6::SchedulesUpdated {
schedules: Vec::new(),
}),
});
let ToClient::V5(downgraded) = ToClient::v6_to_v5(response).unwrap() else {
panic!("expected v5 response")
};
assert_eq!(
downgraded.body,
v5::ToClientBody::Error(v5::Error {
message: SCHEDULES_DROPPED_ERROR.to_owned(),
})
);
}
#[test]
fn v5_init_upgrades_to_v6_with_empty_schedules() {
let response = ToClient::V5(v5::ToClient {
body: v5::ToClientBody::Init(v5_init_with_tabs()),
});
let ToClient::V6(upgraded) = ToClient::v5_to_v6(response).unwrap() else {
panic!("expected v6 response")
};
let v6::ToClientBody::Init(init) = upgraded.body else {
panic!("expected Init body")
};
assert!(init.schedules.is_empty());
assert_eq!(init.tab_config.len(), 1);
}
#[test]
fn v4_workflow_replay_response_downgrades_to_v3_error() {
let response = ToClient::V4(v4::ToClient {
body: v4::ToClientBody::WorkflowReplayResponse(v4::WorkflowReplayResponse {
rid: Uint(11),
history: Some(b"workflow".to_vec()),
is_workflow_enabled: true,
}),
});
let ToClient::V3(downgraded) = ToClient::v4_to_v3(response).unwrap() else {
panic!("expected v3 response")
};
assert_eq!(
downgraded.body,
v3::ToClientBody::Error(v3::Error {
message: WORKFLOW_HISTORY_DROPPED_ERROR.to_owned(),
})
);
}
}