use crate::ack::{AckHandle, AckType};
use crate::binary::AttachmentsBuilder;
use crate::client::Emit;
use crate::error::{EventError, PayloadError};
use crate::marker::{AckMarker, BinaryMarker, HasAck, HasBinary, NoAck, NoBinary};
use crate::payload::{DeserializePayload, SerializePayload, event_from_json, event_to_json};
use bytes::Bytes;
use sioc_socket::packet::{Directive, DynEvent};
use tokio::sync::oneshot;
pub trait EventType: Sized {
const NAME: &'static str;
type Ack: AckMarker;
type Binary: BinaryMarker;
}
pub struct Event<E>
where
E: EventType,
{
pub payload: E,
pub id: <E::Ack as AckMarker>::Id,
pub attachments: <E::Binary as BinaryMarker>::Attachments,
}
impl<E> std::fmt::Debug for Event<E>
where
E: std::fmt::Debug + EventType,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut map = f.debug_map();
map.entry(&"payload", &self.payload);
E::Ack::format(&self.id, &mut map);
E::Binary::format(&self.attachments, &mut map);
map.finish()
}
}
impl<E> TryFrom<DynEvent> for Event<E>
where
E: EventType + DeserializePayload,
{
type Error = EventError;
fn try_from(value: DynEvent) -> Result<Self, EventError> {
let payload = event_from_json(&value.payload)?;
let id = E::Ack::parse(value.id)?;
let attachments = E::Binary::parse(value.attachments)?;
Ok(Self {
payload,
id,
attachments,
})
}
}
pub trait EventHandler: Sized {
type Payload: EventType;
fn handle(
payload: Self::Payload,
id: Option<u64>,
attachments: Option<Vec<Bytes>>,
) -> Result<Self, EventError>;
}
impl<E> EventHandler for Event<E>
where
E: EventType + DeserializePayload,
{
type Payload = E;
fn handle(
payload: Self::Payload,
id: Option<u64>,
attachments: Option<Vec<Bytes>>,
) -> Result<Self, EventError> {
let id = E::Ack::parse(id)?;
let attachments = E::Binary::parse(attachments)?;
Ok(Self {
payload,
id,
attachments,
})
}
}
impl<E> Emit<NoAck, NoBinary> for E
where
E: EventType<Ack = NoAck, Binary = NoBinary> + SerializePayload,
{
type Output = ();
fn prepare(self) -> Result<(Directive, ()), PayloadError> {
let payload = event_to_json(&self)?;
Ok((
Directive::Event {
payload: payload.into(),
tx: None,
attachments: None,
},
(),
))
}
}
impl<E, A> Emit<HasAck<A>, NoBinary> for E
where
E: EventType<Ack = HasAck<A>, Binary = NoBinary> + SerializePayload,
A: AckType,
{
type Output = AckHandle<A>;
fn prepare(self) -> Result<(Directive, AckHandle<A>), PayloadError> {
let (tx, rx) = oneshot::channel();
let payload = event_to_json(&self)?.into();
Ok((
Directive::Event {
payload,
tx: Some(tx),
attachments: None,
},
AckHandle::new(rx),
))
}
}
impl<F, E> Emit<NoAck, HasBinary> for F
where
F: FnOnce(&mut AttachmentsBuilder) -> E,
E: EventType<Ack = NoAck, Binary = HasBinary> + SerializePayload,
{
type Output = ();
fn prepare(self) -> Result<(Directive, ()), PayloadError> {
let mut builder = AttachmentsBuilder::new();
let payload = event_to_json(&self(&mut builder))?.into();
Ok((
Directive::Event {
payload,
tx: None,
attachments: Some(builder.finish()),
},
(),
))
}
}
impl<F, E, A> Emit<HasAck<A>, HasBinary> for F
where
F: FnOnce(&mut AttachmentsBuilder) -> E,
E: EventType<Ack = HasAck<A>, Binary = HasBinary> + SerializePayload,
A: AckType,
{
type Output = AckHandle<A>;
fn prepare(self) -> Result<(Directive, AckHandle<A>), PayloadError> {
let (tx, rx) = oneshot::channel();
let mut builder = AttachmentsBuilder::new();
let payload = event_to_json(&self(&mut builder))?.into();
Ok((
Directive::Event {
payload,
tx: Some(tx),
attachments: Some(builder.finish()),
},
AckHandle::new(rx),
))
}
}