use std::collections::HashMap;
use ruststream::RawMessage;
use ruststream::testing::Coordinator;
use sea_streamer_types::{
Buffer as _, Message as _, MessageHeader, SeqNo, ShardId, SharedMessage, StreamKey, Timestamp,
};
use tokio::sync::mpsc;
use crate::wire;
const SHARD: ShardId = ShardId::new(0);
pub(crate) enum Entry {
Message(SharedMessage),
End,
}
pub(crate) type EntrySender = mpsc::UnboundedSender<Entry>;
pub(crate) type EntryReceiver = mpsc::UnboundedReceiver<Entry>;
pub(crate) type SubscriptionId = u64;
struct Subscription {
key: String,
sender: EntrySender,
}
#[derive(Default)]
pub(crate) struct Registry {
next_id: SubscriptionId,
subscriptions: HashMap<SubscriptionId, Subscription>,
}
impl Registry {
pub(crate) fn open(&mut self, key: &str) -> (SubscriptionId, EntrySender, EntryReceiver) {
let (sender, receiver) = mpsc::unbounded_channel();
let id = self.next_id;
self.next_id += 1;
self.subscriptions.insert(
id,
Subscription {
key: key.to_owned(),
sender: sender.clone(),
},
);
(id, sender, receiver)
}
pub(crate) fn close(&mut self, id: SubscriptionId) -> bool {
self.subscriptions.remove(&id).is_some()
}
pub(crate) fn fan_out(
&self,
key: &str,
message: &SharedMessage,
coordinator: Option<&Coordinator>,
) {
for sub in self.subscriptions.values() {
if sub.key == key
&& sub.sender.send(Entry::Message(message.clone())).is_ok()
&& let Some(coordinator) = coordinator
{
coordinator.enqueued();
}
}
}
pub(crate) fn end_all(&self) {
for sub in self.subscriptions.values() {
let _ = sub.sender.send(Entry::End);
}
}
}
pub(crate) struct Release(Coordinator);
impl Release {
pub(crate) fn of(coordinator: Option<&Coordinator>) -> Option<Self> {
coordinator.cloned().map(Self)
}
}
impl Drop for Release {
fn drop(&mut self) {
self.0.consumed();
}
}
pub(crate) fn stamp(key: StreamKey, sequence: SeqNo, bytes: Vec<u8>) -> SharedMessage {
let length = bytes.len();
SharedMessage::new(
MessageHeader::new(key, SHARD, sequence, Timestamp::now_utc()),
bytes,
0,
length,
)
}
pub(crate) fn raw(message: &SharedMessage) -> RawMessage {
let (headers, payload) = wire::decode(message.message().as_bytes());
RawMessage::new(message.header().stream_key().name(), payload).with_headers(headers)
}
pub(crate) fn release_one(coordinator: Option<&Coordinator>) {
if let Some(coordinator) = coordinator {
coordinator.consumed();
}
}
pub(crate) fn release_queued(receiver: &mut EntryReceiver, coordinator: Option<&Coordinator>) {
while let Ok(entry) = receiver.try_recv() {
if let Entry::Message(_) = entry {
release_one(coordinator);
}
}
}