diff --git a/CHANGELOG.md b/CHANGELOG.md index acfa2a47..5462514b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,10 +70,20 @@ Access the sub-sections directly : ## SDK -### SDK [unreleased] +### SDK [0.1.1-alpha.7] - 2025-04-03 + +#### Changed + +- js : doc_create : parameters are session_id, crdt, class_name, destination, store_repo (defaults to Private Store) +- nodejs & python : doc_create : parameters are session_id, crdt, class_name, destination, store_type (string), store_repo (string) if 2 last params omitted, defaults to Private Store. +- all : sparql_update : returns list of Nuri of new commits, in the form `did:ng:o:c` #### Added +- python : wallet_open_with_mnemonic_words +- python : disconnect_and_close +- python : doc_create +- python : doc_sparql_update - js & nodejs : fetch_header - js & nodejs : update_header - js & nodejs : signature_status diff --git a/nextgraph/src/local_broker.rs b/nextgraph/src/local_broker.rs index 005ae158..c376e5f3 100644 --- a/nextgraph/src/local_broker.rs +++ b/nextgraph/src/local_broker.rs @@ -2671,7 +2671,7 @@ pub async fn doc_sparql_update( session_id: u64, sparql: String, nuri: Option, -) -> Result<(), String> { +) -> Result, String> { let (nuri, base) = if let Some(n) = nuri { let nuri = NuriV0::new_from(&n).map_err(|e| e.to_string())?; let b = nuri.repo(); @@ -2690,10 +2690,67 @@ pub async fn doc_sparql_update( let res = app_request(request) .await .map_err(|e: NgError| e.to_string())?; - if let AppResponse::V0(AppResponseV0::Error(e)) = res { - Err(e) + match res { + AppResponse::V0(AppResponseV0::Error(e)) => Err(e), + AppResponse::V0(AppResponseV0::Commits(commits)) => Ok(commits), + _ => Err(NgError::InvalidResponse.to_string()) + } +} + +pub async fn doc_create( + session_id: u64, + crdt: String, + class_name: String, + destination: String, + store_type: Option, + store_repo: Option, +) -> Result { + + let store_repo = if store_type.is_none() || store_repo.is_none() { + None } else { - Ok(()) + Some(StoreRepo::from_type_and_repo(&store_type.unwrap(), &store_repo.unwrap())?) + }; + + doc_create_with_store_repo(session_id,crdt,class_name,destination,store_repo).await +} + +pub async fn doc_create_with_store_repo( + session_id: u64, + crdt: String, + class_name: String, + destination: String, + store_repo: Option, +) -> Result { + + let class = BranchCrdt::from(crdt, class_name)?; + + let nuri = if store_repo.is_none() { + NuriV0::new_private_store_target() + } else { + NuriV0::from_store_repo(&store_repo.unwrap()) + }; + + let destination = DocCreateDestination::from(destination)?; + + let request = AppRequest::V0(AppRequestV0 { + session_id, + command: AppRequestCommandV0::new_create(), + nuri, + payload: Some(AppRequestPayload::V0(AppRequestPayloadV0::Create( + DocCreate { + class, + destination, + }, + ))), + }); + + let response = app_request(request).await?; + + if let AppResponse::V0(AppResponseV0::Nuri(nuri)) = response { + Ok(nuri) + } else { + Err(NgError::InvalidResponse) } } diff --git a/ng-app/src-tauri/src/lib.rs b/ng-app/src-tauri/src/lib.rs index b5866633..d6251113 100644 --- a/ng-app/src-tauri/src/lib.rs +++ b/ng-app/src-tauri/src/lib.rs @@ -612,7 +612,7 @@ async fn sparql_update( session_id: u64, sparql: String, nuri: Option, -) -> Result<(), String> { +) -> Result, String> { let (nuri, base) = if let Some(n) = nuri { let nuri = NuriV0::new_from(&n).map_err(|e| e.to_string())?; let b = nuri.repo(); @@ -631,10 +631,10 @@ async fn sparql_update( let res = nextgraph::local_broker::app_request(request) .await .map_err(|e: NgError| e.to_string())?; - if let AppResponse::V0(AppResponseV0::Error(e)) = res { - Err(e) - } else { - Ok(()) + match res { + AppResponse::V0(AppResponseV0::Error(e)) => Err(e), + AppResponse::V0(AppResponseV0::Commits(commits)) => Ok(commits), + _ => Err(NgError::InvalidResponse.to_string()) } } @@ -790,35 +790,12 @@ async fn doc_create( session_id: u64, crdt: String, class_name: String, - store_repo: StoreRepo, destination: String, + store_repo: Option ) -> Result { - let class = BranchCrdt::from(crdt, class_name).map_err(|e| e.to_string())?; - - let destination = DocCreateDestination::from(destination).map_err(|e| e.to_string())?; - - let request = AppRequest::V0(AppRequestV0 { - session_id, - command: AppRequestCommandV0::new_create(), - nuri: NuriV0::new_empty(), - payload: Some(AppRequestPayload::V0(AppRequestPayloadV0::Create( - DocCreate { - store: store_repo, - class, - destination, - }, - ))), - }); - - let response = nextgraph::local_broker::app_request(request) - .await - .map_err(|e: NgError| e.to_string())?; - - if let AppResponse::V0(AppResponseV0::Nuri(nuri)) = response { - Ok(nuri) - } else { - Err("invalid response".to_string()) - } + nextgraph::local_broker::doc_create_with_store_repo(session_id, crdt, class_name, destination, store_repo) + .await + .map_err(|e| e.to_string()) } #[tauri::command(rename_all = "snake_case")] diff --git a/ng-app/src/api.ts b/ng-app/src/api.ts index f4fc36e5..770b4973 100644 --- a/ng-app/src/api.ts +++ b/ng-app/src/api.ts @@ -45,7 +45,7 @@ const mapping = { "sparql_update": ["session_id","sparql","nuri"], "test": [ ], "get_device_name": [], - "doc_create": [ "session_id", "crdt", "class_name", "store_repo", "destination" ], + "doc_create": [ "session_id", "crdt", "class_name", "destination", "store_repo" ], "doc_fetch_private_subscribe": [], "doc_fetch_repo_subscribe": ["repo_o"], "branch_history": ["session_id", "nuri"], diff --git a/ng-app/src/lib/FullLayout.svelte b/ng-app/src/lib/FullLayout.svelte index 1b67b2a7..1cbefd81 100644 --- a/ng-app/src/lib/FullLayout.svelte +++ b/ng-app/src/lib/FullLayout.svelte @@ -590,10 +590,10 @@ try { await reset_toasts(); let store_repo = $cur_tab.store.repo; - if (!store_repo) { - store_repo = $all_tabs[$active_session.private_store_id].store.repo - } - let nuri = await ng.doc_create($active_session.session_id, get_class(class_name)["ng:crdt"], class_name, store_repo, destination); + // if (!store_repo) { + // store_repo = $all_tabs[$active_session.private_store_id].store.repo + // } + let nuri = await ng.doc_create($active_session.session_id, get_class(class_name)["ng:crdt"], class_name, destination, store_repo); closeSpinner(); push("#/"+nuri); diff --git a/ng-net/src/app_protocol.rs b/ng-net/src/app_protocol.rs index 4dcce796..1c9f4af8 100644 --- a/ng-net/src/app_protocol.rs +++ b/ng-net/src/app_protocol.rs @@ -322,6 +322,10 @@ impl NuriV0 { format!("{DID_PREFIX}:o:{repo_id}:t:{commit_id}") } + pub fn commit(repo_id: &RepoId, commit_id: &ObjectId) -> String { + format!("{DID_PREFIX}:o:{repo_id}:c:{commit_id}") + } + pub fn locator(locator: &Locator) -> String { format!("l:{locator}") } @@ -848,7 +852,6 @@ impl DocCreateDestination { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct DocCreate { - pub store: StoreRepo, pub class: BranchCrdt, pub destination: DocCreateDestination, } @@ -1123,6 +1126,7 @@ pub enum AppResponseV0 { EndOfStream, Nuri(String), Header(AppHeader), + Commits(Vec), } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -1137,4 +1141,7 @@ impl AppResponse { pub fn ok() -> Self { AppResponse::V0(AppResponseV0::Ok) } + pub fn commits(commits: Vec) -> Self { + AppResponse::V0(AppResponseV0::Commits(commits)) + } } diff --git a/ng-repo/src/lib.rs b/ng-repo/src/lib.rs index d296b53f..ac7a4b40 100644 --- a/ng-repo/src/lib.rs +++ b/ng-repo/src/lib.rs @@ -34,7 +34,7 @@ pub mod kcv_storage; pub mod os_info; -pub use threshold_crypto::PublicKeySet; +pub use ng_threshold_crypto::PublicKeySet; #[macro_use] extern crate slice_as_array; diff --git a/ng-repo/src/store.rs b/ng-repo/src/store.rs index 77c3fefc..022c7fa3 100644 --- a/ng-repo/src/store.rs +++ b/ng-repo/src/store.rs @@ -15,7 +15,7 @@ use core::fmt; use std::collections::HashMap; use std::sync::{Arc, RwLock}; -use threshold_crypto::SecretKeySet; +use ng_threshold_crypto::SecretKeySet; use crate::block_storage::{BlockStorage, HashMapBlockStorage}; use crate::errors::{NgError, StorageError}; @@ -568,7 +568,7 @@ impl Store { let signer_cap = SignerCap { repo: repo_pub_key, epoch: root_branch_readcap_id, - owner: Some(threshold_crypto::serde_impl::SerdeSecret(sk_share)), + owner: Some(ng_threshold_crypto::serde_impl::SerdeSecret(sk_share)), total_order: None, partial_order: None, }; diff --git a/ng-repo/src/types.rs b/ng-repo/src/types.rs index a7a8019a..42811b0a 100644 --- a/ng-repo/src/types.rs +++ b/ng-repo/src/types.rs @@ -19,8 +19,8 @@ use std::hash::{Hash, Hasher}; use once_cell::sync::OnceCell; use sbbf_rs_safe::Filter; use serde::{Deserialize, Serialize}; -use threshold_crypto::serde_impl::SerdeSecret; -use threshold_crypto::SignatureShare; +use ng_threshold_crypto::serde_impl::SerdeSecret; +use ng_threshold_crypto::SignatureShare; use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::errors::NgError; @@ -1694,11 +1694,11 @@ pub struct SignerCap { /// latest RootBranch commit or Quorum commit that defines the signing epoch pub epoch: ObjectId, - pub owner: Option>, + pub owner: Option>, - pub total_order: Option>, + pub total_order: Option>, - pub partial_order: Option>, + pub partial_order: Option>, } impl SignerCap { @@ -2414,9 +2414,9 @@ impl fmt::Display for SignatureContent { /// A Threshold Signature and the set used to generate it #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] pub enum ThresholdSignatureV0 { - PartialOrder(threshold_crypto::Signature), - TotalOrder(threshold_crypto::Signature), - Owners(threshold_crypto::Signature), + PartialOrder(ng_threshold_crypto::Signature), + TotalOrder(ng_threshold_crypto::Signature), + Owners(ng_threshold_crypto::Signature), } impl fmt::Display for ThresholdSignatureV0 { @@ -2509,8 +2509,8 @@ pub enum OrdersPublicKeySetsV0 { Store(ObjectRef), Repo( ( - threshold_crypto::PublicKey, - Option, + ng_threshold_crypto::PublicKey, + Option, ), ), None, // the total_order quorum is not defined (yet, or anymore). there are no signers for the total_order, neither for the partial_order. The owners replace them. @@ -2527,7 +2527,7 @@ pub struct CertificateContentV0 { pub readcap_id: ObjectId, /// PublicKey used by the Owners. verifier uses this PK if the signature was issued by the Owners. - pub owners_pk_set: threshold_crypto::PublicKey, + pub owners_pk_set: ng_threshold_crypto::PublicKey, /// two "orders" PublicKeys (total_order and partial_order). pub orders_pk_sets: OrdersPublicKeySetsV0, @@ -2539,14 +2539,14 @@ pub enum CertificateSignatureV0 { /// the root CertificateContentV0 is signed with the PrivKey of the Repo Repo(Sig), /// Any other certificate in the chain of trust is signed by the total_order quorum of the previous certificate, hence establishing the chain of trust. - TotalOrder(threshold_crypto::Signature), + TotalOrder(ng_threshold_crypto::Signature), /// if the previous cert's total order PKset has a threshold value of 0 or 1 (1 or 2 signers in the quorum), /// then it is allowed that the next certificate (this one) will be signed by the owners PKset instead. /// This is for a simple reason: if a user is removed from the list of signers in the total_order quorum, /// then in those 2 cases, the excluded signer will probably not cooperate to their exclusion, and will not sign the new certificate. /// to avoid deadlocks, we allow the owners to step in and sign the new cert instead. /// The Owners are also used when there is no quorum/signer defined (OrdersPublicKeySetsV0::None). - Owners(threshold_crypto::Signature), + Owners(ng_threshold_crypto::Signature), /// in case the new certificate being signed is an update on the store certificate (OrdersPublicKeySetsV0::Store(ObjectRef) has changed from previous cert) /// then the signature is in that new store certificate, and not here. nothing else should have changed in the CertificateContent, and the validity of the new store cert has to be checked Store, @@ -2570,7 +2570,7 @@ impl CertificateV0 { _ => Err(NgError::InvalidArgument), } } - pub fn get_owners_pub_key(&self) -> &threshold_crypto::PublicKey { + pub fn get_owners_pub_key(&self) -> &ng_threshold_crypto::PublicKey { &self.content.owners_pk_set } } diff --git a/ng-sdk-js/app-node/index.js b/ng-sdk-js/app-node/index.js index 98cabf78..f2bf8b02 100644 --- a/ng-sdk-js/app-node/index.js +++ b/ng-sdk-js/app-node/index.js @@ -23,7 +23,7 @@ global.WebSocket = WebSocket; const fs = require('fs'); -let buffer = fs.readFileSync("/Users/nl/Downloads/wallet-Hr-UITwGtjE1k6lXBoVGzD4FQMiDkM3T6bSeAi9PXt4A.ngw"); +let buffer = fs.readFileSync("/home/nn/Downloads/wallet-bCHhOmlelVtZ60jjGu7m-YtzF4TfD5WyErAMnEDOn-kA.ngw"); ng.wallet_read_file(buffer).then(async (wallet)=>{ console.log("start"); @@ -31,18 +31,8 @@ ng.wallet_read_file(buffer).then(async (wallet)=>{ //let wal = await ng.gen_wallet_for_test("rS6pZiroUZ5yjq9eraesDkpxWWOAoX_8QZ_5U9GXsOgA"); //console.log(wal); - let opened_wallet = await ng.wallet_open_with_mnemonic_words(wallet, ["jealous", - "during", - "elevator", - "swallow", - "pen", - "phone", - "like", - "employ", - "myth", - "remember", - "question", - "lemon"], + let opened_wallet = await ng.wallet_open_with_mnemonic_words(wallet, [ + "mutual", "wife", "section", "actual", "spend", "illness", "save", "delay", "kiss", "crash", "baby", "degree" ], [2, 3, 2, 3]); let user_id = opened_wallet.V0.personal_site; @@ -75,9 +65,9 @@ ng.wallet_read_file(buffer).then(async (wallet)=>{ console.log("==== END of DUMP ===="); // we create a new document in the protected store of the user. - //let nuri = await ng.doc_create(session_id, "Graph", "data:graph", "protected", protected_repo_id, "store"); + let nuri = await ng.doc_create(session_id, "Graph", "data:graph", "store", "protected", protected_repo_id ); // once you have created a document, you can reuse its Nuri by entering it in the line below, remove the commenting, and comment out the above line - let nuri = "did:ng:o:W6GCQRfQkNTLtSS_2-QhKPJPkhEtLVh-B5lzpWMjGNEA:v:h8ViqyhCYMS2I6IKwPrY6UZi4ougUm1gpM4QnxlmNMQA"; + //let nuri = "did:ng:o:W6GCQRfQkNTLtSS_2-QhKPJPkhEtLVh-B5lzpWMjGNEA:v:h8ViqyhCYMS2I6IKwPrY6UZi4ougUm1gpM4QnxlmNMQA"; console.log("nuri=",nuri); let base = nuri.substring(0,53); console.log("base=",base); @@ -85,40 +75,41 @@ ng.wallet_read_file(buffer).then(async (wallet)=>{ // EXAMPLE OF SUBSCRIBING TO A DOCUMENT. base is the Nuri half first part (the document ID proper). //call unsub when you are done subscribing you don't want to receive updates anymore - let unsub = await ng.doc_subscribe(base, session_id, - async (response) => { + // let unsub = await ng.doc_subscribe(base, session_id, + // async (response) => { - if (response.V0.State?.graph) { + // if (response.V0.State?.graph) { - let json_str = new TextDecoder().decode(response.V0.State.graph.triples); - triples = JSON.parse(json_str); + // let json_str = new TextDecoder().decode(response.V0.State.graph.triples); + // triples = JSON.parse(json_str); - for (const triple of triples){ - // deal with each triple - console.log("STATE",triple); - } + // for (const triple of triples){ + // // deal with each triple + // console.log("STATE",triple); + // } - } else if (response.V0.Patch?.graph) { + // } else if (response.V0.Patch?.graph) { - let inserts_json_str = new TextDecoder().decode(response.V0.Patch.graph.inserts); - let inserts = JSON.parse(inserts_json_str); - let removes_json_str = new TextDecoder().decode(response.V0.Patch.graph.removes); - let removes = JSON.parse(removes_json_str); - - for (const insert of inserts){ - // deal with each insert - console.log("INSERT",insert); - } - for (const remove of removes){ - // deal with each remove - console.log("REMOVE",remove); - } + // let inserts_json_str = new TextDecoder().decode(response.V0.Patch.graph.inserts); + // let inserts = JSON.parse(inserts_json_str); + // let removes_json_str = new TextDecoder().decode(response.V0.Patch.graph.removes); + // let removes = JSON.parse(removes_json_str); + + // for (const insert of inserts){ + // // deal with each insert + // console.log("INSERT",insert); + // } + // for (const remove of removes){ + // // deal with each remove + // console.log("REMOVE",remove); + // } - } - } - ); + // } + // } + // ); - //await ng.sparql_update(session_id, "INSERT DATA { <> \"An example value1000\". }", nuri ); + let res = await ng.sparql_update(session_id, "INSERT DATA { <> \"An example value1000\". }", nuri ); + console.log(res); // SELECT // we use base to replace <> in the subject diff --git a/ng-sdk-js/prepare-node.js b/ng-sdk-js/prepare-node.js index f974a3d8..ae6e6d9e 100644 --- a/ng-sdk-js/prepare-node.js +++ b/ng-sdk-js/prepare-node.js @@ -6,7 +6,7 @@ const PATH_README = './pkg-node/README.md'; const pkg_json = fs.readFileSync(PATH); let pkg = JSON.parse(pkg_json) pkg.name = "nextgraph"; -pkg.version = "0.1.1-alpha.5"; +pkg.version = "0.1.1-alpha.7"; pkg.description = "nodeJS SDK of NextGraph"; pkg.files.push("ng_sdk_js_bg.wasm.d.ts"); pkg.files.push("snippets/**/*.js"); diff --git a/ng-sdk-js/src/lib.rs b/ng-sdk-js/src/lib.rs index 723a6e37..8a3d4e96 100644 --- a/ng-sdk-js/src/lib.rs +++ b/ng-sdk-js/src/lib.rs @@ -409,7 +409,7 @@ pub async fn sparql_update( session_id: JsValue, sparql: String, nuri: JsValue, -) -> Result<(), String> { +) -> Result { let session_id: u64 = serde_wasm_bindgen::from_value::(session_id) .map_err(|_| "Invalid session_id".to_string())?; @@ -432,10 +432,10 @@ pub async fn sparql_update( let res = nextgraph::local_broker::app_request(request) .await .map_err(|e: NgError| e.to_string())?; - if let AppResponse::V0(AppResponseV0::Error(e)) = res { - Err(e) - } else { - Ok(()) + match res { + AppResponse::V0(AppResponseV0::Error(e)) => Err(e), + AppResponse::V0(AppResponseV0::Commits(commits)) => Ok(serde_wasm_bindgen::to_value(&commits).unwrap()), + _ => Err(NgError::InvalidResponse.to_string()) } } @@ -1322,41 +1322,18 @@ pub async fn doc_create( session_id: JsValue, crdt: String, class_name: String, - store_repo: JsValue, destination: String, + store_repo: JsValue, ) -> Result { let session_id: u64 = serde_wasm_bindgen::from_value::(session_id) .map_err(|_| "Deserialization error of session_id".to_string())?; - let class = BranchCrdt::from(crdt, class_name).map_err(|e| e.to_string())?; - - let store = serde_wasm_bindgen::from_value::(store_repo) + let store_repo = serde_wasm_bindgen::from_value::>(store_repo) .map_err(|_| "Deserialization error of store_repo".to_string())?; - let destination = DocCreateDestination::from(destination).map_err(|e| e.to_string())?; - - let request = AppRequest::V0(AppRequestV0 { - session_id, - command: AppRequestCommandV0::new_create(), - nuri: NuriV0::new_empty(), - payload: Some(AppRequestPayload::V0(AppRequestPayloadV0::Create( - DocCreate { - store, - class, - destination, - }, - ))), - }); - - let response = nextgraph::local_broker::app_request(request) + nextgraph::local_broker::doc_create_with_store_repo(session_id, crdt, class_name, destination, store_repo) .await - .map_err(|e: NgError| e.to_string())?; - - if let AppResponse::V0(AppResponseV0::Nuri(nuri)) = response { - Ok(serde_wasm_bindgen::to_value(&nuri).unwrap()) - } else { - Err("invalid response".to_string()) - } + .map_err(|e| e.to_string()).map(|nuri| serde_wasm_bindgen::to_value(&nuri).unwrap()) } #[cfg(wasmpack_target = "nodejs")] @@ -1365,42 +1342,22 @@ pub async fn doc_create( session_id: JsValue, crdt: String, class_name: String, - store_type: String, - store_repo: String, destination: String, + store_type: JsValue, + store_repo: JsValue, ) -> Result { let session_id: u64 = serde_wasm_bindgen::from_value::(session_id) .map_err(|_| "Deserialization error of session_id".to_string())?; - let class = BranchCrdt::from(crdt, class_name).map_err(|e| e.to_string())?; + let store_type = serde_wasm_bindgen::from_value::>(store_type) + .map_err(|_| "Deserialization error of store_type".to_string())?; - let store = StoreRepo::from_type_and_repo(&store_type, &store_repo) - .map_err(|_| "invalid store_repo".to_string())?; - - let destination = DocCreateDestination::from(destination).map_err(|e| e.to_string())?; - - let request = AppRequest::V0(AppRequestV0 { - session_id, - command: AppRequestCommandV0::new_create(), - nuri: NuriV0::new_empty(), - payload: Some(AppRequestPayload::V0(AppRequestPayloadV0::Create( - DocCreate { - store, - class, - destination, - }, - ))), - }); + let store_repo = serde_wasm_bindgen::from_value::>(store_repo) + .map_err(|_| "Deserialization error of store_repo".to_string())?; - let response = nextgraph::local_broker::app_request(request) + nextgraph::local_broker::doc_create(session_id, crdt, class_name, destination, store_type, store_repo) .await - .map_err(|e: NgError| e.to_string())?; - - if let AppResponse::V0(AppResponseV0::Nuri(nuri)) = response { - Ok(serde_wasm_bindgen::to_value(&nuri).unwrap()) - } else { - Err("invalid response".to_string()) - } + .map_err(|e| e.to_string()).map(|nuri| serde_wasm_bindgen::to_value(&nuri).unwrap()) } #[wasm_bindgen] diff --git a/ng-sdk-python/pyproject.toml b/ng-sdk-python/pyproject.toml index f51a2d1b..2cbbff9d 100644 --- a/ng-sdk-python/pyproject.toml +++ b/ng-sdk-python/pyproject.toml @@ -12,6 +12,6 @@ classifiers = [ "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ] -version = "0.1a1.dev2" +version = "0.1a1.dev4" [tool.maturin] features = ["pyo3/extension-module"] diff --git a/ng-sdk-python/src/lib.rs b/ng-sdk-python/src/lib.rs index dd921fb5..aba840d9 100644 --- a/ng-sdk-python/src/lib.rs +++ b/ng-sdk-python/src/lib.rs @@ -21,10 +21,11 @@ use ::nextgraph::local_broker::{ wallet_get_file, wallet_import, wallet_read_file, wallet_was_opened, LocalBrokerConfig, SessionConfig, }; +use ::nextgraph::net::app_protocol::*; use ::nextgraph::net::types::BootstrapContentV0; use ::nextgraph::repo::errors::NgError; use ::nextgraph::repo::log::*; -use ::nextgraph::repo::types::PubKey; +use ::nextgraph::repo::types::{BranchCrdt, StoreRepo, PubKey}; use ::nextgraph::wallet::types::{CreateWalletV0, SessionInfo}; use ::nextgraph::wallet::{display_mnemonic, emojis::display_pazzle}; use async_std::stream::StreamExt; @@ -104,10 +105,10 @@ fn doc_sparql_update( nuri: Option, ) -> PyResult> { pyo3_async_runtimes::async_std::future_into_py(py, async move { - ::nextgraph::local_broker::doc_sparql_update(session_id, sparql, nuri) + let res = ::nextgraph::local_broker::doc_sparql_update(session_id, sparql, nuri) .await .map_err(|e| PyTypeError::new_err(e))?; - Ok(()) + Ok(res) }) } @@ -136,10 +137,31 @@ fn disconnect_and_close<'a>( }) } +#[pyfunction] +#[pyo3(signature = (session_id, crdt, class_name, destination="store".to_string(), store_type=None, store_repo=None))] +fn doc_create( + py: Python, + session_id: u64, + crdt: String, + class_name: String, + destination: String, + store_type: Option, + store_repo: Option, +) -> PyResult> { + pyo3_async_runtimes::async_std::future_into_py(py, async move { + + Ok(nextgraph::local_broker::doc_create(session_id, crdt, class_name, destination, store_type, store_repo) + .await + .map_err(|e| Into::::into(e))? + ) + }) +} + #[pymodule] fn nextgraphpy(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(wallet_open_with_mnemonic_words, m)?)?; m.add_function(wrap_pyfunction!(doc_sparql_update, m)?)?; m.add_function(wrap_pyfunction!(disconnect_and_close, m)?)?; + m.add_function(wrap_pyfunction!(doc_create, m)?)?; Ok(()) } diff --git a/ng-sdk-python/test.py b/ng-sdk-python/test.py index 76d3d732..00f2258e 100644 --- a/ng-sdk-python/test.py +++ b/ng-sdk-python/test.py @@ -1,29 +1,21 @@ import asyncio -from nextgraphpy import wallet_open_with_mnemonic_words, doc_sparql_update, disconnect_and_close +from nextgraphpy import wallet_open_with_mnemonic_words, doc_create, doc_sparql_update, disconnect_and_close async def main(): wallet_session = await wallet_open_with_mnemonic_words( - "/Users/nl/Downloads/wallet-Hr-UITwGtjE1k6lXBoVGzD4FQMiDkM3T6bSeAi9PXt4A.ngw", - ["jealous", - "during", - "elevator", - "swallow", - "pen", - "phone", - "like", - "employ", - "myth", - "remember", - "question", - "lemon"], + "/home/nn/Downloads/wallet-bCHhOmlelVtZ60jjGu7m-YtzF4TfD5WyErAMnEDOn-kA.ngw", + ["mutual", "wife", "section", "actual", "spend", "illness", "save", "delay", "kiss", "crash", "baby", "degree" ], [2, 3, 2, 3]) wallet_name = wallet_session[0] session_info = wallet_session[1] + session_id = session_info["session_id"] print(wallet_name) print(session_info) - await doc_sparql_update(session_info["session_id"], - "INSERT DATA { \"An example value22\". }", - "did:ng:o:Dn0QpE9_4jhta1mUWRl_LZh1SbXUkXfOB5eu38PNIk4A:v:Z4ihjV3KMVIqBxzjP6hogVLyjkZunLsb7MMsCR0kizQA") + doc_id = await doc_create(session_id, "Graph", "data:graph", "store") + print(doc_id) + commits = await doc_sparql_update(session_id, + "INSERT DATA { \"An example value22\". }", doc_id) + print(commits) await disconnect_and_close(session_info["user"], wallet_name) asyncio.run(main()) \ No newline at end of file diff --git a/ng-verifier/src/commits/transaction.rs b/ng-verifier/src/commits/transaction.rs index 09380a39..648625bf 100644 --- a/ng-verifier/src/commits/transaction.rs +++ b/ng-verifier/src/commits/transaction.rs @@ -402,7 +402,7 @@ impl Verifier { inserts: Vec, removes: Vec, peer_id: Vec, - ) -> Result<(), VerifierError> { + ) -> Result, VerifierError> { // options when not a publisher on the repo: // - skip // - TODO: abort (the whole transaction) @@ -522,7 +522,7 @@ impl Verifier { async fn update_graph( &mut self, mut updates: Vec, - ) -> Result<(), VerifierError> { + ) -> Result, VerifierError> { let updates_ref = &mut updates; let res = self .graph_dataset @@ -685,58 +685,63 @@ impl Verifier { }, ) .map_err(|e| VerifierError::OxigraphError(e.to_string())); - if res.is_ok() { - for update in updates { - if update.branch_type.is_header() { - let mut tab_doc_info = AppTabDocInfo::new(); - for removed in update.transaction.removes { - match removed.predicate.as_str() { - NG_ONTOLOGY_ABOUT => tab_doc_info.description = Some("".to_string()), - NG_ONTOLOGY_TITLE => tab_doc_info.title = Some("".to_string()), - _ => {} + match res { + Ok(()) => { + let mut commit_nuris = Vec::with_capacity(updates.len()); + for update in updates { + if update.branch_type.is_header() { + let mut tab_doc_info = AppTabDocInfo::new(); + for removed in update.transaction.removes { + match removed.predicate.as_str() { + NG_ONTOLOGY_ABOUT => tab_doc_info.description = Some("".to_string()), + NG_ONTOLOGY_TITLE => tab_doc_info.title = Some("".to_string()), + _ => {} + } } - } - for inserted in update.transaction.inserts { - match inserted.predicate.as_str() { - NG_ONTOLOGY_ABOUT => { - if let Term::Literal(l) = inserted.object { - tab_doc_info.description = Some(l.value().to_string()) + for inserted in update.transaction.inserts { + match inserted.predicate.as_str() { + NG_ONTOLOGY_ABOUT => { + if let Term::Literal(l) = inserted.object { + tab_doc_info.description = Some(l.value().to_string()) + } } - } - NG_ONTOLOGY_TITLE => { - if let Term::Literal(l) = inserted.object { - tab_doc_info.title = Some(l.value().to_string()) + NG_ONTOLOGY_TITLE => { + if let Term::Literal(l) = inserted.object { + tab_doc_info.title = Some(l.value().to_string()) + } } + _ => {} } - _ => {} } + self.push_app_response( + &update.branch_id, + AppResponse::V0(AppResponseV0::TabInfo(AppTabInfo { + branch: None, + doc: Some(tab_doc_info), + store: None, + })), + ) + .await; + } else { + let graph_patch = update.transaction.as_patch(); + commit_nuris.push(NuriV0::commit(&update.repo_id, &update.commit_id)); + self.push_app_response( + &update.branch_id, + AppResponse::V0(AppResponseV0::Patch(AppPatch { + commit_id: update.commit_id.to_string(), + commit_info: update.commit_info, + graph: Some(graph_patch), + discrete: None, + other: None, + })), + ) + .await; } - self.push_app_response( - &update.branch_id, - AppResponse::V0(AppResponseV0::TabInfo(AppTabInfo { - branch: None, - doc: Some(tab_doc_info), - store: None, - })), - ) - .await; - } else { - let graph_patch = update.transaction.as_patch(); - self.push_app_response( - &update.branch_id, - AppResponse::V0(AppResponseV0::Patch(AppPatch { - commit_id: update.commit_id.to_string(), - commit_info: update.commit_info, - graph: Some(graph_patch), - discrete: None, - other: None, - })), - ) - .await; } - } + Ok(commit_nuris) + }, + Err(e) => Err(e) } - res } pub(crate) async fn process_sparql_update( @@ -745,7 +750,7 @@ impl Verifier { query: &String, base: &Option, peer_id: Vec, - ) -> Result<(), String> { + ) -> Result, String> { let store = self.graph_dataset.as_ref().unwrap(); let update = ng_oxigraph::oxigraph::sparql::Update::parse(query, base.as_deref()) @@ -760,7 +765,7 @@ impl Verifier { Err(e) => Err(e.to_string()), Ok((inserts, removes)) => { if inserts.is_empty() && removes.is_empty() { - Ok(()) + Ok(vec![]) } else { self.prepare_sparql_update( Vec::from_iter(inserts), diff --git a/ng-verifier/src/request_processor.rs b/ng-verifier/src/request_processor.rs index 46ee419e..9baa017b 100644 --- a/ng-verifier/src/request_processor.rs +++ b/ng-verifier/src/request_processor.rs @@ -633,30 +633,31 @@ impl Verifier { let user_id = self.user_id().clone(); let user_priv_key = self.user_privkey().clone(); let primary_class = doc_create.class.class().clone(); + let (_,_,store) = self.resolve_target(&nuri.target)?; let repo_id = self .new_repo_default( &user_id, &user_priv_key, - &doc_create.store, + &store, doc_create.class, ) .await?; let header_branch_id = { - let repo = self.get_repo(&repo_id, &doc_create.store)?; + let repo = self.get_repo(&repo_id, &store)?; repo.header_branch().ok_or(NgError::BranchNotFound)?.id }; // adding an AddRepo commit to the Store branch of store. - self.send_add_repo_to_store(&repo_id, &doc_create.store) + self.send_add_repo_to_store(&repo_id, &store) .await?; // adding an ldp:contains triple to the store main branch - let overlay_id = doc_create.store.outer_overlay(); + let overlay_id = store.outer_overlay(); let nuri = NuriV0::repo_id(&repo_id); let nuri_result = NuriV0::repo_graph_name(&repo_id, &overlay_id); - let store_nuri = NuriV0::from_store_repo(&doc_create.store); - let store_nuri_string = NuriV0::repo_id(doc_create.store.repo_id()); + let store_nuri = NuriV0::from_store_repo(&store); + let store_nuri_string = NuriV0::repo_id(store.repo_id()); let query = format!("INSERT DATA {{ <{store_nuri_string}> <{nuri}>. }}"); let ret = self @@ -789,7 +790,7 @@ impl Verifier { .await { Err(e) => AppResponse::error(e), - Ok(_) => AppResponse::ok(), + Ok(commits) => AppResponse::commits(commits), }, ) } else {