forked from NextGraph/nextgraph-rs
Compare commits
16 Commits
no-need-cr
...
master
Author | SHA1 | Date |
---|---|---|
|
3916dbbfd2 | 3 weeks ago |
|
fed970b55d | 3 weeks ago |
|
abbc63c7a0 | 3 weeks ago |
|
6aa87f1467 | 3 weeks ago |
|
7331289e0f | 3 weeks ago |
|
33e8942a0f | 4 weeks ago |
|
5bfe3750b6 | 4 weeks ago |
|
aff711f505 | 4 weeks ago |
|
da0f550a79 | 4 weeks ago |
|
24521c1009 | 4 weeks ago |
|
63786fa15b | 4 weeks ago |
|
0d038af076 | 4 weeks ago |
|
f3ffc5ce70 | 4 weeks ago |
|
e3e04ce1bd | 4 weeks ago |
|
cf30aee425 | 1 month ago |
|
4ed3670cb6 | 1 month ago |
@ -0,0 +1,103 @@ |
||||
// Copyright (c) 2022-2025 Niko Bonnieure, Par le Peuple, NextGraph.org developers
|
||||
// All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
|
||||
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::fs::read; |
||||
|
||||
use async_std::stream::StreamExt; |
||||
#[allow(unused_imports)] |
||||
use nextgraph::local_broker::{ |
||||
app_request, app_request_stream, doc_fetch_repo_subscribe, doc_sparql_update, |
||||
init_local_broker, session_start, session_stop, user_connect, user_disconnect, wallet_close, |
||||
wallet_create_v0, wallet_get, wallet_get_file, wallet_import, wallet_open_with_mnemonic_words, |
||||
wallet_read_file, wallet_was_opened, LocalBrokerConfig, SessionConfig, |
||||
}; |
||||
use nextgraph::net::types::BootstrapContentV0; |
||||
use nextgraph::repo::errors::NgError; |
||||
use nextgraph::repo::log::*; |
||||
use nextgraph::repo::types::PubKey; |
||||
use nextgraph::wallet::types::CreateWalletV0; |
||||
use nextgraph::wallet::{display_mnemonic, emojis::display_pazzle}; |
||||
|
||||
#[async_std::main] |
||||
async fn main() -> std::io::Result<()> { |
||||
// initialize the local_broker with in-memory config.
|
||||
// all sessions will be lost when the program exits
|
||||
init_local_broker(Box::new(|| LocalBrokerConfig::InMemory)).await; |
||||
|
||||
let wallet_file = |
||||
read("/Users/nl/Downloads/wallet-Hr-UITwGtjE1k6lXBoVGzD4FQMiDkM3T6bSeAi9PXt4A.ngw") |
||||
.expect("read wallet file"); |
||||
|
||||
let wallet = wallet_read_file(wallet_file).await?; |
||||
|
||||
let mnemonic_words = vec![ |
||||
"jealous".to_string(), |
||||
"during".to_string(), |
||||
"elevator".to_string(), |
||||
"swallow".to_string(), |
||||
"pen".to_string(), |
||||
"phone".to_string(), |
||||
"like".to_string(), |
||||
"employ".to_string(), |
||||
"myth".to_string(), |
||||
"remember".to_string(), |
||||
"question".to_string(), |
||||
"lemon".to_string(), |
||||
]; |
||||
|
||||
let opened_wallet = wallet_open_with_mnemonic_words(&wallet, &mnemonic_words, [2, 3, 2, 3])?; |
||||
|
||||
let user_id = opened_wallet.personal_identity(); |
||||
let wallet_name = opened_wallet.name(); |
||||
|
||||
let client = wallet_import(wallet.clone(), opened_wallet, true).await?; |
||||
|
||||
let session = session_start(SessionConfig::new_in_memory(&user_id, &wallet_name)).await?; |
||||
|
||||
// let session = session_start(SessionConfig::new_remote(&user_id, &wallet_name, None)).await?;
|
||||
|
||||
// if the user has internet access, they can now decide to connect to its Server Broker, in order to sync data
|
||||
let status = user_connect(&user_id).await?; |
||||
|
||||
let result = doc_sparql_update( |
||||
session.session_id, |
||||
"INSERT DATA { <did:ng:_> <example:predicate> \"An example value10\". }".to_string(), |
||||
Some("did:ng:o:Dn0QpE9_4jhta1mUWRl_LZh1SbXUkXfOB5eu38PNIk4A:v:Z4ihjV3KMVIqBxzjP6hogVLyjkZunLsb7MMsCR0kizQA".to_string()), |
||||
) |
||||
.await; |
||||
|
||||
log_debug!("{:?}", result); |
||||
|
||||
// // a session ID has been assigned to you in `session.session_id` you can use it to fetch a document
|
||||
// let (mut receiver, cancel) = doc_fetch_repo_subscribe(
|
||||
// session.session_id,
|
||||
// "did:ng:o:Dn0QpE9_4jhta1mUWRl_LZh1SbXUkXfOB5eu38PNIk4A".to_string(),
|
||||
// )
|
||||
// .await?;
|
||||
|
||||
// cancel();
|
||||
|
||||
// while let Some(app_response) = receiver.next().await {
|
||||
// let (inserts, removes) =
|
||||
// nextgraph::verifier::read_triples_in_app_response_from_rust(app_response)?;
|
||||
// log_debug!("inserts {:?}", inserts);
|
||||
// log_debug!("removes {:?}", removes);
|
||||
// }
|
||||
|
||||
// Then we should disconnect
|
||||
user_disconnect(&user_id).await?; |
||||
|
||||
// stop the session
|
||||
session_stop(&user_id).await?; |
||||
|
||||
// closes the wallet
|
||||
wallet_close(&wallet_name).await?; |
||||
|
||||
Ok(()) |
||||
} |
@ -0,0 +1,319 @@ |
||||
<!-- |
||||
// Copyright (c) 2022-2025 Niko Bonnieure, Par le Peuple, NextGraph.org developers |
||||
// All rights reserved. |
||||
// Licensed under the Apache License, Version 2.0 |
||||
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0> |
||||
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>, |
||||
// at your option. All files in the project carrying such |
||||
// notice may not be copied, modified, or distributed except |
||||
// according to those terms. |
||||
--> |
||||
|
||||
<script lang="ts"> |
||||
import { t, format } from "svelte-i18n"; |
||||
import { Alert, Spinner } from "flowbite-svelte"; |
||||
import { |
||||
ArrowLeft, |
||||
ExclamationTriangle, |
||||
Cloud, |
||||
ChevronDoubleRight, |
||||
} from "svelte-heros-v2"; |
||||
import { onDestroy, onMount, tick } from "svelte"; |
||||
import { push } from "svelte-spa-router"; |
||||
import CenteredLayout from "../lib/CenteredLayout.svelte"; |
||||
import PasswordInput from "../lib/components/PasswordInput.svelte"; |
||||
import { wallet_from_import, display_error } from "../store"; |
||||
import ng from "../api"; |
||||
|
||||
let top: HTMLElement; |
||||
|
||||
const set_online = () => { connected = true; }; |
||||
const set_offline = () => { connected = false; }; |
||||
|
||||
let error; |
||||
let connected = true; |
||||
let tauri_platform = import.meta.env.TAURI_PLATFORM; |
||||
let pre_invitation = false; |
||||
let domain = undefined; |
||||
let for_opaque = undefined ; |
||||
let state: "username" | "password" | "connecting" = "username"; |
||||
|
||||
function scrollToTop() { |
||||
top.scrollIntoView(); |
||||
} |
||||
|
||||
onMount(async () => { |
||||
connected = window.navigator.onLine; |
||||
window.addEventListener("offline", set_offline); |
||||
window.addEventListener("online", set_online); |
||||
state = "username"; |
||||
username = ""; |
||||
if (!tauri_platform) { |
||||
let res = await ng.get_local_bootstrap_and_domain( |
||||
import.meta.env.PROD ? location.href : "http://localhost:14400" |
||||
); |
||||
pre_invitation = res[0]; |
||||
domain = res[1]; |
||||
console.log("pre_invitation", pre_invitation, domain); |
||||
} |
||||
scrollToTop(); |
||||
await tick(); |
||||
username_input.focus(); |
||||
}); |
||||
onDestroy(() => { |
||||
window.removeEventListener("offline", set_offline); |
||||
window.removeEventListener("online", set_online); |
||||
}); |
||||
|
||||
let password = ""; |
||||
const validate_password = async () => { |
||||
|
||||
console.log(password, for_opaque); |
||||
|
||||
} |
||||
let username_input; |
||||
let username = ""; |
||||
let redirect = undefined; |
||||
const domainRegex = /^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}$/i; |
||||
const usernameRegex = /^[a-zA-Z_]+[a-zA-Z0-9_-]*$/; |
||||
const validate_username = async (e: any) => { |
||||
if (!e || e.key == "Enter" || e.keyCode == 13) { |
||||
username_input.blur(); |
||||
if (pre_invitation) { |
||||
if (!domain) { |
||||
let u = username.trim(); |
||||
if (u.includes("@")) { |
||||
syntax_error = $t("pages.wallet_login_username.error.nodomainplease"); |
||||
} else if (!usernameRegex.test(u)) { |
||||
syntax_error = $t("pages.wallet_login_username.error.username"); |
||||
} else { |
||||
for_opaque = pre_invitation.V0.bootstrap; |
||||
for_opaque.username = u; |
||||
next(); |
||||
} |
||||
} else { |
||||
let parts = username.trim().split("@"); |
||||
if (!usernameRegex.test(parts[0])) { |
||||
syntax_error = $t("pages.wallet_login_username.error.username"); |
||||
} |
||||
else if ( parts[1] === domain || !parts[1] ) { |
||||
username = parts[0]; |
||||
for_opaque = pre_invitation.V0.bootstrap; |
||||
for_opaque.username = username; |
||||
next(); |
||||
} else { |
||||
// testing that domain is valid |
||||
if (!domainRegex.test(parts[1])) { |
||||
syntax_error = $t("pages.wallet_login_username.error.invalid_domain"); |
||||
} else { |
||||
redirect = `https://${parts[1]}/#/wallet/username?u=${parts[0]}`; |
||||
syntax_error = $t("pages.wallet_login_username.error.need_redirect"); |
||||
// TODO: when receiving a ?u=... after fetching it with opaque, if the wallet is already present locally, dont show an error, just log in with the username/password. |
||||
} |
||||
} |
||||
} |
||||
} else if (tauri_platform) { |
||||
let parts = username.trim().split("@"); |
||||
if (!usernameRegex.test(parts[0])) { |
||||
syntax_error = $t("pages.wallet_login_username.error.username"); |
||||
} |
||||
else if (!parts[1]) { |
||||
syntax_error = $t("pages.wallet_login_username.error.mandatory_domain"); |
||||
} else { |
||||
// testing that domain is valid |
||||
if (!domainRegex.test(parts[1])) { |
||||
syntax_error = $t("pages.wallet_login_username.error.invalid_domain"); |
||||
} else { |
||||
// fetching the .ng_bootstrap of the domain |
||||
state = "connecting"; |
||||
try { |
||||
let bootstrap_info = await ng.retrieve_ng_bootstrap(`https://${parts[1]}`); |
||||
for_opaque = bootstrap_info.V0.bootstrap; |
||||
for_opaque.username = parts[0]; |
||||
// do opaque with that |
||||
next(); |
||||
} catch (e) { |
||||
error = e; |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
syntax_error = "your local broker cannot be found (unexpected error)"; |
||||
} |
||||
} |
||||
}; |
||||
let placeholder = ""; |
||||
$: placeholder = pre_invitation ? domain ? $format("pages.wallet_login_username.username_placeholder_without_domain", { |
||||
values: { domain }}) : $t("pages.wallet_login_username.username_placeholder_without_at") : |
||||
$t("pages.wallet_login_username.username_placeholder_domain"); |
||||
let warning = ""; |
||||
$: warning = domain && username.trim().endsWith("@"+domain) && $format("pages.wallet_login_username.warning.nospecificdomainplease", { |
||||
values: { domain }}) || pre_invitation && !domain && username.includes("@") |
||||
&& $t("pages.wallet_login_username.warning.nodomainplease") || ""; |
||||
const next = () => { |
||||
for_opaque.username = for_opaque.username.toLowerCase(); |
||||
state = "password"; |
||||
} |
||||
|
||||
let syntax_error = ""; |
||||
|
||||
</script> |
||||
|
||||
<CenteredLayout> |
||||
<div class="container3" bind:this={top}> |
||||
<div |
||||
class="flex flex-col justify-center max-w-md mb-5 bg-gray-60 overflow-y-auto py-4 dark:bg-gray-800" |
||||
> |
||||
<!-- Title --> |
||||
<div class="mx-6"> |
||||
<h2 class="text-xl mb-6">{$t("pages.wallet_login_username.title")}</h2> |
||||
</div> |
||||
|
||||
{#if !connected} |
||||
<!-- Warning, if offline --> |
||||
<div class="text-left mx-6"> |
||||
<Alert color="red"> |
||||
{@html $t("wallet_sync.offline_warning")} |
||||
</Alert> |
||||
<Alert color="blue" class="mt-4"> |
||||
{@html $t("pages.wallet_login.offline_advice")} |
||||
</Alert> |
||||
<!-- Go Back --> |
||||
<button |
||||
on:click={() => window.history.go(-1)} |
||||
class="mt-8 w-full text-gray-500 dark:text-gray-400 focus:ring-4 focus:ring-primary-100/50 rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55" |
||||
><ArrowLeft |
||||
tabindex="-1" |
||||
class="w-8 h-8 mr-2 -ml-1 transition duration-75 focus:outline-none group-hover:text-gray-900 dark:group-hover:text-white" |
||||
/>{$t("buttons.back")}</button |
||||
> |
||||
</div> |
||||
{:else if error} |
||||
<div class="max-w-6xl lg:px-8 mx-auto px-4 text-red-800"> |
||||
<ExclamationTriangle class="animate-bounce mt-10 h-16 w-16 mx-auto" /> |
||||
<p class="max-w-xl md:mx-auto lg:max-w-2xl mb-5"> |
||||
{@html $t("errors.error_occurred", { |
||||
values: { message: display_error(error) }, |
||||
})} |
||||
</p> |
||||
<button |
||||
on:click={() => window.history.go(-1)} |
||||
class="mt-8 mr-2 text-gray-500 dark:text-gray-400 focus:ring-4 focus:ring-primary-100/50 rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55" |
||||
><ArrowLeft |
||||
tabindex="-1" |
||||
class="w-8 h-8 mr-2 -ml-1 transition duration-75 focus:outline-none group-hover:text-gray-900 dark:group-hover:text-white" |
||||
/>{$t("buttons.back")}</button |
||||
> |
||||
</div> |
||||
{:else} |
||||
{#if state == "username"} |
||||
<div class="mx-6"> |
||||
<div class="mx-auto"> |
||||
<div class="my-4 mx-1 mt-4"> |
||||
{#if syntax_error} |
||||
<Alert color="red" class="mb-3"> |
||||
{syntax_error} |
||||
</Alert> |
||||
{/if} |
||||
{#if warning} |
||||
<Alert color="blue" class="mb-3"> |
||||
{warning} |
||||
</Alert> |
||||
{/if} |
||||
{$t("pages.wallet_login_username.username")} : |
||||
<input |
||||
bind:this={username_input} |
||||
class="w-[240px] mr-0" |
||||
id="username_input" |
||||
placeholder={placeholder} |
||||
bind:value={username} |
||||
on:keypress={validate_username} |
||||
on:focus={()=>{syntax_error="";redirect=undefined;}} |
||||
/> |
||||
<!-- Go Back --> |
||||
<button |
||||
on:click={() => {if (redirect) {username_input.focus();} else {window.history.go(-1)}}} |
||||
class="mt-8 mr-2 text-gray-500 dark:text-gray-400 focus:ring-4 focus:ring-primary-100/50 rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55" |
||||
><ArrowLeft |
||||
tabindex="-1" |
||||
class="w-8 h-8 mr-2 -ml-1 transition duration-75 focus:outline-none group-hover:text-gray-900 dark:group-hover:text-white" |
||||
/>{$t("buttons.back")}</button |
||||
> |
||||
{#if redirect} |
||||
<button |
||||
on:click={() => {window.location.href = redirect;}} |
||||
class="mt-4 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-100/50 rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55 mb-2" |
||||
> |
||||
<ChevronDoubleRight |
||||
tabindex="-1" |
||||
class="w-8 h-8 mr-2 -ml-1 transition duration-75 focus:outline-none group-hover:text-gray-900 dark:group-hover:text-white" |
||||
/> |
||||
{$t("pages.wallet_login_username.redirect")} |
||||
</button> |
||||
{:else} |
||||
<button |
||||
on:click={() => validate_username(null)} |
||||
class="mt-4 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-100/50 rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55 mb-2" |
||||
> |
||||
<ChevronDoubleRight |
||||
tabindex="-1" |
||||
class="w-8 h-8 mr-2 -ml-1 transition duration-75 focus:outline-none group-hover:text-gray-900 dark:group-hover:text-white" |
||||
/> |
||||
{$t("pages.wallet_login_username.next")} |
||||
</button> |
||||
{/if} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
{:else if state === "password"} |
||||
<div class="mx-6"> |
||||
<div class="mx-auto"> |
||||
<div class="my-4 mx-1 mt-4"> |
||||
{$t("pages.wallet_login_username.password")} : |
||||
<!-- <input |
||||
bind:this={password_input} |
||||
class="w-[240px] mr-0" |
||||
id="password_input" |
||||
bind:value={password} |
||||
on:keypress={validate_password} |
||||
/> --> |
||||
<PasswordInput |
||||
id="password_input" |
||||
placeholder={$t("pages.wallet_login_username.password_placeholder")} |
||||
bind:value={password} |
||||
on:enter={validate_password} |
||||
classNameToggle="right-[-26px]" |
||||
className="w-[240px] bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" |
||||
/> |
||||
<!-- Go Back --> |
||||
<button |
||||
on:click={async () => {state = "username";for_opaque = undefined; await tick(); username_input.focus();}} |
||||
class="mt-8 mr-1 text-gray-500 dark:text-gray-400 focus:ring-4 focus:ring-primary-100/50 rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55" |
||||
><ArrowLeft |
||||
tabindex="-1" |
||||
class="w-8 h-8 -ml-1 transition duration-75 focus:outline-none group-hover:text-gray-900 dark:group-hover:text-white" |
||||
/>{$t("buttons.back")}</button |
||||
> |
||||
<button |
||||
on:click={validate_password} |
||||
class="mt-4 text-white bg-primary-700 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-100/50 rounded-lg text-lg px-5 py-2.5 text-center inline-flex items-center dark:focus:ring-primary-700/55 mb-2" |
||||
> |
||||
<ChevronDoubleRight |
||||
tabindex="-1" |
||||
class="w-8 h-8 -ml-1 transition duration-75 focus:outline-none group-hover:text-gray-900 dark:group-hover:text-white" |
||||
/> |
||||
{$t("pages.wallet_login_username.connect")} |
||||
</button> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
{:else if state === "connecting"} |
||||
<div> |
||||
<Spinner class="w-full" /> |
||||
</div> |
||||
{/if} |
||||
{/if} |
||||
</div> |
||||
</div> |
||||
</CenteredLayout> |
@ -0,0 +1,3 @@ |
||||
pkg/* |
||||
pkg-node/* |
||||
web/* |
@ -0,0 +1,42 @@ |
||||
# app-node |
||||
|
||||
NodeJS demo client of NextGraph |
||||
|
||||
## NextGraph |
||||
|
||||
> NextGraph brings about the convergence of P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs. |
||||
> |
||||
> This open source ecosystem provides solutions for end-users (a platform) and software developers (a framework), wishing to use or create **decentralized** apps featuring: **live collaboration** on rich-text documents, peer to peer communication with **end-to-end encryption**, offline-first, **local-first**, portable and interoperable data, total ownership of data and software, security and privacy. Centered on repositories containing **semantic data** (RDF), **rich text**, and structured data formats like **JSON**, synced between peers belonging to permissioned groups of users, it offers strong eventual consistency, thanks to the use of **CRDTs**. Documents can be linked together, signed, shared securely, queried using the **SPARQL** language and organized into sites and containers. |
||||
> |
||||
> More info here [https://nextgraph.org](https://nextgraph.org) |
||||
|
||||
## For contributors |
||||
|
||||
Build the JS SDK |
||||
|
||||
``` |
||||
cd .. |
||||
cargo run-script node |
||||
``` |
||||
|
||||
``` |
||||
cd app-node |
||||
npm install --no-save ../pkg-node |
||||
npm start |
||||
``` |
||||
|
||||
Open this URL in browser : [http://localhost:8080](http://localhost:8080) |
||||
|
||||
## License |
||||
|
||||
Licensed under either of |
||||
|
||||
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0) |
||||
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) |
||||
at your option. |
||||
|
||||
`SPDX-License-Identifier: Apache-2.0 OR MIT` |
||||
|
||||
--- |
||||
|
||||
NextGraph received funding through the [NGI Assure Fund](https://nlnet.nl/assure) and the [NGI Zero Commons Fund](https://nlnet.nl/commonsfund/), both funds established by [NLnet](https://nlnet.nl/) Foundation with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme, under the aegis of DG Communications Networks, Content and Technology under grant agreements No 957073 and No 101092990, respectively. |
@ -1,117 +0,0 @@ |
||||
{ |
||||
"name": "ng-app-node", |
||||
"version": "0.1.0", |
||||
"lockfileVersion": 2, |
||||
"requires": true, |
||||
"packages": { |
||||
"": { |
||||
"name": "ng-app-node", |
||||
"version": "0.1.0", |
||||
"license": "(MIT OR Apache-2.0)", |
||||
"dependencies": { |
||||
"nextgraph": "^0.1.0", |
||||
"ws": "^8.13.0" |
||||
} |
||||
}, |
||||
"../pkg-node": { |
||||
"name": "nextgraph", |
||||
"version": "0.1.0", |
||||
"license": "MIT/Apache-2.0" |
||||
}, |
||||
"node_modules/bufferutil": { |
||||
"version": "4.0.7", |
||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", |
||||
"integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", |
||||
"hasInstallScript": true, |
||||
"optional": true, |
||||
"peer": true, |
||||
"dependencies": { |
||||
"node-gyp-build": "^4.3.0" |
||||
}, |
||||
"engines": { |
||||
"node": ">=6.14.2" |
||||
} |
||||
}, |
||||
"node_modules/node-gyp-build": { |
||||
"version": "4.6.0", |
||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", |
||||
"integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", |
||||
"optional": true, |
||||
"peer": true, |
||||
"bin": { |
||||
"node-gyp-build": "bin.js", |
||||
"node-gyp-build-optional": "optional.js", |
||||
"node-gyp-build-test": "build-test.js" |
||||
} |
||||
}, |
||||
"node_modules/utf-8-validate": { |
||||
"version": "5.0.10", |
||||
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", |
||||
"integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", |
||||
"hasInstallScript": true, |
||||
"optional": true, |
||||
"peer": true, |
||||
"dependencies": { |
||||
"node-gyp-build": "^4.3.0" |
||||
}, |
||||
"engines": { |
||||
"node": ">=6.14.2" |
||||
} |
||||
}, |
||||
"node_modules/ws": { |
||||
"version": "8.13.0", |
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", |
||||
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", |
||||
"engines": { |
||||
"node": ">=10.0.0" |
||||
}, |
||||
"peerDependencies": { |
||||
"bufferutil": "^4.0.1", |
||||
"utf-8-validate": ">=5.0.2" |
||||
}, |
||||
"peerDependenciesMeta": { |
||||
"bufferutil": { |
||||
"optional": true |
||||
}, |
||||
"utf-8-validate": { |
||||
"optional": true |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
"dependencies": { |
||||
"bufferutil": { |
||||
"version": "4.0.7", |
||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", |
||||
"integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", |
||||
"optional": true, |
||||
"peer": true, |
||||
"requires": { |
||||
"node-gyp-build": "^4.3.0" |
||||
} |
||||
}, |
||||
"node-gyp-build": { |
||||
"version": "4.6.0", |
||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", |
||||
"integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", |
||||
"optional": true, |
||||
"peer": true |
||||
}, |
||||
"utf-8-validate": { |
||||
"version": "5.0.10", |
||||
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", |
||||
"integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", |
||||
"optional": true, |
||||
"peer": true, |
||||
"requires": { |
||||
"node-gyp-build": "^4.3.0" |
||||
} |
||||
}, |
||||
"ws": { |
||||
"version": "8.13.0", |
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", |
||||
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", |
||||
"requires": {} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,181 @@ |
||||
# This file is autogenerated by maturin v1.8.2 |
||||
# To update, run |
||||
# |
||||
# maturin generate-ci github |
||||
# |
||||
name: CI |
||||
|
||||
on: |
||||
push: |
||||
branches: |
||||
- main |
||||
- master |
||||
tags: |
||||
- '*' |
||||
pull_request: |
||||
workflow_dispatch: |
||||
|
||||
permissions: |
||||
contents: read |
||||
|
||||
jobs: |
||||
linux: |
||||
runs-on: ${{ matrix.platform.runner }} |
||||
strategy: |
||||
matrix: |
||||
platform: |
||||
- runner: ubuntu-22.04 |
||||
target: x86_64 |
||||
- runner: ubuntu-22.04 |
||||
target: x86 |
||||
- runner: ubuntu-22.04 |
||||
target: aarch64 |
||||
- runner: ubuntu-22.04 |
||||
target: armv7 |
||||
- runner: ubuntu-22.04 |
||||
target: s390x |
||||
- runner: ubuntu-22.04 |
||||
target: ppc64le |
||||
steps: |
||||
- uses: actions/checkout@v4 |
||||
- uses: actions/setup-python@v5 |
||||
with: |
||||
python-version: 3.x |
||||
- name: Build wheels |
||||
uses: PyO3/maturin-action@v1 |
||||
with: |
||||
target: ${{ matrix.platform.target }} |
||||
args: --release --out dist --find-interpreter |
||||
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }} |
||||
manylinux: auto |
||||
- name: Upload wheels |
||||
uses: actions/upload-artifact@v4 |
||||
with: |
||||
name: wheels-linux-${{ matrix.platform.target }} |
||||
path: dist |
||||
|
||||
musllinux: |
||||
runs-on: ${{ matrix.platform.runner }} |
||||
strategy: |
||||
matrix: |
||||
platform: |
||||
- runner: ubuntu-22.04 |
||||
target: x86_64 |
||||
- runner: ubuntu-22.04 |
||||
target: x86 |
||||
- runner: ubuntu-22.04 |
||||
target: aarch64 |
||||
- runner: ubuntu-22.04 |
||||
target: armv7 |
||||
steps: |
||||
- uses: actions/checkout@v4 |
||||
- uses: actions/setup-python@v5 |
||||
with: |
||||
python-version: 3.x |
||||
- name: Build wheels |
||||
uses: PyO3/maturin-action@v1 |
||||
with: |
||||
target: ${{ matrix.platform.target }} |
||||
args: --release --out dist --find-interpreter |
||||
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }} |
||||
manylinux: musllinux_1_2 |
||||
- name: Upload wheels |
||||
uses: actions/upload-artifact@v4 |
||||
with: |
||||
name: wheels-musllinux-${{ matrix.platform.target }} |
||||
path: dist |
||||
|
||||
windows: |
||||
runs-on: ${{ matrix.platform.runner }} |
||||
strategy: |
||||
matrix: |
||||
platform: |
||||
- runner: windows-latest |
||||
target: x64 |
||||
- runner: windows-latest |
||||
target: x86 |
||||
steps: |
||||
- uses: actions/checkout@v4 |
||||
- uses: actions/setup-python@v5 |
||||
with: |
||||
python-version: 3.x |
||||
architecture: ${{ matrix.platform.target }} |
||||
- name: Build wheels |
||||
uses: PyO3/maturin-action@v1 |
||||
with: |
||||
target: ${{ matrix.platform.target }} |
||||
args: --release --out dist --find-interpreter |
||||
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }} |
||||
- name: Upload wheels |
||||
uses: actions/upload-artifact@v4 |
||||
with: |
||||
name: wheels-windows-${{ matrix.platform.target }} |
||||
path: dist |
||||
|
||||
macos: |
||||
runs-on: ${{ matrix.platform.runner }} |
||||
strategy: |
||||
matrix: |
||||
platform: |
||||
- runner: macos-13 |
||||
target: x86_64 |
||||
- runner: macos-14 |
||||
target: aarch64 |
||||
steps: |
||||
- uses: actions/checkout@v4 |
||||
- uses: actions/setup-python@v5 |
||||
with: |
||||
python-version: 3.x |
||||
- name: Build wheels |
||||
uses: PyO3/maturin-action@v1 |
||||
with: |
||||
target: ${{ matrix.platform.target }} |
||||
args: --release --out dist --find-interpreter |
||||
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }} |
||||
- name: Upload wheels |
||||
uses: actions/upload-artifact@v4 |
||||
with: |
||||
name: wheels-macos-${{ matrix.platform.target }} |
||||
path: dist |
||||
|
||||
sdist: |
||||
runs-on: ubuntu-latest |
||||
steps: |
||||
- uses: actions/checkout@v4 |
||||
- name: Build sdist |
||||
uses: PyO3/maturin-action@v1 |
||||
with: |
||||
command: sdist |
||||
args: --out dist |
||||
- name: Upload sdist |
||||
uses: actions/upload-artifact@v4 |
||||
with: |
||||
name: wheels-sdist |
||||
path: dist |
||||
|
||||
release: |
||||
name: Release |
||||
runs-on: ubuntu-latest |
||||
if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }} |
||||
needs: [linux, musllinux, windows, macos, sdist] |
||||
permissions: |
||||
# Use to sign the release artifacts |
||||
id-token: write |
||||
# Used to upload release artifacts |
||||
contents: write |
||||
# Used to generate artifact attestation |
||||
attestations: write |
||||
steps: |
||||
- uses: actions/download-artifact@v4 |
||||
- name: Generate artifact attestation |
||||
uses: actions/attest-build-provenance@v1 |
||||
with: |
||||
subject-path: 'wheels-*/*' |
||||
- name: Publish to PyPI |
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }} |
||||
uses: PyO3/maturin-action@v1 |
||||
env: |
||||
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} |
||||
with: |
||||
command: upload |
||||
args: --non-interactive --skip-existing wheels-*/* |
@ -0,0 +1,72 @@ |
||||
/target |
||||
.env/ |
||||
# Byte-compiled / optimized / DLL files |
||||
__pycache__/ |
||||
.pytest_cache/ |
||||
*.py[cod] |
||||
|
||||
# C extensions |
||||
*.so |
||||
|
||||
# Distribution / packaging |
||||
.Python |
||||
.venv/ |
||||
env/ |
||||
bin/ |
||||
build/ |
||||
develop-eggs/ |
||||
dist/ |
||||
eggs/ |
||||
lib/ |
||||
lib64/ |
||||
parts/ |
||||
sdist/ |
||||
var/ |
||||
include/ |
||||
man/ |
||||
venv/ |
||||
*.egg-info/ |
||||
.installed.cfg |
||||
*.egg |
||||
|
||||
# Installer logs |
||||
pip-log.txt |
||||
pip-delete-this-directory.txt |
||||
pip-selfcheck.json |
||||
|
||||
# Unit test / coverage reports |
||||
htmlcov/ |
||||
.tox/ |
||||
.coverage |
||||
.cache |
||||
nosetests.xml |
||||
coverage.xml |
||||
|
||||
# Translations |
||||
*.mo |
||||
|
||||
# Mr Developer |
||||
.mr.developer.cfg |
||||
.project |
||||
.pydevproject |
||||
|
||||
# Rope |
||||
.ropeproject |
||||
|
||||
# Django stuff: |
||||
*.log |
||||
*.pot |
||||
|
||||
.DS_Store |
||||
|
||||
# Sphinx documentation |
||||
docs/_build/ |
||||
|
||||
# PyCharm |
||||
.idea/ |
||||
|
||||
# VSCode |
||||
.vscode/ |
||||
|
||||
# Pyenv |
||||
.python-version |
@ -0,0 +1,25 @@ |
||||
[package] |
||||
name = "ng-sdk-python" |
||||
version.workspace = true |
||||
description = "NextGraph python package. Nextgraph is a decentralized, secure and local-first web 3.0 ecosystem based on Semantic Web and CRDTs" |
||||
edition.workspace = true |
||||
license.workspace = true |
||||
authors.workspace = true |
||||
repository.workspace = true |
||||
homepage.workspace = true |
||||
keywords = [ "crdt","e2ee","local-first","p2p","semantic-web" ] |
||||
documentation.workspace = true |
||||
rust-version.workspace = true |
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||
[lib] |
||||
name = "nextgraphpy" |
||||
crate-type = ["cdylib"] |
||||
|
||||
[dependencies] |
||||
pyo3 = "0.23.3" |
||||
pyo3-async-runtimes = { version = "0.23", features = ["async-std-runtime"] } |
||||
pythonize = "0.23.0" |
||||
async-std = "1.12.0" |
||||
serde = { version = "1.0.142", features = ["derive"] } |
||||
nextgraph = { path = "../nextgraph" } |
@ -0,0 +1,63 @@ |
||||
<p align="center"> |
||||
<img src="https://git.nextgraph.org/NextGraph/nextgraph-rs/raw/branch/master/nextgraph/.static/header.png" alt="nextgraph-header" /> |
||||
</p> |
||||
|
||||
# nextgraphpy |
||||
|
||||
![MSRV][rustc-image] |
||||
[![Apache 2.0 Licensed][license-image]][license-link] |
||||
[![MIT Licensed][license-image2]][license-link2] |
||||
[](https://forum.nextgraph.org) |
||||
[](https://pypi.org/project/nextgraphpy/) |
||||
|
||||
Python package for NextGraph, implemented in Rust |
||||
|
||||
This repository is in active development at [https://git.nextgraph.org/NextGraph/nextgraph-rs](https://git.nextgraph.org/NextGraph/nextgraph-rs), a Gitea instance. For bug reports, issues, merge requests, and in order to join the dev team, please visit the link above and create an account (you can do so with a github account). The [github repo](https://github.com/nextgraph-org/nextgraph-rs) is just a read-only mirror that does not accept issues. |
||||
|
||||
## NextGraph |
||||
|
||||
> NextGraph brings about the convergence of P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs. |
||||
> |
||||
> This open source ecosystem provides solutions for end-users (a platform) and software developers (a framework), wishing to use or create **decentralized** apps featuring: **live collaboration** on rich-text documents, peer to peer communication with **end-to-end encryption**, offline-first, **local-first**, portable and interoperable data, total ownership of data and software, security and privacy. Centered on repositories containing **semantic data** (RDF), **rich text**, and structured data formats like **JSON**, synced between peers belonging to permissioned groups of users, it offers strong eventual consistency, thanks to the use of **CRDTs**. Documents can be linked together, signed, shared securely, queried using the **SPARQL** language and organized into sites and containers. |
||||
> |
||||
> More info here [https://nextgraph.org](https://nextgraph.org) |
||||
|
||||
## Support |
||||
|
||||
Documentation can be found here [https://docs.nextgraph.org](https://docs.nextgraph.org) |
||||
|
||||
And our community forum where you can ask questions is here [https://forum.nextgraph.org](https://forum.nextgraph.org) |
||||
|
||||
[](https://fosstodon.org/@nextgraph) |
||||
|
||||
## How to use NextGraph App & Platform |
||||
|
||||
NextGraph is in alpha release! |
||||
|
||||
You can try it online or by installing the apps. Please follow our [Getting started](https://docs.nextgraph.org/en/getting-started/) guide . |
||||
|
||||
You can also subscribe to [our newsletter](https://list.nextgraph.org/subscription/form) to get updates, and support us with a [donation](https://nextgraph.org/donate/). |
||||
|
||||
## NextGraph is also a Framework for App developers |
||||
|
||||
Read our [getting started guide for developers](https://docs.nextgraph.org/en/framework/getting-started/). |
||||
|
||||
## License |
||||
|
||||
Licensed under either of |
||||
|
||||
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0) |
||||
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) |
||||
at your option. |
||||
|
||||
`SPDX-License-Identifier: Apache-2.0 OR MIT` |
||||
|
||||
--- |
||||
|
||||
NextGraph received funding through the [NGI Assure Fund](https://nlnet.nl/assure) and the [NGI Zero Commons Fund](https://nlnet.nl/commonsfund/), both funds established by [NLnet](https://nlnet.nl/) Foundation with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme, under the aegis of DG Communications Networks, Content and Technology under grant agreements No 957073 and No 101092990, respectively. |
||||
|
||||
[rustc-image]: https://img.shields.io/badge/rustc-1.74+-blue.svg |
||||
[license-image]: https://img.shields.io/badge/license-Apache2.0-blue.svg |
||||
[license-link]: https://git.nextgraph.org/NextGraph/nextgraph-rs/raw/branch/master/LICENSE-APACHE2 |
||||
[license-image2]: https://img.shields.io/badge/license-MIT-blue.svg |
||||
[license-link2]: https://git.nextgraph.org/NextGraph/nextgraph-rs/src/branch/master/LICENSE-MIT |
@ -0,0 +1,17 @@ |
||||
[build-system] |
||||
requires = ["maturin>=1.8,<2.0"] |
||||
build-backend = "maturin" |
||||
|
||||
[project] |
||||
name = "nextgraphpy" |
||||
requires-python = ">=3.7.3" |
||||
description = "NextGraph brings about the convergence of P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs." |
||||
readme = "README.md" |
||||
classifiers = [ |
||||
"Programming Language :: Rust", |
||||
"Programming Language :: Python :: Implementation :: CPython", |
||||
"Programming Language :: Python :: Implementation :: PyPy", |
||||
] |
||||
version = "0.1a1.dev2" |
||||
[tool.maturin] |
||||
features = ["pyo3/extension-module"] |
@ -0,0 +1,145 @@ |
||||
// Copyright (c) 2022-2025 Niko Bonnieure, Par le Peuple, NextGraph.org developers
|
||||
// All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
|
||||
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use pyo3::exceptions::PyTypeError; |
||||
use pyo3::prelude::*; |
||||
use pythonize::{depythonize, pythonize}; |
||||
use serde::{Deserialize, Serialize}; |
||||
|
||||
use std::fs::read; |
||||
|
||||
#[allow(unused_imports)] |
||||
use ::nextgraph::local_broker::{ |
||||
app_request, app_request_stream, doc_fetch_repo_subscribe, init_local_broker, session_start, |
||||
session_stop, user_connect, user_disconnect, wallet_close, wallet_create_v0, wallet_get, |
||||
wallet_get_file, wallet_import, wallet_read_file, wallet_was_opened, LocalBrokerConfig, |
||||
SessionConfig, |
||||
}; |
||||
use ::nextgraph::net::types::BootstrapContentV0; |
||||
use ::nextgraph::repo::errors::NgError; |
||||
use ::nextgraph::repo::log::*; |
||||
use ::nextgraph::repo::types::PubKey; |
||||
use ::nextgraph::wallet::types::{CreateWalletV0, SessionInfo}; |
||||
use ::nextgraph::wallet::{display_mnemonic, emojis::display_pazzle}; |
||||
use async_std::stream::StreamExt; |
||||
|
||||
#[pyfunction] |
||||
fn init_local_broker_in_memory() -> PyResult<()> { |
||||
Ok(()) |
||||
} |
||||
|
||||
struct PyNgError(NgError); |
||||
|
||||
impl From<PyNgError> for PyErr { |
||||
fn from(e: PyNgError) -> PyErr { |
||||
let ioe: std::io::Error = e.0.into(); |
||||
ioe.into() |
||||
} |
||||
} |
||||
|
||||
impl From<NgError> for PyNgError { |
||||
fn from(e: NgError) -> PyNgError { |
||||
PyNgError(e) |
||||
} |
||||
} |
||||
|
||||
/// Open the wallet with mnemonic and PIN, and returns the wallet_name and the SessionInfo
|
||||
#[pyfunction] |
||||
fn wallet_open_with_mnemonic_words( |
||||
py: Python, |
||||
wallet_file_path: String, |
||||
mnemonic_words: Vec<String>, |
||||
pin: [u8; 4], |
||||
) -> PyResult<Bound<PyAny>> { |
||||
pyo3_async_runtimes::async_std::future_into_py(py, async move { |
||||
init_local_broker(Box::new(|| LocalBrokerConfig::InMemory)).await; |
||||
|
||||
let wallet_file = read(wallet_file_path).expect("read wallet file"); |
||||
|
||||
let wallet = wallet_read_file(wallet_file) |
||||
.await |
||||
.map_err(|e| Into::<PyNgError>::into(e))?; |
||||
|
||||
let opened_wallet = ::nextgraph::local_broker::wallet_open_with_mnemonic_words( |
||||
&wallet, |
||||
&mnemonic_words, |
||||
pin, |
||||
) |
||||
.map_err(|e| Into::<PyNgError>::into(e))?; |
||||
|
||||
let user_id = opened_wallet.personal_identity(); |
||||
let wallet_name = opened_wallet.name(); |
||||
|
||||
let _client = wallet_import(wallet.clone(), opened_wallet, true) |
||||
.await |
||||
.map_err(|e| Into::<PyNgError>::into(e))?; |
||||
|
||||
let session = session_start(SessionConfig::new_in_memory(&user_id, &wallet_name)) |
||||
.await |
||||
.map_err(|e| Into::<PyNgError>::into(e))?; |
||||
|
||||
// let session = session_start(SessionConfig::new_remote(&user_id, &wallet_name, None)).await?;
|
||||
|
||||
let _status = user_connect(&user_id) |
||||
.await |
||||
.map_err(|e| Into::<PyNgError>::into(e))?; |
||||
|
||||
let s = Python::with_gil(|py| pythonize(py, &session).unwrap().unbind()); |
||||
Ok((wallet_name, s)) |
||||
}) |
||||
} |
||||
|
||||
#[pyfunction] |
||||
#[pyo3(signature = (session_id, sparql, nuri=None))] |
||||
fn doc_sparql_update( |
||||
py: Python, |
||||
session_id: u64, |
||||
sparql: String, |
||||
nuri: Option<String>, |
||||
) -> PyResult<Bound<PyAny>> { |
||||
pyo3_async_runtimes::async_std::future_into_py(py, async move { |
||||
::nextgraph::local_broker::doc_sparql_update(session_id, sparql, nuri) |
||||
.await |
||||
.map_err(|e| PyTypeError::new_err(e))?; |
||||
Ok(()) |
||||
}) |
||||
} |
||||
|
||||
#[pyfunction] |
||||
fn disconnect_and_close<'a>( |
||||
py: Python<'a>, |
||||
user_id: Bound<'a, PyAny>, |
||||
wallet_name: String, |
||||
) -> PyResult<Bound<'a, PyAny>> { |
||||
let user_id: PubKey = depythonize(&user_id)?; |
||||
pyo3_async_runtimes::async_std::future_into_py(py, async move { |
||||
user_disconnect(&user_id) |
||||
.await |
||||
.map_err(|e| Into::<PyNgError>::into(e))?; |
||||
|
||||
// stop the session
|
||||
session_stop(&user_id) |
||||
.await |
||||
.map_err(|e| Into::<PyNgError>::into(e))?; |
||||
|
||||
// closes the wallet
|
||||
wallet_close(&wallet_name) |
||||
.await |
||||
.map_err(|e| Into::<PyNgError>::into(e))?; |
||||
Ok(()) |
||||
}) |
||||
} |
||||
|
||||
#[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)?)?; |
||||
Ok(()) |
||||
} |
@ -0,0 +1,29 @@ |
||||
import asyncio |
||||
from nextgraphpy import wallet_open_with_mnemonic_words, 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"], |
||||
[2, 3, 2, 3]) |
||||
wallet_name = wallet_session[0] |
||||
session_info = wallet_session[1] |
||||
print(wallet_name) |
||||
print(session_info) |
||||
await doc_sparql_update(session_info["session_id"], |
||||
"INSERT DATA { <did:ng:_> <example:predicate> \"An example value22\". }", |
||||
"did:ng:o:Dn0QpE9_4jhta1mUWRl_LZh1SbXUkXfOB5eu38PNIk4A:v:Z4ihjV3KMVIqBxzjP6hogVLyjkZunLsb7MMsCR0kizQA") |
||||
await disconnect_and_close(session_info["user"], wallet_name) |
||||
|
||||
asyncio.run(main()) |
@ -1,5 +1,5 @@ |
||||
NG_ACCOUNT_DOMAIN= |
||||
NG_ACCOUNT_ADMIN= |
||||
NG_ACCOUNT_LOCAL_PEER_KEY= |
||||
NG_ACCOUNT_SERVER=127.0.0.1,1440,[the broker's peer ID] |
||||
NG_ACCOUNT_SERVER=127.0.0.1,14400,[the broker's peer ID] |
||||
RUST_LOG= |
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue