Registry crate implementation
This commit is contained in:
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use rdkafka::{
|
||||
ClientConfig, ClientContext, TopicPartitionList,
|
||||
consumer::{BaseConsumer, ConsumerContext, Rebalance, StreamConsumer},
|
||||
error::KafkaResult,
|
||||
producer::FutureProducer,
|
||||
};
|
||||
use std::{fmt::Debug, time::Duration};
|
||||
use utils::config::{Config, utils::AsKey};
|
||||
|
||||
pub mod pubsub;
|
||||
|
||||
pub(super) type LoggingConsumer = StreamConsumer<CustomContext>;
|
||||
|
||||
pub struct KafkaPubSub {
|
||||
consumer_builder: ClientConfig,
|
||||
producer: FutureProducer,
|
||||
}
|
||||
|
||||
impl KafkaPubSub {
|
||||
pub async fn open(config: &mut Config, prefix: impl AsKey) -> Option<Self> {
|
||||
let prefix = prefix.as_key();
|
||||
let brokers = config
|
||||
.values((&prefix, "brokers"))
|
||||
.map(|(_, v)| v.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
if brokers.is_empty() {
|
||||
config.new_build_error((&prefix, "brokers"), "No Kafka brokers specified");
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut consumer_builder = ClientConfig::new();
|
||||
|
||||
consumer_builder
|
||||
.set(
|
||||
"group.id",
|
||||
config.value_require_non_empty((&prefix, "group-id"))?,
|
||||
)
|
||||
.set(
|
||||
"bootstrap.servers",
|
||||
config.value_require_non_empty((&prefix, "brokers"))?,
|
||||
)
|
||||
.set("enable.partition.eof", "false")
|
||||
.set(
|
||||
"session.timeout.ms",
|
||||
config
|
||||
.property_or_default((&prefix, "timeout.session"), "5s")
|
||||
.unwrap_or(Duration::from_secs(5))
|
||||
.as_millis()
|
||||
.to_string(),
|
||||
)
|
||||
.set("enable.auto.commit", "true");
|
||||
|
||||
let producer = ClientConfig::new()
|
||||
.set(
|
||||
"bootstrap.servers",
|
||||
config.value_require_non_empty((&prefix, "brokers"))?,
|
||||
)
|
||||
.set(
|
||||
"message.timeout.ms",
|
||||
config
|
||||
.property_or_default((&prefix, "timeout.message"), "5s")
|
||||
.unwrap_or(Duration::from_secs(5))
|
||||
.as_millis()
|
||||
.to_string(),
|
||||
)
|
||||
.create()
|
||||
.map_err(|err| {
|
||||
config.new_build_error(
|
||||
(&prefix, "config"),
|
||||
format!("Failed to create Kafka producer: {}", err),
|
||||
);
|
||||
})
|
||||
.ok()?;
|
||||
|
||||
KafkaPubSub {
|
||||
consumer_builder,
|
||||
producer,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for KafkaPubSub {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("KafkaPubSub").finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct CustomContext;
|
||||
|
||||
impl ClientContext for CustomContext {}
|
||||
|
||||
impl ConsumerContext for CustomContext {
|
||||
fn pre_rebalance(&self, _: &BaseConsumer<Self>, _: &Rebalance) {}
|
||||
|
||||
fn post_rebalance(&self, _: &BaseConsumer<Self>, _: &Rebalance) {}
|
||||
|
||||
fn commit_callback(&self, _: KafkaResult<()>, _: &TopicPartitionList) {}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use super::{CustomContext, KafkaPubSub, LoggingConsumer};
|
||||
use crate::dispatch::pubsub::{Msg, PubSubStream};
|
||||
use rdkafka::{
|
||||
Message,
|
||||
consumer::{CommitMode, Consumer, StreamConsumer},
|
||||
producer::FutureRecord,
|
||||
};
|
||||
use trc::{ClusterEvent, Error, EventType};
|
||||
|
||||
pub struct KafkaPubSubStream {
|
||||
subs: LoggingConsumer,
|
||||
}
|
||||
|
||||
impl KafkaPubSub {
|
||||
pub async fn publish(&self, topic: &'static str, message: Vec<u8>) -> trc::Result<()> {
|
||||
self.producer
|
||||
.send(
|
||||
FutureRecord::<(), [u8]>::to(topic).payload(message.as_slice()),
|
||||
Duration::from_secs(0),
|
||||
)
|
||||
.await
|
||||
.map(|_| ())
|
||||
.map_err(|(err, _)| {
|
||||
Error::new(EventType::Cluster(ClusterEvent::PublisherError)).reason(err)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn subscribe(&self, topic: &'static str) -> trc::Result<PubSubStream> {
|
||||
let subs: StreamConsumer<CustomContext> = self
|
||||
.consumer_builder
|
||||
.create_with_context(CustomContext)
|
||||
.map_err(|err| {
|
||||
Error::new(EventType::Cluster(ClusterEvent::SubscriberError)).reason(err)
|
||||
})?;
|
||||
subs.subscribe(&[topic]).map_err(|err| {
|
||||
Error::new(EventType::Cluster(ClusterEvent::SubscriberError)).reason(err)
|
||||
})?;
|
||||
|
||||
Ok(PubSubStream::Kafka(KafkaPubSubStream { subs }))
|
||||
}
|
||||
}
|
||||
|
||||
impl KafkaPubSubStream {
|
||||
pub async fn next(&mut self) -> Option<Msg> {
|
||||
let msg = self.subs.recv().await.ok()?;
|
||||
let _ = self.subs.commit_message(&msg, CommitMode::Async);
|
||||
Msg::Kafka(msg.payload().unwrap_or_default().to_vec()).into()
|
||||
}
|
||||
}
|
||||
@@ -11,14 +11,10 @@ pub mod elastic;
|
||||
pub mod foundationdb;
|
||||
pub mod fs;
|
||||
pub mod http;
|
||||
#[cfg(feature = "kafka")]
|
||||
pub mod kafka;
|
||||
pub mod meili;
|
||||
pub mod memory;
|
||||
#[cfg(feature = "mysql")]
|
||||
pub mod mysql;
|
||||
#[cfg(feature = "nats")]
|
||||
pub mod nats;
|
||||
#[cfg(feature = "postgres")]
|
||||
pub mod postgres;
|
||||
#[cfg(feature = "redis")]
|
||||
@@ -29,8 +25,6 @@ pub mod rocksdb;
|
||||
pub mod s3;
|
||||
#[cfg(feature = "sqlite")]
|
||||
pub mod sqlite;
|
||||
#[cfg(feature = "zenoh")]
|
||||
pub mod zenoh;
|
||||
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use async_nats::Client;
|
||||
use utils::config::{Config, utils::AsKey};
|
||||
|
||||
pub mod pubsub;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NatsPubSub {
|
||||
client: Client,
|
||||
}
|
||||
|
||||
impl NatsPubSub {
|
||||
pub async fn open(config: &mut Config, prefix: impl AsKey) -> Option<Self> {
|
||||
let prefix = prefix.as_key();
|
||||
let urls = config
|
||||
.values((&prefix, "address"))
|
||||
.map(|(_, v)| v.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
if urls.is_empty() {
|
||||
config.new_build_error((&prefix, "address"), "No Nats addresses specified");
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut opts = async_nats::ConnectOptions::new()
|
||||
.max_reconnects(
|
||||
config
|
||||
.property_or_default::<Option<usize>>((&prefix, "max-reconnects"), "false")
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.connection_timeout(
|
||||
config
|
||||
.property_or_default((&prefix, "timeout.connection"), "5s")
|
||||
.unwrap_or_else(|| Duration::from_secs(5)),
|
||||
)
|
||||
.request_timeout(
|
||||
config
|
||||
.property_or_default::<Option<Duration>>((&prefix, "timeout.request"), "10s")
|
||||
.unwrap_or_else(|| Some(Duration::from_secs(10))),
|
||||
)
|
||||
.ping_interval(
|
||||
config
|
||||
.property_or_default((&prefix, "ping-interval"), "60s")
|
||||
.unwrap_or_else(|| Duration::from_secs(5)),
|
||||
)
|
||||
.client_capacity(
|
||||
config
|
||||
.property_or_default((&prefix, "capacity.client"), "2048")
|
||||
.unwrap_or(2048),
|
||||
)
|
||||
.subscription_capacity(
|
||||
config
|
||||
.property_or_default((&prefix, "capacity.subscription"), "65536")
|
||||
.unwrap_or(65536),
|
||||
)
|
||||
.read_buffer_capacity(
|
||||
config
|
||||
.property_or_default((&prefix, "capacity.read-buffer"), "65535")
|
||||
.unwrap_or(65535),
|
||||
)
|
||||
.require_tls(
|
||||
config
|
||||
.property_or_default((&prefix, "tls.enable"), "false")
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
|
||||
if config
|
||||
.property_or_default((&prefix, "no-echo"), "true")
|
||||
.unwrap_or(true)
|
||||
{
|
||||
opts = opts.no_echo();
|
||||
}
|
||||
|
||||
if let (Some(user), Some(pass)) = (
|
||||
config.value((&prefix, "user")),
|
||||
config.value((&prefix, "password")),
|
||||
) {
|
||||
opts = opts.user_and_password(user.to_string(), pass.to_string());
|
||||
} else if let Some(credentials) = config.value((&prefix, "credentials")) {
|
||||
opts = opts
|
||||
.credentials(credentials)
|
||||
.map_err(|err| {
|
||||
config.new_build_error(
|
||||
(&prefix, "credentials"),
|
||||
format!("Failed to parse Nats credentials: {}", err),
|
||||
);
|
||||
})
|
||||
.ok()?;
|
||||
}
|
||||
|
||||
async_nats::connect_with_options(urls, opts)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
config.new_build_error(
|
||||
(&prefix, "urls"),
|
||||
format!("Failed to connect to Nats: {}", err),
|
||||
);
|
||||
})
|
||||
.map(|client| NatsPubSub { client })
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use super::NatsPubSub;
|
||||
use crate::dispatch::pubsub::{Msg, PubSubStream};
|
||||
use futures::StreamExt;
|
||||
use trc::{ClusterEvent, Error, EventType};
|
||||
|
||||
pub struct NatsPubSubStream {
|
||||
subs: async_nats::Subscriber,
|
||||
}
|
||||
|
||||
impl NatsPubSub {
|
||||
pub async fn publish(&self, topic: &'static str, message: Vec<u8>) -> trc::Result<()> {
|
||||
self.client
|
||||
.publish(topic, message.into())
|
||||
.await
|
||||
.map_err(|err| Error::new(EventType::Cluster(ClusterEvent::PublisherError)).reason(err))
|
||||
}
|
||||
|
||||
pub async fn subscribe(&self, topic: &'static str) -> trc::Result<PubSubStream> {
|
||||
self.client
|
||||
.subscribe(topic)
|
||||
.await
|
||||
.map(|subs| PubSubStream::Nats(NatsPubSubStream { subs }))
|
||||
.map_err(|err| {
|
||||
Error::new(EventType::Cluster(ClusterEvent::SubscriberError)).reason(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl NatsPubSubStream {
|
||||
pub async fn next(&mut self) -> Option<Msg> {
|
||||
self.subs.next().await.map(Msg::Nats)
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,6 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::{fmt::Display, time::Duration};
|
||||
|
||||
use deadpool::{
|
||||
Runtime,
|
||||
managed::{Manager, Pool},
|
||||
@@ -14,28 +12,28 @@ use redis::{
|
||||
Client, ProtocolVersion,
|
||||
cluster::{ClusterClient, ClusterClientBuilder},
|
||||
};
|
||||
use std::{fmt::Display, time::Duration};
|
||||
use utils::config::{Config, utils::AsKey};
|
||||
|
||||
pub mod lookup;
|
||||
pub mod pool;
|
||||
pub mod pubsub;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RedisStore {
|
||||
pool: RedisPool,
|
||||
pub pool: RedisPool,
|
||||
}
|
||||
|
||||
struct RedisConnectionManager {
|
||||
client: Client,
|
||||
pub struct RedisConnectionManager {
|
||||
pub client: Client,
|
||||
timeout: Duration,
|
||||
}
|
||||
|
||||
struct RedisClusterConnectionManager {
|
||||
client: ClusterClient,
|
||||
pub struct RedisClusterConnectionManager {
|
||||
pub client: ClusterClient,
|
||||
timeout: Duration,
|
||||
}
|
||||
|
||||
enum RedisPool {
|
||||
pub enum RedisPool {
|
||||
Single(Pool<RedisConnectionManager>),
|
||||
Cluster(Pool<RedisClusterConnectionManager>),
|
||||
}
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use super::{RedisPool, RedisStore, into_error};
|
||||
use crate::dispatch::pubsub::{Msg, PubSubStream};
|
||||
use futures::StreamExt;
|
||||
use redis::{AsyncCommands, PushInfo, cluster::ClusterConfig, cluster_async::ClusterConnection};
|
||||
use tokio::sync::mpsc::UnboundedReceiver;
|
||||
|
||||
pub struct RedisPubSubStream {
|
||||
stream: redis::aio::PubSubStream,
|
||||
}
|
||||
|
||||
pub struct RedisClusterPubSubStream {
|
||||
_conn: ClusterConnection,
|
||||
rx: UnboundedReceiver<PushInfo>,
|
||||
}
|
||||
|
||||
impl RedisStore {
|
||||
pub async fn publish(&self, topic: &'static str, message: Vec<u8>) -> trc::Result<()> {
|
||||
match &self.pool {
|
||||
RedisPool::Single(pool) => pool
|
||||
.get()
|
||||
.await
|
||||
.map_err(into_error)?
|
||||
.as_mut()
|
||||
.publish(topic, message)
|
||||
.await
|
||||
.map_err(into_error),
|
||||
RedisPool::Cluster(pool) => pool
|
||||
.get()
|
||||
.await
|
||||
.map_err(into_error)?
|
||||
.as_mut()
|
||||
.publish(topic, message)
|
||||
.await
|
||||
.map_err(into_error),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn subscribe(&self, topic: &'static str) -> trc::Result<PubSubStream> {
|
||||
match &self.pool {
|
||||
RedisPool::Single(pool) => {
|
||||
let mut pubsub = pool
|
||||
.manager()
|
||||
.client
|
||||
.get_async_pubsub()
|
||||
.await
|
||||
.map_err(into_error)?;
|
||||
pubsub.subscribe(topic).await.map_err(into_error)?;
|
||||
|
||||
Ok(PubSubStream::Redis(RedisPubSubStream {
|
||||
stream: pubsub.into_on_message(),
|
||||
}))
|
||||
}
|
||||
RedisPool::Cluster(pool) => {
|
||||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
|
||||
let mut _conn = pool
|
||||
.manager()
|
||||
.client
|
||||
.get_async_connection_with_config(ClusterConfig::default().set_push_sender(tx))
|
||||
.await
|
||||
.map_err(into_error)?;
|
||||
|
||||
_conn.subscribe(topic).await.map_err(into_error)?;
|
||||
|
||||
Ok(PubSubStream::RedisCluster(RedisClusterPubSubStream {
|
||||
_conn,
|
||||
rx,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RedisPubSubStream {
|
||||
pub async fn next(&mut self) -> Option<Msg> {
|
||||
self.stream.next().await.map(Msg::Redis)
|
||||
}
|
||||
}
|
||||
|
||||
impl RedisClusterPubSubStream {
|
||||
pub async fn next(&mut self) -> Option<Msg> {
|
||||
loop {
|
||||
if let Some(msg) = redis::Msg::from_push_info(self.rx.recv().await?) {
|
||||
return Some(Msg::Redis(msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use utils::config::{Config, utils::AsKey};
|
||||
pub mod pubsub;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ZenohPubSub {
|
||||
session: zenoh::Session,
|
||||
}
|
||||
|
||||
impl ZenohPubSub {
|
||||
pub async fn open(config: &mut Config, prefix: impl AsKey) -> Option<Self> {
|
||||
let prefix = prefix.as_key();
|
||||
let zenoh_config =
|
||||
zenoh::Config::from_json5(config.value_require_non_empty((&prefix, "config"))?)
|
||||
.map_err(|err| {
|
||||
config.new_build_error(
|
||||
(&prefix, "config"),
|
||||
format!("Invalid zenoh config: {}", err),
|
||||
);
|
||||
})
|
||||
.ok()?;
|
||||
zenoh::open(zenoh_config)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
config.new_build_error(
|
||||
(&prefix, "config"),
|
||||
format!("Failed to create zenoh session: {}", err),
|
||||
);
|
||||
})
|
||||
.map(|session| ZenohPubSub { session })
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use super::ZenohPubSub;
|
||||
use crate::dispatch::pubsub::{Msg, PubSubStream};
|
||||
use trc::{ClusterEvent, Error, EventType};
|
||||
|
||||
pub struct ZenohPubSubStream {
|
||||
subs: zenoh::pubsub::Subscriber<zenoh::handlers::FifoChannelHandler<zenoh::sample::Sample>>,
|
||||
}
|
||||
|
||||
impl ZenohPubSub {
|
||||
pub async fn publish(&self, topic: &'static str, message: Vec<u8>) -> trc::Result<()> {
|
||||
self.session
|
||||
.declare_publisher(topic)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
Error::new(EventType::Cluster(ClusterEvent::PublisherError)).reason(err)
|
||||
})?
|
||||
.put(message)
|
||||
.await
|
||||
.map_err(|err| Error::new(EventType::Cluster(ClusterEvent::PublisherError)).reason(err))
|
||||
}
|
||||
|
||||
pub async fn subscribe(&self, topic: &'static str) -> trc::Result<PubSubStream> {
|
||||
self.session
|
||||
.declare_subscriber(topic)
|
||||
.await
|
||||
.map(|subs| PubSubStream::Zenoh(ZenohPubSubStream { subs }))
|
||||
.map_err(|err| {
|
||||
Error::new(EventType::Cluster(ClusterEvent::SubscriberError)).reason(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ZenohPubSubStream {
|
||||
pub async fn next(&mut self) -> Option<Msg> {
|
||||
self.subs
|
||||
.recv_async()
|
||||
.await
|
||||
.map(|sample| Msg::Zenoh(sample.payload().to_bytes().into_owned()))
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
@@ -227,11 +227,11 @@ impl Stores {
|
||||
{
|
||||
self.in_memory_stores
|
||||
.insert(store_id.clone(), InMemoryStore::Redis(db.clone()));
|
||||
self.pubsub_stores
|
||||
.insert(store_id, crate::PubSubStore::Redis(db));
|
||||
//self.pubsub_stores
|
||||
// .insert(store_id, crate::PubSubStore::Redis(db));
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "nats")]
|
||||
/*#[cfg(feature = "nats")]
|
||||
"nats" => {
|
||||
if let Some(db) = crate::backend::nats::NatsPubSub::open(config, prefix)
|
||||
.await
|
||||
@@ -260,7 +260,7 @@ impl Stores {
|
||||
self.pubsub_stores
|
||||
.insert(store_id, crate::PubSubStore::Kafka(db));
|
||||
}
|
||||
}
|
||||
}*/
|
||||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
@@ -4,13 +4,12 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use roaring::RoaringBitmap;
|
||||
|
||||
use crate::Store;
|
||||
use roaring::RoaringBitmap;
|
||||
|
||||
pub mod blob;
|
||||
pub mod lookup;
|
||||
pub mod pubsub;
|
||||
pub mod registry;
|
||||
pub mod search;
|
||||
pub mod store;
|
||||
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::PubSubStore;
|
||||
|
||||
pub enum PubSubStream {
|
||||
#[cfg(feature = "redis")]
|
||||
Redis(crate::backend::redis::pubsub::RedisPubSubStream),
|
||||
#[cfg(feature = "redis")]
|
||||
RedisCluster(crate::backend::redis::pubsub::RedisClusterPubSubStream),
|
||||
#[cfg(feature = "nats")]
|
||||
Nats(crate::backend::nats::pubsub::NatsPubSubStream),
|
||||
#[cfg(feature = "zenoh")]
|
||||
Zenoh(crate::backend::zenoh::pubsub::ZenohPubSubStream),
|
||||
#[cfg(feature = "kafka")]
|
||||
Kafka(crate::backend::kafka::pubsub::KafkaPubSubStream),
|
||||
#[cfg(not(any(feature = "redis", feature = "nats")))]
|
||||
Unimplemented,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
#[cfg(feature = "redis")]
|
||||
Redis(redis::Msg),
|
||||
#[cfg(feature = "nats")]
|
||||
Nats(async_nats::Message),
|
||||
#[cfg(feature = "zenoh")]
|
||||
Zenoh(Vec<u8>),
|
||||
#[cfg(feature = "kafka")]
|
||||
Kafka(Vec<u8>),
|
||||
#[cfg(not(any(feature = "redis", feature = "nats")))]
|
||||
Unimplemented,
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
impl PubSubStore {
|
||||
pub async fn publish(&self, topic: &'static str, message: Vec<u8>) -> trc::Result<()> {
|
||||
match self {
|
||||
#[cfg(feature = "redis")]
|
||||
PubSubStore::Redis(store) => store.publish(topic, message).await,
|
||||
#[cfg(feature = "nats")]
|
||||
PubSubStore::Nats(store) => store.publish(topic, message).await,
|
||||
#[cfg(feature = "zenoh")]
|
||||
PubSubStore::Zenoh(store) => store.publish(topic, message).await,
|
||||
#[cfg(feature = "kafka")]
|
||||
PubSubStore::Kafka(store) => store.publish(topic, message).await,
|
||||
PubSubStore::None => Err(trc::StoreEvent::NotSupported.into_err()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn subscribe(&self, topic: &'static str) -> trc::Result<PubSubStream> {
|
||||
match self {
|
||||
#[cfg(feature = "redis")]
|
||||
PubSubStore::Redis(store) => store.subscribe(topic).await,
|
||||
#[cfg(feature = "nats")]
|
||||
PubSubStore::Nats(store) => store.subscribe(topic).await,
|
||||
#[cfg(feature = "zenoh")]
|
||||
PubSubStore::Zenoh(store) => store.subscribe(topic).await,
|
||||
#[cfg(feature = "kafka")]
|
||||
PubSubStore::Kafka(store) => store.subscribe(topic).await,
|
||||
PubSubStore::None => Err(trc::StoreEvent::NotSupported.into_err()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_none(&self) -> bool {
|
||||
matches!(self, PubSubStore::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl PubSubStream {
|
||||
pub async fn next(&mut self) -> Option<Msg> {
|
||||
match self {
|
||||
#[cfg(feature = "redis")]
|
||||
PubSubStream::Redis(stream) => stream.next().await,
|
||||
#[cfg(feature = "redis")]
|
||||
PubSubStream::RedisCluster(stream) => stream.next().await,
|
||||
#[cfg(feature = "nats")]
|
||||
PubSubStream::Nats(stream) => stream.next().await,
|
||||
#[cfg(feature = "zenoh")]
|
||||
PubSubStream::Zenoh(stream) => stream.next().await,
|
||||
#[cfg(feature = "kafka")]
|
||||
PubSubStream::Kafka(stream) => stream.next().await,
|
||||
#[cfg(not(any(feature = "redis", feature = "nats")))]
|
||||
PubSubStream::Unimplemented => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Msg {
|
||||
pub fn payload(&self) -> &[u8] {
|
||||
match self {
|
||||
#[cfg(feature = "redis")]
|
||||
Msg::Redis(msg) => msg.get_payload_bytes(),
|
||||
#[cfg(feature = "nats")]
|
||||
Msg::Nats(msg) => msg.payload.as_ref(),
|
||||
#[cfg(feature = "zenoh")]
|
||||
Msg::Zenoh(msg) => msg.as_slice(),
|
||||
#[cfg(feature = "kafka")]
|
||||
Msg::Kafka(msg) => msg.as_slice(),
|
||||
#[cfg(not(any(feature = "redis", feature = "nats")))]
|
||||
Msg::Unimplemented => &[],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn topic(&self) -> &str {
|
||||
match self {
|
||||
#[cfg(feature = "redis")]
|
||||
Msg::Redis(msg) => msg.get_channel_name(),
|
||||
#[cfg(feature = "nats")]
|
||||
Msg::Nats(msg) => msg.subject.as_str(),
|
||||
#[cfg(feature = "zenoh")]
|
||||
Msg::Zenoh(_) => "",
|
||||
#[cfg(feature = "kafka")]
|
||||
Msg::Kafka(_) => "",
|
||||
#[cfg(not(any(feature = "redis", feature = "nats")))]
|
||||
Msg::Unimplemented => "",
|
||||
}
|
||||
}
|
||||
}
|
||||
23
crates/store/src/dispatch/registry.rs
Normal file
23
crates/store/src/dispatch/registry.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use registry::{schema::prelude::Registry, types::id::Id};
|
||||
|
||||
use crate::RegistryStore;
|
||||
|
||||
impl RegistryStore {
|
||||
pub async fn get(&self, id: Id) -> trc::Result<Option<Registry>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub async fn get_or_default(&self, id: Id) -> trc::Result<Registry> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub async fn delete(&self, id: Id) -> trc::Result<()> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ pub mod backend;
|
||||
pub mod config;
|
||||
pub mod dispatch;
|
||||
pub mod query;
|
||||
pub mod registry;
|
||||
pub mod search;
|
||||
pub mod write;
|
||||
|
||||
@@ -21,7 +22,7 @@ pub use xxhash_rust;
|
||||
|
||||
use ahash::AHashMap;
|
||||
use backend::{fs::FsStore, http::HttpStore, memory::StaticMemoryStore};
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
use std::{borrow::Cow, path::PathBuf, sync::Arc};
|
||||
use utils::config::cron::SimpleCron;
|
||||
use write::ValueClass;
|
||||
|
||||
@@ -129,7 +130,6 @@ pub struct Stores {
|
||||
pub blob_stores: AHashMap<String, BlobStore>,
|
||||
pub search_stores: AHashMap<String, SearchStore>,
|
||||
pub in_memory_stores: AHashMap<String, InMemoryStore>,
|
||||
pub pubsub_stores: AHashMap<String, PubSubStore>,
|
||||
pub purge_schedules: Vec<PurgeSchedule>,
|
||||
}
|
||||
|
||||
@@ -205,18 +205,10 @@ pub enum InMemoryStore {
|
||||
// SPDX-SnippetEnd
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub enum PubSubStore {
|
||||
#[cfg(feature = "redis")]
|
||||
Redis(Arc<backend::redis::RedisStore>),
|
||||
#[cfg(feature = "nats")]
|
||||
Nats(Arc<backend::nats::NatsPubSub>),
|
||||
#[cfg(feature = "zenoh")]
|
||||
Zenoh(Arc<backend::zenoh::ZenohPubSub>),
|
||||
#[cfg(feature = "kafka")]
|
||||
Kafka(Arc<backend::kafka::KafkaPubSub>),
|
||||
#[default]
|
||||
None,
|
||||
#[derive(Clone)]
|
||||
pub enum RegistryStore {
|
||||
Remote(Store),
|
||||
Local(PathBuf),
|
||||
}
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
|
||||
5
crates/store/src/registry/mod.rs
Normal file
5
crates/store/src/registry/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
@@ -278,6 +278,20 @@ pub enum DirectoryClass {
|
||||
UsedQuota(u32),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
|
||||
pub enum RegistryClass {
|
||||
Item(u64),
|
||||
Relation {
|
||||
from: u64,
|
||||
to: u64,
|
||||
},
|
||||
Index {
|
||||
index_id: u16,
|
||||
item_id: u64,
|
||||
key: Vec<u8>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
|
||||
pub enum QueueClass {
|
||||
Message(u64),
|
||||
|
||||
Reference in New Issue
Block a user