Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Help] How to maintain state in Gloo? #99

Closed
robert-snakard opened this issue Nov 28, 2019 · 10 comments
Closed

[Help] How to maintain state in Gloo? #99

robert-snakard opened this issue Nov 28, 2019 · 10 comments

Comments

@robert-snakard
Copy link

Hey all, if there's a better place to ask my question please redirect me. How do I maintain state in Gloo? eg

fn main() {
    let mut count = 0;
    Interval::new(1000, || { 
        console.log_1(format!("{} seconds have passed"), count);  
        count += 1;
    });
}

This doesn't work because the interval outlives the main function. A global variable doesn't work because 'static muts are unsafe. I end up with some complicated static Arc<Mutex<u32>> that I really don't want. Is there a better way to maintain state?

@jhpratt
Copy link

jhpratt commented Nov 29, 2019 via email

@robert-snakard
Copy link
Author

It would if this was all I was doing. I have a State struct however and the usize was just used to make a simple example. I guess I'm looking for some way to block on Interval until I receive a signal? So to expand on my example:

struct State { count: usize }
fn main() {
    let mut state = State { count: 0 };
    let handle = Interval::new(1000, || {
        console.log_1(format!("{} seconds have passed", count));
        count += 1;
        if (count == 60) {
            signal_end_interval();
        }
    });

    while (!end_interval());
    handle.cancel();
    console.log("approximately 1 minute has passed");
}

I'm imagining the signal_end_interval working through some kind of mspc channel. I want to have thread communication between the Interval loop and my main function and I don't want main to end until I've cancelled Interval. I just need to tell the compiler "This is how it's working"

@Pauan
Copy link
Contributor

Pauan commented Nov 29, 2019

@robert-snakard For your original code, you can just use a move || { ... } closure, which will move the count variable inside of the closure.

For state in general, you would use Rc<RefCell<State>>, since that allows you to access the state inside of the closure and also outside of the closure.

For your specific use case, it sounds like what you want is a Stream, which gloo has native support for:

use gloo_timers::future::IntervalStream;
use futures::stream::StreamExt;
use wasm_bindgen_futures::spawn_local;

fn main() {
    spawn_local(async {
        let mut count = 0;

        IntervalStream::new(1000).take_while(move |_| {
            count += 1;
            return count < 60;
        }).for_each(|value| {
            // Put your code here...
        }).await;
    });
}

If you just want to wait for a certain number of seconds, you should use gloo_timers::future:TimeoutFuture instead:

use gloo_timers::future::TimeoutFuture;
use wasm_bindgen_futures::spawn_local;

fn main() {
    spawn_local(async {
        TimeoutFuture::new(60_000).await;
    });
}

The only problem is that gloo currently supports the old style of Streams, but there is a PR for upgrading to the new style.

@robert-snakard
Copy link
Author

Awesome, thanks a lot @Pauan

@heilhead
Copy link

heilhead commented Dec 5, 2019

@Pauan I'm having troubles running your TimeoutFuture example on the recently landed #98 version.

Complete code:

extern crate gloo;
extern crate wasm_bindgen;

use gloo::timers::future::TimeoutFuture;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;

#[wasm_bindgen]
pub fn main() {
    spawn_local(async {
        TimeoutFuture::new(100).await;
    });
}

And this is what I get in console:

bootstrap:67 Uncaught (in promise) TypeError: Illegal invocation
    at __wbg_clearTimeout_42a8676f07d366c5 (bootstrap:67)
    at gloo_timers::sys::clear_timeout::h8f99796a78143817 (:53735/wasm-function[616]:0x22ef8)

IntervalStream is working fine, but TimeoutFuture I just can't get to work - none of the examples from gloo's docs have worked for me, all with the same error. I feel like I'm missing something obvious here, but can't figure out what. Any hints?

@heilhead
Copy link

heilhead commented Dec 5, 2019

Okay, I've found a workaround: #96 (comment). Related to rustwasm/wasm-bindgen#1046.

@Pauan
Copy link
Contributor

Pauan commented Dec 6, 2019

@heilhead I'm not getting that error. What browser are you running the code in?

@heilhead
Copy link

heilhead commented Dec 6, 2019

@Pauan Chrome@78. But as pointed out somewhere, the error occurs only if you build your code with webpack (in my case it's webpack + @wasm-tool/wasm-pack-plugin).

I've ended up with something like this as a workaround in my fork (to work both in window/webpack, and web worker contexts): https://github.com/heilhead/gloo/blob/future-factories/crates/timers/src/sys.rs#L35-L70

@Pauan
Copy link
Contributor

Pauan commented Dec 12, 2019

@heilhead Okay, I was able to reproduce it with Webpack. It seems to be some sort of bug with Webpack. I'll fix it by using the setTimeout defined in web-sys.

@Pauan
Copy link
Contributor

Pauan commented Dec 12, 2019

@heilhead It should be fixed in version 0.2.0 (which is out now!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants