use std::sync::Arc;
use futures::stream::Stream;
use photon_core::IdentityFactory;
use photon_backend::{Event, PhotonBackend, ReclaimReport, Result, StoragePort, TopicRegistry, ExecutorServices, BackendCapabilities};
use crate::admin::collect_admin_snapshot;
use crate::admin::AdminSnapshot;
use crate::executor::ExecutorController;
#[derive(Clone)]
pub struct PhotonRuntimeState {
pub storage_port: Arc<dyn StoragePort>,
pub executor_services: Arc<ExecutorServices>,
pub executor: Arc<ExecutorController>,
}
#[derive(Clone)]
pub struct Photon {
backend: Arc<dyn PhotonBackend>,
runtime: PhotonRuntimeState,
}
static DEFAULT_PHOTON: std::sync::RwLock<Option<Photon>> = std::sync::RwLock::new(None);
pub fn configure(photon: Photon) {
let mut guard = DEFAULT_PHOTON.write().unwrap();
*guard = Some(photon);
}
pub fn default() -> Option<Photon> {
let guard = DEFAULT_PHOTON.read().unwrap();
guard.clone()
}
impl Photon {
pub(crate) fn new(backend: Arc<dyn PhotonBackend>, runtime: PhotonRuntimeState) -> Self {
Self { backend, runtime }
}
#[must_use]
pub fn builder() -> crate::builder::PhotonBuilder {
crate::builder::PhotonBuilder::default()
}
#[must_use]
pub fn backend_label(&self) -> &'static str {
self.backend.telemetry_label()
}
pub(crate) fn backend_capabilities(&self) -> BackendCapabilities {
PhotonBackend::capabilities(self.backend.as_ref())
}
pub async fn admin_snapshot(&self) -> Result<AdminSnapshot> {
collect_admin_snapshot(self).await
}
pub async fn publish(
&self,
topic_name: &str,
topic_key: Option<&str>,
actor_json: serde_json::Value,
payload_json: serde_json::Value,
) -> Result<String> {
PhotonBackend::publish(
self.backend.as_ref(),
topic_name,
topic_key,
actor_json,
payload_json,
)
.await
}
#[must_use]
pub fn subscribe(
&self,
topic_name: &str,
topic_key_filter: Option<&str>,
after_seq: Option<i64>,
) -> std::pin::Pin<Box<dyn Stream<Item = Result<Event>> + Send>> {
PhotonBackend::subscribe(
self.backend.as_ref(),
topic_name.to_string(),
topic_key_filter.map(std::string::ToString::to_string),
after_seq,
)
}
#[must_use]
pub fn subscribe_consumer_group(
&self,
topic_name: &str,
shard_ids: &[u32],
after_seq_by_shard: std::collections::HashMap<u32, Option<i64>>,
) -> std::pin::Pin<Box<dyn Stream<Item = Result<Event>> + Send>> {
photon_backend::merge_shard_streams(
Arc::clone(&self.backend),
topic_name.to_string(),
shard_ids,
after_seq_by_shard,
)
}
pub async fn get_event(&self, event_id: &str) -> Result<Option<Event>> {
PhotonBackend::get_event(self.backend.as_ref(), event_id).await
}
#[must_use]
pub fn registry(&self) -> &TopicRegistry {
PhotonBackend::registry(self.backend.as_ref())
}
pub async fn get_checkpoint_seq(
&self,
subscription_name: &str,
topic_name: &str,
topic_key: Option<&str>,
) -> Result<Option<i64>> {
PhotonBackend::get_checkpoint_seq(
self.backend.as_ref(),
subscription_name,
topic_name,
topic_key,
)
.await
}
pub async fn set_checkpoint(
&self,
subscription_name: &str,
topic_name: &str,
topic_key: Option<&str>,
last_seq: i64,
) -> Result<()> {
PhotonBackend::set_checkpoint(
self.backend.as_ref(),
subscription_name,
topic_name,
topic_key,
last_seq,
)
.await
}
#[must_use]
pub const fn runtime(&self) -> &PhotonRuntimeState {
&self.runtime
}
pub async fn reclaim_transport(&self) -> Result<Vec<ReclaimReport>> {
self.runtime
.executor_services
.retention_reclaimer
.sweep_all()
.await
}
#[allow(clippy::needless_pass_by_value)] pub fn start_executor(&self, identity: Arc<dyn IdentityFactory>) -> Result<()> {
self.runtime.executor.start(self, &identity)
}
pub fn shutdown_executor(&self) {
self.runtime.executor.shutdown();
}
pub async fn join_executor(&self) {
self.runtime.executor.join().await;
}
}