1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
//! # gwasm-api - gWasm API for Rust apps
//! [gWasm](https://docs.golem.network/#/Products/gWASM/About) is Golem's new
//! meta use-case which allows Golem's developers/users to deploy their Wasm apps
//! on Golem Network. This API providers convenience structures and functions for
//! creating a gWasm task and connecting with Golem Network all from native Rust code.
//!
//! ## Example
//!
//! ```rust,no_run
//! use gwasm_api::prelude::*;
//! use anyhow::Result;
//! use std::path::PathBuf;
//!
//! struct ProgressTracker;
//!
//! impl ProgressUpdate for ProgressTracker {
//!     fn update(&self, progress: f64) {
//!         println!("Current progress = {}", progress);
//!     }
//! }
//!
//! fn main() -> Result<()> {
//!     let binary = GWasmBinary {
//!         js: &[0u8; 100],   // JavaScript file generated by Emscripten
//!         wasm: &[0u8; 100], // Wasm binary generated by Emscripten
//!     };
//!     let task = TaskBuilder::try_new("workspace", binary)?
//!         .push_subtask_data(vec![0u8; 100])
//!         .build()?;
//!     let computed_task = compute(
//!         PathBuf::from("datadir"),
//!         "127.0.0.1".to_string(),
//!         61000,
//!         Net::TestNet,
//!         task,
//!         ProgressTracker,
//!     )?;
//!
//!     for subtask in computed_task.subtasks {
//!         for (_, reader) in subtask.data {
//!             assert!(!reader.buffer().is_empty());
//!         }
//!     }
//!
//!     Ok(())
//! }
//! ```
//! ## Subtask input/output
//! For each subtask, two command line arguments are passed to the WASM binary.
//! Conceptually, you should expect your application to be invoked as:
//! ```shell
//! ./app input output
//! ```
//! where:
//! * `input` is the input file path
//! * `output` is the expected output file path
//!
//! The app is expected to create the `output` file or the task will fail.
//! Applications requiring multiple input or output files are currently unsupported.
//!
//! For more information about how to write gWASM apps see the
//! [sp-wasm documentation](https://github.com/golemfactory/sp-wasm)
//!
//! ## More examples
//! * [g-flite](https://github.com/golemfactory/g-flite) is a CLI which uses `gwasm-api`
//!   internally
#![deny(
    missing_docs,
    trivial_numeric_casts,
    unused_extern_crates,
    unstable_features
)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../clippy.toml")))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
#![cfg_attr(
    feature = "cargo-clippy",
    warn(
        clippy::float_arithmetic,
        clippy::mut_mut,
        clippy::nonminimal_bool,
        clippy::option_map_unwrap_or,
        clippy::option_map_unwrap_or_else,
        clippy::unicode_not_nfc,
        clippy::use_self
    )
)]

pub mod error;
pub mod golem;
pub mod task;
pub mod timeout;

use actix::System;
use error::Result;
pub use golem_rpc_api::Net;
use std::path::PathBuf;
use task::{ComputedTask, Task};

/// Trait specifying the required interface for an object tracking the computation's
/// progress
///
/// Note that progress is tracked via active polling thus it might be prudent to store
/// the value of current progress in the struct implementing the trait and update it
/// only when the new reported progress value has actually risen
/// (see [Example: ProgressBar](#example-progressbar)).
///
/// # Example: simple tracker
/// ```
/// use gwasm_api::ProgressUpdate;
///
/// struct SimpleTracker;
///
/// impl ProgressUpdate for SimpleTracker {
///     fn update(&self, progress: f64) {
///         println!("Current progress = {}", progress);
///     }
/// }
/// ```
///
/// # Example: ProgressBar
/// ```
/// use std::cell::Cell;
/// use gwasm_api::ProgressUpdate;
/// use indicatif::ProgressBar;
///
/// struct ProgressBarTracker {
///     bar: ProgressBar,
///     progress: Cell<f64>,
/// }
///
/// impl ProgressBarTracker {
///     fn new(num_subtasks: u64) -> Self {
///         Self {
///             bar: ProgressBar::new(num_subtasks),
///             progress: Cell::new(0.0),
///         }
///     }
/// }
///
/// impl ProgressUpdate for ProgressBarTracker {
///     fn update(&self, progress: f64) {
///         if progress > self.progress.get() {
///             self.progress.set(progress);
///             self.bar.inc(1);
///         }
///     }
///
///     fn start(&self) {
///         self.bar.inc(0);
///     }
///
///     fn stop(&self) {
///         self.bar.finish_and_clear()
///     }
/// }
/// ```
pub trait ProgressUpdate {
    /// Called when progress value was polled from Golem
    fn update(&self, progress: f64);
    /// Called when progress updates started
    fn start(&self) {}
    /// Called when progress updates finished
    fn stop(&self) {}
}

/// A convenience function for running a gWasm [`Task`] on Golem
///
/// The function uses actix's `System` to spawn an event loop in the current thread,
/// and blocks until either a gWasm [`Task`] is computed, or it registers a Ctrl-C event,
/// or there was an [`Error`].
///
/// [`Task`]: task/struct.Task.html
/// [`Error`]: error/enum.Error.html
pub fn compute<P, S>(
    datadir: P,
    address: S,
    port: u16,
    net: Net,
    task: Task,
    progress_handler: impl ProgressUpdate + 'static,
) -> Result<ComputedTask>
where
    P: Into<PathBuf> + 'static,
    S: Into<String> + 'static,
{
    let mut system = System::new(task.name());
    system.block_on(golem::compute(
        datadir,
        address,
        port,
        task,
        net,
        progress_handler,
        None,
    ))
}

pub mod prelude {
    //! The `gwasm-api` prelude
    //!
    //! The purpose of this module is to alleviate imports of common structures and functions
    //! by adding a glob import to the top of the `gwasm-api` heavy modules:
    //!
    //! ```
    //! # #![allow(unused_imports)]
    //! use gwasm_api::prelude::*;
    //! ```
    pub use super::error::{Error, Result};
    pub use super::task::{
        ComputedSubtask, ComputedTask, GWasmBinary, Options, Subtask, Task, TaskBuilder,
    };
    pub use super::timeout::Timeout;
    pub use super::{compute, Net, ProgressUpdate};
}