// Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers // All rights reserved. // Licensed under the Apache License, Version 2.0 // // or the MIT license , // at your option. All files in the project carrying such // notice may not be copied, modified, or distributed except // according to those terms. //! Types for Verifier use core::fmt; use std::path::PathBuf; use serde::{Deserialize, Serialize}; //use oxigraph::io::{RdfFormat, RdfParser, RdfSerializer}; //use oxigraph::store::Store; //use oxigraph::model::GroundQuad; //use yrs::{StateVector, Update}; use ng_repo::{errors::NgError, types::*}; use ng_net::types::*; #[doc(hidden)] #[derive(Clone, Debug, Serialize, Deserialize)] pub enum SessionPeerLastSeq { V0(u64), V1((u64, Sig)), } impl SessionPeerLastSeq { pub fn ser(&self) -> Result, NgError> { Ok(serde_bare::to_vec(self)?) } pub fn deser(ser: &[u8]) -> Result { Ok(serde_bare::from_slice(ser).map_err(|_| NgError::SerializationError)?) } } #[derive(Debug, Clone, PartialEq, Eq)] pub enum VerifierType { /// nothing will be saved on disk during the session Memory, /// will save all user data locally, with RocksDb backend on native, and on webapp, will save only the session and wallet, not the data itself Save, /// the verifier will be remote. a Noise connection will be opened /// optional peerId to connect to. If None, will try any that has the flag `can_verify` Remote(Option), /// IndexedDb based rocksdb compiled to WASM... not ready yet. obviously. only works in the browser WebRocksDb, // Server, this type is for Server Broker that act as verifier. They answer to VerifierType::Remote types of verifier. deprecated } impl VerifierType { pub fn is_memory(&self) -> bool { match self { Self::Memory => true, _ => false, } } pub fn is_persistent(&self) -> bool { match self { Self::Save => true, _ => false, } } } #[doc(hidden)] //type LastSeqFn = fn(peer_id: PubKey, qty: u16) -> Result; pub type LastSeqFn = dyn Fn(PubKey, u16) -> Result + 'static + Sync + Send; #[doc(hidden)] // peer_id: PubKey, seq_num:u64, event_ser: vec, pub type OutboxWriteFn = dyn Fn(PubKey, u64, Vec) -> Result<(), NgError> + 'static + Sync + Send; #[doc(hidden)] // peer_id: PubKey, pub type OutboxReadFn = dyn Fn(PubKey) -> Result>, NgError> + 'static + Sync + Send; #[doc(hidden)] pub struct JsSaveSessionConfig { pub last_seq_function: Box, pub outbox_write_function: Box, pub outbox_read_function: Box, } impl fmt::Debug for JsSaveSessionConfig { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "JsSaveSessionConfig") } } #[derive(Debug)] pub enum VerifierConfigType { /// nothing will be saved on disk during the session Memory, /// only the session information is saved locally. the UserStorage is not saved. JsSaveSession(JsSaveSessionConfig), /// will save all user data locally, with RocksDb backend RocksDb(PathBuf), /// the verifier will be remote. a Noise connection will be opened /// optional peerId to connect to. If None, will try any that has the flag `can_verify` /// // TODO: Pass the AppConfig Remote(Option), /// IndexedDb based rocksdb compiled to WASM... not ready yet. obviously. only works in the browser WebRocksDb, } impl VerifierConfigType { pub(crate) fn should_load_last_seq_num(&self) -> bool { match self { Self::JsSaveSession(_) | Self::RocksDb(_) => true, _ => false, } } pub(crate) fn is_persistent(&self) -> bool { match self { Self::RocksDb(_) => true, _ => false, } } #[allow(dead_code)] pub(crate) fn is_in_memory(&self) -> bool { match self { Self::Memory | Self::JsSaveSession(_) => true, _ => false, } } } #[derive(Debug)] pub struct VerifierConfig { pub config_type: VerifierConfigType, /// not used for Memory pub user_master_key: [u8; 32], /// not used for Memory pub peer_priv_key: PrivKey, pub user_priv_key: PrivKey, pub private_store_read_cap: Option, pub private_store_id: Option, pub public_store_id: Option, pub protected_store_id: Option, } #[doc(hidden)] pub type CancelFn = Box; // // APP PROTOCOL (between APP and VERIFIER) // #[derive(Clone, Debug, Serialize, Deserialize)] pub enum AppFetchContentV0 { Get, // does not subscribe. more to be detailed Subscribe, // more to be detailed Update, //Invoke, ReadQuery, // more to be detailed WriteQuery, // more to be detailed } impl AppFetchContentV0 { pub fn get_or_subscribe(subscribe: bool) -> Self { if !subscribe { AppFetchContentV0::Get } else { AppFetchContentV0::Subscribe } } } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum NgAccessV0 { ReadCap(ReadCap), Token(Digest), #[serde(with = "serde_bytes")] ExtRequest(Vec), Key(BlockKey), Inbox(Digest), } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum TargetBranchV0 { Chat, Stream, Context, Ontology, BranchId(BranchId), Named(String), // branch or commit Commits(Vec), // only possible if access to their branch is given. must belong to the same branch. } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum NuriTargetV0 { UserSite, // targets the whole data set of the user PublicStore, ProtectedStore, PrivateStore, AllDialogs, Dialog(String), // shortname of a Dialog AllGroups, Group(String), // shortname of a Group Repo(RepoId), Identity(UserId), } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct NuriV0 { pub target: NuriTargetV0, pub entire_store: bool, // If it is a store, will (try to) include all the docs belonging to the store pub object: Option, // used only for FileGet. // cannot be used for queries. only to download an object (file,commit..) pub branch: Option, // if None, the main branch is chosen pub overlay: Option, pub access: Vec, pub topic: Option, pub locator: Vec, } impl NuriV0 { pub fn new_repo_target_from_string(repo_id_string: String) -> Result { let repo_id: RepoId = repo_id_string.as_str().try_into()?; Ok(Self { target: NuriTargetV0::Repo(repo_id), entire_store: false, object: None, branch: None, overlay: None, access: vec![], topic: None, locator: vec![], }) } pub fn new_private_store_target() -> Self { Self { target: NuriTargetV0::PrivateStore, entire_store: false, object: None, branch: None, overlay: None, access: vec![], topic: None, locator: vec![], } } pub fn new(_from: String) -> Self { todo!(); } } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum AppRequestCommandV0 { Fetch(AppFetchContentV0), Pin, UnPin, Delete, Create, FileGet, // needs the Nuri of branch/doc/store AND ObjectId FilePut, // needs the Nuri of branch/doc/store } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AppRequestV0 { pub command: AppRequestCommandV0, pub nuri: NuriV0, pub payload: Option, } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum AppRequest { V0(AppRequestV0), } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum DocQuery { V0(String), // Sparql } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct GraphUpdate { add: Vec, remove: Vec, } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum DiscreteUpdate { /// A yrs::Update #[serde(with = "serde_bytes")] YMap(Vec), #[serde(with = "serde_bytes")] YXml(Vec), #[serde(with = "serde_bytes")] YText(Vec), /// An automerge::Patch #[serde(with = "serde_bytes")] Automerge(Vec), } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct DocUpdate { heads: Vec, graph: Option, discrete: Option, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct DocAddFile { pub filename: Option, pub object: ObjectRef, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct DocCreate { store: StoreRepo, content_type: BranchContentType, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct DocDelete { /// Nuri of doc to delete nuri: String, } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum AppRequestPayloadV0 { Create(DocCreate), Query(DocQuery), Update(DocUpdate), AddFile(DocAddFile), //RemoveFile Delete(DocDelete), //Invoke(InvokeArguments), SmallFilePut(SmallFile), RandomAccessFilePut(String), // content_type RandomAccessFilePutChunk((u32, serde_bytes::ByteBuf)), // end the upload with an empty vec } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum AppRequestPayload { V0(AppRequestPayloadV0), } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum DiscretePatch { /// A yrs::Update #[serde(with = "serde_bytes")] YMap(Vec), #[serde(with = "serde_bytes")] YXml(Vec), #[serde(with = "serde_bytes")] YText(Vec), /// An automerge::Patch #[serde(with = "serde_bytes")] Automerge(Vec), } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct GraphPatch { /// oxigraph::model::GroundQuad serialized to n-quads with oxrdfio pub adds: Vec, pub removes: Vec, } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum DiscreteState { /// A yrs::StateVector #[serde(with = "serde_bytes")] YMap(Vec), #[serde(with = "serde_bytes")] YXml(Vec), #[serde(with = "serde_bytes")] YText(Vec), // the output of Automerge::save() #[serde(with = "serde_bytes")] Automerge(Vec), } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct GraphState { pub tuples: Vec, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AppState { heads: Vec, graph: Option, // there is always a graph present in the branch. but it might not have been asked in the request discrete: Option, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AppPatch { heads: Vec, graph: Option, discrete: Option, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct FileName { pub heads: Vec, pub name: Option, pub reference: ObjectRef, pub nuri: String, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct FileMetaV0 { pub content_type: String, pub size: u64, } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum AppResponseV0 { State(AppState), Patch(AppPatch), Text(String), File(FileName), FileUploading(u32), FileUploaded(ObjectRef), #[serde(with = "serde_bytes")] FileBinary(Vec), FileMeta(FileMetaV0), QueryResult, // see sparesults Ok, } #[derive(Clone, Debug, Serialize, Deserialize)] pub enum AppResponse { V0(AppResponseV0), }