├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── node ├── date-helper.js ├── request-helper.js └── sqlite-helper.js └── src ├── console.rs ├── date.rs ├── fs.rs ├── lib.rs ├── request.rs └── sqlite3.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nodejs-helper" 3 | version = "0.0.3" 4 | authors = ["Shishuo Wang", "Michael Yuan"] 5 | edition = "2018" 6 | license = "MIT OR Apache-2.0" 7 | repository = "https://github.com/second-state/nodejs-helper" 8 | documentation = "https://cloud.secondstate.io/server-side-webassembly/rust-and-javascript/call-javascript-functions-from-rust" 9 | homepage = "https://cloud.secondstate.io/" 10 | readme = "README.md" 11 | description = "Call Node.js functions from Rust" 12 | categories = ["filesystem", "database", "web-programming", "development-tools", "wasm"] 13 | keywords = ["nodejs", "WebAssembly", "wasm", "second-state", "javascript"] 14 | 15 | [lib] 16 | name = "nodejs_helper" 17 | path = "src/lib.rs" 18 | crate-type =["lib"] 19 | 20 | [dependencies] 21 | wasm-bindgen = "^0.2" 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Second State 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Call Node.js functions from Rust 2 | 3 | ![Crates.io](https://img.shields.io/crates/d/nodejs-helper) 4 | ![Crates.io](https://img.shields.io/crates/l/nodejs-helper) 5 | ![Crates.io](https://img.shields.io/crates/v/nodejs-helper) 6 | 7 | ## Prerequisite 8 | 9 | Must have Node.js installed with the following packages. 10 | 11 | ``` 12 | npm i ssvm sync-request better-sqlite3 13 | npm i -g ssvmup 14 | npm i -g wasm-pack 15 | ``` 16 | 17 | ## How to use 18 | 19 | Add cargo dependency 20 | 21 | ``` 22 | [dependencies] 23 | nodejs-helper = "0.0.3" 24 | ``` 25 | 26 | Make Node.js Javascript API calls from Rust code! 27 | 28 | ``` 29 | #[wasm_bindgen] 30 | pub fn utc_now() { 31 | let now: String = nodejs_helper::date::utc_string(); 32 | nodejs_helper::console::log("UTC time: "); 33 | nodejs_helper::console::log(&now); 34 | } 35 | ``` 36 | 37 | The Rust code must be compiled to WebAssembly and run from inside Node.js. [See how](https://cloud.secondstate.io/server-side-webassembly/getting-started) 38 | 39 | ## Examples 40 | 41 | Demo code is [available here](https://github.com/second-state/wasm-learning/tree/master/nodejs/nodejs_example) 42 | 43 | ## Documentation 44 | 45 | See [how the examples work](https://cloud.secondstate.io/server-side-webassembly/rust-and-javascript/call-javascript-functions-from-rust) 46 | 47 | -------------------------------------------------------------------------------- /node/date-helper.js: -------------------------------------------------------------------------------- 1 | function timestamp_unix() { 2 | let ts = Date.now(); 3 | return Math.floor(ts/1000); 4 | } 5 | 6 | function timestamp() { 7 | let ts = Date.now(); 8 | return JSON.stringify(ts); 9 | } 10 | 11 | 12 | function utc_string() { 13 | var date = new Date(); 14 | return date.toUTCString(); 15 | } 16 | 17 | function format_date(locale, weekday, year, month, day, time_zone, time_zone_name) { 18 | var date = new Date(); 19 | var options = {}; 20 | options.weekday = weekday; 21 | options.year = year; 22 | options.month = month; 23 | options.day = day; 24 | options.timeZone = time_zone; 25 | options.timeZoneName = time_zone_name; 26 | return date.toLocaleDateString(locale, options); 27 | } 28 | 29 | module.exports = { timestamp_unix, timestamp, utc_string, format_date } 30 | -------------------------------------------------------------------------------- /node/request-helper.js: -------------------------------------------------------------------------------- 1 | const req = require('sync-request'); 2 | 3 | function request(method, url) { 4 | var res = req(method, url); 5 | return JSON.stringify(res); 6 | } 7 | 8 | function fetch(url) { 9 | var res = req('GET', url); 10 | return res.getBody(); 11 | } 12 | 13 | function fetch_as_string(url) { 14 | var res = req('GET', url); 15 | return res.getBody('utf8'); 16 | } 17 | 18 | function request_with_options(method, url, options) { 19 | var res = req(method, url, JSON.parse(options)); 20 | return JSON.stringify(res); 21 | } 22 | 23 | module.exports = { request, fetch, fetch_as_string, request_with_options } 24 | -------------------------------------------------------------------------------- /node/sqlite-helper.js: -------------------------------------------------------------------------------- 1 | const sqlite3 = require('better-sqlite3'); 2 | 3 | function create(path) { 4 | const db = new sqlite3(path); 5 | db.close(); 6 | } 7 | 8 | function query(path, sql) { 9 | const db = new sqlite3(path); 10 | const stmt = db.prepare(sql); 11 | const rows = stmt.all(); 12 | db.close(); 13 | return JSON.stringify(rows); 14 | } 15 | 16 | function update(path, sql) { 17 | const db = new sqlite3(path); 18 | const stmt = db.prepare(sql); 19 | stmt.run(); 20 | db.close(); 21 | } 22 | 23 | function exec(path, sql) { 24 | const db = new sqlite3(path); 25 | db.exec(sql); 26 | db.close(); 27 | } 28 | 29 | module.exports = { create, query, update, exec } 30 | -------------------------------------------------------------------------------- /src/console.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | #[wasm_bindgen] 4 | extern "C" { 5 | // Use `js_namespace` here to bind `console.log(..)` instead of just 6 | // `log(..)` 7 | #[wasm_bindgen(js_namespace = console)] 8 | pub fn log(s: &str); 9 | 10 | #[wasm_bindgen(js_namespace = console)] 11 | pub fn error(s: &str); 12 | 13 | #[wasm_bindgen(js_namespace = console)] 14 | pub fn time(s: &str); 15 | 16 | #[wasm_bindgen(js_namespace = console)] 17 | pub fn timeEnd(s: &str); 18 | 19 | #[wasm_bindgen(js_namespace = console)] 20 | pub fn timeLog(s: &str, v: &str); 21 | } 22 | 23 | // Provide function names that comform to Rust's convention 24 | pub fn time_end(s: &str) { 25 | timeEnd(s); 26 | } 27 | 28 | pub fn time_log(s: &str, v: &str) { 29 | timeLog(s, v); 30 | } 31 | -------------------------------------------------------------------------------- /src/date.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | #[wasm_bindgen(module="/node/date-helper.js")] 4 | extern "C" { 5 | pub fn timestamp_unix() -> i32; 6 | pub fn timestamp() -> String; 7 | pub fn utc_string() -> String; 8 | pub fn format_date(locale: &str, weekday: &str, year: &str, month: &str, day: &str, time_zone: &str, time_zone_name: &str) -> String; 9 | } 10 | -------------------------------------------------------------------------------- /src/fs.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | pub fn read_file_sync(path: &str) -> Vec { 4 | let fs = node_require("fs"); 5 | fs.readFileSync(path) 6 | } 7 | 8 | pub fn write_file_sync(path: &str, data: &[u8]) { 9 | let fs = node_require("fs"); 10 | fs.writeFileSync(path, data); 11 | } 12 | 13 | pub fn append_file_sync(path: &str, data: &[u8]) { 14 | let fs = node_require("fs"); 15 | fs.appendFileSync(path, data); 16 | } 17 | 18 | pub fn copy_file_sync(path_src: &str, path_dest: &str) { 19 | let fs = node_require("fs"); 20 | fs.copyFileSync(path_src, path_dest); 21 | } 22 | 23 | pub fn rename_sync(path_src: &str, path_dest: &str) { 24 | let fs = node_require("fs"); 25 | fs.renameSync(path_src, path_dest); 26 | } 27 | 28 | pub fn unlink_sync(path: &str) { 29 | let fs = node_require("fs"); 30 | fs.unlinkSync(path); 31 | } 32 | 33 | #[wasm_bindgen] 34 | extern "C" { 35 | #[wasm_bindgen(js_name = require)] 36 | fn node_require(s: &str) -> NodeFs; 37 | 38 | #[derive(Clone, Debug)] 39 | type NodeFs; 40 | 41 | #[wasm_bindgen(method, js_name = readFileSync, structural)] 42 | fn readFileSync(me: &NodeFs, path: &str) -> Vec; 43 | 44 | #[wasm_bindgen(method, js_name = writeFileSync, structural)] 45 | fn writeFileSync(me: &NodeFs, path: &str, data: &[u8]); 46 | 47 | #[wasm_bindgen(method, js_name = appendFileSync, structural)] 48 | fn appendFileSync(me: &NodeFs, path: &str, data: &[u8]); 49 | 50 | #[wasm_bindgen(method, js_name = copyFileSync, structural)] 51 | fn copyFileSync(me: &NodeFs, path_src: &str, path_dest: &str); 52 | 53 | #[wasm_bindgen(method, js_name = renameSync, structural)] 54 | fn renameSync(me: &NodeFs, path_src: &str, path_dest: &str); 55 | 56 | #[wasm_bindgen(method, js_name = unlinkSync, structural)] 57 | fn unlinkSync(me: &NodeFs, path: &str); 58 | } 59 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod fs; 2 | pub mod console; 3 | pub mod sqlite3; 4 | pub mod request; 5 | pub mod date; 6 | -------------------------------------------------------------------------------- /src/request.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | #[wasm_bindgen(module="/node/request-helper.js")] 4 | extern "C" { 5 | pub fn request(method: &str, url: &str) -> String; 6 | pub fn fetch(url: &str) -> Vec; 7 | pub fn fetch_as_string(url: &str) -> String; 8 | pub fn request_with_options(method: &str, url: &str, options: &str) -> String; 9 | } 10 | -------------------------------------------------------------------------------- /src/sqlite3.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | #[wasm_bindgen(module="/node/sqlite-helper.js")] 4 | extern "C" { 5 | pub fn create(path: &str); 6 | pub fn update(path: &str, sql: &str); 7 | pub fn exec(path: &str, sql: &str); 8 | pub fn query(path: &str, sql: &str) -> String; 9 | } 10 | --------------------------------------------------------------------------------