Skip to content

Commit 9c1495d

Browse files
committed
Revert "🧵 Service::handle now blocking"
This reverts commit 2491fea. When implementing the async handling, I realized how limiting that is w/o having the whole handler async. With the reverted change, a lot of async code will be forced to use interior mutability and method handling being non-async, would mean that either handlers will be limited to sync locks (which isn't what you always want in async code) or having to spawn tasks for all method handling. This especially sucks given that the whole Server machinery is completely single-threaded itself. Moreover, it looks very likely that the reason we can't just `tokio::spawn` `Server::run` is not because the future is always `!Send` but rather that the compiler is unable to determine that to be the case because of known issue[1]. [1]: rust-lang/rust#100013
1 parent 7a18740 commit 9c1495d

File tree

3 files changed

+15
-10
lines changed

3 files changed

+15
-10
lines changed

zlink-tokio/tests/lowlevel-ftl.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::time::Duration;
22

33
use serde::{Deserialize, Serialize};
4-
use tokio::{spawn, time::sleep};
4+
use tokio::{select, spawn, time::sleep};
55
use zlink::connection::Reply;
66
use zlink_tokio::{
77
connection::Call,
@@ -36,8 +36,15 @@ async fn lowlevel_ftl() -> Result<(), Box<dyn std::error::Error>> {
3636
let listener = bind(SOCKET_PATH).unwrap();
3737
let service = Ftl::new(conditions[0]);
3838
let server = zlink_tokio::Server::new(listener, service);
39-
spawn(server.run());
39+
select! {
40+
_ = server.run() => {},
41+
_ = run_client(&conditions) => {}
42+
}
43+
44+
Ok(())
45+
}
4046

47+
async fn run_client(conditions: &[DriveCondition]) -> Result<(), Box<dyn std::error::Error>> {
4148
// Now create a client connection that monitor changes in the drive condition.
4249
let mut drive_monitor_conn = connect(SOCKET_PATH).await?;
4350
drive_monitor_conn
@@ -154,7 +161,7 @@ impl Service for Ftl {
154161
type ReplyStreamParams = Replies;
155162
type ReplyError<'ser> = Errors;
156163

157-
fn handle<'ser>(
164+
async fn handle<'ser>(
158165
&'ser mut self,
159166
call: Call<Self::MethodCall<'_>>,
160167
) -> MethodReply<Self::ReplyParams<'ser>, Self::ReplyStream, Self::ReplyError<'ser>> {

zlink/src/server/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ where
165165
writer: &mut WriteConnection<<Listener::Socket as Socket>::WriteHalf>,
166166
) -> crate::Result<Option<Service::ReplyStream>> {
167167
let mut stream = None;
168-
match self.service.handle(call) {
168+
match self.service.handle(call).await {
169169
MethodReply::Single(params) => {
170170
writer
171171
.send_reply(Reply::new(params).set_continues(Some(false)))

zlink/src/server/service.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Serice-related API.
22
3-
use core::fmt::Debug;
3+
use core::{fmt::Debug, future::Future};
44

55
use futures_util::Stream;
66
use serde::{Deserialize, Serialize};
@@ -40,14 +40,12 @@ pub trait Service {
4040
Self: 'ser;
4141

4242
/// Handle a method call.
43-
///
44-
/// While this methos is no async, it can return a reply stream that can be used to
45-
/// ascynchronously send out replies. The main use case for allowing to return a stream is
46-
/// multiple replies but it can be used for single reply as well.
4743
fn handle<'ser>(
4844
&'ser mut self,
4945
method: Call<Self::MethodCall<'_>>,
50-
) -> MethodReply<Self::ReplyParams<'ser>, Self::ReplyStream, Self::ReplyError<'ser>>;
46+
) -> impl Future<
47+
Output = MethodReply<Self::ReplyParams<'ser>, Self::ReplyStream, Self::ReplyError<'ser>>,
48+
>;
5149
}
5250

5351
/// A service method call reply.

0 commit comments

Comments
 (0)