Skip to content

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

New issue

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

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

Already on GitHub? # to your account

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!)

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

No branches or pull requests

4 participants