mirror of
https://github.com/fluencelabs/aquavm
synced 2024-12-04 23:20:18 +00:00
Merge pull request #3 from fluencelabs/improved_call
Request-response stepper
This commit is contained in:
commit
8cec0163b1
167
Cargo.lock
generated
167
Cargo.lock
generated
@ -1,10 +1,20 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aquamarine"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fluence",
|
||||
"jsonpath_lib",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
@ -13,6 +23,29 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "array_tool"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f8cb5d814eb646a863c4f24978cff2880c4be96ad8cde2c0f0678732902e271"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.4.0"
|
||||
@ -25,6 +58,19 @@ version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluence"
|
||||
version = "0.2.7"
|
||||
@ -76,12 +122,59 @@ dependencies = [
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
|
||||
dependencies = [
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
|
||||
|
||||
[[package]]
|
||||
name = "jsonpath_lib"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8727f6987896c010ec9add275f59de2ae418b672fafa77bc3673b4cee1f09ca"
|
||||
dependencies = [
|
||||
"array_tool",
|
||||
"env_logger",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
@ -134,6 +227,12 @@ dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.7"
|
||||
@ -184,6 +283,24 @@ dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
"thread_local",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
@ -216,6 +333,7 @@ version = "1.0.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
@ -242,6 +360,24 @@ dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
@ -322,3 +458,34 @@ name = "wasm-bindgen-shared"
|
||||
version = "0.2.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
@ -5,11 +5,13 @@ authors = ["Fluence Labs"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "aquamarine_client"
|
||||
crate-type = ["cdylib"]
|
||||
path = "src/wasm_bindgen.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "aquamarine"
|
||||
path = "src/main.rs"
|
||||
path = "src/fce.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "aqua_test_module"
|
||||
@ -17,9 +19,13 @@ path = "test_module/main.rs"
|
||||
|
||||
[dependencies]
|
||||
fluence = { git = "https://github.com/fluencelabs/rust-sdk", features = ["logger"] }
|
||||
|
||||
serde = { version = "1.0.116", features = ["derive"] }
|
||||
serde_derive = "1.0.116"
|
||||
serde_sexpr = "0.1.0"
|
||||
|
||||
jsonpath_lib = "0.2.5"
|
||||
|
||||
log = "0.4.11"
|
||||
serde_json = "1.0"
|
||||
wasm-bindgen = "0.2.68"
|
||||
|
@ -9,3 +9,6 @@ modules_dir = "./target/wasm32-wasi/release/"
|
||||
name = "aquamarine"
|
||||
mem_pages_count = 100
|
||||
logger_enabled = true
|
||||
|
||||
[module.wasi]
|
||||
envs = ["CURRENT_PEER_ID=asd"]
|
||||
|
12
README.md
12
README.md
@ -1,2 +1,12 @@
|
||||
# aquamarine
|
||||
# Aquamarine
|
||||
|
||||
Aquamarine is a distributed choreography language & platform
|
||||
|
||||
## Examples
|
||||
|
||||
```lisp
|
||||
((call (%current% (local_service_id local_fn_name) () result_name)) (call (remote_peer_id (service_id fn_name) () g)))
|
||||
```
|
||||
This instruction sequence contains two call instructions:
|
||||
1. call a function with `local_fn_name` name of a local service with `local_service_id` id and bind result to `result_name`
|
||||
2. call a remote peer with `remote_peer_id` id
|
||||
|
11
src/air.rs
11
src/air.rs
@ -63,6 +63,15 @@ a -> B
|
||||
(call fn [x.0])
|
||||
)
|
||||
|
||||
data - HashMap<String, serde_json::Value>
|
||||
x.h.a.v -> (x - key in data, h.a.v - json path)
|
||||
|
||||
0
|
||||
1
|
||||
|
||||
(call 1 (counter inc) [x.a] b)
|
||||
(call 0 (response inc) [b] _)
|
||||
|
||||
-- any (fastest) -- does not work
|
||||
(seq
|
||||
(seq
|
||||
@ -71,7 +80,7 @@ a -> B
|
||||
y <- Q
|
||||
)
|
||||
(xor
|
||||
(call fn [x] z)
|
||||
(call fn [x.h.a.v, x.a.b.n] z)
|
||||
(call fn [y] z)
|
||||
)
|
||||
)
|
||||
|
34
src/defines.rs
Normal file
34
src/defines.rs
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/// This file contains defines similar for both FCE and browser targets.
|
||||
|
||||
pub(crate) type Result<T> = std::result::Result<T, AquamarineError>;
|
||||
pub(crate) type AquaData = std::collections::HashMap<String, serde_json::Value>;
|
||||
pub(crate) use crate::errors::AquamarineError;
|
||||
pub(crate) use crate::stepper::StepperOutcome;
|
||||
|
||||
pub(crate) const CALL_SERVICE_SUCCESS: i32 = 0;
|
||||
|
||||
use serde_derive::Deserialize;
|
||||
use serde_derive::Serialize;
|
||||
|
||||
#[fluence::fce]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CallServiceResult {
|
||||
pub ret_code: i32,
|
||||
pub result: String,
|
||||
}
|
120
src/errors.rs
Normal file
120
src/errors.rs
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::StepperOutcome;
|
||||
|
||||
use jsonpath_lib::JsonPathError;
|
||||
use serde_json::Error as SerdeJsonError;
|
||||
use serde_sexpr::Error as SExprError;
|
||||
|
||||
use std::convert::Into;
|
||||
use std::env::VarError;
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AquamarineError {
|
||||
/// Errors occurred while parsing aqua script in the form of S expressions.
|
||||
SExprParseError(SExprError),
|
||||
|
||||
/// Errors occurred while parsing supplied data.
|
||||
DataParseError(SerdeJsonError),
|
||||
|
||||
/// Indicates that environment variable with name CURRENT_PEER_ID isn't set.
|
||||
CurrentPeerIdNotSet(VarError),
|
||||
|
||||
/// Semantic errors in instructions.
|
||||
InstructionError(String),
|
||||
|
||||
/// Semantic errors in instructions.
|
||||
LocalServiceError(String),
|
||||
|
||||
/// Value with such name isn't presence in data.
|
||||
VariableNotFound(String),
|
||||
|
||||
/// Value with such path isn't found in data with such error.
|
||||
VariableNotInJsonPath(String, JsonPathError),
|
||||
|
||||
/// Multiple values found for such json path.
|
||||
MultipleValuesInJsonPath(String),
|
||||
}
|
||||
|
||||
impl Error for AquamarineError {}
|
||||
|
||||
impl std::fmt::Display for AquamarineError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
match self {
|
||||
AquamarineError::SExprParseError(err) => write!(f, "{}", err),
|
||||
AquamarineError::DataParseError(err) => write!(f, "{}", err),
|
||||
AquamarineError::CurrentPeerIdNotSet(err) => write!(f, "{}", err),
|
||||
AquamarineError::InstructionError(err_msg) => write!(f, "{}", err_msg),
|
||||
AquamarineError::LocalServiceError(err_msg) => write!(f, "{}", err_msg),
|
||||
AquamarineError::VariableNotFound(variable_name) => write!(
|
||||
f,
|
||||
"variable with name {} isn't present in data",
|
||||
variable_name
|
||||
),
|
||||
AquamarineError::VariableNotInJsonPath(json_path, json_path_err) => write!(
|
||||
f,
|
||||
"variable with path {} not found with error: {}",
|
||||
json_path, json_path_err
|
||||
),
|
||||
AquamarineError::MultipleValuesInJsonPath(json_path) => write!(
|
||||
f,
|
||||
"multiple variables found for this json path {}",
|
||||
json_path
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SExprError> for AquamarineError {
|
||||
fn from(err: SExprError) -> Self {
|
||||
AquamarineError::SExprParseError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SerdeJsonError> for AquamarineError {
|
||||
fn from(err: SerdeJsonError) -> Self {
|
||||
AquamarineError::DataParseError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::convert::Infallible> for AquamarineError {
|
||||
fn from(_: std::convert::Infallible) -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<StepperOutcome> for AquamarineError {
|
||||
fn into(self) -> StepperOutcome {
|
||||
let ret_code = match self {
|
||||
AquamarineError::SExprParseError(_) => 1,
|
||||
AquamarineError::DataParseError(..) => 2,
|
||||
AquamarineError::CurrentPeerIdNotSet(..) => 3,
|
||||
AquamarineError::InstructionError(..) => 4,
|
||||
AquamarineError::LocalServiceError(..) => 5,
|
||||
AquamarineError::VariableNotFound(..) => 6,
|
||||
AquamarineError::VariableNotInJsonPath(..) => 7,
|
||||
AquamarineError::MultipleValuesInJsonPath(..) => 8,
|
||||
};
|
||||
|
||||
StepperOutcome {
|
||||
ret_code,
|
||||
data: format!("{}", self),
|
||||
next_peer_pks: vec![],
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
use crate::instructions::Instruction;
|
||||
use crate::stepper_outcome::StepperOutcome;
|
||||
|
||||
pub fn exec(init_user_id: String, aqua: String, data: String) -> StepperOutcome {
|
||||
log::info!(
|
||||
"stepper invoked with user_id = {}, aqua = {:?}, data = {:?}",
|
||||
init_user_id,
|
||||
aqua,
|
||||
data
|
||||
);
|
||||
|
||||
let outcome = StepperOutcome {
|
||||
data,
|
||||
next_peer_pks: vec![init_user_id],
|
||||
};
|
||||
|
||||
let parsed_aqua = match serde_sexpr::from_str::<Vec<Instruction>>(&aqua) {
|
||||
Ok(parsed) => parsed,
|
||||
Err(e) => {
|
||||
log::error!("supplied aqua script can't be parsed: {:?}", e);
|
||||
|
||||
return outcome;
|
||||
}
|
||||
};
|
||||
log::info!("parsed_aqua: {:?}", parsed_aqua);
|
||||
|
||||
crate::stepper::execute(parsed_aqua);
|
||||
|
||||
outcome
|
||||
}
|
@ -13,14 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
mod air;
|
||||
mod execution;
|
||||
mod defines;
|
||||
mod errors;
|
||||
mod instructions;
|
||||
mod stepper;
|
||||
mod stepper_outcome;
|
||||
|
||||
use crate::execution::exec;
|
||||
use crate::stepper_outcome::StepperOutcome;
|
||||
pub(crate) use crate::defines::*;
|
||||
|
||||
use crate::stepper::execute_aqua;
|
||||
use fluence::fce;
|
||||
|
||||
pub fn main() {
|
||||
@ -29,13 +31,7 @@ pub fn main() {
|
||||
|
||||
#[fce]
|
||||
pub fn invoke(init_user_id: String, aqua: String, data: String) -> StepperOutcome {
|
||||
exec(init_user_id, aqua, data)
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub struct CallServiceResult {
|
||||
pub result: i32,
|
||||
pub outcome: String,
|
||||
execute_aqua(init_user_id, aqua, data)
|
||||
}
|
||||
|
||||
#[fce]
|
@ -14,25 +14,131 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use crate::AquaData;
|
||||
use crate::AquamarineError;
|
||||
use crate::Result;
|
||||
|
||||
use serde_derive::Deserialize;
|
||||
use serde_derive::Serialize;
|
||||
|
||||
const CURRENT_PEER_ALIAS: &str = "%current%";
|
||||
const CURRENT_PEER_ID_ENV_NAME: &str = "CURRENT_PEER_ID";
|
||||
|
||||
/*
|
||||
(current)
|
||||
(pk $pk)
|
||||
(pk $pk $srv_id)
|
||||
PEER_PART: resolves to (peer_pk) \/ (peer_pk, pk_srv_id)
|
||||
|
||||
(fn $name)
|
||||
(fn $name $srv_id)
|
||||
FN_PART: resolves to (fn_name) \/ (fn_srv_id, fn_name)
|
||||
*/
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct Call {
|
||||
pub peer_part: (String, Option<String>),
|
||||
pub fn_part: (Option<String>, String),
|
||||
pub args: String,
|
||||
pub result_name: String,
|
||||
#[serde(untagged)]
|
||||
pub enum PeerPart {
|
||||
PeerPk(String),
|
||||
PeerPkWithPkServiceId(String, String),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||
#[serde(untagged)]
|
||||
pub enum FunctionPart {
|
||||
FuncName(String),
|
||||
ServiceIdWithFuncName(String, String),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct Call(PeerPart, FunctionPart, Vec<String>, String);
|
||||
|
||||
impl super::ExecutableInstruction for Call {
|
||||
fn execute(self, _data: &mut HashMap<String, Vec<u8>>) {
|
||||
let service_id = match (self.peer_part.1, self.fn_part.0) {
|
||||
(Some(service_id), None) => service_id,
|
||||
(None, Some(service_id)) => service_id,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
fn execute(self, data: &mut AquaData, next_peer_pks: &mut Vec<String>) -> Result<()> {
|
||||
log::info!("call called with data: {:?} and next_peer_pks: {:?}", data, next_peer_pks);
|
||||
|
||||
let _result = unsafe { crate::call_service(service_id, self.fn_part.1, self.args) };
|
||||
let (peer_pk, service_id, func_name) = parse_peer_fn_parts(self.0, self.1)?;
|
||||
let function_args = parse_args(self.2, data)?;
|
||||
let function_args = serde_json::to_string(&function_args)?;
|
||||
let result_name = parse_result_name(self.3)?;
|
||||
|
||||
let current_peer_id = std::env::var(CURRENT_PEER_ID_ENV_NAME)
|
||||
.map_err(|e| AquamarineError::CurrentPeerIdNotSet(e))?;
|
||||
|
||||
if peer_pk == current_peer_id || peer_pk == CURRENT_PEER_ALIAS {
|
||||
let result = unsafe { crate::call_service(service_id, func_name, function_args) };
|
||||
if result.ret_code != crate::CALL_SERVICE_SUCCESS {
|
||||
return Err(AquamarineError::LocalServiceError(result.result));
|
||||
}
|
||||
|
||||
let result: serde_json::Value = serde_json::from_str(&result.result)?;
|
||||
data.insert(result_name, result);
|
||||
} else {
|
||||
next_peer_pks.push(peer_pk);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn parse_peer_fn_parts(
|
||||
peer_part: PeerPart,
|
||||
fn_part: FunctionPart,
|
||||
) -> Result<(String, String, String)> {
|
||||
match (peer_part, fn_part) {
|
||||
(PeerPart::PeerPkWithPkServiceId(peer_pk, peer_service_id), FunctionPart::ServiceIdWithFuncName(_service_id, func_name)) => {
|
||||
Ok((peer_pk, peer_service_id, func_name))
|
||||
},
|
||||
(PeerPart::PeerPkWithPkServiceId(peer_pk, peer_service_id), FunctionPart::FuncName(func_name)) => {
|
||||
Ok((peer_pk, peer_service_id, func_name))
|
||||
},
|
||||
(PeerPart::PeerPk(peer_pk), FunctionPart::ServiceIdWithFuncName(service_id, func_name)) => {
|
||||
Ok((peer_pk, service_id, func_name))
|
||||
}
|
||||
(PeerPart::PeerPk(_), FunctionPart::FuncName(_)) => Err(AquamarineError::InstructionError(
|
||||
String::from("call should have service id specified by peer part or function part"),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_args(args: Vec<String>, data: &AquaData) -> Result<serde_json::Value> {
|
||||
let mut result = Vec::with_capacity(args.len());
|
||||
|
||||
for arg in args {
|
||||
let mut split_arg: Vec<&str> = arg.splitn(1, '.').collect();
|
||||
let variable_name = split_arg.remove(0);
|
||||
|
||||
let value_by_key = data
|
||||
.get(variable_name)
|
||||
.ok_or_else(|| AquamarineError::VariableNotFound(String::from(variable_name)))?;
|
||||
|
||||
let value = if !split_arg.is_empty() {
|
||||
let json_path = split_arg.remove(0);
|
||||
let values = jsonpath_lib::select(&value_by_key, json_path)
|
||||
.map_err(|e| AquamarineError::VariableNotInJsonPath(String::from(json_path), e))?;
|
||||
if values.len() != 1 {
|
||||
return Err(AquamarineError::MultipleValuesInJsonPath(String::from(
|
||||
json_path,
|
||||
)));
|
||||
}
|
||||
|
||||
values[0].clone()
|
||||
} else {
|
||||
value_by_key.clone()
|
||||
};
|
||||
|
||||
result.push(value);
|
||||
}
|
||||
|
||||
Ok(serde_json::Value::Array(result))
|
||||
}
|
||||
|
||||
fn parse_result_name(result_name: String) -> Result<String> {
|
||||
if !result_name.is_empty() {
|
||||
Ok(result_name)
|
||||
} else {
|
||||
Err(AquamarineError::InstructionError(String::from(
|
||||
"result name of a call instruction must be non empty",
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
@ -15,19 +15,22 @@
|
||||
*/
|
||||
|
||||
mod call;
|
||||
|
||||
pub(crate) use call::Call;
|
||||
mod null;
|
||||
|
||||
pub(self) use crate::stepper::ExecutableInstruction;
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::hash_map::RandomState;
|
||||
use std::collections::HashMap;
|
||||
use crate::AquaData;
|
||||
use crate::Result;
|
||||
use call::Call;
|
||||
use null::Null;
|
||||
|
||||
use serde_derive::Deserialize;
|
||||
use serde_derive::Serialize;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub(crate) enum Instruction {
|
||||
Null,
|
||||
Null(Null),
|
||||
Call(Call),
|
||||
/*
|
||||
Par(Box<Instruction>, Box<Instruction>),
|
||||
@ -37,10 +40,10 @@ pub(crate) enum Instruction {
|
||||
}
|
||||
|
||||
impl ExecutableInstruction for Instruction {
|
||||
fn execute(self, data: &mut HashMap<String, Vec<u8>, RandomState>) {
|
||||
fn execute(self, data: &mut AquaData, next_peer_pks: &mut Vec<String>) -> Result<()> {
|
||||
match self {
|
||||
Instruction::Null => {}
|
||||
Instruction::Call(call) => call.execute(data),
|
||||
Instruction::Null(null) => null.execute(data, next_peer_pks),
|
||||
Instruction::Call(call) => call.execute(data, next_peer_pks),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
32
src/instructions/null.rs
Normal file
32
src/instructions/null.rs
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::AquaData;
|
||||
use crate::Result;
|
||||
|
||||
use serde_derive::Deserialize;
|
||||
use serde_derive::Serialize;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct Null {}
|
||||
|
||||
impl super::ExecutableInstruction for Null {
|
||||
fn execute(self, data: &mut AquaData, next_peer_pks: &mut Vec<String>) -> Result<()> {
|
||||
log::info!("null called with data: {:?} and next_peer_pks: {:?}", data, next_peer_pks);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
51
src/stepper/execution.rs
Normal file
51
src/stepper/execution.rs
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use super::StepperOutcome;
|
||||
use crate::instructions::Instruction;
|
||||
use crate::AquaData;
|
||||
use crate::Result;
|
||||
|
||||
pub(crate) fn execute_aqua(init_user_id: String, aqua: String, data: String) -> StepperOutcome {
|
||||
log::info!(
|
||||
"stepper invoked with user_id = {}, aqua = {:?}, data = {:?}",
|
||||
init_user_id,
|
||||
aqua,
|
||||
data
|
||||
);
|
||||
|
||||
execute_aqua_impl(init_user_id, aqua, data).unwrap_or_else(Into::into)
|
||||
}
|
||||
|
||||
fn execute_aqua_impl(init_user_id: String, aqua: String, data: String) -> Result<StepperOutcome> {
|
||||
let mut parsed_data: AquaData = serde_json::from_str(&data)?;
|
||||
let parsed_aqua = serde_sexpr::from_str::<Vec<Instruction>>(&aqua)?;
|
||||
|
||||
log::info!(
|
||||
"parsed_aqua: {:?}\nparsed_data: {:?}",
|
||||
parsed_aqua,
|
||||
parsed_data
|
||||
);
|
||||
|
||||
let next_peer_pks = super::stepper::execute(parsed_aqua, &mut parsed_data)?;
|
||||
let data = serde_json::to_string(&parsed_data)?;
|
||||
|
||||
Ok(StepperOutcome {
|
||||
ret_code: 0,
|
||||
data,
|
||||
next_peer_pks,
|
||||
})
|
||||
}
|
25
src/stepper/mod.rs
Normal file
25
src/stepper/mod.rs
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
mod execution;
|
||||
mod stepper;
|
||||
mod stepper_outcome;
|
||||
|
||||
pub use stepper_outcome::StepperOutcome;
|
||||
pub use stepper_outcome::SUCCESS_ERROR_CODE;
|
||||
|
||||
pub(crate) use execution::execute_aqua;
|
||||
pub(crate) use stepper::ExecutableInstruction;
|
@ -15,16 +15,19 @@
|
||||
*/
|
||||
|
||||
use crate::instructions::Instruction;
|
||||
use std::collections::HashMap;
|
||||
use crate::AquaData;
|
||||
use crate::Result;
|
||||
|
||||
pub(crate) trait ExecutableInstruction {
|
||||
fn execute(self, data: &mut HashMap<String, Vec<u8>>);
|
||||
fn execute(self, data: &mut AquaData, next_peer_pks: &mut Vec<String>) -> Result<()>;
|
||||
}
|
||||
|
||||
pub(crate) fn execute(instructions: Vec<Instruction>) {
|
||||
let mut data = HashMap::new();
|
||||
pub(crate) fn execute(instructions: Vec<Instruction>, data: &mut AquaData) -> Result<Vec<String>> {
|
||||
let mut next_peer_pks = Vec::new();
|
||||
|
||||
for instruction in instructions {
|
||||
instruction.execute(&mut data);
|
||||
instruction.execute(data, &mut next_peer_pks)?;
|
||||
}
|
||||
|
||||
Ok(next_peer_pks)
|
||||
}
|
@ -17,9 +17,17 @@
|
||||
use fluence::fce;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const SUCCESS_ERROR_CODE: i32 = 0;
|
||||
|
||||
#[fce]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct StepperOutcome {
|
||||
/// A return code, where SUCCESS_ERROR_CODE means success.
|
||||
pub ret_code: i32,
|
||||
|
||||
/// Contains data if ret_code == 0, otherwise error message (that could be empty string).
|
||||
pub data: String,
|
||||
|
||||
/// Public keys of peers that should receive data.
|
||||
pub next_peer_pks: Vec<String>,
|
||||
}
|
@ -13,18 +13,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
mod air;
|
||||
mod execution;
|
||||
mod defines;
|
||||
mod errors;
|
||||
mod instructions;
|
||||
mod stepper;
|
||||
mod stepper_outcome;
|
||||
|
||||
use crate::execution::exec;
|
||||
pub(crate) use crate::defines::*;
|
||||
|
||||
use crate::stepper::execute_aqua;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn invoke(init_user_id: String, aqua: String, data: String) -> String {
|
||||
let outcome = exec(init_user_id, aqua, data);
|
||||
let outcome = execute_aqua(init_user_id, aqua, data);
|
||||
serde_json::to_string(&outcome).unwrap()
|
||||
}
|
||||
|
||||
@ -34,7 +38,13 @@ extern "C" {
|
||||
fn log(s: &str);
|
||||
}
|
||||
|
||||
pub fn call_service(service_id: String, fn_name: String, args: String) -> CallServiceResult {
|
||||
let result = call_service_impl(service_id, fn_name, args);
|
||||
serde_json::from_str(&result).unwrap()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(raw_module = "../src/call_service.ts")]
|
||||
extern "C" {
|
||||
pub fn call_service(service_id: String, fn_name: String, args: String) -> String;
|
||||
#[link_name = "call_service"]
|
||||
fn call_service_impl(service_id: String, fn_name: String, args: String) -> String;
|
||||
}
|
@ -4,19 +4,19 @@ fn main() {}
|
||||
|
||||
#[fce]
|
||||
pub struct CallServiceResult {
|
||||
pub result: i32,
|
||||
pub outcome: Vec<u8>,
|
||||
pub ret_code: i32,
|
||||
pub result: String,
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn call_service(service_id: String, fn_name: String, args: Vec<u8>) -> CallServiceResult {
|
||||
pub fn call_service(service_id: String, fn_name: String, args: String) -> CallServiceResult {
|
||||
println!(
|
||||
"call service invoked with:\n service_id: {}\n fn_name: {}\n args: {:?}",
|
||||
service_id, fn_name, args
|
||||
);
|
||||
|
||||
CallServiceResult {
|
||||
result: 0,
|
||||
outcome: vec![1, 2, 3],
|
||||
ret_code: 0,
|
||||
result: String::from("[\"result string\"]"),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user