Local Data Storage
A peer hosting services may agree to provide access to their filesystem or allocate additional RAM. However, such persistence provisioning generally comes with no guarantees of availability. For example, a peer reboot will wipe a SQLite in-memory data base. Moreover, by the very nature of their local provisioning, such data sources are only available through the "sponsoring" service: there is no direct data access and when the service ceases to exist so does the data.While local data persistence has its use cases, developers need to be aware of their limitations.
Local Filesystem
While Wasm modules in general are sandboxed to not have access to host resources, Marine Wasm modules may be granted access to a variety of host resources iff the host peer agrees to such access. The request for resource access and allocation come in form of deployment parameters, which we'll see very soon
The accompanying repo.
Let's start by creating a new, minimal Fluence CLI project by the name of your choice:
fluence init write-to-file? Select template minimalSuccessfully initialized Fluence project template at ~/localdev/write-to-filecd write-to-file
fluence init write-to-file? Select template minimalSuccessfully initialized Fluence project template at ~/localdev/write-to-filecd write-to-file
In the new project directory, we scaffold a new service:
fluence service new? Enter service path services? Do you want to use services as the name of your new service? No? Enter service name (must start with a lowercase letter and contain only letters, numbers, and underscores)filesys_adapterSuccessfully generated template for new service at services? Do you want add filesys_adapter to fluence.yaml? YesUpdating crates.io index
fluence service new? Enter service path services? Do you want to use services as the name of your new service? No? Enter service name (must start with a lowercase letter and contain only letters, numbers, and underscores)filesys_adapterSuccessfully generated template for new service at services? Do you want add filesys_adapter to fluence.yaml? YesUpdating crates.io index
Which gives us the project scaffold:
tree services -L 4 -I targetservices├── modules│ ├── filesys_adapter│ │ ├── Cargo.lock│ │ ├── Cargo.toml│ │ ├── module.yaml│ │ └── src│ │ └── main.rs│ └── use_filesys│ ├── Cargo.lock│ ├── Cargo.toml│ ├── module.yaml│ └── src│ └── main.rs└── service.yaml
tree services -L 4 -I targetservices├── modules│ ├── filesys_adapter│ │ ├── Cargo.lock│ │ ├── Cargo.toml│ │ ├── module.yaml│ │ └── src│ │ └── main.rs│ └── use_filesys│ ├── Cargo.lock│ ├── Cargo.toml│ ├── module.yaml│ └── src│ └── main.rs└── service.yaml
And the Rust template:
rust
// services/modules/filesys_adapter/src/main.rs#![allow(non_snake_case)]use marine_rs_sdk::marine;use marine_rs_sdk::module_manifest;module_manifest!();pub fn main() {}#[marine]pub fn greeting(name: String) -> String {format!("Hi, {}", name)}
rust
// services/modules/filesys_adapter/src/main.rs#![allow(non_snake_case)]use marine_rs_sdk::marine;use marine_rs_sdk::module_manifest;module_manifest!();pub fn main() {}#[marine]pub fn greeting(name: String) -> String {format!("Hi, {}", name)}
Which we'll have to modify. In addition to the adapter, which handles the access to the local resource, we also want a to add some minimal business logic to use our adapter.
bash
fluence module new? Enter service path services? Do you want to use services as the name of your new service? No? Enter service name (must start with a lowercase letter and contain only letters, numbers, and underscores) use_filesysSuccessfully generated template for new service at services? Do you want add use_filesys to fluence.yaml? YesFinished release [optimized] target(s) in 0.19sAdded use_filesys to fluence.yaml
bash
fluence module new? Enter service path services? Do you want to use services as the name of your new service? No? Enter service name (must start with a lowercase letter and contain only letters, numbers, and underscores) use_filesysSuccessfully generated template for new service at services? Do you want add use_filesys to fluence.yaml? YesFinished release [optimized] target(s) in 0.19sAdded use_filesys to fluence.yaml
With the scaffolding out of the way, let's code our modules. First, we create our general-purpose, reusable "adapter" module to handle the put/get operations to/from the local, i.e., host peer, filesystem and add a file removal method, rm
, as well:
rust
use marine_rs_sdk::marine;use std::fs;use std::path::PathBuf;const SITES_DIR: &str = "/sites/";pub fn main() {}#[marine]pub fn put(name: String, file_content: Vec<u8>) -> String {let rpc_tmp_filepath = format!("{}{}", SITES_DIR, name);let result = fs::write(PathBuf::from(rpc_tmp_filepath.clone()), file_content);if let Err(e) = result {return format!("file can't be written: {}", e);}String::from("Ok")}#[marine]pub fn get(file_name: String) -> Vec<u8> {let tmp_filepath = format!("{}{}", SITES_DIR, file_name);fs::read(tmp_filepath).unwrap_or_else(|_| b"error while reading file".to_vec())}#[marine]pub fn rm(name: String) -> String {let rpc_tmp_filepath = format!("{}{}", SITES_DIR, name);let result = fs::remove_file(rpc_tmp_filepath);match result {Ok(_) => "OK".to_string(),Err(e) => e.to_string(),}}```The code is pretty straight forward read/write but a few lines are noteworthy: The `const SITES_DIR` is the *alias* to the local path and needs to match up with the mapping in `modules.yaml`.The scaffolded default file looks like this:```yamlversion: 0type: rustname: filesys_adapter
rust
use marine_rs_sdk::marine;use std::fs;use std::path::PathBuf;const SITES_DIR: &str = "/sites/";pub fn main() {}#[marine]pub fn put(name: String, file_content: Vec<u8>) -> String {let rpc_tmp_filepath = format!("{}{}", SITES_DIR, name);let result = fs::write(PathBuf::from(rpc_tmp_filepath.clone()), file_content);if let Err(e) = result {return format!("file can't be written: {}", e);}String::from("Ok")}#[marine]pub fn get(file_name: String) -> Vec<u8> {let tmp_filepath = format!("{}{}", SITES_DIR, file_name);fs::read(tmp_filepath).unwrap_or_else(|_| b"error while reading file".to_vec())}#[marine]pub fn rm(name: String) -> String {let rpc_tmp_filepath = format!("{}{}", SITES_DIR, name);let result = fs::remove_file(rpc_tmp_filepath);match result {Ok(_) => "OK".to_string(),Err(e) => e.to_string(),}}```The code is pretty straight forward read/write but a few lines are noteworthy: The `const SITES_DIR` is the *alias* to the local path and needs to match up with the mapping in `modules.yaml`.The scaffolded default file looks like this:```yamlversion: 0type: rustname: filesys_adapter
Which is not enough. We need to specify that we want this module to be able to access the hosts filesystem via some specified directory and we do this my mounting a named directory mapped to the SITES_DIR alias:
//services/modules/filesys_adapter/module.yamlversion: 0type: rustname: filesys_adaptervolumes:sites: ./tmp
//services/modules/filesys_adapter/module.yamlversion: 0type: rustname: filesys_adaptervolumes:sites: ./tmp
For more information on import functions see the Marine book and the configuration properties provided by Fluence CLI.
With our configuration in place, let's build our adapter:
bash
# in the project root directoryFluence buildMaking sure all services are downloaded... doneCompiling filesys_adapter v0.1.0 (/Users/bebo/localdev/write-to-file/services/modules/filesys_adapter)Finished release [optimized] target(s) in 0.40sMaking sure all modules are downloaded and built... done
bash
# in the project root directoryFluence buildMaking sure all services are downloaded... doneCompiling filesys_adapter v0.1.0 (/Users/bebo/localdev/write-to-file/services/modules/filesys_adapter)Finished release [optimized] target(s) in 0.40sMaking sure all modules are downloaded and built... done
where the volumes section contains the mapping of the actual directory to the alias we set as in the . For more information on configuring Marine modules, see the Marine book.
For more effective ways to read/write files, see the Rust documentation and cookbook and create your own custom file IO adapter!
Now that we have our effector module in place, let's code our facade module, which in our case consists of simple read and write methods essentially wrapping the effector methods with a little convenience: instead of byte arrays we can use human readable strings to write and read our file content.
Recall that Wasm IT modules are shared nothing and that we need to explicitly link dependencies. Before we code our facade, let's have a look at what we need to do to link our effector, aka adapter, module:
rust
#[marine]#[link(wasm_import_module = "filesys_adapter")] // 1extern "C" {#[link_name = "get"]pub fn file_get(file_name: String) -> Vec<u8>; // 2#[link_name = "put"]pub fn file_put(name: String, file_content: Vec<u8>) -> String;}
rust
#[marine]#[link(wasm_import_module = "filesys_adapter")] // 1extern "C" {#[link_name = "get"]pub fn file_get(file_name: String) -> Vec<u8>; // 2#[link_name = "put"]pub fn file_put(name: String, file_content: Vec<u8>) -> String;}
- (1): here we use Rust's FFI to specify the module name we want to import
- (2): for each (public) method in our effector module, we create a link reference and assign a link name, i.e. get or put, which are now available to the facade module.
Let's put it all together:
rust
// services/modules/use_filesys/src/main.rsuse marine_rs_sdk::marine;pub fn main() {}#[marine]pub struct IOResult {pub stdout: String,pub stderr: String,}#[marine]pub fn read_file(name: String) -> IOResult {let response: Vec<u8> = file_get(name);if response == b"error while reading file".to_vec() {return IOResult {stdout: "".to_string(),stderr: "error reading file".to_string(),};} else {IOResult {stdout: String::from_utf8_lossy(&response).to_string(),stderr: "".to_string(),}}}#[marine]pub fn write_file(name: String, payload: String) -> IOResult {let content = payload.as_bytes().to_vec();let response = file_put(name, content);let result = response.as_str().contains("file can't be written:");if result {return IOResult {stdout: "".to_string(),stderr: response,};} else {IOResult {stdout: "OK".to_string(),stderr: "".to_string(),}}}#[marine]pub fn rm_file(name: String) -> IOResult {let result = file_remove(name);if &result == "OK" {return IOResult {stdout: result,stderr: "".to_string(),};} else {IOResult {stdout: "".to_string(),stderr: result,}}}#[marine]#[link(wasm_import_module = "filesys_adapter")] // 1extern "C" {#[link_name = "get"]pub fn file_get(file_name: String) -> Vec<u8>; // 2#[link_name = "put"]pub fn file_put(name: String, file_content: Vec<u8>) -> String;#[link_name = "rm"]pub fn file_remove(name: String) -> String;}
rust
// services/modules/use_filesys/src/main.rsuse marine_rs_sdk::marine;pub fn main() {}#[marine]pub struct IOResult {pub stdout: String,pub stderr: String,}#[marine]pub fn read_file(name: String) -> IOResult {let response: Vec<u8> = file_get(name);if response == b"error while reading file".to_vec() {return IOResult {stdout: "".to_string(),stderr: "error reading file".to_string(),};} else {IOResult {stdout: String::from_utf8_lossy(&response).to_string(),stderr: "".to_string(),}}}#[marine]pub fn write_file(name: String, payload: String) -> IOResult {let content = payload.as_bytes().to_vec();let response = file_put(name, content);let result = response.as_str().contains("file can't be written:");if result {return IOResult {stdout: "".to_string(),stderr: response,};} else {IOResult {stdout: "OK".to_string(),stderr: "".to_string(),}}}#[marine]pub fn rm_file(name: String) -> IOResult {let result = file_remove(name);if &result == "OK" {return IOResult {stdout: result,stderr: "".to_string(),};} else {IOResult {stdout: "".to_string(),stderr: result,}}}#[marine]#[link(wasm_import_module = "filesys_adapter")] // 1extern "C" {#[link_name = "get"]pub fn file_get(file_name: String) -> Vec<u8>; // 2#[link_name = "put"]pub fn file_put(name: String, file_content: Vec<u8>) -> String;#[link_name = "rm"]pub fn file_remove(name: String) -> String;}
Now that our business logic is in place we can compile our code to the Wasm modules:
fluence buildMaking sure all services are downloaded... doneBlocking waiting for file lock on package cache<...>Finished release [optimized] target(s) in 0.20sFinished release [optimized] target(s) in 0.20sMaking sure all modules are downloaded and built... done
fluence buildMaking sure all services are downloaded... doneBlocking waiting for file lock on package cache<...>Finished release [optimized] target(s) in 0.20sFinished release [optimized] target(s) in 0.20sMaking sure all modules are downloaded and built... done
All looks good and we now have two Wasm module we'd like to use as a service. See the respective target\\wasm32-wasi\\release
directories for the *.wasm files.
We have one more step to complete the create a service from our Wasm modules: specify the linking configuration in the services/services.yaml
file by naming the appropriate facade and linked module(s). Update your services.yaml to:
version: 0 name: local_storage modules: facade: get: modules/use_filesys filesys_adapter: get: modules/filesys_adapter
version: 0 name: local_storage modules: facade: get: modules/use_filesys filesys_adapter: get: modules/filesys_adapter
Now we can use our service, aptly called local_storage, even without deployment to the network in the Marine REPL:
bash
fluence service repl? Enter service name from fluence.yaml, path to a service or url to .tar.gz archive servicesBlocking waiting for file lock on package cacheBlocking waiting for file lock on package cacheBlocking waiting for file lock on package cacheBlocking waiting for file lock on package cacheBlocking waiting for file lock on package cacheBlocking waiting for file lock on package cacheFinished release [optimized] target(s) in 0.19sFinished release [optimized] target(s) in 0.18sMaking sure service and modules are downloaded and built... done^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Execute help inside repl to see available commands.Current service <module_name> is: use_filesysCall use_filesys service functions in repl like this:call use_filesys <function_name> [<arg1>, <arg2>]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Welcome to the Marine REPL (version 0.18.8)Minimal supported versionssdk: 0.6.0interface-types: 0.20.0app service was created with service id = 940e0492-86c0-493d-887d-d306dfde024delapsed time 86.652549ms1>
bash
fluence service repl? Enter service name from fluence.yaml, path to a service or url to .tar.gz archive servicesBlocking waiting for file lock on package cacheBlocking waiting for file lock on package cacheBlocking waiting for file lock on package cacheBlocking waiting for file lock on package cacheBlocking waiting for file lock on package cacheBlocking waiting for file lock on package cacheFinished release [optimized] target(s) in 0.19sFinished release [optimized] target(s) in 0.18sMaking sure service and modules are downloaded and built... done^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Execute help inside repl to see available commands.Current service <module_name> is: use_filesysCall use_filesys service functions in repl like this:call use_filesys <function_name> [<arg1>, <arg2>]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Welcome to the Marine REPL (version 0.18.8)Minimal supported versionssdk: 0.6.0interface-types: 0.20.0app service was created with service id = 940e0492-86c0-493d-887d-d306dfde024delapsed time 86.652549ms1>
Note you can list the available/exposed interfaces with i:
bash
1> iLoaded modules interface:exported data types (combined from all modules):data IOResult:stdout: stringstderr: stringexported functions:filesys_adapter:fn put(name: string, file_content: []u8) -> stringfn rm(name: string) -> stringfn get(file_name: string) -> []u8use_filesys:fn rm_file(name: string) -> IOResultfn read_file(name: string) -> IOResultfn write_file(name: string, payload: string) -> IOResult
bash
1> iLoaded modules interface:exported data types (combined from all modules):data IOResult:stdout: stringstderr: stringexported functions:filesys_adapter:fn put(name: string, file_content: []u8) -> stringfn rm(name: string) -> stringfn get(file_name: string) -> []u8use_filesys:fn rm_file(name: string) -> IOResultfn read_file(name: string) -> IOResultfn write_file(name: string, payload: string) -> IOResult
Recall, our facade, i.e., entry, API is use_filesys. Let's interact with our service by writing a file, reading the file, removing the file and reading the files again:
bash
2> call use_filesys write_file ["test-file.txt", "Hello, Fluence!"]result: Object {"stderr": String(""), "stdout": String("OK")}elapsed time: 639.177µs3> call use_filesys read_file ["test-file.txt"]result: Object {"stderr": String(""), "stdout": String("Hello, Fluence!")}elapsed time: 309.581µs4> call use_filesys rm_file ["test-file.txt"]result: Object {"stderr": String(""), "stdout": String("OK")}elapsed time: 383.201µs5> call use_filesys read_file ["test-file.txt"]result: Object {"stderr": String("error reading file"), "stdout": String("")}elapsed time: 180.241µs6>
bash
2> call use_filesys write_file ["test-file.txt", "Hello, Fluence!"]result: Object {"stderr": String(""), "stdout": String("OK")}elapsed time: 639.177µs3> call use_filesys read_file ["test-file.txt"]result: Object {"stderr": String(""), "stdout": String("Hello, Fluence!")}elapsed time: 309.581µs4> call use_filesys rm_file ["test-file.txt"]result: Object {"stderr": String(""), "stdout": String("OK")}elapsed time: 383.201µs5> call use_filesys read_file ["test-file.txt"]result: Object {"stderr": String("error reading file"), "stdout": String("")}elapsed time: 180.241µs6>
todo: worker deploy
- delete old deploy: **
bash
fluence deployMaking sure all services are downloaded... doneBlocking waiting for file lock on package cache<...>Making sure all modules are downloaded and built... doneGoing to deploy services described in ~/localdev/documentation-examples/write-to-file/fluence.yaml:filesys_adapter:get: servicesdeploy:- deployId: defaultuse_filesys:get: servicesdeploy:- deployId: default? Do you want to deploy all of these services? YesGoing to upload module: filesys_adapterGoing to upload module: use_filesysModule 'filesys_adapter' was uploadedModule 'use_filesys' was uploadedNow time to make the blueprint...{"blueprint_id": "5c6f2b9adb96ca87672fc9917f11b8c7249fce7b73c8769af73f83702ae0c68d","service_id": "b1adf912-abbe-45e8-9b2f-ac26158ba7db"}Deploying:service: filesys_adapterdeployId: defaulton: 12D3KooWD7CvsYcpF9HE9CCV9aY3SJ317tkXVykjtZnht2EbzDPm... doneGoing to upload module: filesys_adapterGoing to upload module: use_filesysModule 'filesys_adapter' was uploadedModule 'use_filesys' was uploadedNow time to make the blueprint...{"blueprint_id": "5c6f2b9adb96ca87672fc9917f11b8c7249fce7b73c8769af73f83702ae0c68d","service_id": "2a6b3077-67ad-43d8-a181-0d24e8683d08"}Deploying:service: use_filesysdeployId: defaulton: 12D3KooWKnEqMfYo9zvfHmqTLpLdiHXPe4SVqUWcWHDJdFGrSmcA... doneCurrently deployed services listed in ~/localdev/documentation-examples/write-to-file/.fluence/app.yaml:filesys_adapter:default:- blueprintId: 5c6f2b9adb96ca87672fc9917f11b8c7249fce7b73c8769af73f83702ae0c68dserviceId: b1adf912-abbe-45e8-9b2f-ac26158ba7dbpeerId: 12D3KooWD7CvsYcpF9HE9CCV9aY3SJ317tkXVykjtZnht2EbzDPmkeyPairName: auto-generateduse_filesys:default:- blueprintId: 5c6f2b9adb96ca87672fc9917f11b8c7249fce7b73c8769af73f83702ae0c68dserviceId: 2a6b3077-67ad-43d8-a181-0d24e8683d08peerId: 12D3KooWKnEqMfYo9zvfHmqTLpLdiHXPe4SVqUWcWHDJdFGrSmcAkeyPairName: auto-generated
bash
fluence deployMaking sure all services are downloaded... doneBlocking waiting for file lock on package cache<...>Making sure all modules are downloaded and built... doneGoing to deploy services described in ~/localdev/documentation-examples/write-to-file/fluence.yaml:filesys_adapter:get: servicesdeploy:- deployId: defaultuse_filesys:get: servicesdeploy:- deployId: default? Do you want to deploy all of these services? YesGoing to upload module: filesys_adapterGoing to upload module: use_filesysModule 'filesys_adapter' was uploadedModule 'use_filesys' was uploadedNow time to make the blueprint...{"blueprint_id": "5c6f2b9adb96ca87672fc9917f11b8c7249fce7b73c8769af73f83702ae0c68d","service_id": "b1adf912-abbe-45e8-9b2f-ac26158ba7db"}Deploying:service: filesys_adapterdeployId: defaulton: 12D3KooWD7CvsYcpF9HE9CCV9aY3SJ317tkXVykjtZnht2EbzDPm... doneGoing to upload module: filesys_adapterGoing to upload module: use_filesysModule 'filesys_adapter' was uploadedModule 'use_filesys' was uploadedNow time to make the blueprint...{"blueprint_id": "5c6f2b9adb96ca87672fc9917f11b8c7249fce7b73c8769af73f83702ae0c68d","service_id": "2a6b3077-67ad-43d8-a181-0d24e8683d08"}Deploying:service: use_filesysdeployId: defaulton: 12D3KooWKnEqMfYo9zvfHmqTLpLdiHXPe4SVqUWcWHDJdFGrSmcA... doneCurrently deployed services listed in ~/localdev/documentation-examples/write-to-file/.fluence/app.yaml:filesys_adapter:default:- blueprintId: 5c6f2b9adb96ca87672fc9917f11b8c7249fce7b73c8769af73f83702ae0c68dserviceId: b1adf912-abbe-45e8-9b2f-ac26158ba7dbpeerId: 12D3KooWD7CvsYcpF9HE9CCV9aY3SJ317tkXVykjtZnht2EbzDPmkeyPairName: auto-generateduse_filesys:default:- blueprintId: 5c6f2b9adb96ca87672fc9917f11b8c7249fce7b73c8769af73f83702ae0c68dserviceId: 2a6b3077-67ad-43d8-a181-0d24e8683d08peerId: 12D3KooWKnEqMfYo9zvfHmqTLpLdiHXPe4SVqUWcWHDJdFGrSmcAkeyPairName: auto-generated
Now that we have our services deployed, we can turn our focus on writing the necessary Aqua code. First, we clear out the template code in the src/aqua/main.aqua
file and start from scratch:
-- src/aqua.main aqua Main import App from "deployed.app.aqua" -- we get these params from .fluence/aqua/services/use_filesys.aqua import IOResult, UseFilesys from "services/use_filesys.aqua" export App, write_to_file, read_from_file, remove_file func write_to_file(filename: string, content: string) -> IOResult: services <- App.services() on services.use_filesys.default!.peerId: UseFilesys services.use_filesys.default!.serviceId res <- UseFilesys.write_file(filename, content) <- res func read_from_file(filename:string) -> IOResult: services <- App.services() on services.use_filesys.default!.peerId: UseFilesys services.use_filesys.default!.serviceId res <- UseFilesys.read_file(filename) <- res func remove_file(filename: string) -> IOResult: services <- App.services() on services.use_filesys.default!.peerId: UseFilesys services.use_filesys.default!.serviceId res <- UseFilesys.rm_file(filename) <- res
-- src/aqua.main aqua Main import App from "deployed.app.aqua" -- we get these params from .fluence/aqua/services/use_filesys.aqua import IOResult, UseFilesys from "services/use_filesys.aqua" export App, write_to_file, read_from_file, remove_file func write_to_file(filename: string, content: string) -> IOResult: services <- App.services() on services.use_filesys.default!.peerId: UseFilesys services.use_filesys.default!.serviceId res <- UseFilesys.write_file(filename, content) <- res func read_from_file(filename:string) -> IOResult: services <- App.services() on services.use_filesys.default!.peerId: UseFilesys services.use_filesys.default!.serviceId res <- UseFilesys.read_file(filename) <- res func remove_file(filename: string) -> IOResult: services <- App.services() on services.use_filesys.default!.peerId: UseFilesys services.use_filesys.default!.serviceId res <- UseFilesys.rm_file(filename) <- res
We simply wrapped the exposed facade interfaces with Aqua code and just pass through the returned IOResult data. Let's run our Aqua against the deployed service with familiar parameters:
bash
# write to filefluence run? Enter a function call that you want to execute write_to_file("test_file.txt", "Hello, Fluence!"){"stderr": "","stdout": "OK"}Running:function: write_to_file("test_file.txt", "Hello, Fluence!")relay: /dns4/kras-01.fluence.dev/tcp/19001/wss/p2p/12D3KooWKnEqMfYo9zvfHmqTLpLdiHXPe4SVqUWcWHDJdFGrSmcA... doneResult:"{\\n \\"stderr\\": \\"\\",\\n \\"stdout\\": \\"OK\\"\\n}\\n"# read from filefluence run? Enter a function call that you want to execute read_from_file("test_file.txt"){"stderr": "","stdout": "Hello, Fluence!"}Running:function: read_from_file("test_file.txt")relay: /dns4/kras-02.fluence.dev/tcp/19001/wss/p2p/12D3KooWHLxVhUQyAuZe6AHMB29P7wkvTNMn7eDMcsqimJYLKREf... doneResult:"{\\n \\"stderr\\": \\"\\",\\n \\"stdout\\": \\"Hello, Fluence!\\"\\n}\\n"# remove the filefluence run? Enter a function call that you want to execute remove_file("test_file.txt"){"stderr": "","stdout": "OK"}Running:function: remove_file("test_file.txt")relay: /dns4/kras-00.fluence.dev/tcp/19990/wss/p2p/12D3KooWSD5PToNiLQwKDXsu8JSysCwUt8BVUJEqCHcDe7P5h45e... doneResult:"{\\n \\"stderr\\": \\"\\",\\n \\"stdout\\": \\"OK\\"\\n}\\n"# try to read from delete filefluence run? Enter a function call that you want to execute read_from_file("test_file.txt"){"stderr": "error reading file","stdout": ""}Running:function: read_from_file("test_file.txt")relay: /dns4/kras-06.fluence.dev/tcp/19001/wss/p2p/12D3KooWDUszU2NeWyUVjCXhGEt1MoZrhvdmaQQwtZUriuGN1jTr... doneResult:"{\\n \\"stderr\\": \\"error reading file\\",\\n \\"stdout\\": \\"\\"\\n}\\n"
bash
# write to filefluence run? Enter a function call that you want to execute write_to_file("test_file.txt", "Hello, Fluence!"){"stderr": "","stdout": "OK"}Running:function: write_to_file("test_file.txt", "Hello, Fluence!")relay: /dns4/kras-01.fluence.dev/tcp/19001/wss/p2p/12D3KooWKnEqMfYo9zvfHmqTLpLdiHXPe4SVqUWcWHDJdFGrSmcA... doneResult:"{\\n \\"stderr\\": \\"\\",\\n \\"stdout\\": \\"OK\\"\\n}\\n"# read from filefluence run? Enter a function call that you want to execute read_from_file("test_file.txt"){"stderr": "","stdout": "Hello, Fluence!"}Running:function: read_from_file("test_file.txt")relay: /dns4/kras-02.fluence.dev/tcp/19001/wss/p2p/12D3KooWHLxVhUQyAuZe6AHMB29P7wkvTNMn7eDMcsqimJYLKREf... doneResult:"{\\n \\"stderr\\": \\"\\",\\n \\"stdout\\": \\"Hello, Fluence!\\"\\n}\\n"# remove the filefluence run? Enter a function call that you want to execute remove_file("test_file.txt"){"stderr": "","stdout": "OK"}Running:function: remove_file("test_file.txt")relay: /dns4/kras-00.fluence.dev/tcp/19990/wss/p2p/12D3KooWSD5PToNiLQwKDXsu8JSysCwUt8BVUJEqCHcDe7P5h45e... doneResult:"{\\n \\"stderr\\": \\"\\",\\n \\"stdout\\": \\"OK\\"\\n}\\n"# try to read from delete filefluence run? Enter a function call that you want to execute read_from_file("test_file.txt"){"stderr": "error reading file","stdout": ""}Running:function: read_from_file("test_file.txt")relay: /dns4/kras-06.fluence.dev/tcp/19001/wss/p2p/12D3KooWDUszU2NeWyUVjCXhGEt1MoZrhvdmaQQwtZUriuGN1jTr... doneResult:"{\\n \\"stderr\\": \\"error reading file\\",\\n \\"stdout\\": \\"\\"\\n}\\n"
All looks in order, well done! You now have the basic effector module for to write to hosts' filesystem, if permissioned, and a facade template to use.
SQLite
coming soon.