gnostr_asyncgit/
remote_progress.rs1use std::{
4 sync::{Arc, Mutex},
5 thread::{self, JoinHandle},
6};
7
8use crossbeam_channel::{Receiver, Sender};
9use git2::PackBuilderStage;
10
11use crate::{
12 AsyncGitNotification,
13 error::Result,
14 progress::ProgressPercent,
15 sync::remotes::push::{AsyncProgress, ProgressNotification},
16};
17
18#[derive(Clone, Debug)]
20pub enum RemoteProgressState {
21 PackingAddingObject,
23 PackingDeltafiction,
25 Pushing,
27 Transfer,
29 Done,
31}
32
33#[derive(Clone, Debug)]
35pub struct RemoteProgress {
36 pub state: RemoteProgressState,
38 pub progress: ProgressPercent,
40}
41
42impl RemoteProgress {
43 pub fn new(
45 state: RemoteProgressState,
46 current: usize,
47 total: usize,
48 ) -> Self {
49 Self {
50 state,
51 progress: ProgressPercent::new(current, total),
52 }
53 }
54
55 pub const fn get_progress_percent(&self) -> u8 {
57 self.progress.progress
58 }
59
60 pub(crate) fn set_progress<T>(
61 progress: &Arc<Mutex<Option<T>>>,
62 state: Option<T>,
63 ) -> Result<()> {
64 let mut progress = progress.lock()?;
65
66 *progress = state;
67
68 Ok(())
69 }
70
71 pub(crate) fn spawn_receiver_thread<
74 T: 'static + AsyncProgress,
75 >(
76 notification_type: AsyncGitNotification,
77 sender: Sender<AsyncGitNotification>,
78 receiver: Receiver<T>,
79 progress: Arc<Mutex<Option<T>>>,
80 ) -> JoinHandle<()> {
81 thread::spawn(move || {
82 loop {
83 let incoming = receiver.recv();
84 match incoming {
85 Ok(update) => {
86 Self::set_progress(
87 &progress,
88 Some(update.clone()),
89 )
90 .expect("set progress failed");
91 sender
92 .send(notification_type)
93 .expect("Notification error");
94
95 thread::yield_now();
96
97 if update.is_done() {
98 break;
99 }
100 }
101 Err(e) => {
102 log::error!(
103 "remote progress receiver error: {}",
104 e
105 );
106 break;
107 }
108 }
109 }
110 })
111 }
112}
113
114impl From<ProgressNotification> for RemoteProgress {
115 fn from(progress: ProgressNotification) -> Self {
116 match progress {
117 ProgressNotification::Packing {
118 stage,
119 current,
120 total,
121 } => match stage {
122 PackBuilderStage::AddingObjects => Self::new(
123 RemoteProgressState::PackingAddingObject,
124 current,
125 total,
126 ),
127 PackBuilderStage::Deltafication => Self::new(
128 RemoteProgressState::PackingDeltafiction,
129 current,
130 total,
131 ),
132 },
133 ProgressNotification::PushTransfer {
134 current,
135 total,
136 ..
137 } => Self::new(
138 RemoteProgressState::Pushing,
139 current,
140 total,
141 ),
142 ProgressNotification::Transfer {
143 objects,
144 total_objects,
145 ..
146 } => Self::new(
147 RemoteProgressState::Transfer,
148 objects,
149 total_objects,
150 ),
151 _ => Self::new(RemoteProgressState::Done, 1, 1),
152 }
153 }
154}