use crate::access_control::{
manifest::ManifestParams, traits::AccessController, traits::Option as AccessControllerOption,
};
use crate::address::Address;
use crate::data_store::Datastore;
use crate::events::{self, EmitterInterface};
use crate::guardian::error::GuardianError;
use crate::log::{Log, entry::Entry, identity::Identity};
use crate::p2p::EventBus;
use crate::p2p::network::client::IrohClient;
use crate::stores::{operation::Operation, replicator::replication_info::ReplicationInfo};
use futures::stream::Stream;
use iroh::NodeId;
use iroh_blobs::Hash;
use opentelemetry::global::{BoxedSpan, BoxedTracer};
use opentelemetry::trace::{Tracer, noop::NoopTracer};
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use std::any::Any;
use std::error::Error;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::mpsc;
use tracing::Span;
type KeyExtractorFn =
Arc<dyn Fn(&serde_json::Value) -> Result<String, GuardianError> + Send + Sync>;
type MarshalFn = Arc<dyn Fn(&serde_json::Value) -> Result<Vec<u8>, GuardianError> + Send + Sync>;
type UnmarshalFn = Arc<dyn Fn(&[u8]) -> Result<serde_json::Value, GuardianError> + Send + Sync>;
type ItemFactoryFn = Arc<dyn Fn() -> serde_json::Value + Send + Sync>;
type CleanupCallback = Box<
dyn FnOnce() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> + Send + Sync,
>;
pub type SortFn = fn(&Entry, &Entry) -> std::cmp::Ordering;
pub type Document = Box<dyn Any + Send + Sync>;
pub type GuardianResult<T> = std::result::Result<T, GuardianError>;
pub type AsyncDocumentFilter = Pin<
Box<
dyn Fn(
&Document,
)
-> Pin<Box<dyn Future<Output = Result<bool, Box<dyn Error + Send + Sync>>> + Send>>
+ Send
+ Sync,
>,
>;
pub type ProgressCallback = mpsc::Sender<Entry>;
#[derive(Default)]
pub enum TracerWrapper {
OpenTelemetry(Arc<BoxedTracer>),
#[default]
Tracing,
Noop(NoopTracer),
}
impl Clone for TracerWrapper {
fn clone(&self) -> Self {
match self {
TracerWrapper::OpenTelemetry(tracer) => TracerWrapper::OpenTelemetry(tracer.clone()),
TracerWrapper::Tracing => TracerWrapper::Tracing,
TracerWrapper::Noop(_) => TracerWrapper::Noop(NoopTracer::new()),
}
}
}
impl TracerWrapper {
pub fn new_tracing() -> Self {
TracerWrapper::Tracing
}
pub fn new_opentelemetry(tracer: Arc<BoxedTracer>) -> Self {
TracerWrapper::OpenTelemetry(tracer)
}
pub fn new_noop() -> Self {
TracerWrapper::Noop(NoopTracer::new())
}
pub fn start_span(&self, name: &str) -> TracerSpan {
match self {
TracerWrapper::OpenTelemetry(tracer) => {
let span = tracer.start(name.to_string());
TracerSpan::OpenTelemetry(span)
}
TracerWrapper::Tracing => {
let span = tracing::info_span!("guardian_db", operation = name);
TracerSpan::Tracing(span)
}
TracerWrapper::Noop(_) => {
TracerSpan::Noop
}
}
}
pub fn is_active(&self) -> bool {
!matches!(self, TracerWrapper::Noop(_))
}
pub fn tracer_type(&self) -> &'static str {
match self {
TracerWrapper::OpenTelemetry(_) => "opentelemetry",
TracerWrapper::Tracing => "tracing",
TracerWrapper::Noop(_) => "noop",
}
}
}
pub enum TracerSpan {
OpenTelemetry(BoxedSpan),
Tracing(tracing::Span),
Noop,
}
impl TracerSpan {
pub fn set_attribute<T: Into<opentelemetry::Value>>(&mut self, key: &str, value: T) {
match self {
TracerSpan::OpenTelemetry(span) => {
use opentelemetry::trace::Span as OtelSpan;
span.set_attribute(opentelemetry::KeyValue::new(key.to_string(), value));
}
TracerSpan::Tracing(span) => {
span.in_scope(|| {
tracing::info!(key = %format!("{:?}", value.into()), "span_attribute");
});
}
TracerSpan::Noop => {
}
}
}
pub fn add_event(&mut self, name: &str, attributes: Vec<(&str, &str)>) {
match self {
TracerSpan::OpenTelemetry(span) => {
use opentelemetry::trace::Span as OtelSpan;
let attrs: Vec<opentelemetry::KeyValue> = attributes
.into_iter()
.map(|(k, v)| opentelemetry::KeyValue::new(k.to_string(), v.to_string()))
.collect();
span.add_event(name.to_string(), attrs);
}
TracerSpan::Tracing(span) => {
span.in_scope(|| {
let fields: std::collections::HashMap<&str, &str> =
attributes.into_iter().collect();
tracing::info!(event = name, ?fields, "span_event");
});
}
TracerSpan::Noop => {
}
}
}
pub fn set_error<E: std::fmt::Display>(&mut self, error: E) {
match self {
TracerSpan::OpenTelemetry(span) => {
use opentelemetry::trace::Span as OtelSpan;
span.set_status(opentelemetry::trace::Status::Error {
description: std::borrow::Cow::Owned(error.to_string()),
});
span.set_attribute(opentelemetry::KeyValue::new("error".to_string(), true));
span.set_attribute(opentelemetry::KeyValue::new(
"error.message".to_string(),
error.to_string(),
));
}
TracerSpan::Tracing(span) => {
span.in_scope(|| {
tracing::error!(error = %error, "span_error");
});
}
TracerSpan::Noop => {
}
}
}
pub fn finish(mut self) {
match &mut self {
TracerSpan::OpenTelemetry(_span) => {
}
TracerSpan::Tracing(_span) => {
}
TracerSpan::Noop => {
}
}
}
}
impl Drop for TracerSpan {
fn drop(&mut self) {
match self {
TracerSpan::OpenTelemetry(_span) => {
}
TracerSpan::Tracing(_) => {
}
TracerSpan::Noop => {
}
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct MessageExchangeHeads {
#[serde(rename = "address")]
pub address: String,
#[serde(rename = "heads")]
pub heads: Vec<Entry>,
}
pub trait MessageMarshaler: Send + Sync {
type Error: std::error::Error + Send + Sync + 'static;
fn marshal(&self, msg: &MessageExchangeHeads) -> Result<Vec<u8>, Self::Error>;
fn unmarshal(&self, data: &[u8]) -> Result<MessageExchangeHeads, Self::Error>;
}
#[derive(Default)]
pub struct CreateDBOptions {
pub event_bus: Option<EventBus>,
pub directory: Option<String>,
pub overwrite: Option<bool>,
pub local_only: Option<bool>,
pub create: Option<bool>,
pub store_type: Option<String>,
pub access_controller_address: Option<String>,
pub access_controller: Option<Box<dyn ManifestParams>>,
pub replicate: Option<bool>,
pub keystore: Option<Arc<dyn crate::log::identity_provider::Keystore>>,
pub cache: Option<Arc<dyn Datastore>>,
pub identity: Option<Identity>,
pub sort_fn: Option<SortFn>,
pub timeout: Option<Duration>,
pub message_marshaler: Option<Arc<dyn MessageMarshaler<Error = GuardianError>>>,
pub span: Option<Span>,
pub close_func: Option<Box<dyn FnOnce() + Send>>,
pub store_specific_opts: Option<Box<dyn Any + Send + Sync>>,
}
impl Clone for CreateDBOptions {
fn clone(&self) -> Self {
Self {
event_bus: self.event_bus.clone(),
directory: self.directory.clone(),
overwrite: self.overwrite,
local_only: self.local_only,
create: self.create,
store_type: self.store_type.clone(),
access_controller_address: self.access_controller_address.clone(),
access_controller: None, replicate: self.replicate,
keystore: self.keystore.clone(),
cache: self.cache.clone(),
identity: self.identity.clone(),
sort_fn: self.sort_fn,
timeout: self.timeout,
message_marshaler: self.message_marshaler.clone(),
span: self.span.clone(),
close_func: None, store_specific_opts: None, }
}
}
pub type StoreConstructor = Arc<
dyn Fn(
Arc<IrohClient>,
Arc<Identity>,
Box<dyn Address>,
NewStoreOptions,
) -> Pin<
Box<
dyn Future<Output = Result<Box<dyn Store<Error = GuardianError>>, GuardianError>>
+ Send,
>,
> + Send
+ Sync,
>;
#[derive(Clone)]
pub struct CreateDocumentDBOptions {
pub key_extractor: KeyExtractorFn,
pub marshal: MarshalFn,
pub unmarshal: UnmarshalFn,
pub item_factory: ItemFactoryFn,
}
#[derive(Default, Clone)]
pub struct DetermineAddressOptions {
pub only_hash: Option<bool>,
pub replicate: Option<bool>,
pub access_controller: crate::access_control::manifest::CreateAccessControllerOptions,
}
#[async_trait::async_trait]
pub trait BaseGuardianDB: Send + Sync {
type Error: Error + Send + Sync + 'static;
fn client(&self) -> Arc<IrohClient>;
fn identity(&self) -> Arc<Identity>;
async fn open(
&self,
address: &str,
options: &mut CreateDBOptions,
) -> Result<Arc<dyn Store<Error = GuardianError>>, Self::Error>;
fn get_store(&self, address: &str) -> Option<Arc<dyn Store<Error = GuardianError>>>;
async fn create(
&self,
name: &str,
store_type: &str,
options: &mut CreateDBOptions,
) -> Result<Arc<dyn Store<Error = GuardianError>>, Self::Error>;
async fn determine_address(
&self,
name: &str,
store_type: &str,
options: &DetermineAddressOptions,
) -> Result<Box<dyn Address>, Self::Error>;
fn register_store_type(&mut self, store_type: &str, constructor: StoreConstructor);
fn unregister_store_type(&mut self, store_type: &str);
fn register_access_controller_type(
&mut self,
constructor: AccessControllerConstructor,
) -> Result<(), Self::Error>;
fn unregister_access_controller_type(&mut self, controller_type: &str);
fn get_access_controller_type(
&self,
controller_type: &str,
) -> Option<AccessControllerConstructor>;
fn event_bus(&self) -> EventBus;
fn span(&self) -> &tracing::Span;
fn tracer(&self) -> Arc<TracerWrapper>;
}
#[async_trait::async_trait]
pub trait GuardianDBDocumentStoreProvider {
type Error: Error + Send + Sync + 'static;
async fn docs(
&self,
address: &str,
options: &mut CreateDBOptions,
) -> Result<Box<dyn DocumentStore<Error = GuardianError>>, Self::Error>;
}
pub trait GuardianDBDocumentStore: BaseGuardianDB + GuardianDBDocumentStoreProvider {}
impl<T: BaseGuardianDB + GuardianDBDocumentStoreProvider> GuardianDBDocumentStore for T {}
#[async_trait::async_trait]
pub trait GuardianDBKVStoreProvider: Send + Sync {
type Error: Error + Send + Sync + 'static;
async fn key_value(
&self,
address: &str,
options: &mut CreateDBOptions,
) -> Result<Box<dyn KeyValueStore<Error = GuardianError>>, Self::Error>;
}
pub trait GuardianDBKVStore: BaseGuardianDB + GuardianDBKVStoreProvider {}
impl<T: BaseGuardianDB + GuardianDBKVStoreProvider> GuardianDBKVStore for T {}
#[async_trait::async_trait]
pub trait GuardianDBLogStoreProvider {
type Error: Error + Send + Sync + 'static;
async fn log(
&self,
address: &str,
options: &mut CreateDBOptions,
) -> Result<Box<dyn EventLogStore<Error = GuardianError>>, Self::Error>;
}
pub trait GuardianDBLogStore: BaseGuardianDB + GuardianDBLogStoreProvider {}
impl<T: BaseGuardianDB + GuardianDBLogStoreProvider> GuardianDBLogStore for T {}
pub trait GuardianDB:
BaseGuardianDB
+ GuardianDBKVStoreProvider
+ GuardianDBLogStoreProvider
+ GuardianDBDocumentStoreProvider
{
}
impl<
T: BaseGuardianDB
+ GuardianDBKVStoreProvider
+ GuardianDBLogStoreProvider
+ GuardianDBDocumentStoreProvider,
> GuardianDB for T
{
}
#[derive(Default, Debug, Clone)]
pub struct StreamOptions {
pub gt: Option<Hash>,
pub gte: Option<Hash>,
pub lt: Option<Hash>,
pub lte: Option<Hash>,
pub amount: Option<i32>,
}
pub trait StoreEvents {
fn subscribe(&mut self);
}
#[async_trait::async_trait]
pub trait Store: Send + Sync {
type Error: std::error::Error + Send + Sync + 'static;
#[deprecated(note = "use event_bus() instead")]
fn events(&self) -> &dyn EmitterInterface;
async fn close(&self) -> Result<(), Self::Error>;
fn address(&self) -> &dyn Address;
fn index(&self) -> Box<dyn StoreIndex<Error = Self::Error> + Send + Sync>;
fn store_type(&self) -> &str;
fn replication_status(&self) -> ReplicationInfo;
fn cache(&self) -> Arc<dyn Datastore>;
async fn drop(&self) -> Result<(), Self::Error>;
async fn load(&self, amount: usize) -> Result<(), Self::Error>;
async fn sync(&self, heads: Vec<Entry>) -> Result<(), Self::Error>;
async fn load_more_from(&self, amount: u64, entries: Vec<Entry>);
async fn load_from_snapshot(&self) -> Result<(), Self::Error>;
fn op_log(&self) -> Arc<RwLock<Log>>;
fn client(&self) -> Arc<IrohClient>;
fn db_name(&self) -> &str;
fn identity(&self) -> &Identity;
fn access_controller(&self) -> &dyn AccessController;
async fn add_operation(
&self,
op: Operation,
on_progress_callback: Option<ProgressCallback>,
) -> Result<Entry, Self::Error>;
fn span(&self) -> Arc<Span>;
fn tracer(&self) -> Arc<TracerWrapper>;
fn event_bus(&self) -> Arc<EventBus>;
fn as_any(&self) -> &dyn std::any::Any;
}
#[async_trait::async_trait]
pub trait EventLogStore: Store {
async fn add(&self, data: Vec<u8>) -> Result<Operation, Self::Error>;
async fn get(&self, hash: &Hash) -> Result<Operation, Self::Error>;
async fn list(&self, options: Option<StreamOptions>) -> Result<Vec<Operation>, Self::Error>;
}
#[async_trait::async_trait]
pub trait KeyValueStore: Store {
fn all(&self) -> std::collections::HashMap<String, Vec<u8>>;
async fn put(&self, key: &str, value: Vec<u8>) -> Result<Operation, Self::Error>;
async fn delete(&self, key: &str) -> Result<Operation, Self::Error>;
async fn get(&self, key: &str) -> Result<Option<Vec<u8>>, Self::Error>;
}
#[derive(Default, Debug, Clone, Copy)]
pub struct DocumentStoreGetOptions {
pub case_insensitive: bool,
pub partial_matches: bool,
}
#[derive(Default, Debug, Clone)]
pub struct DocumentStoreQueryOptions {
pub limit: Option<usize>,
pub skip: Option<usize>,
pub sort: Option<String>,
}
#[async_trait::async_trait]
pub trait DocumentStore: Store {
async fn put(&self, document: Document) -> Result<Operation, Self::Error>;
async fn delete(&self, key: &str) -> Result<Operation, Self::Error>;
async fn put_batch(&self, values: Vec<Document>) -> Result<Operation, Self::Error>;
async fn put_all(&self, values: Vec<Document>) -> Result<Operation, Self::Error>;
async fn get(
&self,
key: &str,
opts: Option<DocumentStoreGetOptions>,
) -> Result<Vec<Document>, Self::Error>;
async fn query(&self, filter: AsyncDocumentFilter) -> Result<Vec<Document>, Self::Error>;
}
pub trait StoreIndex: Send + Sync {
type Error: Error + Send + Sync + 'static;
fn contains_key(&self, key: &str) -> std::result::Result<bool, Self::Error>;
fn get_bytes(&self, key: &str) -> std::result::Result<Option<Vec<u8>>, Self::Error>;
fn keys(&self) -> std::result::Result<Vec<String>, Self::Error>;
fn len(&self) -> std::result::Result<usize, Self::Error>;
fn is_empty(&self) -> std::result::Result<bool, Self::Error>;
fn update_index(
&mut self,
log: &Log,
entries: &[Entry],
) -> std::result::Result<(), Self::Error>;
fn clear(&mut self) -> std::result::Result<(), Self::Error>;
fn get_entries_range(&self, _start: usize, _end: usize) -> Option<Vec<Entry>> {
None
}
fn get_last_entries(&self, _count: usize) -> Option<Vec<Entry>> {
None
}
fn get_entry_by_hash(&self, _hash: &Hash) -> Option<Entry> {
None
}
fn supports_entry_queries(&self) -> bool {
false
}
}
pub struct NewStoreOptions {
pub event_bus: Option<EventBus>,
pub index: Option<IndexConstructor>,
pub access_controller: Option<Arc<dyn AccessController>>,
pub directory: String,
pub sort_fn: Option<SortFn>,
pub node_id: NodeId,
pub pubsub: Option<Arc<dyn PubSubInterface<Error = GuardianError>>>,
pub direct_channel: Option<Arc<dyn DirectChannel<Error = GuardianError>>>,
pub message_marshaler: Option<Arc<dyn MessageMarshaler<Error = GuardianError>>>,
pub cache: Option<Arc<dyn Datastore>>,
pub cache_destroy: Option<CleanupCallback>,
pub replication_concurrency: Option<u32>,
pub reference_count: Option<i32>,
pub max_history: Option<i32>,
pub replicate: Option<bool>,
pub span: Option<Span>,
pub tracer: Option<Arc<TracerWrapper>>,
pub close_func: Option<Box<dyn FnOnce() + Send>>,
pub store_specific_opts: Option<Box<dyn Any + Send + Sync>>,
}
impl Default for NewStoreOptions {
fn default() -> Self {
let node_id = NodeId::from_bytes(&[0u8; 32]).unwrap();
Self {
event_bus: None,
index: None,
access_controller: None,
directory: String::new(),
sort_fn: None,
node_id,
pubsub: None,
direct_channel: None,
message_marshaler: None,
cache: None,
cache_destroy: None,
replication_concurrency: None,
reference_count: None,
max_history: None,
replicate: None,
span: None,
tracer: None,
close_func: None,
store_specific_opts: None,
}
}
}
#[derive(Default, Clone)]
pub struct DirectChannelOptions {
pub span: Option<Span>,
}
#[async_trait::async_trait]
pub trait DirectChannel: Send + Sync + std::any::Any {
type Error: Error + Send + Sync + 'static;
async fn connect(&mut self, peer: NodeId) -> Result<(), Self::Error>;
async fn send(&mut self, peer: NodeId, data: Vec<u8>) -> Result<(), Self::Error>;
async fn close(&mut self) -> Result<(), Self::Error>;
async fn close_shared(&self) -> Result<(), Self::Error>;
fn as_any(&self) -> &dyn std::any::Any;
}
#[derive(Debug, Clone)]
pub struct EventPubSubPayload {
pub payload: Vec<u8>,
pub peer: NodeId,
}
#[async_trait::async_trait]
pub trait DirectChannelEmitter: Send + Sync {
type Error: Error + Send + Sync + 'static;
async fn emit(&self, payload: EventPubSubPayload) -> Result<(), Self::Error>;
async fn close(&self) -> Result<(), Self::Error>;
}
pub type DirectChannelFactory = Arc<
dyn Fn(
Arc<dyn DirectChannelEmitter<Error = GuardianError>>,
Option<DirectChannelOptions>,
) -> Pin<
Box<
dyn Future<
Output = Result<
Arc<dyn DirectChannel<Error = GuardianError>>,
Box<dyn Error + Send + Sync>,
>,
> + Send,
>,
> + Send
+ Sync,
>;
pub type IndexConstructor =
Box<dyn Fn(&[u8]) -> Box<dyn StoreIndex<Error = GuardianError>> + Send + Sync>;
pub type OnWritePrototype = Box<
dyn Fn(
Hash,
Entry,
Vec<Hash>,
)
-> Pin<Box<dyn Future<Output = Result<(), Box<dyn Error + Send + Sync>>> + Send>>
+ Send
+ Sync,
>;
#[derive(Debug, Clone)]
pub struct EventPubSubMessage {
pub content: Vec<u8>,
}
pub type AccessControllerConstructor = Arc<
dyn Fn(
Arc<dyn BaseGuardianDB<Error = GuardianError>>,
&crate::access_control::manifest::CreateAccessControllerOptions,
Option<Vec<AccessControllerOption>>,
)
-> Pin<Box<dyn Future<Output = Result<Arc<dyn AccessController>, GuardianError>> + Send>>
+ Send
+ Sync,
>;
#[async_trait::async_trait]
pub trait PubSubTopic: Send + Sync {
type Error: Error + Send + Sync + 'static;
async fn publish(&self, message: Vec<u8>) -> Result<(), Self::Error>;
async fn peers(&self) -> Result<Vec<iroh::NodeId>, Self::Error>;
async fn watch_peers(
&self,
) -> Result<Pin<Box<dyn Stream<Item = events::Event> + Send>>, Self::Error>;
async fn watch_messages(
&self,
) -> Result<Pin<Box<dyn Stream<Item = EventPubSubMessage> + Send>>, Self::Error>;
fn topic(&self) -> &str;
}
#[async_trait::async_trait]
pub trait PubSubInterface: Send + Sync + std::any::Any {
type Error: Error + Send + Sync + 'static;
async fn topic_subscribe(
&self,
topic: &str,
) -> Result<Arc<dyn PubSubTopic<Error = GuardianError>>, Self::Error>;
fn as_any(&self) -> &dyn std::any::Any;
}
#[derive(Default, Clone)]
pub struct PubSubSubscriptionOptions {
pub span: Option<Span>,
pub tracer: Option<Arc<TracerWrapper>>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventPubSub {
Join { topic: String, peer: NodeId },
Leave { topic: String, peer: NodeId },
}