protocol_jobs_manager.rs 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::sync::Arc;
  19. use smol::{future::Future, lock::Mutex, Executor, Task};
  20. use tracing::{debug, trace};
  21. use super::super::channel::ChannelPtr;
  22. use crate::Result;
  23. /// Pointer to protocol jobs manager
  24. pub type ProtocolJobsManagerPtr = Arc<ProtocolJobsManager>;
  25. pub struct ProtocolJobsManager {
  26. name: &'static str,
  27. channel: ChannelPtr,
  28. tasks: Mutex<Vec<Task<Result<()>>>>,
  29. }
  30. impl ProtocolJobsManager {
  31. /// Create a new protocol jobs manager
  32. pub fn new(name: &'static str, channel: ChannelPtr) -> ProtocolJobsManagerPtr {
  33. Arc::new(Self { name, channel, tasks: Mutex::new(vec![]) })
  34. }
  35. /// Returns configured name
  36. pub fn name(self: Arc<Self>) -> &'static str {
  37. self.name
  38. }
  39. /// Runs the task on an executor
  40. pub fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) {
  41. executor.spawn(self.handle_stop()).detach()
  42. }
  43. /// Spawns a new task and adds it to the internal queue
  44. pub async fn spawn<'a, F>(&self, future: F, executor: Arc<Executor<'a>>)
  45. where
  46. F: Future<Output = Result<()>> + Send + 'a,
  47. {
  48. self.tasks.lock().await.push(executor.spawn(future))
  49. }
  50. /// Waits for a stop signal, then closes all tasks.
  51. /// Ensures that all tasks are stopped when a channel closes.
  52. /// Called in `start()`
  53. async fn handle_stop(self: Arc<Self>) {
  54. let stop_sub = self.channel.subscribe_stop().await;
  55. if let Ok(stop_sub) = stop_sub {
  56. // Wait for the stop signal
  57. stop_sub.receive().await;
  58. }
  59. self.close_all_tasks().await
  60. }
  61. /// Closes all open tasks. Takes all the tasks from the internal queue.
  62. async fn close_all_tasks(self: Arc<Self>) {
  63. debug!(
  64. target: "net::protocol_jobs_manager",
  65. "ProtocolJobsManager::close_all_tasks() [START, name={}, addr={}]",
  66. self.name, self.channel.display_address(),
  67. );
  68. let tasks = std::mem::take(&mut *self.tasks.lock().await);
  69. trace!(target: "net::protocol_jobs_manager", "Cancelling {} tasks", tasks.len());
  70. let mut i = 0;
  71. #[allow(clippy::explicit_counter_loop)]
  72. for task in tasks {
  73. trace!(target: "net::protocol_jobs_manager", "Cancelling task #{i}");
  74. let _ = task.cancel().await;
  75. trace!(target: "net::protocol_jobs_manager", "Cancelled task #{i}");
  76. i += 1;
  77. }
  78. }
  79. }