syncweb_core/sync/
intents.rs1use std::{
2 pin::Pin,
3 task::{Context, Poll},
4};
5
6use n0_future::{Sink, Stream};
7use tokio::sync::mpsc;
8
9use super::TransferStats;
10
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13#[non_exhaustive]
14pub enum SyncCommand {
15 Pause,
16 Resume,
17 Cancel,
18}
19
20#[derive(Clone, Debug, Eq, PartialEq)]
22#[non_exhaustive]
23pub enum SyncEvent {
24 Started,
25 Progress { completed: u64, total: Option<u64> },
26 Stats(TransferStats),
27 Paused,
28 Resumed,
29 Cancelled,
30 Finished,
31 Failed(String),
32}
33
34#[derive(Clone, Debug)]
36pub struct IntentControl {
37 commands: mpsc::UnboundedSender<SyncCommand>,
38}
39
40impl IntentControl {
41 pub fn pause(&self) -> Result<(), mpsc::error::SendError<SyncCommand>> {
47 self.commands.send(SyncCommand::Pause)
48 }
49
50 pub fn resume(&self) -> Result<(), mpsc::error::SendError<SyncCommand>> {
56 self.commands.send(SyncCommand::Resume)
57 }
58
59 pub fn cancel(&self) -> Result<(), mpsc::error::SendError<SyncCommand>> {
65 self.commands.send(SyncCommand::Cancel)
66 }
67}
68
69pub struct IntentHandle {
74 events: mpsc::UnboundedReceiver<SyncEvent>,
75 commands: mpsc::UnboundedSender<SyncCommand>,
76}
77
78impl std::fmt::Debug for IntentHandle {
79 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 formatter.debug_struct("IntentHandle").finish_non_exhaustive()
81 }
82}
83
84impl IntentHandle {
85 #[must_use]
86 pub fn channel() -> (
87 mpsc::UnboundedSender<SyncEvent>,
88 mpsc::UnboundedReceiver<SyncCommand>,
89 Self,
90 ) {
91 let (event_sender, events) = mpsc::unbounded_channel();
92 let (commands, command_receiver) = mpsc::unbounded_channel();
93 (event_sender, command_receiver, Self { events, commands })
94 }
95
96 pub fn pause(&self) -> Result<(), mpsc::error::SendError<SyncCommand>> {
101 self.commands.send(SyncCommand::Pause)
102 }
103
104 pub fn resume(&self) -> Result<(), mpsc::error::SendError<SyncCommand>> {
109 self.commands.send(SyncCommand::Resume)
110 }
111
112 pub fn cancel(&self) -> Result<(), mpsc::error::SendError<SyncCommand>> {
117 self.commands.send(SyncCommand::Cancel)
118 }
119
120 #[must_use]
122 pub fn cancel_sender(&self) -> mpsc::UnboundedSender<SyncCommand> {
123 self.commands.clone()
124 }
125
126 #[must_use]
127 pub fn control(&self) -> IntentControl {
128 IntentControl {
129 commands: self.commands.clone(),
130 }
131 }
132}
133
134impl Stream for IntentHandle {
135 type Item = SyncEvent;
136
137 fn poll_next(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Option<Self::Item>> {
138 self.events.poll_recv(context)
139 }
140}
141
142impl Sink<SyncCommand> for IntentHandle {
143 type Error = mpsc::error::SendError<SyncCommand>;
144
145 fn poll_ready(self: Pin<&mut Self>, _context: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
146 if self.commands.is_closed() {
147 Poll::Ready(Err(mpsc::error::SendError(SyncCommand::Cancel)))
148 } else {
149 Poll::Ready(Ok(()))
150 }
151 }
152
153 fn start_send(self: Pin<&mut Self>, item: SyncCommand) -> Result<(), Self::Error> {
154 self.commands.send(item)
155 }
156
157 fn poll_flush(self: Pin<&mut Self>, _context: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
158 Poll::Ready(Ok(()))
159 }
160
161 fn poll_close(self: Pin<&mut Self>, _context: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
162 Poll::Ready(Ok(()))
163 }
164}