Does Rust have an equivalent of Python's threading.Timer? - timer

I'm looking for a timer which uses threads, not plain time.sleep:
from threading import Timer
def x():
print "hello"
t = Timer(2.0, x)
t.start()
t = Timer(2.0, x)
t.start()

You can use the timer crate
extern crate timer;
extern crate chrono;
use timer::Timer;
use chrono::Duration;
use std::thread;
fn x() {
println!("hello");
}
fn main() {
let timer = Timer::new();
let guard = timer.schedule_repeating(Duration::seconds(2), x);
// give some time so we can see hello printed
// you can execute any code here
thread::sleep(::std::time::Duration::new(10, 0));
// stop repeating
drop(guard);
}

It's easy enough to write a similar version yourself, using only tools from the standard library:
use std::thread;
use std::time::Duration;
struct Timer<F> {
delay: Duration,
action: F,
}
impl<F> Timer<F>
where
F: FnOnce() + Send + Sync + 'static,
{
fn new(delay: Duration, action: F) -> Self {
Timer { delay, action }
}
fn start(self) {
thread::spawn(move || {
thread::sleep(self.delay);
(self.action)();
});
}
}
fn main() {
fn x() {
println!("hello");
let t = Timer::new(Duration::from_secs(2), x);
t.start();
}
let t = Timer::new(Duration::from_secs(2), x);
t.start();
// Wait for output
thread::sleep(Duration::from_secs(10));
}
As pointed out by malbarbo, this does create a new thread for each timer. This can be more expensive than a solution which reuses threads but it's a very simple example.

Related

Swift Async/Await for C Callbacks

I am trying to convert some code from objective-c to swift and along with that use async/await as much as possible.
This code leverages a C library that uses callbacks with a void* context. There are parts of our code where we need to "wait" until the callback is completed. This can often be 2 different callbacks for success or failure.
Below is an example of the code
class Test
{
var sessionStarted: Bool = false
let sessionSemaphore = DispatchSemaphore(value: 0)
// We need the session to be available once this function returns
func startSession() throws
{
guard !sessionStarted else {
print("Session already started")
return
}
let callback: KMSessionEventCallback = { inSession, inEvent, inContext in
guard let session = inSession, let context = inContext else { return }
let testContext: Test = Unmanaged<Test>.fromOpaque(context).takeUnretainedValue()
testContext.handleSessionUpdate(session: session, event: inEvent)
}
let result = KMSessionAttach("SessionTest", &callback, Unmanaged.passUnretained(self).toOpaque())
if result != KM_SUCCESS {
print("Failed to attach session")
}
// Currently uses a semaphore to wait. =(
let dispatchResult = self.sessionSemaphore.wait(timeout: .now() + DispatchTimeInterval.seconds(30))
if dispatchResult == .timedOut {
print("Waited 30 seconds and never attached session")
}
}
private func handleSessionUpdate(session: KMSession, event: KMSessionEvent)
{
switch event
{
case KM_SESSION_ATTACHED:
self.sessionStarted = true
case KM_SESSION_TERMINATED:
fallthrough
case KM_SESSION_FAILED:
fallthrough
case KM_SESSION_DETACHED:
self.sessionStarted = false
default:
print("Unknown State")
}
self.sessionSemaphore.signal()
}
}
I am struggling to figure out how to use continuations here because I cannot capture any context within these C callbacks.

Render thousands/millions times with React and Tauri (rust)

I am learning Rust. I am creating a desktop app which read thousand/million rows of data in csv file and then transfer them one by one using tauri event.
Result: Rust has no problem read through the file (under 5 seconds). On the frontend side, my React app seems unable to keep up with events. On the screen, the altitude value is updated intermittently.
How to handle this situation is React? or What did I do wrong?
React side:
// App.js
import { listen } from '#tauri-apps/api/event';
import { useEffect, useCallback, useState } from 'react';
import { invoke } from '#tauri-apps/api/tauri'
const App = () => {
const [altitude, setAltitude] = useState("0");
useEffect(() => {
listen('rust-event', myCallback)
}, [])
const myCallback = useCallback((e) => {
console.log(e);
setAltitude(e.payload);
},[])
const handleClick = async () => {
invoke('my_custom_command').catch(error => console.log(error));
};
return (
<div>
<button onClick={handleClick}>Click Me To Start Fetching!</button>
<span>{altitude}</span>
</div>
);
}
export default App;
Tauri side:
// main.rs
use arrow::csv;
use arrow::datatypes::{DataType, Field, Schema};
use std::fs::File;
use std::sync::Arc;
use arrow::array::{StringArray, ArrayRef};
#[tauri::command]
async fn my_custom_command(window: tauri::Window) {
let schema = Schema::new(vec![
Field::new("altitude", DataType::Utf8, false)
]);
// Open file
let file = File::open("src/data.csv").unwrap();
// Get csv Reader using schema
let mut csv = csv::Reader::new(file, Arc::new(schema), true, None, 1, None, None);
// Loop through each row
while let Some(m) = csv.next() {
let n = m.unwrap();
// Get reference of array of a column
let col: &ArrayRef = n.column(0);
// Cast the reference of array to array of string
let col = col.as_any().downcast_ref::<StringArray>().unwrap();
// Get value from the array using index
let v = col.value(0);
println!("{}", col.value(0));
// Send each value through an event
window
.emit("rust-event", v)
.expect("failed to emit");
}
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![my_custom_command])
.run(tauri::generate_context!())
.expect("failed to run app");
}
I personally do not suggest what you are doing as you can get a stack overflow.
The best would be to emit them in batch, you can fill a local buffer, when there are X elements (or the end is reached), emit the event, and clear the buffer.
Example
#[tauri::command]
async fn my_custom_command(window: tauri::Window) {
// Your code
// [...]
// send 20 elements in the Vec (array)
let should_trigger_at = 20;
// local buffer
let local_buffer: Vec<String> = Vec::new();
// Loop through each row
while let Some(m) = csv.next() {
let n = m.unwrap();
// Get reference of array of a column
let col: &ArrayRef = n.column(0);
// Cast the reference of array to array of string
let col = col.as_any().downcast_ref::<StringArray>().unwrap();
// Get value from the array using index
let v = col.value(0);
println!("{}", col.value(0));
// add the value in the buffer
local_buffer.push(col.value(0));
if local_buffer.len() == should_trigger_at {
// Send each value through an event
window
.emit("rust-event", local_buffer)
.expect("failed to emit");
// reset local buffer
local_buffer = Vec::new();
}
}
// if buffer not empty, lets emit the values
if local_buffer.len() > 0 {
window
.emit("rust-event", local_buffer)
.expect("failed to emit");
}
// [...]
// Your code
}
Please note; doing this will send an Array of String to the Webview instead of a String.
Well, I guess Rust is too fast :) React is unable to handle the speed.
I slow down the event emit with settimeout rust lib and I am happy with it for now.
// Before emit an event, delay it 100 microsecond;
set_timeout(Duration::from_micros(100)).await;
window
.emit("rust-event", v)
.expect("failed to emit");

How to wait until a file is created in Rust?

The file may or may not be created before my program starts, so I need to ensure that this file exists before proceeding. What is the most idiomatic way to do that?
Taking into account suggestions from comments I've written the following code:
fn wait_until_file_created(file_path: &PathBuf) -> Result<(), Box<Error>> {
let (tx, rx) = mpsc::channel();
let mut watcher = notify::raw_watcher(tx)?;
// Watcher can't be registered for file that don't exists.
// I use its parent directory instead, because I'm sure that it always exists
let file_dir = file_path.parent().unwrap();
watcher.watch(&file_dir, RecursiveMode::NonRecursive)?;
if !file_path.exists() {
loop {
match rx.recv_timeout(Duration::from_secs(2))? {
RawEvent { path: Some(p), op: Ok(op::CREATE), .. } =>
if p == file_path {
break
},
_ => continue,
}
}
}
watcher.unwatch(file_dir)?;
Ok(())
}

How to stream a message with tokio_proto and tokio_service in Rust

In my SmtpService I'd like to send the response header right away and the body when processing is finished. This should follow the SMTP exchange:
C: DATA
S: 354 Start mail input
C: ... data ...
C: ... more ...
C: .
S: 250 Ok
I've got this much in the playground:
#[macro_use]
extern crate log;
extern crate bytes;
extern crate tokio_proto;
extern crate tokio_service;
extern crate futures;
use std::io;
use bytes::Bytes;
use tokio_service::Service;
use tokio_proto::streaming::{Message, Body};
use futures::{future, Future, Stream};
use futures::sync::oneshot;
//use model::request::SmtpCommand;
//use model::response::SmtpReply;
#[derive(Eq, PartialEq, Debug)]
enum SmtpCommand {
Data,
}
#[derive(Eq, PartialEq, Debug)]
enum SmtpReply {
OkInfo,
StartMailInputChallenge,
TransactionFailure,
CommandNotImplementedFailure
}
pub struct SmtpService;
impl Service for SmtpService {
// For non-streaming protocols, service errors are always io::Error
type Error = io::Error;
// These types must match the corresponding protocol types:
type Request = Message<SmtpCommand, Body<Bytes, Self::Error>>;
type Response = Message<SmtpReply, Body<SmtpReply, Self::Error>>;
// The future for computing the response; box it for simplicity.
type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;
// Produce a future for computing a response from a request.
fn call(&self, command: Self::Request) -> Self::Future {
info!("Received {:?}", command);
match command {
Message::WithBody(cmd, cmd_body) => {
match cmd {
SmtpCommand::Data => {
// start => SmtpReply::StartMailInputChallenge
// ok => SmtpReply::OkInfo
// err => SmtpReply::TransactionFailure
let (tx, rx) = oneshot::channel();
let fut = cmd_body
.inspect(|chunk| info!("data: {:?}", chunk))
.map(|_| tx.send(SmtpReply::OkInfo))
.map_err(|_| tx.send(SmtpReply::TransactionFailure))
.map(|_| Body::from(rx));
// ??? How to wire the fut future into the response message?
let msg = Message::WithBody(SmtpReply::StartMailInputChallenge, fut);
Box::new(future::ok(msg)) as Self::Future
}
_ => Box::new(future::ok(Message::WithoutBody(
SmtpReply::CommandNotImplementedFailure,
))),
}
}
Message::WithoutBody(cmd) => {
Box::new(future::ok(Message::WithoutBody(match cmd {
_ => SmtpReply::CommandNotImplementedFailure,
})))
}
}
}
}
fn main() {
println!("Hello, world!");
}
I'm wondering if it's even possible or do I need to produce two messages instead - one for DATA and a second for the actual byte stream?
The error I get shows a mismatch in the message structure; the body/future is obviously out of place:
error[E0271]: type mismatch resolving `<futures::FutureResult<tokio_proto::streaming::Message<SmtpReply, futures::stream::Map<futures::stream::MapErr<futures::stream::Map<futures::stream::Inspect<tokio_proto::streaming::Body<bytes::Bytes, std::io::Error>, [closure#src/main.rs:57:42: 57:76]>, [closure#src/main.rs:58:38: 58:68 tx:futures::Sender<SmtpReply>]>, [closure#src/main.rs:59:42: 59:84 tx:futures::Sender<SmtpReply>]>, [closure#src/main.rs:60:38: 60:56 rx:futures::Receiver<SmtpReply>]>>, std::io::Error> as futures::Future>::Item == tokio_proto::streaming::Message<SmtpReply, tokio_proto::streaming::Body<SmtpReply, std::io::Error>>`
--> src/main.rs:66:25
|
66 | Box::new(future::ok(msg)) as Self::Future
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `futures::stream::Map`, found struct `tokio_proto::streaming::Body`
|
= note: expected type `tokio_proto::streaming::Message<_, futures::stream::Map<futures::stream::MapErr<futures::stream::Map<futures::stream::Inspect<tokio_proto::streaming::Body<bytes::Bytes, std::io::Error>, [closure#src/main.rs:57:42: 57:76]>, [closure#src/main.rs:58:38: 58:68 tx:futures::Sender<SmtpReply>]>, [closure#src/main.rs:59:42: 59:84 tx:futures::Sender<SmtpReply>]>, [closure#src/main.rs:60:38: 60:56 rx:futures::Receiver<SmtpReply>]>>`
found type `tokio_proto::streaming::Message<_, tokio_proto::streaming::Body<SmtpReply, std::io::Error>>`
= note: required for the cast to the object type `futures::Future<Error=std::io::Error, Item=tokio_proto::streaming::Message<SmtpReply, tokio_proto::streaming::Body<SmtpReply, std::io::Error>>>`
The future returned by call ends when the Response is returned; you cannot "drive" further actions in that future.
This means you need to spawn a new task generating the (streamed) body; you'll need a Handle from tokio_core for that.
Also the Body needs to be created from a mpsc channel, not a oneshot; you could send many body chunks.
Playground
#[macro_use]
extern crate log;
extern crate bytes;
extern crate tokio_core;
extern crate tokio_proto;
extern crate tokio_service;
extern crate futures;
use std::io;
use bytes::Bytes;
use tokio_service::Service;
use tokio_proto::streaming::{Message, Body};
use futures::{future, Future, Stream, Sink};
use futures::sync::mpsc;
//use model::request::SmtpCommand;
//use model::response::SmtpReply;
#[derive(Eq, PartialEq, Debug)]
pub enum SmtpCommand {
Data,
}
#[derive(Eq, PartialEq, Debug)]
pub enum SmtpReply {
OkInfo,
StartMailInputChallenge,
TransactionFailure,
CommandNotImplementedFailure
}
pub struct SmtpService {
handle: tokio_core::reactor::Handle,
}
impl Service for SmtpService {
// For non-streaming protocols, service errors are always io::Error
type Error = io::Error;
// These types must match the corresponding protocol types:
type Request = Message<SmtpCommand, Body<Bytes, Self::Error>>;
type Response = Message<SmtpReply, Body<SmtpReply, Self::Error>>;
// The future for computing the response; box it for simplicity.
type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;
// Produce a future for computing a response from a request.
fn call(&self, command: Self::Request) -> Self::Future {
info!("Received {:?}", command);
match command {
Message::WithBody(cmd, cmd_body) => {
match cmd {
SmtpCommand::Data => {
// start => SmtpReply::StartMailInputChallenge
// ok => SmtpReply::OkInfo
// err => SmtpReply::TransactionFailure
let (tx, rx) = mpsc::channel::<io::Result<SmtpReply>>(1);
let fut = cmd_body
// read cmd stream; for_each results in a Future,
// which completes when the stream is finished
.for_each(|chunk| {
info!("data: {:?}", chunk);
Ok(())
})
// now send the result body
.then(move |r| match r {
Ok(_) => tx.send(Ok(SmtpReply::OkInfo)),
Err(_) => tx.send(Ok(SmtpReply::TransactionFailure)),
})
// could send further body messages:
// .and_then(|tx| tx.send(...))
// ignore any send errors; spawn needs a future with
// Item=() and Error=().
.then(|_| Ok(()))
;
self.handle.spawn(fut);
let body : Body<SmtpReply, Self::Error> = Body::from(rx);
let msg : Self::Response = Message::WithBody(SmtpReply::StartMailInputChallenge, body);
Box::new(future::ok(msg)) as Self::Future
}
_ => Box::new(future::ok(Message::WithoutBody(
SmtpReply::CommandNotImplementedFailure,
))),
}
}
Message::WithoutBody(cmd) => {
Box::new(future::ok(Message::WithoutBody(match cmd {
_ => SmtpReply::CommandNotImplementedFailure,
})))
}
}
}
}
fn main() {
println!("Hello, world!");
}

How to push several function with args into an array

Hello everyone,
In a Node.js module (a custom queue) i am working on,
I am using the queue module, and I need to push into its array "jobs" several functions with an argument (an int for the estimated time)
When I start the queue, an error that says that the job is not a function.
I think I understand why, it's because the function "process" is executed when I push it. But I need to execute this process later with arguments.
my code :
module.exports = Queue
var process = require("../test/processjob")
var q = require("queue");
function Queue(options) {
if (!(this instanceof Queue)) {
return new Queue(options);
}
options = options || {}
this.queue = q();
/*
handling other options
*/
}
Queue.prototype.processJob = function() {
for (var i = 0, len = this.tasks.length; i < len; i++) {
this.queue.push(process.process(this.tasks[i].estimated_time));// <== push here
}
this.queue.start(); //<== exception here
}
Thanks a lot, and sorry for my poor english.
To push a function into an array, that you'll want to execute at a later point in time, you could wrap that function with another function, i.e.:
this.queue.push(
function(cb) {
process.process(this.tasks[i].estimated_time)
cb();
}
);// <== push here
Or using ES6
this.queue.push((cb) => {
process.process(this.tasks[i].estimated_time);
cb();
});

Resources