Compare commits
No commits in common. 'master' and 'master' have entirely different histories.
@ -1,103 +0,0 @@ |
|||||||
// 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(()) |
|
||||||
} |
|
Before Width: | Height: | Size: 437 B |
@ -1,319 +0,0 @@ |
|||||||
<!-- |
|
||||||
// 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> |
|
@ -1,3 +0,0 @@ |
|||||||
pkg/* |
|
||||||
pkg-node/* |
|
||||||
web/* |
|
@ -1,42 +0,0 @@ |
|||||||
# 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. |
|
@ -0,0 +1,117 @@ |
|||||||
|
{ |
||||||
|
"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": {} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,181 +0,0 @@ |
|||||||
# 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-*/* |
|
@ -1,72 +0,0 @@ |
|||||||
/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 |
|
@ -1,25 +0,0 @@ |
|||||||
[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" } |
|
@ -1,63 +0,0 @@ |
|||||||
<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 |
|
@ -1,17 +0,0 @@ |
|||||||
[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.dev4" |
|
||||||
[tool.maturin] |
|
||||||
features = ["pyo3/extension-module"] |
|
@ -1,167 +0,0 @@ |
|||||||
// 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::app_protocol::*; |
|
||||||
use ::nextgraph::net::types::BootstrapContentV0; |
|
||||||
use ::nextgraph::repo::errors::NgError; |
|
||||||
use ::nextgraph::repo::log::*; |
|
||||||
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; |
|
||||||
|
|
||||||
#[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 { |
|
||||||
let res = ::nextgraph::local_broker::doc_sparql_update(session_id, sparql, nuri) |
|
||||||
.await |
|
||||||
.map_err(|e| PyTypeError::new_err(e))?; |
|
||||||
Ok(res) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
#[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(()) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
#[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<String>, |
|
||||||
store_repo: Option<String>, |
|
||||||
) -> PyResult<Bound<PyAny>> { |
|
||||||
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::<PyNgError>::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(()) |
|
||||||
} |
|
@ -1,21 +0,0 @@ |
|||||||
import asyncio |
|
||||||
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( |
|
||||||
"/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) |
|
||||||
doc_id = await doc_create(session_id, "Graph", "data:graph", "store") |
|
||||||
print(doc_id) |
|
||||||
commits = await doc_sparql_update(session_id, |
|
||||||
"INSERT DATA { <did:ng:_> <example:predicate> \"An example value22\". }", doc_id) |
|
||||||
print(commits) |
|
||||||
await disconnect_and_close(session_info["user"], wallet_name) |
|
||||||
|
|
||||||
asyncio.run(main()) |
|
@ -1,5 +1,5 @@ |
|||||||
NG_ACCOUNT_DOMAIN= |
NG_ACCOUNT_DOMAIN= |
||||||
NG_ACCOUNT_ADMIN= |
NG_ACCOUNT_ADMIN= |
||||||
NG_ACCOUNT_LOCAL_PEER_KEY= |
NG_ACCOUNT_LOCAL_PEER_KEY= |
||||||
NG_ACCOUNT_SERVER=127.0.0.1,14400,[the broker's peer ID] |
NG_ACCOUNT_SERVER=127.0.0.1,1440,[the broker's peer ID] |
||||||
RUST_LOG= |
RUST_LOG= |
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue