gnostr_asyncgit/
remote_progress.rs

1//!
2
3use 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/// used for push/pull
19#[derive(Clone, Debug)]
20pub enum RemoteProgressState {
21	///
22	PackingAddingObject,
23	///
24	PackingDeltafiction,
25	///
26	Pushing,
27	/// fetch progress
28	Transfer,
29	/// remote progress done
30	Done,
31}
32
33///
34#[derive(Clone, Debug)]
35pub struct RemoteProgress {
36	///
37	pub state: RemoteProgressState,
38	///
39	pub progress: ProgressPercent,
40}
41
42impl RemoteProgress {
43	///
44	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	///
56	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	/// spawn thread to listen to progress notifications coming in
72	/// from blocking remote git method (fetch/push)
73	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}