rifts/lib.rs
1#![allow(rustdoc::broken_intra_doc_links, rustdoc::private_intra_doc_links)]
2//! # Rifts — Rift Realtime Protocol / 1.0 Server Implementation
3//!
4//! This crate implements the server-side of the [Rift Realtime Protocol v1.0][spec],
5//! providing an embeddable, high-performance real-time pub/sub engine.
6//!
7//! ## Core Concepts
8//!
9//! - **Broker** — the message routing core responsible for publishing,
10//! subscribing, fan-out delivery, and replay. Ships with
11//! [`InMemoryBroker`] (in-process, all storage in memory).
12//! - **Frame / Message** — a [`Frame`] is the wire-level transport unit
13//! (JSON or CBOR encoded); a [`Message`] is the business-semantic layer
14//! carried inside a frame (commands, events, datagrams, snapshots, etc.).
15//! - **Session** — each WebSocket connection maps to a [`Session`] that
16//! manages authentication state, offset tracking, and heartbeat.
17//! - **Transport** — transport-layer abstraction with built-in adapters
18//! for `axum`, `actix-web`, `warp`, `ntex`, plus a standalone
19//! WebSocket listener.
20//! - **Topic Profile** — each topic can carry its own retention policy,
21//! ordering policy, subscriber/publisher limits, snapshot toggle, etc.
22//!
23//! ## Quick Start
24//!
25//! ```no_run
26//! use rifts::RiftServer;
27//! use std::sync::Arc;
28//! use tokio::sync::Notify;
29//!
30//! # async fn run() -> rifts::Result<()> {
31//! let shutdown = Arc::new(Notify::new());
32//! let server = RiftServer::builder()
33//! .websocket_transport()
34//! .build()?;
35//! server.run("127.0.0.1:9000".parse().unwrap(), shutdown).await?;
36//! # Ok(()) }
37//! ```
38//!
39//! ## Module Overview (spec §30)
40//!
41//! | Module | Responsibility |
42//! |--------|----------------|
43//! | [`ack`] | Message acknowledgement (ack / nack) semantics and tracking |
44//! | [`broker`] | Message routing core — publish, subscribe, fan-out, dedupe |
45//! | [`codec`] | Serialization codecs (JSON / CBOR) |
46//! | [`config`] | Server configuration (payload limits, heartbeat policy, etc.) |
47//! | [`connection`] | Connection-level processing — frame parsing, dispatch, backpressure |
48//! | [`error`] | Global error type hierarchy |
49//! | [`flow`] | Flow control — backpressure, rate limiting |
50//! | [`frame`] | Protocol frame structure and codec helpers |
51//! | [`message`] | Message semantic layer (Command / Event / Datagram / Stream / Snapshot) |
52//! | [`metrics`] | Process-local metric counters (exportable to Prometheus) |
53//! | [`protocol`] | Protocol constants — handshake, heartbeat, error codes, versioning, close codes |
54//! | [`session`] | Session management — authentication, offset tracking, resume |
55//! | [`storage`] | Persistent storage engine — append log, offset index, dedupe, snapshot |
56//! | [`topic`] | Topic profile — retention policy, ordering policy, storage binding |
57//! | [`transport`] | Transport-layer abstraction and framework adapters |
58//!
59//! [spec]: https://github.com/rift-proto/rifts
60
61#![forbid(unsafe_code)]
62#![deny(unreachable_pub)]
63#![warn(rust_2018_idioms)]
64
65// ── Module declarations ──────────────────────────────────────────────────────
66
67/// Message acknowledgement (ack / nack) semantics and tracking.
68pub mod ack;
69
70/// Async client SDK with auto-reconnect, heartbeat, and typed events.
71#[cfg(feature = "client")]
72pub mod client;
73
74/// Message routing core — Broker trait and implementations.
75pub mod broker;
76
77/// Serialization codecs (JSON, CBOR).
78pub mod codec;
79
80/// Server configuration structures and defaults.
81pub mod config;
82
83/// Connection-level processing — frame parsing, command dispatch, backpressure.
84pub mod connection;
85
86/// Global error type hierarchy.
87pub mod error;
88
89/// Flow control strategies — backpressure, rate limiting.
90pub mod flow;
91
92/// Protocol frame (Frame) structure and codec helpers.
93pub mod frame;
94
95/// Message semantic layer — Command, Event, Datagram, Stream, Snapshot, etc.
96pub mod message;
97
98/// Process-local metric counters.
99pub mod metrics;
100
101/// Protocol constants — handshake, heartbeat, error codes, versioning, close codes.
102pub mod protocol;
103
104/// Redis-backed multi-instance broker and storage (feature `redis`).
105#[cfg(feature = "redis")]
106pub mod redis;
107
108/// Server entry point — `RiftServer` and its Builder.
109pub mod server;
110
111/// Session management — authentication, offset tracking, resume.
112pub mod session;
113
114/// Persistent storage engine.
115pub mod storage;
116
117/// Topic profile — retention policy, ordering policy, storage.
118pub mod topic;
119
120/// Transport-layer abstraction and framework adapters.
121pub mod transport;
122
123// ── Public API re-exports ────────────────────────────────────────────────────
124
125pub use broker::{Broker, InMemoryBroker, PublishOutcome, SubscribeIntent};
126pub use config::ServerConfig;
127pub use error::{BoxedStdError, ConfigError, Result, RiftError};
128pub use frame::{Codec, Frame, FrameFlags, FrameType, Priority};
129pub use message::{DeliveryMode, Message, MessageClass, SubscribeResult};
130pub use metrics::Metrics;
131pub use protocol::close::CloseCode;
132pub use protocol::error_code::ErrorCode;
133pub use protocol::hello::{AuthMode, Hello, Ready, ResumeResult, SdkInfo, Welcome};
134pub use server::{RiftServer, RiftServerBuilder};
135pub use session::{
136 AllowAllAuth, AuthContext, AuthHints, AuthProvider, ClientId, OffsetTracker, Session,
137 SessionId, SessionState, SessionStore, TokenAuth,
138};
139pub use topic::{OrderingPolicy, RetentionPolicy, TopicProfile, TopicStore};
140pub use transport::frame_codec::DEFAULT_MAX_BINARY_PAYLOAD;
141pub use transport::frame_codec::{decode_binary_frame, decode_text_frame, encode_frame};
142#[cfg(feature = "websocket")]
143pub use transport::websocket::WebSocketTransport;
144pub use transport::{Transport, TransportConnection, TransportListener};
145
146// ── Shared utilities ─────────────────────────────────────────────────────────
147
148/// Returns the current UTC time as milliseconds since the Unix epoch.
149///
150/// # Overflow Handling
151///
152/// Returns `i64::MIN` when the system clock is before the Unix epoch
153/// (extremely rare but theoretically possible). `i64::MIN` is
154/// unambiguously invalid as a real-world timestamp (the real epoch in
155/// i64 ms is ~ year 292 million), so callers can treat it as a
156/// sentinel. Any caller that checks freshness will treat it as
157/// "expired", keeping behaviour safe.
158///
159/// # Use Cases
160///
161/// - Message timestamp fields (`created_at`)
162/// - Session expiry checks
163/// - Dedupe window checks
164/// - Heartbeat timeout detection
165///
166/// **Important**: protocol-critical paths must not depend on the absolute
167/// accuracy of this value — it reflects the server's local clock and may
168/// drift from client clocks.
169pub(crate) fn now_ms() -> i64 {
170 std::time::SystemTime::now()
171 .duration_since(std::time::UNIX_EPOCH)
172 .map(|d| d.as_millis() as i64)
173 // Return `i64::MIN` if the system clock is set before
174 // the Unix epoch. `i64::MIN` is unambiguously invalid as
175 // a real-world timestamp (the real epoch in i64 ms is
176 // ~ year 292 million), so callers can treat it as a
177 // sentinel.
178 .unwrap_or(i64::MIN)
179}