mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-06-27 19:49:31 +00:00
125 lines
4.3 KiB
Rust
125 lines
4.3 KiB
Rust
use components::EphemeralRegistry;
|
|
use crossbeam_channel::Receiver;
|
|
use libchat::{ChatError, ChatStorage, IdentityProvider, RegistrationService, StorageConfig};
|
|
use storage::ChatStore;
|
|
|
|
use crate::Transport;
|
|
use crate::client::ChatClient;
|
|
use crate::delegate::DelegateSigner;
|
|
use crate::errors::ClientError;
|
|
use crate::event::Event;
|
|
|
|
/// Marker for a builder field that has not been configured. A field left `Unset`
|
|
/// at `build()` is a compile error: `build()` requires every component to have a
|
|
/// concrete type. Use [`ChatClientBuilder::default`] to start from filled-in
|
|
/// defaults instead.
|
|
pub struct Unset;
|
|
|
|
pub struct ChatClientBuilder<I = Unset, T = Unset, R = Unset, S = Unset> {
|
|
ident: I,
|
|
transport: T,
|
|
registration: R,
|
|
storage: S,
|
|
}
|
|
|
|
impl ChatClientBuilder {
|
|
/// An empty builder: every component is `Unset` and must be supplied before
|
|
/// [`build`](ChatClientBuilder::build). For the common case, prefer
|
|
/// [`default`](ChatClientBuilder::default), which pre-fills the components.
|
|
//
|
|
// `Default` is intentionally not implemented: `default()` below is a distinct
|
|
// constructor that returns a *different*, pre-filled builder type, which the
|
|
// `Default` trait (`fn() -> Self`) cannot express.
|
|
#[allow(clippy::new_without_default)]
|
|
pub fn new() -> Self {
|
|
Self {
|
|
ident: Unset,
|
|
transport: Unset,
|
|
registration: Unset,
|
|
storage: Unset,
|
|
}
|
|
}
|
|
|
|
/// A builder pre-filled with the default identity, registration, and storage.
|
|
/// Only the transport is left to set; override any default with the matching
|
|
/// setter. A complete entry point on its own — there is no need to call
|
|
/// [`new`](ChatClientBuilder::new) first.
|
|
#[allow(clippy::should_implement_trait)]
|
|
pub fn default() -> ChatClientBuilder<DelegateSigner, Unset, EphemeralRegistry, ChatStorage> {
|
|
Self::new()
|
|
.ident(DelegateSigner::random())
|
|
.registration(EphemeralRegistry::new())
|
|
.storage(ChatStorage::in_memory())
|
|
}
|
|
}
|
|
|
|
impl<I, T, R, S> ChatClientBuilder<I, T, R, S> {
|
|
pub fn ident<NI>(self, ident: NI) -> ChatClientBuilder<NI, T, R, S> {
|
|
ChatClientBuilder {
|
|
ident,
|
|
transport: self.transport,
|
|
registration: self.registration,
|
|
storage: self.storage,
|
|
}
|
|
}
|
|
|
|
pub fn transport<NT>(self, transport: NT) -> ChatClientBuilder<I, NT, R, S> {
|
|
ChatClientBuilder {
|
|
ident: self.ident,
|
|
transport,
|
|
registration: self.registration,
|
|
storage: self.storage,
|
|
}
|
|
}
|
|
|
|
pub fn registration<NR>(self, registration: NR) -> ChatClientBuilder<I, T, NR, S> {
|
|
ChatClientBuilder {
|
|
ident: self.ident,
|
|
transport: self.transport,
|
|
registration,
|
|
storage: self.storage,
|
|
}
|
|
}
|
|
|
|
pub fn storage<NS>(self, storage: NS) -> ChatClientBuilder<I, T, R, NS> {
|
|
ChatClientBuilder {
|
|
ident: self.ident,
|
|
transport: self.transport,
|
|
registration: self.registration,
|
|
storage,
|
|
}
|
|
}
|
|
|
|
pub fn storage_config(self, config: StorageConfig) -> ChatClientBuilder<I, T, R, ChatStorage> {
|
|
let storage = ChatStorage::new(config)
|
|
.map_err(ChatError::from)
|
|
.expect("Storage config file should be valid");
|
|
|
|
ChatClientBuilder {
|
|
ident: self.ident,
|
|
transport: self.transport,
|
|
registration: self.registration,
|
|
storage,
|
|
}
|
|
}
|
|
}
|
|
|
|
type Built<I, T, R, S> = Result<(ChatClient<I, T, R, S>, Receiver<Event>), ClientError>;
|
|
|
|
/// `build()` exists only once every component has a concrete type. Any field
|
|
/// still `Unset` (always at least the transport, which has no default) fails the
|
|
/// bounds below, so an incomplete builder is a compile error rather than a
|
|
/// runtime one. Start from [`default`](ChatClientBuilder::default) to fill the
|
|
/// identity/registration/storage slots, then set the transport.
|
|
impl<I, T, R, S> ChatClientBuilder<I, T, R, S>
|
|
where
|
|
I: IdentityProvider + Send + 'static,
|
|
T: Transport + Send + 'static,
|
|
R: RegistrationService + Send + 'static,
|
|
S: ChatStore + Send + 'static,
|
|
{
|
|
pub fn build(self) -> Built<I, T, R, S> {
|
|
ChatClient::new(self.ident, self.transport, self.registration, self.storage)
|
|
}
|
|
}
|