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 error::Result,
13 progress::ProgressPercent,
14 sync::remotes::push::{AsyncProgress, ProgressNotification},
15 AsyncGitNotification,
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(state: RemoteProgressState, current: usize, total: usize) -> Self {
45 Self {
46 state,
47 progress: ProgressPercent::new(current, total),
48 }
49 }
50
51 pub const fn get_progress_percent(&self) -> u8 {
53 self.progress.progress
54 }
55
56 pub(crate) fn set_progress<T>(
57 progress: &Arc<Mutex<Option<T>>>,
58 state: Option<T>,
59 ) -> Result<()> {
60 let mut progress = progress.lock()?;
61
62 *progress = state;
63
64 Ok(())
65 }
66
67 pub(crate) fn spawn_receiver_thread<T: 'static + AsyncProgress>(
70 notification_type: AsyncGitNotification,
71 sender: Sender<AsyncGitNotification>,
72 receiver: Receiver<T>,
73 progress: Arc<Mutex<Option<T>>>,
74 ) -> JoinHandle<()> {
75 thread::spawn(move || loop {
76 let incoming = receiver.recv();
77 match incoming {
78 Ok(update) => {
79 Self::set_progress(&progress, Some(update.clone()))
80 .expect("set progress failed");
81 sender.send(notification_type).expect("Notification error");
82
83 thread::yield_now();
84
85 if update.is_done() {
86 break;
87 }
88 }
89 Err(e) => {
90 log::error!("remote progress receiver error: {}", e);
91 break;
92 }
93 }
94 })
95 }
96}
97
98impl From<ProgressNotification> for RemoteProgress {
99 fn from(progress: ProgressNotification) -> Self {
100 match progress {
101 ProgressNotification::Packing {
102 stage,
103 current,
104 total,
105 } => match stage {
106 PackBuilderStage::AddingObjects => {
107 Self::new(RemoteProgressState::PackingAddingObject, current, total)
108 }
109 PackBuilderStage::Deltafication => {
110 Self::new(RemoteProgressState::PackingDeltafiction, current, total)
111 }
112 },
113 ProgressNotification::PushTransfer { current, total, .. } => {
114 Self::new(RemoteProgressState::Pushing, current, total)
115 }
116 ProgressNotification::Transfer {
117 objects,
118 total_objects,
119 ..
120 } => Self::new(RemoteProgressState::Transfer, objects, total_objects),
121 _ => Self::new(RemoteProgressState::Done, 1, 1),
122 }
123 }
124}