Merge pull request #3 from fluencelabs/improved_call

Request-response stepper
This commit is contained in:
vms 2020-09-30 22:30:44 +03:00 committed by GitHub
commit 8cec0163b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 635 additions and 82 deletions

167
Cargo.lock generated
View File

@ -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"

View File

@ -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"

View File

@ -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"]

View File

@ -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

View File

@ -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
View 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
View 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![],
}
}
}

View File

@ -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
}

View File

@ -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]

View File

@ -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",
)))
}
}

View File

@ -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
View 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
View 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
View 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;

View File

@ -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)
}

View File

@ -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>,
}

View File

@ -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;
}

View File

@ -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\"]"),
}
}