two-way file system sync
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

client_side_sync.rs 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. use std::sync::Arc;
  2. use tokio::sync::{mpsc, oneshot, Mutex};
  3. use super::file_tree::{FileTree, NewVersionSource};
  4. use super::{Error, SynchronizationError};
  5. pub struct ClientSideSync {
  6. state_send: mpsc::Sender<(StateChange, oneshot::Sender<()>)>,
  7. new_version_source: NewVersionSource,
  8. }
  9. // TODO: Parametrize the server protocol!
  10. // TODO: Can one directory be synchronized to multiple servers? Cycles are then possible!
  11. impl ClientSideSync {
  12. // TODO: Restrict the size of the files downloaded by the synchronization client?
  13. pub async fn new(
  14. file_tree: Arc<Mutex<FileTree>>,
  15. errors: mpsc::Sender<SynchronizationError>,
  16. ) -> Result<ClientSideSync, Error> {
  17. let new_version_source = file_tree.lock().await.new_version_source();
  18. // Spawn the task that connects to the server as soon as unpause() is called.
  19. let (state_send, pause_receive) = mpsc::channel(1);
  20. tokio::spawn(async move {
  21. let mut sync_task = ClientSideSyncTask {
  22. file_tree,
  23. errors,
  24. new_version_source,
  25. };
  26. sync_task.task_paused(pause_receive).await;
  27. });
  28. Ok(ClientSideSync{
  29. state_send,
  30. new_version_source,
  31. })
  32. }
  33. // TODO: Deduplicate this code.
  34. pub async fn pause(&mut self) {
  35. let (send, receive) = oneshot::channel();
  36. self.state_send
  37. .send((StateChange::Pause, send))
  38. .await
  39. .unwrap();
  40. receive.await.unwrap();
  41. }
  42. pub async fn unpause(&mut self) {
  43. let (send, receive) = oneshot::channel();
  44. self.state_send
  45. .send((StateChange::Unpause, send))
  46. .await
  47. .unwrap();
  48. receive.await.unwrap();
  49. }
  50. }
  51. struct ClientSideSyncTask {
  52. file_tree: Arc<Mutex<FileTree>>,
  53. errors: mpsc::Sender<SynchronizationError>,
  54. new_version_source: NewVersionSource,
  55. }
  56. impl ClientSideSyncTask {
  57. async fn task_paused(
  58. &mut self,
  59. mut state_receive: mpsc::Receiver<(StateChange, oneshot::Sender<()>)>,
  60. ) {
  61. let mut paused = true;
  62. loop {
  63. if paused {
  64. // If we are paused, we only need to wait for state changes.
  65. let (new_state, send) = state_receive.recv().await.unwrap();
  66. match new_state {
  67. StateChange::Pause => paused = true,
  68. StateChange::Unpause => paused = false,
  69. StateChange::Terminate => break, // No reply, see drop().
  70. }
  71. send.send(()).unwrap();
  72. } else {
  73. // We were unpaused, initialize the file system watcher and start waiting for
  74. // that as well.
  75. let next_state = self.task_unpaused(&mut state_receive).await;
  76. match next_state {
  77. StateChange::Pause => paused = true,
  78. StateChange::Unpause => paused = false,
  79. StateChange::Terminate => break,
  80. }
  81. }
  82. }
  83. }
  84. async fn task_unpaused(
  85. &mut self,
  86. state_receive: &mut mpsc::Receiver<(StateChange, oneshot::Sender<()>)>,
  87. ) -> StateChange {
  88. // Connect to the server.
  89. // TODO
  90. // Start listening to local events, remote events and pause commands.
  91. // TODO
  92. // Disconnect again.
  93. // TODO
  94. panic!("Not yet implemented.");
  95. }
  96. }
  97. #[derive(Debug)]
  98. enum StateChange {
  99. Pause,
  100. Unpause,
  101. Terminate,
  102. }