photon_backend/backend/photon_backend.rs
1//! Object-safe backend trait for Photon publish/subscribe runtimes.
2//!
3//! Implement this trait and install via
4//! [`PhotonBuilder::backend_with_context`](https://docs.rs/uf-photon/latest/photon/struct.PhotonBuilder.html#method.backend_with_context).
5//!
6//! See also: [`crate::storage::StoragePort`], [`crate::GenericPhotonBackend`].
7
8use std::pin::Pin;
9
10use async_trait::async_trait;
11use futures::stream::Stream;
12use serde_json::Value;
13
14use crate::backend::BackendCapabilities;
15use crate::error::Result;
16use crate::models::Event;
17use crate::registry::TopicRegistry;
18
19/// Backend for publish/subscribe delivery and checkpoint persistence.
20#[async_trait]
21pub trait PhotonBackend: Send + Sync {
22 /// Stable telemetry label for ops metrics (e.g. `"mem"`, `"nats"`).
23 fn telemetry_label(&self) -> &'static str {
24 "custom"
25 }
26
27 /// Adapter capabilities (replay window, get-by-id support, …).
28 fn capabilities(&self) -> BackendCapabilities {
29 BackendCapabilities::mem()
30 }
31
32 /// Append an event and return its event id.
33 ///
34 /// # Contract
35 ///
36 /// - Returns the stable `event_id` assigned by the underlying storage port.
37 /// - Ordering and dedupe are per `(topic_name, topic_key)` partition, not global.
38 async fn publish(
39 &self,
40 topic_name: &str,
41 topic_key: Option<&str>,
42 actor_json: Value,
43 payload_json: Value,
44 ) -> Result<String>;
45
46 /// Stream events for a topic partition, optionally replaying after `after_seq`.
47 ///
48 /// # Contract
49 ///
50 /// - Same semantics as [`crate::storage::StoragePort::subscribe`].
51 fn subscribe(
52 &self,
53 topic_name: String,
54 topic_key_filter: Option<String>,
55 after_seq: Option<i64>,
56 ) -> Pin<Box<dyn Stream<Item = Result<Event>> + Send>>;
57
58 /// Load a single event by id.
59 ///
60 /// # Contract
61 ///
62 /// - Returns `None` when unknown or truncated; see backend [`BackendCapabilities`].
63 async fn get_event(&self, event_id: &str) -> Result<Option<Event>>;
64
65 /// Inventory-discovered topic descriptors.
66 fn registry(&self) -> &TopicRegistry;
67
68 /// Load the last committed checkpoint seq for a subscription partition.
69 ///
70 /// # Contract
71 ///
72 /// - Returns `None` when no checkpoint exists.
73 async fn get_checkpoint_seq(
74 &self,
75 subscription_name: &str,
76 topic_name: &str,
77 topic_key: Option<&str>,
78 ) -> Result<Option<i64>>;
79
80 /// Persist the high-water checkpoint seq for a subscription partition.
81 ///
82 /// # Contract
83 ///
84 /// - `last_seq` must not regress; coalesced writes may batch behind the scenes.
85 async fn set_checkpoint(
86 &self,
87 subscription_name: &str,
88 topic_name: &str,
89 topic_key: Option<&str>,
90 last_seq: i64,
91 ) -> Result<()>;
92}