How to return a future for a hyper::Request


#1

I’m trying to use librespot for my own little project. Actually, I’ve been using it for almost a year now. Yet, I’m a total noob when it comes to Rust… And today I’m stuck. Here’s what I’m trying to do.

My application is based on librespot’s sample main.rs. But I’d like to expand its event signaling mechanism to do a http request to my server, rather than run some shell script. For this I want to replace the call to its event handler with my own.

I actually had something running. But it seems my method should never have worked. I’m running a core loop inside another core loop. Here’s my event handler, which is called from main’s loop: https://github.com/michaelherger/spotty/blob/f3136f40c9ecee3ba5de2c20fd75ba20312b9867/src/lms.rs#L127.

Something has changed in Rust recently, because now I’m getting a crash 'cannot recursively call into Core'.

So… I’m trying to get rid of this. I understand I should pass the handle from main to the event handler, which in turn should return a future(?). But that’s where I’m stuck. Once I have the hyper::Request, what would I need to do with it in order to have it processed?


#2

Hopefully I can paste the stack trace here… wasn’t allowed to do so in my very first posting :-).

DEBUG:librespot_connect::discovery: Zeroconf server listening on 0.0.0.0:0
WARN:mdns: Failed to register IPv6 receiver: Error { repr: Os { code: 49, message: "Can\'t assign requested address" } }
INFO:librespot_core::session: Connecting to AP "...."
INFO:librespot_core::session: Authenticated as "username" !
DEBUG:librespot_core::session: new Session[0]
DEBUG:librespot_connect::spirc: new Spirc[0]
DEBUG:librespot_core::mercury: new MercuryManager
DEBUG:librespot_playback::player: new Player[0]
DEBUG:librespot_connect::spirc: linear volume: 32768
DEBUG:librespot_playback::player: command=Volume(32768)
INFO:spotty::lms: volume 50
INFO:spotty::lms: Base URL to talk to LMS: 
INFO:spotty::lms: Player MAC address to control: ac:bc:de:ef:ae:d1
INFO:spotty::lms: Command to send to player: ["spottyconnect","volume",50]
thread 'main' panicked at 'cannot recursively call into `Core`', src/libcore/option.rs:839:4
stack backtrace:
   0:        0x10e18ec83 - std::sys::imp::backtrace::tracing::imp::unwind_backtrace::h6f26156f36f91c7c
                               at src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1:        0x10e18b070 - std::sys_common::backtrace::_print::h0b677b64a478c8cb
                               at src/libstd/sys_common/backtrace.rs:69
   2:        0x10e1913b3 - std::panicking::default_hook::{{closure}}::h2a99d1ab84807307
                               at src/libstd/sys_common/backtrace.rs:58
                               at src/libstd/panicking.rs:381
   3:        0x10e1910b2 - std::panicking::default_hook::h540d2e3ab8360bf0
                               at src/libstd/panicking.rs:397
   4:        0x10e1918c2 - std::panicking::begin_panic::had0530100710df8d
                               at src/libstd/panicking.rs:577
   5:        0x10e1917a4 - std::panicking::begin_panic::had0530100710df8d
                               at src/libstd/panicking.rs:538
   6:        0x10e191672 - std::panicking::try::do_call::hab1a42132be4fc65
                               at src/libstd/panicking.rs:522
   7:        0x10e1915da - std::panicking::try::do_call::hab1a42132be4fc65
                               at src/libstd/panicking.rs:498
   8:        0x10e1c97c3 - <core::ops::range::Range<Idx> as core::fmt::Debug>::fmt::h1d8acafc4a3cbc3f
                               at src/libcore/panicking.rs:71
   9:        0x10e1c982d - <core::ops::range::Range<Idx> as core::fmt::Debug>::fmt::h1d8acafc4a3cbc3f
                               at src/libcore/option.rs:839
  10:        0x10d2cf5de - <core::option::Option<T>>::expect::h568c6a1f9319294d
                               at /Users/travis/build/rust-lang/rust/src/libcore/option.rs:302
  11:        0x10d3096eb - tokio_core::reactor::Core::run::h3c136aa2f0b23607
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-core-0.1.16/src/reactor/mod.rs:242
  12:        0x10d2feefc - spotty::lms::LMS::request::h58e1a73788dd0f1a
                               at src/lms.rs:127
  13:        0x10d2fe2e9 - spotty::lms::LMS::volume::h62989f587ef99ecf
                               at src/lms.rs:88
  14:        0x10d2fdf41 - spotty::lms::LMS::signal_event::h2beaaa282b622e07
                               at src/lms.rs:63
  15:        0x10d32ed79 - <spotty::Main as futures::future::Future>::poll::h135eed544ada837f
                               at src/main.rs:407
  16:        0x10d2ee31c - <futures::task_impl::Spawn<T>>::poll_future_notify::{{closure}}::ha0b1760bde4e70cf
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.21/src/task_impl/mod.rs:289
  17:        0x10d2efaef - <futures::task_impl::Spawn<T>>::enter::{{closure}}::h7a7edb91880ae51b
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.21/src/task_impl/mod.rs:363
  18:        0x10d3277d6 - futures::task_impl::std::set::h1b8f65c32b486fba
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.21/src/task_impl/std/mod.rs:78
  19:        0x10d2ef75e - <futures::task_impl::Spawn<T>>::enter::ha37fd360b116b996
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.21/src/task_impl/mod.rs:363
  20:        0x10d2ede24 - <futures::task_impl::Spawn<T>>::poll_future_notify::h9015bee84dac9ab9
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.21/src/task_impl/mod.rs:289
  21:        0x10d30c042 - tokio_core::reactor::Core::run::{{closure}}::{{closure}}::{{closure}}::{{closure}}::hf7ea3b21e064094e
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-core-0.1.16/src/reactor/mod.rs:253
  22:        0x10d2f0d77 - <futures::future::lazy::Lazy<F, R>>::get::h7c9dbfcb5471b096
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.21/src/future/lazy.rs:64
  23:        0x10d2fa79c - <futures::future::lazy::Lazy<F, R> as futures::future::Future>::poll::hfc31a298d4a2224a
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.21/src/future/lazy.rs:82
  24:        0x10d2ee53c - <futures::task_impl::Spawn<T>>::poll_future_notify::{{closure}}::hd5cabfcdce8feaf3
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.21/src/task_impl/mod.rs:289
  25:        0x10d2efc2f - <futures::task_impl::Spawn<T>>::enter::{{closure}}::hb9b0a13b0d594109
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.21/src/task_impl/mod.rs:363
  26:        0x10d328535 - futures::task_impl::std::set::hf6e2eec73297f039
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.21/src/task_impl/std/mod.rs:78
  27:        0x10d2eee9e - <futures::task_impl::Spawn<T>>::enter::h3c60b933659689e1
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.21/src/task_impl/mod.rs:363
  28:        0x10d2edeb4 - <futures::task_impl::Spawn<T>>::poll_future_notify::hb4cc9fc85aecccbc
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.21/src/task_impl/mod.rs:289
  29:        0x10d2b78ef - <tokio::executor::current_thread::Entered<'a, P>>::block_on::{{closure}}::h6d0e38dbd523c1b1
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.1.6/src/executor/current_thread/mod.rs:464
  30:        0x10d2b64da - <tokio::executor::current_thread::Borrow<'a, U>>::enter::{{closure}}::{{closure}}::h0cc1a3401a330566
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.1.6/src/executor/current_thread/mod.rs:688
  31:        0x10d2b47c0 - tokio::executor::current_thread::CurrentRunner::set_spawn::hb8bf56702d16822e
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.1.6/src/executor/current_thread/mod.rs:720
  32:        0x10d2b6223 - <tokio::executor::current_thread::Borrow<'a, U>>::enter::{{closure}}::h0ba9110a83d0962b
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.1.6/src/executor/current_thread/mod.rs:687
  33:        0x10d3720ab - <std::thread::local::LocalKey<T>>::try_with::hbdc69697c1f7c696
                               at /Users/travis/build/rust-lang/rust/src/libstd/thread/local.rs:379
  34:        0x10d36f07a - <std::thread::local::LocalKey<T>>::with::h8e05ead11fc254eb
                               at /Users/travis/build/rust-lang/rust/src/libstd/thread/local.rs:293
  35:        0x10d2b5fe1 - <tokio::executor::current_thread::Borrow<'a, U>>::enter::ha931faaf9ac76b8f
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.1.6/src/executor/current_thread/mod.rs:686
  36:        0x10d2b72c9 - <tokio::executor::current_thread::Entered<'a, P>>::block_on::hdb6f0570032eacbf
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.1.6/src/executor/current_thread/mod.rs:463
  37:        0x10d30ba02 - tokio_core::reactor::Core::run::{{closure}}::{{closure}}::{{closure}}::h056da405e7cde42b
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-core-0.1.16/src/reactor/mod.rs:251
  38:        0x10d2900fd - tokio_executor::global::with_default::{{closure}}::h223a6823ee440a67
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-executor-0.1.2/src/global.rs:176
  39:        0x10d372814 - <std::thread::local::LocalKey<T>>::try_with::hdc6d08b07cda0111
                               at /Users/travis/build/rust-lang/rust/src/libstd/thread/local.rs:379
  40:        0x10d36efb2 - <std::thread::local::LocalKey<T>>::with::h64380b2058263a79
                               at /Users/travis/build/rust-lang/rust/src/libstd/thread/local.rs:293
  41:        0x10d28fd5c - tokio_executor::global::with_default::hf0d7c2321a2f6d2e
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-executor-0.1.2/src/global.rs:150
  42:        0x10d30b943 - tokio_core::reactor::Core::run::{{closure}}::{{closure}}::he223a226870ecf21
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-core-0.1.16/src/reactor/mod.rs:250
  43:        0x10d3a31bf - tokio_reactor::with_default::{{closure}}::h46d792e53668b4ff
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-reactor-0.1.1/src/lib.rs:207
  44:        0x10d371a3e - <std::thread::local::LocalKey<T>>::try_with::ha220c9b1b7208104
                               at /Users/travis/build/rust-lang/rust/src/libstd/thread/local.rs:379
  45:        0x10d36f7ac - <std::thread::local::LocalKey<T>>::with::hf35d70e3a8e5a58e
                               at /Users/travis/build/rust-lang/rust/src/libstd/thread/local.rs:293
  46:        0x10d3a2fbd - tokio_reactor::with_default::had214716788458cd
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-reactor-0.1.1/src/lib.rs:199
  47:        0x10d30b461 - tokio_core::reactor::Core::run::{{closure}}::h49e11aabcd17ed65
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-core-0.1.16/src/reactor/mod.rs:249
  48:        0x10d2d8e0c - <scoped_tls::ScopedKey<T>>::set::h9d36f3149bce1902
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/scoped-tls-0.1.0/src/lib.rs:135
  49:        0x10d30b1ad - tokio_core::reactor::Core::run::hdb6f021fb1bb983c
                               at /Users/mh/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-core-0.1.16/src/reactor/mod.rs:248
  50:        0x10d330a77 - spotty::main::h7fde15a2bf918426
                               at src/main.rs:474
  51:        0x10e19e3dc - panic_unwind::dwarf::eh::read_encoded_pointer::hb58e97d57b98c61e
                               at src/libpanic_unwind/lib.rs:99
  52:        0x10e191dc8 - <std::rand::reader::ReaderRng<R> as rand::Rng>::fill_bytes::hae12a5e967a5c965
                               at src/libstd/panicking.rs:459
                               at src/libstd/panic.rs:361
                               at src/libstd/rt.rs:59
  53:        0x10d331444 - spotty::main::{{closure}}::h7c86a45143210067
DEBUG:librespot_connect::spirc: drop Spirc[0]
DEBUG:librespot_playback::player: Shutting down player thread ...
DEBUG:librespot_playback::player: drop Player[0]
DEBUG:librespot_core::session: drop Session[0]
DEBUG:librespot_core::mercury: drop MercuryManager
DEBUG:librespot_core::session: drop Dispatch

The discussion about “cannot recursively call into Core”: https://github.com/tokio-rs/tokio-core/issues/319


#3

Once you have a Handle to the running loop, you can spawn() the request - that’ll run the request on the loop.


#4

Would I do so inside the event handler? And what exactly would I spawn()? I can’t client.request(req).spawn(): “no method named spawn found for type hyper::client::FutureResponse in the current scope”


#5

You need access to the Handle, which represents a handle to the Core that’s already running. Can you thread that through to your code?

Then you’d do:

let h: Handle = ...;
h.spawn(request);

Note that request will need to be a Future<Item = (), Error = ()> + 'static; practically, that means any error and result handling is contained within that future chain - it’s essentially a standalone task that runs in the loop, to completion, and doesn’t return an error or a value to anyone.


#6

Here’s roughly where I fail:

				let client = Client::new(&handle);

				let json = format!(r#"{{"id": 1,"method":"slim.request","params":["{}",{}]}}"#, player_mac, command);
				let uri = Uri::from_str(base_url).unwrap();
				let mut req = Request::new(Method::Post, uri);

				req.headers_mut().set(ContentType::json());
				req.headers_mut().set(ContentLength(json.len() as u64));
				req.set_body(json);

				let post = client.request(req);
				handle.spawn(post);

But it’s those last two lines which are causing me a headache… And I guess it’s related to your very last comment "Note that request will need to be a Future<Item = (), Error = ()> + 'static;". What am I missing?


#7

You probably want to chain your future and manage the Response / error.

let post = client.request(req).and_then(|_res| {
    /* work with the response here */
}).map_err(|_err| {
  // and probably map your error as well
});

#8

It’s what @tafia said. Based on your github code, you seem to not care about the result or the error, so that would just be:

let post = client.request(req).map(|_| ()).map_err(|_| ());
handle.spawn(post);

(You probably want to at least log the error, however).


#9

Wow… I could have bet I had tried the .and_then() version - but probably never read the resulting error message to the end. I was missing the use futures::Future… added this, and it worked immediately. Thank you very much, guys!


#10

A minor point is that and_then is for when you want the closure given to it to return a future itself; if you just want to change the underlying future’s result with synchronous code, use map().