├── ui
├── start_server.sh
├── favicon.ico
├── main.js
├── rebuild.sh
├── index.html
└── README.adoc
├── update-rep_lang-rev.sh
├── .envrc
├── crates
├── sensemaker_ui
│ ├── yew_style.css
│ ├── index.html
│ ├── src
│ │ ├── lib.rs
│ │ └── app.rs
│ ├── Cargo.toml
│ └── main.js
├── social_sensemaker_core
│ ├── Cargo.toml
│ └── src
│ │ └── lib.rs
├── social_sensemaker_macros
│ ├── Cargo.toml
│ └── src
│ │ └── lib.rs
├── common
│ ├── Cargo.toml
│ └── src
│ │ ├── util.rs
│ │ └── lib.rs
├── frontend-tui
│ ├── Cargo.toml
│ └── src
│ │ ├── event.rs
│ │ └── main.rs
└── social_sensemaker
│ ├── Cargo.toml
│ ├── src
│ └── lib.rs
│ └── tests
│ └── simple.rs
├── .gitmodules
├── happs
└── social_sensemaker
│ ├── dna.yaml
│ └── happ.yaml
├── .gitignore
├── shell.nix
├── Cargo.toml
├── package.json
├── LICENSE
├── README.adoc
├── flake.nix
├── .github
└── workflows
│ └── test.yml
└── flake.lock
/ui/start_server.sh:
--------------------------------------------------------------------------------
1 | miniserve -p 8080 .
2 |
--------------------------------------------------------------------------------
/ui/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neighbour-hoods/social_sensemaker/HEAD/ui/favicon.ico
--------------------------------------------------------------------------------
/update-rep_lang-rev.sh:
--------------------------------------------------------------------------------
1 | find crates -type f -name Cargo.toml -print0 | xargs -0 sed -i "s/$1/$2/g"
2 |
--------------------------------------------------------------------------------
/.envrc:
--------------------------------------------------------------------------------
1 | eval "$(lorri direnv)"
2 |
3 | export CARGO_HOME=~/.cargo
4 | export CARGO_TARGET_DIR=$(pwd)/target
5 |
--------------------------------------------------------------------------------
/crates/sensemaker_ui/yew_style.css:
--------------------------------------------------------------------------------
1 | .alert {
2 | padding: 20px;
3 | background-color: #f44336;
4 | color: white;
5 | }
6 |
--------------------------------------------------------------------------------
/crates/social_sensemaker_core/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "social_sensemaker_core"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
--------------------------------------------------------------------------------
/ui/main.js:
--------------------------------------------------------------------------------
1 | import init, { run_app } from './pkg/frontend.js';
2 | async function main() {
3 | await init('./pkg/frontend_bg.wasm');
4 | run_app();
5 | }
6 | main()
7 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "crates/holochain_client_wrapper"]
2 | path = crates/holochain_client_wrapper
3 | url = git@github.com:neighbour-hoods/holochain_client_wrapper.git
4 |
--------------------------------------------------------------------------------
/happs/social_sensemaker/dna.yaml:
--------------------------------------------------------------------------------
1 | manifest_version: "1"
2 | name: "social_sensemaker"
3 | uuid: ""
4 | properties: null
5 | zomes:
6 | - name: sensemaker_main
7 | bundled: "./social_sensemaker.wasm"
8 | # properties:
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 |
3 | node_modules
4 |
5 | happs/**/*.dna
6 | happs/**/*.happ
7 | happs/**/*.wasm
8 | .hc
9 | .hc_live_*
10 |
11 | ui/pkg/
12 |
13 | # nix
14 | result*
15 |
16 | # unknown cause
17 | crates/LICENSE
18 |
--------------------------------------------------------------------------------
/ui/rebuild.sh:
--------------------------------------------------------------------------------
1 | # must be run from containing directory
2 | CARGO_TARGET_DIR=$(pwd)/../target wasm-pack build --dev $(pwd)/../crates/frontend --target web --out-dir $(pwd)/pkg
3 | rollup ./main.js --format iife --file ./pkg/bundle.js
4 |
--------------------------------------------------------------------------------
/ui/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | rep_lang_playground
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/crates/social_sensemaker_core/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub const OWNER_TAG: &str = "sensemaker_owner";
2 | pub const SENSEMAKER_ZOME_NAME: &str = "sensemaker_main";
3 | pub const SM_COMP_TAG: &str = "sm_comp";
4 | pub const SM_INIT_TAG: &str = "sm_init";
5 | pub const SM_DATA_TAG: &str = "sm_data";
6 |
--------------------------------------------------------------------------------
/ui/README.adoc:
--------------------------------------------------------------------------------
1 | = UI
2 |
3 | == building
4 |
5 | [source]
6 | ----
7 | source ./rebuild.sh
8 | ----
9 |
10 | == serving
11 |
12 | serve with your static content server of choice, and then load `index.html` in a browser.
13 |
14 | `start_server.sh` is provided for convenience, using miniserve.
15 |
--------------------------------------------------------------------------------
/shell.nix:
--------------------------------------------------------------------------------
1 | (import (
2 | let
3 | lock = builtins.fromJSON (builtins.readFile ./flake.lock);
4 | in fetchTarball {
5 | url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
6 | sha256 = lock.nodes.flake-compat.locked.narHash; }
7 | ) {
8 | src = ./.;
9 | }).shellNix.default
10 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | members = [
3 | "crates/common",
4 | "crates/social_sensemaker",
5 | "crates/social_sensemaker_core",
6 | "crates/social_sensemaker_macros",
7 | "crates/sensemaker_ui",
8 |
9 | # this keeps breaking due to not-so-actively maintained deps.
10 | # letting it bitrot for now.
11 | # "crates/frontend-tui",
12 | ]
13 |
--------------------------------------------------------------------------------
/happs/social_sensemaker/happ.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | manifest_version: "1"
3 | name: social_sensemaker
4 | description: ~
5 | roles:
6 | - id: main
7 | provisioning:
8 | strategy: create
9 | deferred: false
10 | dna:
11 | bundled: "./social_sensemaker.dna"
12 | properties: ~
13 | uuid: ~
14 | version: ~
15 | clone_limit: 0
16 |
--------------------------------------------------------------------------------
/crates/social_sensemaker_macros/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "social_sensemaker_macros"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [lib]
7 | proc-macro = true
8 |
9 | [dependencies]
10 | syn = { version = "1", features = ["full", "extra-traits"] }
11 | quote = "1"
12 | proc-macro2 = "1"
13 |
14 | social_sensemaker_core = { path = "../social_sensemaker_core" }
15 |
--------------------------------------------------------------------------------
/crates/sensemaker_ui/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | sensemaker_ui
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/crates/sensemaker_ui/src/lib.rs:
--------------------------------------------------------------------------------
1 | mod app;
2 |
3 | use wasm_bindgen::prelude::*;
4 | use web_sys::Element;
5 |
6 | #[wasm_bindgen]
7 | pub fn run_app(
8 | element: Element,
9 | admin_ws_js: JsValue,
10 | app_ws_js: JsValue,
11 | cell_id_js: JsValue,
12 | ) -> Result<(), JsValue> {
13 | let props = app::ModelProps {
14 | admin_ws_js,
15 | app_ws_js,
16 | cell_id_js,
17 | };
18 | yew::start_app_with_props_in_element::(element, props);
19 | Ok(())
20 | }
21 |
--------------------------------------------------------------------------------
/crates/sensemaker_ui/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "sensemaker_ui"
3 | version = "0.1.0"
4 | edition = "2018"
5 | license-file = "../../LICENSE"
6 |
7 | [lib]
8 | path = "src/lib.rs"
9 | crate-type = ["rlib", "cdylib"]
10 |
11 | [dependencies]
12 | js-sys = "0.3.59"
13 | wasm-bindgen = "0.2"
14 | weblog = "0.3.0"
15 | yew = "0.19.3"
16 |
17 | holochain_client_wrapper = { path = "../holochain_client_wrapper/holochain_client_wrapper" }
18 |
19 | [dependencies.web-sys]
20 | version = "0.3"
21 | features = [
22 | "HtmlInputElement",
23 | ]
24 |
--------------------------------------------------------------------------------
/crates/sensemaker_ui/main.js:
--------------------------------------------------------------------------------
1 | import init, { run_app } from './pkg/sensemaker_ui.js';
2 | import { AppWebsocket, AdminWebsocket } from '@holochain/client';
3 |
4 | async function main() {
5 | await init('/pkg/sensemaker_ui_bg.wasm');
6 | let element = document.getElementById("sensemaker_ui_main");
7 | let admin_ws_js = await AdminWebsocket.connect("ws://localhost:9000");
8 | let app_ws_js = await AppWebsocket.connect("ws://localhost:9999");
9 | // TODO change this \/ to sensemaker at some point
10 | let app_info = await app_ws_js.appInfo({ installed_app_id: 'test-app' });
11 | let cell_id_js = app_info.cell_data[0].cell_id;
12 | run_app(element, admin_ws_js, app_ws_js, cell_id_js);
13 | }
14 | main()
15 |
--------------------------------------------------------------------------------
/crates/common/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "common"
3 | version = "0.1.0"
4 | authors = ["Michael Hueschen "]
5 | edition = "2018"
6 | license-file = "../../LICENSE"
7 |
8 | [dependencies]
9 | base64 = "0.13.0"
10 | combine = "4.6.4"
11 | hdk = "0.0.136"
12 | pretty = "0.11.3"
13 | serde = "1"
14 |
15 | rep_lang_concrete_syntax = { git = "https://github.com/neighbour-hoods/rep_lang.git", rev = "364213a6b1bca2f3ebdedb9a043c0b864e4d6a49" }
16 | rep_lang_core = { git = "https://github.com/neighbour-hoods/rep_lang.git", rev = "364213a6b1bca2f3ebdedb9a043c0b864e4d6a49", features = ["hc"] }
17 | rep_lang_runtime = { git = "https://github.com/neighbour-hoods/rep_lang.git", rev = "364213a6b1bca2f3ebdedb9a043c0b864e4d6a49", features = ["hc"] }
18 | social_sensemaker_core = { path = "../social_sensemaker_core" }
19 | social_sensemaker_macros = { path = "../social_sensemaker_macros" }
20 |
--------------------------------------------------------------------------------
/crates/frontend-tui/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "frontend-tui"
3 | version = "0.1.0"
4 | edition = "2018"
5 | license-file = "../../LICENSE"
6 |
7 | [[bin]]
8 | name = "rlp"
9 | path = "src/main.rs"
10 |
11 | [dependencies]
12 | combine = "4.5.2"
13 | futures = "0.3"
14 | holo_hash = { version = "0.0.14", default-features = false }
15 | holochain_client = { git = "https://github.com/holochain/holochain-client-rust.git", rev = "77fae4a989fd75d5a01580e0226f733a65a1716f" }
16 | holochain_types = "0.0.37"
17 | holochain_zome_types = { version = "0.0.33", default-features = false }
18 | pretty = "0.10.0"
19 | rand = "0.8.4"
20 | scrawl = "1.1.0"
21 | serde_json = "1.0.70"
22 | structopt = "0.3.25"
23 | termion = "1.5.6"
24 | tokio = "1.13.0"
25 | tui = "0.16.0"
26 | xdg = "2.4.0"
27 |
28 | common = { path = "../common" }
29 | rep_lang_concrete_syntax = { git = "https://github.com/neighbour-hoods/rep_lang.git", rev = "bf44c3e80e0c98cfded6b7c1ba7caa38cb2449a8" }
30 | rep_lang_core = { git = "https://github.com/neighbour-hoods/rep_lang.git", rev = "bf44c3e80e0c98cfded6b7c1ba7caa38cb2449a8" }
31 | rep_lang_runtime = { git = "https://github.com/neighbour-hoods/rep_lang.git", rev = "bf44c3e80e0c98cfded6b7c1ba7caa38cb2449a8" }
32 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "social_sensemaker",
3 | "version": "1.0.0",
4 | "dependencies": {
5 | "@holochain/client": "^0.7.0",
6 | "esbuild": "^0.14.54"
7 | },
8 | "scripts": {
9 | "hc-js-build:init": "npm install ./crates/holochain_client_wrapper/submodules/holochain-client-js",
10 | "hc-js-build": "./node_modules/.bin/esbuild ./crates/holochain_client_wrapper/submodules/holochain-client-js/src/index.ts --format=esm --bundle --outfile=./crates/holochain_client_wrapper/holochain_client_wrapper/src/holochain_client_wrapper.js",
11 | "ui:build": "wasm-pack build ./crates/sensemaker_ui --target web && ./node_modules/.bin/esbuild ./crates/sensemaker_ui/main.js --format=iife --bundle --outfile=./crates/sensemaker_ui/pkg/bundle.js",
12 | "ui:serve": "miniserve -p 8080 ./crates/sensemaker_ui",
13 | "hc:test": "cargo test",
14 | "hc:build": "cargo build -p social_sensemaker --release --target wasm32-unknown-unknown && cp $CARGO_TARGET_DIR/wasm32-unknown-unknown/release/social_sensemaker.wasm ./happs/social_sensemaker",
15 | "hc:pack": "hc dna pack happs/social_sensemaker && hc app pack happs/social_sensemaker",
16 | "hc:clean": "rm -rf .hc*",
17 | "hc:run": "hc sandbox -f=9000 generate happs/social_sensemaker -r=9999 network mdns"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/crates/social_sensemaker/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "social_sensemaker"
3 | version = "0.1.0"
4 | authors = ["Michael Hueschen "]
5 | edition = "2018"
6 | license-file = "../../LICENSE"
7 |
8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
9 |
10 | [dependencies]
11 | hdk = "0.0.136"
12 | serde = "1"
13 |
14 | common = { path = "../common" }
15 | rep_lang_concrete_syntax = { git = "https://github.com/neighbour-hoods/rep_lang.git", rev = "364213a6b1bca2f3ebdedb9a043c0b864e4d6a49" }
16 | rep_lang_core = { git = "https://github.com/neighbour-hoods/rep_lang.git", rev = "364213a6b1bca2f3ebdedb9a043c0b864e4d6a49", features = ["hc"] }
17 | rep_lang_runtime = { git = "https://github.com/neighbour-hoods/rep_lang.git", rev = "364213a6b1bca2f3ebdedb9a043c0b864e4d6a49", features = ["hc"] }
18 |
19 | [dev-dependencies]
20 | anyhow = "1.0"
21 | futures = { version = "0.3", default-features = false }
22 | tokio = { version = "1", features = ["full"] }
23 | #
24 | hdk = "0.0.136"
25 | holochain = { version = "0.0.143", default-features = false, features = ["test_utils"] }
26 | kitsune_p2p = "0.0.35"
27 | kitsune_p2p_types ="0.0.24"
28 | observability = "0.1.3"
29 | #
30 | common = { path = "../common" }
31 |
32 | [lib]
33 | path = "src/lib.rs"
34 | crate-type = ["cdylib", "rlib"]
35 |
--------------------------------------------------------------------------------
/crates/frontend-tui/src/event.rs:
--------------------------------------------------------------------------------
1 | use holo_hash::HeaderHash;
2 | use std::io;
3 | use std::sync::mpsc::{self, Receiver, Sender};
4 | use std::thread;
5 | use termion::event::Key;
6 | use termion::input::TermRead;
7 |
8 | use common::SensemakerEntry;
9 |
10 | pub enum Event {
11 | Input(Key),
12 | HcInfo(HI),
13 | ViewerSes(Vec),
14 | SelectorSes(Vec<(HeaderHash, SensemakerEntry)>),
15 | }
16 |
17 | /// A small event handler that wrap termion input and tick events. Each event
18 | /// type is handled in its own thread and returned to a common `Receiver`
19 | pub struct Events {
20 | rx: Receiver>,
21 | #[allow(dead_code)]
22 | input_handle: thread::JoinHandle<()>,
23 | }
24 |
25 | impl Events {
26 | pub fn mk() -> (Events, Sender>) {
27 | let (tx, rx) = mpsc::channel();
28 | let input_handle = {
29 | let tx = tx.clone();
30 | thread::spawn(move || {
31 | let stdin = io::stdin();
32 | for key in stdin.keys().flatten() {
33 | if let Err(_err) = tx.send(Event::Input(key)) {
34 | // silently exit, otherwise output is distractingly visible
35 | return;
36 | }
37 | }
38 | })
39 | };
40 | (Events { rx, input_handle }, tx)
41 | }
42 |
43 | pub fn next(&self) -> Result, mpsc::RecvError> {
44 | self.rx.recv()
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | * Copyright (c) 2022, Neighbourhoods Network Ltd.
2 |
3 | * License. The copyright holder hereby grants you, the royalty-free,
4 | * non-exclusive and worldwide right, under the copyright holder’s
5 | * intellectual property rights, to:
6 | * (i) use the social_sensemaker library ("Library") for evaluation purposes;
7 | * (ii) use and copy the associated documentation that is made available in
8 | * connection with the Library for the purposes of (i) above.
9 |
10 | * For the avoidance of doubt, the above license does not include or imply the grant of any
11 | * right or license to distribute or grant any license or sublicense concerning
12 | * the Library on a “naked” or “stand-alone” basis and such is
13 | * prohibited under this license.
14 |
15 | * There are no implied licenses granted hereunder and all rights, save for those
16 | * expressly granted, shall remain with the copyright holder.
17 |
18 | * Restrictions. you shall not:
19 | * (a) use the Library for any commercial purposes;
20 | * (b) create derivative works of the Library.
21 |
22 | * THE LIBRARY IS PROVIDED BY COPYRIGHT HOLDER 'AS IS' AND
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT,
26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 | * ARISING IN ANY WAY OUT OF THE USE OF THE LIBRARY, EVEN IF ADVISED
31 | * OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
--------------------------------------------------------------------------------
/crates/common/src/util.rs:
--------------------------------------------------------------------------------
1 | use hdk::prelude::*;
2 |
3 | /// Tries to do a DHT get to retrieve data for the entry_hash,
4 | /// and if this get is successful and we get some element, tries
5 | /// to convert this element into a type T and return the result
6 | pub fn try_get_and_convert>(
7 | entry_hash: EntryHash,
8 | get_options: GetOptions,
9 | ) -> ExternResult {
10 | match get(entry_hash.clone(), get_options)? {
11 | Some(element) => try_from_element(element),
12 | None => Err(WasmError::Guest(format!(
13 | "There is no element at the hash {}",
14 | entry_hash
15 | ))),
16 | }
17 | }
18 |
19 | pub fn try_get_and_convert_with_hh>(
20 | entry_hash: EntryHash,
21 | get_options: GetOptions,
22 | ) -> ExternResult<(T, HeaderHash)> {
23 | match get(entry_hash.clone(), get_options)? {
24 | Some(element) => {
25 | let hh = element.header_address().clone();
26 | let v = try_from_element(element)?;
27 | Ok((v, hh))
28 | }
29 | None => Err(WasmError::Guest(format!(
30 | "There is no element at the hash {}",
31 | entry_hash
32 | ))),
33 | }
34 | }
35 |
36 | pub fn get_hh(entry_hash: EntryHash, get_options: GetOptions) -> ExternResult {
37 | match get(entry_hash.clone(), get_options)? {
38 | Some(element) => {
39 | let hh = element.header_address().clone();
40 | Ok(hh)
41 | }
42 | None => Err(WasmError::Guest(format!(
43 | "There is no element at the hash {}",
44 | entry_hash
45 | ))),
46 | }
47 | }
48 |
49 | /// Attempts to get an element at the entry_hash and returns it
50 | /// if the element exists
51 | #[allow(dead_code)]
52 | pub fn try_get_element(entry_hash: EntryHash, get_options: GetOptions) -> ExternResult {
53 | match get(entry_hash.clone(), get_options)? {
54 | Some(element) => Ok(element),
55 | None => Err(WasmError::Guest(format!(
56 | "There is no element at the hash {}",
57 | entry_hash
58 | ))),
59 | }
60 | }
61 |
62 | /// Tries to extract the entry from the element, and if the entry is there
63 | /// tries to convert it to type T and return the result
64 | #[allow(dead_code)]
65 | pub fn try_from_element>(element: Element) -> ExternResult {
66 | match element.entry() {
67 | element::ElementEntry::Present(entry) => T::try_from(entry.clone()).map_err(|_| {
68 | WasmError::Guest(format!(
69 | "Couldn't convert Element entry {:?} into data type {}",
70 | entry,
71 | std::any::type_name::()
72 | ))
73 | }),
74 | _ => Err(WasmError::Guest(format!(
75 | "Element {:?} does not have an entry",
76 | element
77 | ))),
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/crates/social_sensemaker_macros/src/lib.rs:
--------------------------------------------------------------------------------
1 | #![crate_type = "proc-macro"]
2 |
3 | use proc_macro::TokenStream;
4 | use proc_macro2::{Ident, Span};
5 |
6 | use social_sensemaker_core::SENSEMAKER_ZOME_NAME;
7 |
8 | // TODO think about hdk_extern and which zome/happ it goes into. will the widgets want
9 | // to invoke a macro, similar to `sensemaker_cell_id_fns`, s.t. the hdk_extern registers
10 | // in their wasm?
11 | #[proc_macro_attribute]
12 | pub fn expand_remote_calls(_attrs: TokenStream, item: TokenStream) -> TokenStream {
13 | // expand_remote_calls is only valid for functions
14 | let item_fn = syn::parse_macro_input!(item as syn::ItemFn);
15 | let fn_name = item_fn.sig.ident.to_string();
16 |
17 | let mut new_fn = item_fn.clone();
18 |
19 | // prefix fn ident.
20 | new_fn.sig.ident = Ident::new(&format!("remote_{}", fn_name), Span::call_site());
21 |
22 | // arg list. tuple munging.
23 | {
24 | let arg_pat_type = match item_fn
25 | .sig
26 | .inputs
27 | .first()
28 | .expect("hdk fn should have 1 arg")
29 | {
30 | syn::FnArg::Typed(pat_type) => pat_type,
31 | _ => panic!("expand_remote_calls: invalid Receiver FnArg"),
32 | };
33 | let arg_pat_type_ty = &arg_pat_type.ty;
34 | let token_streams = vec![
35 | (quote::quote! { cell_id: CellId }).into(),
36 | (quote::quote! { cap_secret: Option }).into(),
37 | (quote::quote! { payload: #arg_pat_type_ty }).into(),
38 | ];
39 |
40 | // drain element from `inputs`
41 | assert!(new_fn.sig.inputs.pop().is_some());
42 | assert!(new_fn.sig.inputs.is_empty());
43 |
44 | // add our above 3 to `inputs`
45 | for token_stream in token_streams {
46 | let fn_arg = syn::parse_macro_input!(token_stream as syn::FnArg);
47 | new_fn.sig.inputs.push(fn_arg);
48 | }
49 | }
50 |
51 | // body with bridge call.
52 | {
53 | let token_stream = (quote::quote! {
54 | {
55 | match call(
56 | CallTargetCell::Other(cell_id),
57 | #SENSEMAKER_ZOME_NAME.into(),
58 | #fn_name.into(),
59 | cap_secret,
60 | payload,
61 | )? {
62 | ZomeCallResponse::Ok(response) => Ok(response.decode()?),
63 | err => {
64 | error!("ZomeCallResponse error: {:?}", err);
65 | Err(WasmError::Guest(format!("{}: {:?}", #fn_name, err)))
66 | }
67 | }
68 | }
69 | })
70 | .into();
71 | let fn_body = syn::parse_macro_input!(token_stream as syn::Block);
72 | new_fn.block = Box::new(fn_body);
73 | }
74 |
75 | let doc_comment = format!("make a bridge call to `{}`", fn_name);
76 | (quote::quote! {
77 | #[hdk_extern]
78 | #item_fn
79 |
80 | #[doc = #doc_comment]
81 | #new_fn
82 | })
83 | .into()
84 | }
85 |
--------------------------------------------------------------------------------
/README.adoc:
--------------------------------------------------------------------------------
1 | = social_sensemaker
2 |
3 | integrating `rep_lang` & Holochain.
4 |
5 | == submodules
6 |
7 | either:
8 |
9 | [source]
10 | ----
11 | git clone --recurse-submodules $URL
12 | ----
13 |
14 | or, after cloning:
15 |
16 | [source]
17 | ----
18 | git submodule update --init --recursive
19 | ----
20 |
21 | == holochain-client-js wrapper setup
22 |
23 | [source]
24 | ----
25 | npm run hc-js-build:init
26 | npm run hc-js-build
27 | ----
28 |
29 | == entering dev environment
30 |
31 | install a https://nixos.wiki/wiki/Flakes#Installing_flakes[Flakes] supporting https://nixos.org/download.html[`nix`].
32 |
33 | edit `/etc/nix/nix.conf` to include the following:
34 |
35 | ----
36 | experimental-features = nix-command flakes
37 | ----
38 |
39 | optionally (but strongly suggested because it will dramatically speed up first-build times), also add these lines to `nix.conf` in order to enable the Holochain binary caches.
40 | public keys can be checked at the substituter URLs.
41 |
42 | ----
43 | substituters = https://cache.nixos.org/ https://cache.holo.host/ https://holochain-ci.cachix.org
44 | trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= cache.holo.host-1:lNXIXtJgS9Iuw4Cu6X0HINLu9sTfcjEntnrgwMQIMcE= cache.holo.host-2:ZJCkX3AUYZ8soxTLfTb60g+F3MkWD7hkH9y8CgqwhDQ= holochain-ci.cachix.org-1:5IUSkZc0aoRS53rfkvH9Kid40NpyjwCMCzwRTXy+QN8=
45 |
46 | alternately, use https://github.com/nix-community/lorri[`lorri`] and https://github.com/direnv/direnv[`direnv`] to manage tooling and shell environment transparently.
47 | ----
48 |
49 | then (from the repo root) run:
50 |
51 | ----
52 | nix develop --impure
53 | ----
54 |
55 | == building & running
56 |
57 | (inside of the dev shell, from prev section)
58 |
59 | building:
60 |
61 | [source]
62 | ----
63 | # perhaps this can go in package.json?
64 | npm install
65 |
66 | npm run fe:build
67 | npm run hc:build
68 | npm run hc:pack
69 | ----
70 |
71 | running:
72 |
73 | [source]
74 | ----
75 | npm run fe:run
76 | npm run hc:run
77 | ----
78 |
79 | === running with multiple conductors
80 |
81 | [source]
82 | ----
83 | # perform above build steps
84 | npm run hc:clean
85 |
86 | # terminal 1-1
87 | hc sandbox -f=9009 generate happs/social_sensemaker -r=9999 network mdns
88 |
89 | # terminal 1-2
90 | cargo run --bin rlp -- -f 9009 -p 9999 2> /tmp/rlp1.log
91 |
92 | # terminal 2-1
93 | hc sandbox -f=9008 generate happs/social_sensemaker -r=9998 network mdns
94 |
95 | # terminal 2-2
96 | cargo run --bin rlp -- -f 9008 -p 9998 2> /tmp/rlp2.log
97 | ----
98 |
99 | create an IE in terminal 1-2 and see it appear in terminal 2-2.
100 |
101 | == sweettest tests
102 |
103 | [source]
104 | ----
105 | $ npm run hc:build
106 | $ npm run hc:pack
107 |
108 | # INFO
109 | # cargo test depends on having the .happ around to be installed.
110 | # this is due to Holochain having a high degree of "dynamism" in how it runs happs.
111 | # I don't think we can do anything more "compile time" ish instead...
112 | # in CI, for later, we will need to make sure the main build completes and the
113 | # artifacts are available to the test suite...
114 | $ cargo test
115 | ----
116 |
--------------------------------------------------------------------------------
/crates/social_sensemaker/src/lib.rs:
--------------------------------------------------------------------------------
1 | use hdk::prelude::*;
2 |
3 | use common::{
4 | create_sensemaker_entry_full, mk_sensemaker_entry, CreateSensemakerEntryInput, SchemeEntry,
5 | SchemeRoot, SensemakerEntry,
6 | };
7 |
8 | entry_defs![
9 | Path::entry_def(),
10 | PathEntry::entry_def(),
11 | SensemakerEntry::entry_def(),
12 | SchemeEntry::entry_def(),
13 | SchemeRoot::entry_def()
14 | ];
15 |
16 | #[hdk_extern]
17 | pub fn init(_: ()) -> ExternResult {
18 | let mut functions = GrantedFunctions::new();
19 | functions.insert((zome_info()?.name, "get_sensemaker_entry_by_path".into()));
20 | functions.insert((
21 | zome_info()?.name,
22 | "set_sensemaker_entry_parse_rl_expr".into(),
23 | ));
24 | functions.insert((zome_info()?.name, "initialize_sm_data".into()));
25 | functions.insert((zome_info()?.name, "step_sm".into()));
26 |
27 | let grant = ZomeCallCapGrant {
28 | access: CapAccess::Unrestricted,
29 | functions,
30 | tag: "".into(),
31 | };
32 | create_cap_grant(grant)?;
33 |
34 | Ok(InitCallbackResult::Pass)
35 | }
36 |
37 | #[hdk_extern]
38 | pub(crate) fn validate_create_entry_sensemaker_entry(
39 | op: Op,
40 | ) -> ExternResult {
41 | validate_create_update_entry_sensemaker_entry(op)
42 | }
43 |
44 | #[hdk_extern]
45 | pub(crate) fn validate_update_entry_sensemaker_entry(
46 | op: Op,
47 | ) -> ExternResult {
48 | validate_create_update_entry_sensemaker_entry(op)
49 | }
50 |
51 | pub fn validate_create_update_entry_sensemaker_entry(
52 | op: Op,
53 | ) -> ExternResult {
54 | let entry: Entry = match op {
55 | Op::StoreEntry {
56 | entry: entry @ Entry::App(_),
57 | header: _,
58 | } => entry,
59 | Op::RegisterUpdate {
60 | update: _,
61 | new_entry,
62 | original_header: _,
63 | original_entry: _,
64 | } => new_entry,
65 | _ => {
66 | return Ok(ValidateCallbackResult::Invalid(
67 | "Unexpected op: not StoreEntry or RegisterUpdate".into(),
68 | ))
69 | }
70 | };
71 |
72 | let se: SensemakerEntry = match entry_to_struct(&entry)? {
73 | Some(se) => Ok(se),
74 | None => Err(WasmError::Guest(format!(
75 | "Couldn't convert Entry {:?} into SensemakerEntry",
76 | entry
77 | ))),
78 | }?;
79 |
80 | let computed_se = mk_sensemaker_entry(se.operator, se.operands)?;
81 |
82 | if computed_se.output_scheme != se.output_scheme {
83 | return Ok(ValidateCallbackResult::Invalid(format!(
84 | "SensemakerEntry scheme mismatch:\
85 | \ncomputed: {:?}\
86 | \nreceived: {:?}",
87 | computed_se.output_scheme, se.output_scheme
88 | )));
89 | }
90 |
91 | if computed_se.output_flat_value != se.output_flat_value {
92 | return Ok(ValidateCallbackResult::Invalid(format!(
93 | "SensemakerEntry value mismatch:\
94 | \ncomputed: {:?}\
95 | \nreceived: {:?}",
96 | computed_se.output_flat_value, se.output_flat_value
97 | )));
98 | }
99 |
100 | Ok(ValidateCallbackResult::Valid)
101 | }
102 |
103 | #[hdk_extern]
104 | pub fn create_sensemaker_entry(input: CreateSensemakerEntryInput) -> ExternResult {
105 | create_sensemaker_entry_full(input).map(|t| t.0)
106 | }
107 |
108 | pub fn entry_to_struct>(
109 | entry: &Entry,
110 | ) -> Result