forked from github-starred/komodo
Simpllify Option + Result into one encoding layer
This commit is contained in:
@@ -10,8 +10,8 @@ use anyhow::anyhow;
|
||||
use cache::CloneCache;
|
||||
use database::mungos::{by_id::update_one_by_id, mongodb::bson::doc};
|
||||
use encoding::{
|
||||
CastBytes as _, Decode as _, EncodedJsonMessage, EncodedOption,
|
||||
EncodedResult, WithChannel,
|
||||
CastBytes as _, Decode as _, EncodedJsonMessage, EncodedResponse,
|
||||
WithChannel,
|
||||
};
|
||||
use komodo_client::entities::{
|
||||
builder::{AwsBuilderConfig, UrlBuilderConfig},
|
||||
@@ -253,10 +253,8 @@ impl<'a> From<&'a OwnedPeripheryConnectionArgs>
|
||||
}
|
||||
|
||||
/// Sends None as InProgress ping.
|
||||
pub type ResponseChannels = CloneCache<
|
||||
Uuid,
|
||||
Sender<EncodedOption<EncodedResult<EncodedJsonMessage>>>,
|
||||
>;
|
||||
pub type ResponseChannels =
|
||||
CloneCache<Uuid, Sender<EncodedResponse<EncodedJsonMessage>>>;
|
||||
|
||||
pub type TerminalChannels = CloneCache<Uuid, Sender<Vec<u8>>>;
|
||||
|
||||
|
||||
@@ -135,11 +135,11 @@ impl PeripheryClient {
|
||||
.await?;
|
||||
|
||||
// Still in progress, sent to avoid timeout.
|
||||
let Some(message) = message.decode()?.into_std() else {
|
||||
let Some(message) = message.decode()? else {
|
||||
continue;
|
||||
};
|
||||
|
||||
return message.decode_into();
|
||||
return message.decode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use command::run_komodo_command;
|
||||
use derive_variants::EnumVariants;
|
||||
use encoding::{EncodedJsonMessage, EncodedResult};
|
||||
use encoding::{EncodedJsonMessage, EncodedResponse};
|
||||
use futures::FutureExt;
|
||||
use komodo_client::entities::{
|
||||
config::{DockerRegistry, GitProvider},
|
||||
@@ -41,7 +41,7 @@ pub struct Args {
|
||||
Serialize, Deserialize, Debug, Clone, Resolve, EnumVariants,
|
||||
)]
|
||||
#[args(Args)]
|
||||
#[response(EncodedResult<EncodedJsonMessage>)]
|
||||
#[response(EncodedResponse<EncodedJsonMessage>)]
|
||||
#[error(anyhow::Error)]
|
||||
#[variant_derive(Debug)]
|
||||
#[serde(tag = "type", content = "params")]
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use anyhow::{Context, anyhow};
|
||||
use derive_variants::{EnumVariants, ExtractVariant};
|
||||
use encoding::{
|
||||
CastBytes, Decode, Encode, EncodedResult, impl_cast_bytes_vec,
|
||||
CastBytes, Decode, Encode, EncodedResponse, impl_cast_bytes_vec,
|
||||
impl_from_for_wrapper,
|
||||
};
|
||||
use noise::key::SpkiPublicKey;
|
||||
|
||||
@@ -9,18 +10,14 @@ use crate::transport::{EncodedTransportMessage, TransportMessage};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EncodedLoginMessage(
|
||||
EncodedResult<InnerEncodedLoginMessage>,
|
||||
EncodedResponse<InnerEncodedLoginMessage>,
|
||||
);
|
||||
|
||||
impl From<EncodedResult<InnerEncodedLoginMessage>>
|
||||
for EncodedLoginMessage
|
||||
{
|
||||
fn from(value: EncodedResult<InnerEncodedLoginMessage>) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl_cast_bytes_vec!(EncodedLoginMessage, EncodedResult);
|
||||
impl_from_for_wrapper!(
|
||||
EncodedLoginMessage,
|
||||
EncodedResponse<InnerEncodedLoginMessage>
|
||||
);
|
||||
impl_cast_bytes_vec!(EncodedLoginMessage, EncodedResponse);
|
||||
|
||||
/// ```markdown
|
||||
/// | -- u8[] -- | --------- u8 ------------ |
|
||||
@@ -90,7 +87,11 @@ impl Encode<EncodedTransportMessage> for LoginMessage {
|
||||
|
||||
impl Decode<LoginMessage> for EncodedLoginMessage {
|
||||
fn decode(self) -> anyhow::Result<LoginMessage> {
|
||||
let mut bytes = self.0.decode()?.into_vec();
|
||||
let mut bytes = self
|
||||
.0
|
||||
.decode()?
|
||||
.context("Should not receive Pending (2) Response message")?
|
||||
.into_vec();
|
||||
|
||||
let variant_byte = bytes
|
||||
.pop()
|
||||
|
||||
@@ -2,7 +2,8 @@ use anyhow::{Context as _, anyhow};
|
||||
use derive_variants::{EnumVariants, ExtractVariant as _};
|
||||
use encoding::{
|
||||
CastBytes, Decode, Encode, EncodedChannel, EncodedJsonMessage,
|
||||
EncodedOption, EncodedResult, WithChannel, impl_cast_bytes_vec,
|
||||
EncodedResponse, WithChannel, impl_cast_bytes_vec,
|
||||
impl_from_for_wrapper,
|
||||
};
|
||||
|
||||
mod login;
|
||||
@@ -152,15 +153,10 @@ pub struct EncodedResponseMessage(
|
||||
EncodedChannel<InnerEncodedResponseMessage>,
|
||||
);
|
||||
|
||||
impl From<EncodedChannel<InnerEncodedResponseMessage>>
|
||||
for EncodedResponseMessage
|
||||
{
|
||||
fn from(
|
||||
value: EncodedChannel<InnerEncodedResponseMessage>,
|
||||
) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl_from_for_wrapper!(
|
||||
EncodedResponseMessage,
|
||||
EncodedChannel<InnerEncodedResponseMessage>
|
||||
);
|
||||
|
||||
impl_cast_bytes_vec!(EncodedResponseMessage, EncodedChannel);
|
||||
|
||||
@@ -168,28 +164,27 @@ impl_cast_bytes_vec!(EncodedResponseMessage, EncodedChannel);
|
||||
/// and passed to response handler for parsing.
|
||||
#[derive(Debug)]
|
||||
pub struct InnerEncodedResponseMessage(
|
||||
EncodedOption<EncodedResult<EncodedJsonMessage>>,
|
||||
EncodedResponse<EncodedJsonMessage>,
|
||||
);
|
||||
|
||||
impl_cast_bytes_vec!(InnerEncodedResponseMessage, EncodedOption);
|
||||
impl_cast_bytes_vec!(InnerEncodedResponseMessage, EncodedResponse);
|
||||
|
||||
pub struct ResponseMessage(WithChannel<InnerEncodedResponseMessage>);
|
||||
|
||||
impl ResponseMessage {
|
||||
pub fn new(
|
||||
channel: Uuid,
|
||||
response: Option<EncodedResult<EncodedJsonMessage>>,
|
||||
response: EncodedResponse<EncodedJsonMessage>,
|
||||
) -> Self {
|
||||
Self(WithChannel {
|
||||
channel,
|
||||
data: InnerEncodedResponseMessage(response.encode()),
|
||||
data: InnerEncodedResponseMessage(response),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn extract(
|
||||
self,
|
||||
) -> WithChannel<EncodedOption<EncodedResult<EncodedJsonMessage>>>
|
||||
{
|
||||
) -> WithChannel<EncodedResponse<EncodedJsonMessage>> {
|
||||
self.0.map(|data| data.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use anyhow::anyhow;
|
||||
use bytes::Bytes;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{CastBytes, Decode, Encode, impl_wrapper};
|
||||
use crate::{CastBytes, Decode, Encode};
|
||||
|
||||
/// Message wrapper to handle Error unwrapping
|
||||
/// anywhere in the en/decoding chain.
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use anyhow::Context;
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
|
||||
use crate::{
|
||||
CastBytes, Decode, Encode, EncodedResult, impl_identity,
|
||||
};
|
||||
use crate::{CastBytes, Decode, Encode, EncodedResponse};
|
||||
|
||||
/// ```markdown
|
||||
/// | --- u8[] --- |
|
||||
@@ -26,15 +24,14 @@ impl CastBytes for EncodedJsonMessage {
|
||||
pub struct JsonMessage<'a, T>(pub &'a T);
|
||||
|
||||
impl<'a, T: Serialize + Send>
|
||||
Encode<crate::Result<EncodedJsonMessage>> for JsonMessage<'a, T>
|
||||
Encode<anyhow::Result<EncodedJsonMessage>> for JsonMessage<'a, T>
|
||||
where
|
||||
&'a T: Send,
|
||||
{
|
||||
fn encode(self) -> crate::Result<EncodedJsonMessage> {
|
||||
fn encode(self) -> anyhow::Result<EncodedJsonMessage> {
|
||||
serde_json::to_vec(self.0)
|
||||
.context("Failed to serialize data to bytes")
|
||||
.map(EncodedJsonMessage)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +43,7 @@ impl<T: DeserializeOwned> Decode<T> for EncodedJsonMessage {
|
||||
}
|
||||
|
||||
impl<T: Serialize + Send> From<T>
|
||||
for EncodedResult<EncodedJsonMessage>
|
||||
for EncodedResponse<EncodedJsonMessage>
|
||||
{
|
||||
fn from(value: T) -> Self {
|
||||
serde_json::to_vec(&value)
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
|
||||
use bytes::Bytes;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod channel;
|
||||
mod json;
|
||||
mod option;
|
||||
mod result;
|
||||
mod response;
|
||||
|
||||
pub use channel::*;
|
||||
pub use json::*;
|
||||
pub use option::*;
|
||||
pub use result::*;
|
||||
pub use response::*;
|
||||
|
||||
pub trait Encode<Target>: Sized + Send {
|
||||
fn encode(self) -> Target;
|
||||
@@ -70,57 +71,3 @@ impl CastBytes for Vec<u8> {
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_identity {
|
||||
($typ:ty) => {
|
||||
impl Encode<$typ> for $typ {
|
||||
fn encode(self) -> $typ {
|
||||
self
|
||||
}
|
||||
}
|
||||
impl Decode<$typ> for $typ {
|
||||
fn decode(self) -> anyhow::Result<$typ> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_wrapper {
|
||||
($struct:ident) => {
|
||||
impl<T> From<T> for $struct<T> {
|
||||
fn from(value: T) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl<T: CastBytes> CastBytes for $struct<T> {
|
||||
fn from_bytes(bytes: Bytes) -> Self {
|
||||
Self(T::from_bytes(bytes))
|
||||
}
|
||||
fn into_bytes(self) -> Bytes {
|
||||
self.0.into_bytes()
|
||||
}
|
||||
fn from_vec(vec: Vec<u8>) -> Self {
|
||||
Self(T::from_vec(vec))
|
||||
}
|
||||
fn into_vec(self) -> Vec<u8> {
|
||||
self.0.into_vec()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_cast_bytes_vec {
|
||||
($typ:ty, $through:ident) => {
|
||||
impl CastBytes for $typ {
|
||||
fn from_vec(bytes: Vec<u8>) -> Self {
|
||||
Self($through::from_vec(bytes))
|
||||
}
|
||||
fn into_vec(self) -> Vec<u8> {
|
||||
self.0.into_vec()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
63
lib/encoding/src/macros.rs
Normal file
63
lib/encoding/src/macros.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
#[macro_export]
|
||||
macro_rules! impl_cast_bytes_vec {
|
||||
($typ:ty, $through:ident) => {
|
||||
impl CastBytes for $typ {
|
||||
fn from_vec(bytes: Vec<u8>) -> Self {
|
||||
Self($through::from_vec(bytes))
|
||||
}
|
||||
fn into_vec(self) -> Vec<u8> {
|
||||
self.0.into_vec()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_from_for_wrapper {
|
||||
($typ:ty, $through:ty) => {
|
||||
impl From<$through> for $typ {
|
||||
fn from(value: $through) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_identity {
|
||||
($typ:ty) => {
|
||||
impl Encode<$typ> for $typ {
|
||||
fn encode(self) -> $typ {
|
||||
self
|
||||
}
|
||||
}
|
||||
impl Decode<$typ> for $typ {
|
||||
fn decode(self) -> anyhow::Result<$typ> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_wrapper {
|
||||
($struct:ident) => {
|
||||
impl<T> From<T> for $struct<T> {
|
||||
fn from(value: T) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl<T: CastBytes> CastBytes for $struct<T> {
|
||||
fn from_bytes(bytes: Bytes) -> Self {
|
||||
Self(T::from_bytes(bytes))
|
||||
}
|
||||
fn into_bytes(self) -> Bytes {
|
||||
self.0.into_bytes()
|
||||
}
|
||||
fn from_vec(vec: Vec<u8>) -> Self {
|
||||
Self(T::from_vec(vec))
|
||||
}
|
||||
fn into_vec(self) -> Vec<u8> {
|
||||
self.0.into_vec()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
use std::option::Option as StdOption;
|
||||
|
||||
use anyhow::Context;
|
||||
use bytes::Bytes;
|
||||
|
||||
use crate::{CastBytes, Decode, Encode, impl_wrapper};
|
||||
|
||||
/// Message wrapper to handle Option unwrapping
|
||||
/// anywhere in the en/decoding chain.
|
||||
/// ```markdown
|
||||
/// | -- u8[] -- | ------- u8 ------- |
|
||||
/// | <CONTENTS> | 0: Some or _: None |
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EncodedOption<T>(T);
|
||||
|
||||
impl_wrapper!(EncodedOption);
|
||||
|
||||
impl<B: CastBytes + Send> EncodedOption<B> {
|
||||
/// Will only produce None if really None, with confirmed None byte.
|
||||
/// Any error in decoding will lead to Some(Err(e))
|
||||
pub fn decode_map<T>(self) -> StdOption<anyhow::Result<T>>
|
||||
where
|
||||
B: Decode<T>,
|
||||
{
|
||||
self.decode().and_then(|data| data.map_decode()).transpose()
|
||||
}
|
||||
}
|
||||
|
||||
/// Just std Option,
|
||||
/// but can implement on it.
|
||||
pub enum Option<T> {
|
||||
Some(T),
|
||||
None,
|
||||
}
|
||||
|
||||
impl<T> Option<T> {
|
||||
pub fn into_std(self) -> StdOption<T> {
|
||||
self.into()
|
||||
}
|
||||
|
||||
pub fn map<R>(self, map: impl FnOnce(T) -> R) -> Option<R> {
|
||||
use Option::*;
|
||||
match self {
|
||||
Some(t) => Some(map(t)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_encode<B: CastBytes + Send>(self) -> EncodedOption<B>
|
||||
where
|
||||
T: Encode<B>,
|
||||
{
|
||||
self.map(Encode::encode).encode()
|
||||
}
|
||||
|
||||
pub fn map_decode<D>(self) -> anyhow::Result<StdOption<D>>
|
||||
where
|
||||
T: CastBytes + Send + Decode<D>,
|
||||
{
|
||||
match self.map(Decode::decode) {
|
||||
Option::Some(res) => res.map(Some),
|
||||
Option::None => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CastBytes + Send> Encode<EncodedOption<T>> for Option<T> {
|
||||
fn encode(self) -> EncodedOption<T> {
|
||||
use Option::*;
|
||||
match self {
|
||||
Some(data) => {
|
||||
let mut bytes = data.into_vec();
|
||||
bytes.push(0);
|
||||
EncodedOption(T::from_vec(bytes))
|
||||
}
|
||||
None => EncodedOption(T::from_vec(vec![1])),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CastBytes + Send> Encode<EncodedOption<T>> for StdOption<T> {
|
||||
fn encode(self) -> EncodedOption<T> {
|
||||
Option::from(self).encode()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CastBytes> Decode<Option<T>> for EncodedOption<T> {
|
||||
fn decode(self) -> anyhow::Result<Option<T>> {
|
||||
use Option::*;
|
||||
let mut bytes = self.0.into_vec();
|
||||
let option_byte =
|
||||
bytes.pop().context("OptionWrapper bytes cannot be empty")?;
|
||||
if option_byte == 0 {
|
||||
Ok(Some(T::from_vec(bytes)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<StdOption<T>> for Option<T> {
|
||||
fn from(value: StdOption<T>) -> Self {
|
||||
match value {
|
||||
Some(t) => Self::Some(t),
|
||||
None => Self::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Option<T>> for StdOption<T> {
|
||||
fn from(value: Option<T>) -> Self {
|
||||
match value {
|
||||
Option::Some(t) => Some(t),
|
||||
Option::None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
125
lib/encoding/src/response.rs
Normal file
125
lib/encoding/src/response.rs
Normal file
@@ -0,0 +1,125 @@
|
||||
use anyhow::{Context, Result as AnyhowResult};
|
||||
use bytes::Bytes;
|
||||
use serror::{deserialize_error_bytes, serialize_error_bytes};
|
||||
|
||||
use crate::{CastBytes, Decode, Encode};
|
||||
|
||||
/// Message wrapper to handle Error unwrapping
|
||||
/// anywhere in the en/decoding chain.
|
||||
/// ```markdown
|
||||
/// | -- u8[] -- | ---------- u8 ----------- |
|
||||
/// | <CONTENTS> | 0: Ok, 1: Err, 2: Pending |
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EncodedResponse<T>(T);
|
||||
|
||||
impl_wrapper!(EncodedResponse);
|
||||
|
||||
pub enum Response<T> {
|
||||
Ok(T),
|
||||
Err(anyhow::Error),
|
||||
Pending,
|
||||
}
|
||||
|
||||
impl<T> Response<T> {
|
||||
pub fn into_anyhow(self) -> AnyhowResult<Option<T>> {
|
||||
self.into()
|
||||
}
|
||||
|
||||
pub fn map<R>(self, map: impl FnOnce(T) -> R) -> Response<R> {
|
||||
use Response::*;
|
||||
match self {
|
||||
Ok(t) => Ok(map(t)),
|
||||
Err(e) => Err(e),
|
||||
Pending => Pending,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_encode<B: CastBytes + Send>(self) -> EncodedResponse<B>
|
||||
where
|
||||
T: Encode<B>,
|
||||
{
|
||||
self.map(Encode::encode).encode()
|
||||
}
|
||||
|
||||
pub fn map_decode<D>(self) -> anyhow::Result<Option<D>>
|
||||
where
|
||||
T: CastBytes + Send + Decode<D>,
|
||||
{
|
||||
match self.map(Decode::decode) {
|
||||
Response::Ok(res) => res.map(Some),
|
||||
Response::Err(e) => Err(e),
|
||||
Response::Pending => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CastBytes + Send> Encode<EncodedResponse<T>> for Response<T> {
|
||||
fn encode(self) -> EncodedResponse<T> {
|
||||
use Response::*;
|
||||
let bytes = match self {
|
||||
Ok(data) => {
|
||||
let mut bytes = data.into_vec();
|
||||
bytes.push(0);
|
||||
bytes
|
||||
}
|
||||
Err(e) => {
|
||||
let mut bytes = serialize_error_bytes(&e);
|
||||
bytes.push(1);
|
||||
bytes
|
||||
}
|
||||
Pending => {
|
||||
vec![2]
|
||||
}
|
||||
};
|
||||
EncodedResponse(T::from_vec(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CastBytes + Send> Encode<EncodedResponse<T>>
|
||||
for AnyhowResult<T>
|
||||
{
|
||||
fn encode(self) -> EncodedResponse<T> {
|
||||
Response::from(self).encode()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CastBytes> Encode<EncodedResponse<T>> for &anyhow::Error {
|
||||
fn encode(self) -> EncodedResponse<T> {
|
||||
let mut bytes = serialize_error_bytes(self);
|
||||
bytes.push(1);
|
||||
EncodedResponse::from_vec(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CastBytes> Decode<Option<T>> for EncodedResponse<T> {
|
||||
fn decode(self) -> AnyhowResult<Option<T>> {
|
||||
let mut bytes = self.0.into_vec();
|
||||
let result_byte =
|
||||
bytes.pop().context("ResultWrapper bytes cannot be empty")?;
|
||||
match result_byte {
|
||||
0 => Ok(Some(T::from_vec(bytes))),
|
||||
1 => Err(deserialize_error_bytes(&bytes)),
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<AnyhowResult<T>> for Response<T> {
|
||||
fn from(value: AnyhowResult<T>) -> Self {
|
||||
match value {
|
||||
Ok(t) => Self::Ok(t),
|
||||
Err(e) => Self::Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Response<T>> for AnyhowResult<Option<T>> {
|
||||
fn from(value: Response<T>) -> Self {
|
||||
match value {
|
||||
Response::Ok(t) => Ok(Some(t)),
|
||||
Response::Err(e) => Err(e),
|
||||
Response::Pending => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
use anyhow::{Context, Result as AnyhowResult};
|
||||
use bytes::Bytes;
|
||||
use serror::{deserialize_error_bytes, serialize_error_bytes};
|
||||
|
||||
use crate::{CastBytes, Decode, Encode, impl_wrapper};
|
||||
|
||||
/// Message wrapper to handle Error unwrapping
|
||||
/// anywhere in the en/decoding chain.
|
||||
/// ```markdown
|
||||
/// | -- u8[] -- | ----- u8 ------ |
|
||||
/// | <CONTENTS> | 0: Ok or _: Err |
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EncodedResult<T>(T);
|
||||
|
||||
impl_wrapper!(EncodedResult);
|
||||
|
||||
/// Just anyhow's Result,
|
||||
/// but can implement on it.
|
||||
pub enum Result<T> {
|
||||
Ok(T),
|
||||
Err(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<T> Result<T> {
|
||||
pub fn into_anyhow(self) -> AnyhowResult<T> {
|
||||
self.into()
|
||||
}
|
||||
|
||||
pub fn map<R>(self, map: impl FnOnce(T) -> R) -> Result<R> {
|
||||
use Result::*;
|
||||
match self {
|
||||
Ok(t) => Ok(map(t)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_encode<B: CastBytes + Send>(self) -> EncodedResult<B>
|
||||
where
|
||||
T: Encode<B>,
|
||||
{
|
||||
self.map(Encode::encode).encode()
|
||||
}
|
||||
|
||||
pub fn map_decode<D>(self) -> anyhow::Result<D>
|
||||
where
|
||||
T: CastBytes + Send + Decode<D>,
|
||||
{
|
||||
match self.map(Decode::decode) {
|
||||
Result::Ok(res) => res,
|
||||
Result::Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CastBytes + Send> Encode<EncodedResult<T>> for Result<T> {
|
||||
fn encode(self) -> EncodedResult<T> {
|
||||
use Result::*;
|
||||
let bytes = match self {
|
||||
Ok(data) => {
|
||||
let mut bytes = data.into_vec();
|
||||
bytes.push(0);
|
||||
bytes
|
||||
}
|
||||
Err(e) => {
|
||||
let mut bytes = serialize_error_bytes(&e);
|
||||
bytes.push(1);
|
||||
bytes
|
||||
}
|
||||
};
|
||||
EncodedResult(T::from_vec(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CastBytes + Send> Encode<EncodedResult<T>>
|
||||
for AnyhowResult<T>
|
||||
{
|
||||
fn encode(self) -> EncodedResult<T> {
|
||||
Result::from(self).encode()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CastBytes> Encode<EncodedResult<T>> for &anyhow::Error {
|
||||
fn encode(self) -> EncodedResult<T> {
|
||||
let mut bytes = serialize_error_bytes(self);
|
||||
bytes.push(1);
|
||||
EncodedResult::from_vec(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CastBytes> Decode<T> for EncodedResult<T> {
|
||||
fn decode(self) -> AnyhowResult<T> {
|
||||
let mut bytes = self.0.into_vec();
|
||||
let result_byte =
|
||||
bytes.pop().context("ResultWrapper bytes cannot be empty")?;
|
||||
if result_byte == 0 {
|
||||
Ok(T::from_vec(bytes))
|
||||
} else {
|
||||
Err(deserialize_error_bytes(&bytes))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<AnyhowResult<T>> for Result<T> {
|
||||
fn from(value: AnyhowResult<T>) -> Self {
|
||||
match value {
|
||||
Ok(t) => Self::Ok(t),
|
||||
Err(e) => Self::Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Result<T>> for AnyhowResult<T> {
|
||||
fn from(value: Result<T>) -> Self {
|
||||
match value {
|
||||
Result::Ok(t) => Ok(t),
|
||||
Result::Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,20 +74,3 @@ impl JsonString {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum JsonBytes {
|
||||
Ok(Vec<u8>),
|
||||
Err(serde_json::Error),
|
||||
}
|
||||
|
||||
impl<T> From<T> for JsonBytes
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn from(value: T) -> JsonBytes {
|
||||
match serde_json::to_vec(&value) {
|
||||
Ok(body) => JsonBytes::Ok(body),
|
||||
Err(e) => JsonBytes::Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use anyhow::{Context, anyhow};
|
||||
use encoding::{
|
||||
Encode, EncodedJsonMessage, EncodedResult, JsonMessage,
|
||||
Encode, EncodedJsonMessage, EncodedResponse, JsonMessage,
|
||||
};
|
||||
use futures_util::FutureExt;
|
||||
use periphery_client::transport::{
|
||||
@@ -87,7 +87,7 @@ impl Sender<EncodedTransportMessage> {
|
||||
where
|
||||
&'a T: Send,
|
||||
{
|
||||
let json = JsonMessage(request).encode().into_anyhow()?;
|
||||
let json = JsonMessage(request).encode()?;
|
||||
self.send_message(RequestMessage::new(channel, json)).await
|
||||
}
|
||||
|
||||
@@ -95,16 +95,21 @@ impl Sender<EncodedTransportMessage> {
|
||||
&self,
|
||||
channel: Uuid,
|
||||
) -> anyhow::Result<()> {
|
||||
self.send_message(ResponseMessage::new(channel, None)).await
|
||||
self
|
||||
.send_message(ResponseMessage::new(
|
||||
channel,
|
||||
encoding::Response::Pending.encode(),
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_response(
|
||||
&self,
|
||||
channel: Uuid,
|
||||
response: EncodedResult<EncodedJsonMessage>,
|
||||
response: EncodedResponse<EncodedJsonMessage>,
|
||||
) -> anyhow::Result<()> {
|
||||
self
|
||||
.send_message(ResponseMessage::new(channel, Some(response)))
|
||||
.send_message(ResponseMessage::new(channel, response))
|
||||
.await
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use anyhow::{Context, anyhow};
|
||||
use bytes::Bytes;
|
||||
use encoding::{
|
||||
CastBytes as _, Decode as _, Encode, EncodedJsonMessage,
|
||||
EncodedResult, JsonMessage,
|
||||
EncodedResponse, JsonMessage,
|
||||
};
|
||||
use periphery_client::transport::{
|
||||
EncodedTransportMessage, RequestMessage, ResponseMessage,
|
||||
@@ -120,7 +120,7 @@ pub trait WebsocketSenderExt: WebsocketSender + Send {
|
||||
&'a T: Send,
|
||||
{
|
||||
async move {
|
||||
let json = JsonMessage(request).encode().into_anyhow()?;
|
||||
let json = JsonMessage(request).encode()?;
|
||||
self.send_message(RequestMessage::new(channel, json)).await
|
||||
}
|
||||
}
|
||||
@@ -129,15 +129,18 @@ pub trait WebsocketSenderExt: WebsocketSender + Send {
|
||||
&mut self,
|
||||
channel: Uuid,
|
||||
) -> impl Future<Output = anyhow::Result<()>> + Send {
|
||||
self.send_message(ResponseMessage::new(channel, None))
|
||||
self.send_message(ResponseMessage::new(
|
||||
channel,
|
||||
encoding::Response::Pending.encode(),
|
||||
))
|
||||
}
|
||||
|
||||
fn send_response(
|
||||
&mut self,
|
||||
channel: Uuid,
|
||||
response: EncodedResult<EncodedJsonMessage>,
|
||||
response: EncodedResponse<EncodedJsonMessage>,
|
||||
) -> impl Future<Output = anyhow::Result<()>> + Send {
|
||||
self.send_message(ResponseMessage::new(channel, Some(response)))
|
||||
self.send_message(ResponseMessage::new(channel, response))
|
||||
}
|
||||
|
||||
fn send_terminal(
|
||||
|
||||
Reference in New Issue
Block a user