I'm trying to construct an object that can manage a feed from a websocket but be able to switch between multiple feeds.
There is a Feed
trait:
trait Feed {
async fn start(&mut self);
async fn stop(&mut self);
}
There are three structs that implement Feed
: A
, B
, and C
.
When start
is called, it starts an infinite loop of listening for messages from a websocket and processing each one as it comes in.
I want to implement a FeedManager
that maintains a single active feed but can receive commands to switch what feed source it is using.
enum FeedCommand {
Start(String),
Stop,
}
struct FeedManager {
active_feed_handle: tokio::task::JoinHandle,
controller: mpsc::Receiver<FeedCommand>,
}
impl FeedManager {
async fn start(&self) {
while let Some(command) = self.controller.recv().await {
match command {
FeedCommand::Start(feed_type) => {
// somehow tell the active feed to stop (need channel probably) or kill the task?
if feed_type == "A" {
// replace active feed task with a new tokio task for consuming feed A
} else if feed_type == "B" {
// replace active feed task with a new tokio task for consuming feed B
} else {
// replace active feed task with a new tokio task for consuming feed C
}
}
}
}
}
}
I'm struggling to understand how to manage all the of Tokio tasks properly. FeedManager
's core loop is to listen forever for new commands that come in, but it needs to be able to spawn another long lived task without blocking on it (so it can listen for commands).
My first attempt was:
if feed_type == "A" {
self.active_feed_handle = tokio::spawn(async {
A::new().start().await;
});
self.active_feed_handle.await
}
- the
.await
on the handle would cause the core loop to no longer accept commands, right? - can I omit that last
.await
and have the task still run? - do I need to clean up the currently active task some way?