Today I'm going to implement HTTP request & response mocks for testing purposes. But first, some minor config tweaks...
This architecture allows me to impl Top for any HTTP implementation, and also allows me to use a custom mock for running the test suite, or for iocaine runtime decide.
One complicating factor is that different methods may return different types. Most of them return a String currently, but for example .header() would return an Option<String>.
This means that functions like Dom::method() and Dom::path() are essentially the same, and differ only in the type they tx.send(), and differ from .header() in the type they return. I wonder if I can use some generics trickery to remove the boilerplate.
Hah! I CAN!
impl Dom {
fn communicate<T, F>(&self, req: F) -> T
where
F: FnOnce(oneshot::Sender<T>) -> DomRequest,
{
let (resp_tx, resp_rx) = oneshot::channel();
let tx = self.channel.clone();
tx.send(req(resp_tx)).ok().unwrap();
tokio::task::block_in_place(move || resp_rx.blocking_recv().unwrap())
}
pub fn method(&self) -> String {
self.communicate(|responder| DomRequest::Method { responder })
}
}
Sweet.
Yes, this will panic when communicating on the channel fails. I think that's more suitable behaviour than trying to handle such a catastrophic situation on the scripting side.
Yay, I have the skeleton code for dealing with HTTP requests! The way I'm approaching this, to remain mostly HTTP implementation-agnostic, is that there's gonna be two main types exposed to the iocaine runtime:
RequestandResponse. On the Rust side, these are a simple struct that wrap anmpscchannel, and provide a new function:Where
Topis a trait that requires implementing a few functions like.method(&self) -> impl Into<String>,path(&self) -> impl Into<String>, and so on. Those implementations send a request over the wrappedmpscchannel, along with aoneshot::Senderto respond on, then wait for the response, and return that.