From 8bc7ac36b22adc278848d18a5fc81cfec1af3141 Mon Sep 17 00:00:00 2001 From: vms Date: Sat, 17 Aug 2019 00:58:17 +0300 Subject: [PATCH] initial commit --- .../step2-database-only/src/database.rs | 64 ------------------- backend-rust/step2-database-only/src/ffi.rs | 26 -------- backend-rust/step2-database-only/src/lib.rs | 28 ++++---- backend-rust/step2-database-only/src/utils.rs | 24 +++++++ backend-rust/step3-finished-app/Cargo.toml | 2 +- .../step3-finished-app/src/database.rs | 63 ------------------ backend-rust/step3-finished-app/src/ffi.rs | 26 -------- backend-rust/step3-finished-app/src/lib.rs | 5 +- backend-rust/step3-finished-app/src/model.rs | 46 ++++++------- backend-rust/step3-finished-app/src/utils.rs | 24 +++++++ 10 files changed, 86 insertions(+), 222 deletions(-) delete mode 100644 backend-rust/step2-database-only/src/database.rs delete mode 100644 backend-rust/step2-database-only/src/ffi.rs create mode 100644 backend-rust/step2-database-only/src/utils.rs delete mode 100644 backend-rust/step3-finished-app/src/database.rs delete mode 100644 backend-rust/step3-finished-app/src/ffi.rs create mode 100644 backend-rust/step3-finished-app/src/utils.rs diff --git a/backend-rust/step2-database-only/src/database.rs b/backend-rust/step2-database-only/src/database.rs deleted file mode 100644 index 3f4c4a2..0000000 --- a/backend-rust/step2-database-only/src/database.rs +++ /dev/null @@ -1,64 +0,0 @@ -use log; - -use crate::errors::AppResult; - -use crate::errors::err_msg; -use crate::ffi; - -// Execute query on SQLite -pub fn query(query: String) -> AppResult { - log::debug!("executing query: '{}'", query); - - unsafe { - // Convert query string to bytes - let query_bytes = query.as_bytes(); - // Allocate memory for query in SQLite module - let query_ptr = ffi::allocate(query_bytes.len()); - - // Store query in SQLite's memory - for (i, byte) in query_bytes.iter().enumerate() { - let ptr = query_ptr + i as i32; - ffi::store(ptr, *byte); - } - - // Execute the query, and get pointer to the result - let result_ptr = ffi::invoke(query_ptr, query_bytes.len()); - - // First 4 bytes at result_ptr location encode result size, read that first - let mut result_size: usize = 0; - for i in 0..3 { - let ptr = result_ptr + i as i32; - let b = ffi::load(ptr) as usize; - result_size = result_size + (b << (8 * i)); - } - // Now we know exact size of the query execution result - - // Read query execution result byte-by-byte - let mut result_bytes = vec![0; result_size as usize]; - for i in 4..(result_size + 4) { - let ptr = result_ptr + i as i32; - let b = ffi::load(ptr); - result_bytes[i as usize - 4] = b; - } - - // Deallocate query result - ffi::deallocate(result_ptr, result_size + 4); - - // Decode query result to a utf8 string - let result_str = std::str::from_utf8(result_bytes.as_slice()); - - // Log if there's an error - if result_str.is_err() { - log::error!("unable to decode result from bytes: {:#x?}", result_bytes); - } - // Wrap error with a better message, and return Result - result_str - .map_err(|e| { - err_msg(&format!( - "unable to decode result from bytes {:#x?}: {}", - result_bytes, e - )) - }) - .map(|s| s.to_string()) - } -} diff --git a/backend-rust/step2-database-only/src/ffi.rs b/backend-rust/step2-database-only/src/ffi.rs deleted file mode 100644 index 69a7a24..0000000 --- a/backend-rust/step2-database-only/src/ffi.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Description of inter-module communication -// -// Allows fluid module to call methods from sqlite module - -#[link(wasm_import_module = "sqlite")] -extern "C" { - // Allocate chunk of SQLite memory, and return a pointer to that memory - #[link_name = "sqlite_allocate"] - pub fn allocate(size: usize) -> i32; - - // Deallocate chunk of memory after it's not used anymore - #[link_name = "sqlite_deallocate"] - pub fn deallocate(ptr: i32, size: usize); - - // Put 1 byte at ptr location in SQLite memory - #[link_name = "sqlite_store"] - pub fn store(ptr: i32, byte: u8); - - // Read 1 byte from ptr location of SQLite memory - #[link_name = "sqlite_load"] - pub fn load(ptr: i32) -> u8; - - // Call SQLite's invocation handler with data specified by pointer and size - #[link_name = "sqlite_invoke"] - pub fn invoke(ptr: i32, size: usize) -> i32; -} diff --git a/backend-rust/step2-database-only/src/lib.rs b/backend-rust/step2-database-only/src/lib.rs index 9e69496..d26fb61 100644 --- a/backend-rust/step2-database-only/src/lib.rs +++ b/backend-rust/step2-database-only/src/lib.rs @@ -1,37 +1,39 @@ use fluence::sdk::*; -pub mod database; pub mod errors; -pub mod ffi; +pub mod utils; + +use crate::utils::sqlite_call_wrapper; fn init() { logger::WasmLogger::init_with_level(log::Level::Info).unwrap(); } -#[invocation_handler(init_fn = init)] +#[invocation_handler(init_fn = init, side_modules = sqlite)] fn run(nickname: String) -> String { // Create table for messages storage - database::query("CREATE TABLE messages(message text, username text)".to_string()) + sqlite_call_wrapper("CREATE TABLE messages(message text, username text)") .expect("error on CREATE TABLE"); // Insert message 'Hello, username!' using `nickname` as author's username - database::query(format!( - r#"INSERT INTO messages VALUES("{}","{}")"#, - "Hello, username!", nickname - )) + sqlite_call_wrapper( + format!( + r#"INSERT INTO messages VALUES("{}","{}")"#, + "Hello, username!", nickname + ) + .as_str(), + ) .expect("error on INSERT INTO"); // Get all messages - let messages = - database::query("SELECT * FROM messages".to_string()).expect("error on SELECT *"); + let messages = sqlite_call_wrapper("SELECT * FROM messages").expect("error on SELECT *"); log::info!("messages: {:?}", messages); // Get all messages as JSON via SQLite's JSON extension - database::query( + sqlite_call_wrapper( "SELECT json_group_array( json_object('message', message, 'username', username) - ) AS json_result FROM (SELECT * FROM messages)" - .to_string(), + ) AS json_result FROM (SELECT * FROM messages)", ) .expect("error on SELECT as json") } diff --git a/backend-rust/step2-database-only/src/utils.rs b/backend-rust/step2-database-only/src/utils.rs new file mode 100644 index 0000000..f18d302 --- /dev/null +++ b/backend-rust/step2-database-only/src/utils.rs @@ -0,0 +1,24 @@ +use crate::errors::{err_msg, AppResult}; +use crate::sqlite; + +pub fn sqlite_call_wrapper(bytes: &str) -> AppResult { + let response = sqlite::call(bytes.as_bytes()); + + // Decode query result to a utf8 string + let result_str = std::str::from_utf8(&response); + + // Log if there's an error + if result_str.is_err() { + log::error!("unable to decode result from bytes: {:#x?}", bytes); + } + + // Wrap error with a better message, and return Result + result_str + .map_err(|e| { + err_msg(&format!( + "unable to decode result from bytes {:#x?}: {}", + bytes, e + )) + }) + .map(|s| s.to_string()) +} diff --git a/backend-rust/step3-finished-app/Cargo.toml b/backend-rust/step3-finished-app/Cargo.toml index 457230d..f3c6f7f 100644 --- a/backend-rust/step3-finished-app/Cargo.toml +++ b/backend-rust/step3-finished-app/Cargo.toml @@ -21,4 +21,4 @@ panic = "abort" serde = { version = "=1.0.88", features = ["derive"] } serde_json = { version = "=1.0.38", features = ["raw_value"] } log = "0.4" -fluence = { version = "0.1.6", features = ["wasm_logger"] } +fluence = { version = "0.1.7", features = ["wasm_logger"] } diff --git a/backend-rust/step3-finished-app/src/database.rs b/backend-rust/step3-finished-app/src/database.rs deleted file mode 100644 index de5e32c..0000000 --- a/backend-rust/step3-finished-app/src/database.rs +++ /dev/null @@ -1,63 +0,0 @@ -use log; - -use crate::errors::err_msg; -use crate::errors::AppResult; -use crate::ffi; - -// Execute query on SQLite -pub fn query(query: String) -> AppResult { - log::debug!("executing query: '{}'", query); - - unsafe { - // Convert query string to bytes - let query_bytes = query.as_bytes(); - // Allocate memory for query in SQLite module - let query_ptr = ffi::allocate(query_bytes.len()); - - // Store query in SQLite's memory - for (i, byte) in query_bytes.iter().enumerate() { - let ptr = query_ptr + i as i32; - ffi::store(ptr, *byte); - } - - // Execute the query, and get pointer to the result - let result_ptr = ffi::invoke(query_ptr, query_bytes.len()); - - // First 4 bytes at result_ptr location encode result size, read that first - let mut result_size: usize = 0; - for i in 0..3 { - let ptr = result_ptr + i as i32; - let b = ffi::load(ptr) as usize; - result_size = result_size + (b << (8 * i)); - } - // Now we know exact size of the query execution result - - // Read query execution result byte-by-byte - let mut result_bytes = vec![0; result_size as usize]; - for i in 4..(result_size + 4) { - let ptr = result_ptr + i as i32; - let b = ffi::load(ptr); - result_bytes[i as usize - 4] = b; - } - - // Deallocate query result - ffi::deallocate(result_ptr, result_size + 4); - - // Decode query result to a utf8 string - let result_str = std::str::from_utf8(result_bytes.as_slice()); - - // Log if there's an error - if result_str.is_err() { - log::error!("unable to decode result from bytes: {:#x?}", result_bytes); - } - // Wrap error with a better message, and return Result - result_str - .map_err(|e| { - err_msg(&format!( - "unable to decode result from bytes {:#x?}: {}", - result_bytes, e - )) - }) - .map(|s| s.to_string()) - } -} diff --git a/backend-rust/step3-finished-app/src/ffi.rs b/backend-rust/step3-finished-app/src/ffi.rs deleted file mode 100644 index 69a7a24..0000000 --- a/backend-rust/step3-finished-app/src/ffi.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Description of inter-module communication -// -// Allows fluid module to call methods from sqlite module - -#[link(wasm_import_module = "sqlite")] -extern "C" { - // Allocate chunk of SQLite memory, and return a pointer to that memory - #[link_name = "sqlite_allocate"] - pub fn allocate(size: usize) -> i32; - - // Deallocate chunk of memory after it's not used anymore - #[link_name = "sqlite_deallocate"] - pub fn deallocate(ptr: i32, size: usize); - - // Put 1 byte at ptr location in SQLite memory - #[link_name = "sqlite_store"] - pub fn store(ptr: i32, byte: u8); - - // Read 1 byte from ptr location of SQLite memory - #[link_name = "sqlite_load"] - pub fn load(ptr: i32) -> u8; - - // Call SQLite's invocation handler with data specified by pointer and size - #[link_name = "sqlite_invoke"] - pub fn invoke(ptr: i32, size: usize) -> i32; -} diff --git a/backend-rust/step3-finished-app/src/lib.rs b/backend-rust/step3-finished-app/src/lib.rs index 0d9b63d..43e0ba4 100644 --- a/backend-rust/step3-finished-app/src/lib.rs +++ b/backend-rust/step3-finished-app/src/lib.rs @@ -8,17 +8,16 @@ use crate::errors::err_msg; use crate::errors::AppResult; pub mod api; -pub mod database; pub mod errors; -pub mod ffi; pub mod model; +pub mod utils; fn init() { logger::WasmLogger::init_with_level(log::Level::Info).unwrap(); model::create_scheme().unwrap(); } -#[invocation_handler(init_fn = init)] +#[invocation_handler(init_fn = init, side_modules = sqlite)] fn run(arg: String) -> String { // Parse and username JSON request let result = api::parse(arg).and_then(|request| match request { diff --git a/backend-rust/step3-finished-app/src/model.rs b/backend-rust/step3-finished-app/src/model.rs index 289ef38..96ef033 100644 --- a/backend-rust/step3-finished-app/src/model.rs +++ b/backend-rust/step3-finished-app/src/model.rs @@ -1,52 +1,46 @@ use std::str::FromStr; -use crate::database; use crate::errors::err_msg; use crate::errors::AppResult; +use crate::utils::sqlite_call_wrapper; pub fn create_scheme() -> AppResult<()> { - database::query("CREATE TABLE messages(message text, username text)".to_string()) - .map_err(|e| err_msg(&format!("Error creating table messages: {}", e))) - .map(drop) + sqlite_call_wrapper("CREATE TABLE messages(message text, username text)").map(drop) } pub fn add_post(message: String, username: String) -> AppResult<()> { - database::query(format!( - r#"INSERT INTO messages VALUES("{}","{}")"#, - message, username - )) - .map_err(|e| { - err_msg(&format!( - "Error inserting post {} by {}: {}", - message, username, e - )) - }) + sqlite_call_wrapper( + format!( + r#"INSERT INTO messages VALUES("{}","{}")"#, + message, username + ) + .as_str(), + ) .map(drop) } pub fn get_all_posts() -> AppResult { - database::query( + sqlite_call_wrapper( "SELECT json_group_array( json_object('message', message, 'username', username) - ) AS json_result FROM (SELECT * FROM messages)" - .to_string(), + ) AS json_result FROM (SELECT * FROM messages)", ) - .map_err(|e| err_msg(&format!("Error retrieving posts: {}", e))) } pub fn get_posts_by_username(username: String) -> AppResult { - database::query(format!( - "SELECT json_group_array( + sqlite_call_wrapper( + format!( + "SELECT json_group_array( json_object('message', message, 'username', username) - ) AS json_result FROM (SELECT * FROM messages where username = '{}')", - username - )) - .map_err(|e| err_msg(&format!("Error retrieving posts: {}", e))) + ) AS json_result FROM (SELECT * FROM messages where username = '{}')", + username + ) + .as_str(), + ) } pub fn get_posts_count() -> AppResult { - let result = database::query("SELECT COUNT(*) from messages".to_string()) - .map_err(|e| err_msg(&format!("Error retrieving posts count: {}", e)))?; + let result = sqlite_call_wrapper("SELECT COUNT(*) from messages")?; i32::from_str(result.as_str()).map_err(|e| { err_msg(&format!( diff --git a/backend-rust/step3-finished-app/src/utils.rs b/backend-rust/step3-finished-app/src/utils.rs new file mode 100644 index 0000000..f18d302 --- /dev/null +++ b/backend-rust/step3-finished-app/src/utils.rs @@ -0,0 +1,24 @@ +use crate::errors::{err_msg, AppResult}; +use crate::sqlite; + +pub fn sqlite_call_wrapper(bytes: &str) -> AppResult { + let response = sqlite::call(bytes.as_bytes()); + + // Decode query result to a utf8 string + let result_str = std::str::from_utf8(&response); + + // Log if there's an error + if result_str.is_err() { + log::error!("unable to decode result from bytes: {:#x?}", bytes); + } + + // Wrap error with a better message, and return Result + result_str + .map_err(|e| { + err_msg(&format!( + "unable to decode result from bytes {:#x?}: {}", + bytes, e + )) + }) + .map(|s| s.to_string()) +}