]> git.ipfire.org Git - pakfire.git/blob - src/libpakfire/progress.c
progress: Implement setting the title as a separate call
[pakfire.git] / src / libpakfire / progress.c
1 /*#############################################################################
2 # #
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2023 Pakfire development team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <time.h>
24
25 #include <pakfire/pakfire.h>
26 #include <pakfire/private.h>
27 #include <pakfire/progress.h>
28
29 struct pakfire_progress {
30 struct pakfire* pakfire;
31 int nrefs;
32
33 // Title
34 char* title;
35
36 // Flags what to show
37 int flags;
38
39 // Status
40 enum pakfire_progress_status {
41 PAKFIRE_PROGRESS_INIT = 0,
42 PAKFIRE_PROGRESS_RUNNING,
43 PAKFIRE_PROGRESS_FINISHED,
44 } status;
45
46 // Callbacks
47 struct pakfire_progress_callbacks {
48 void* data;
49
50 pakfire_progress_start_callback start;
51 pakfire_progress_finish_callback finish;
52 pakfire_progress_update_callback update;
53 pakfire_progress_free_callback free;
54 } callbacks;
55
56 // Start Time
57 struct timespec time_start;
58 struct timespec time_finished;
59
60 // Values
61 unsigned long int value;
62 unsigned long int max_value;
63 };
64
65 static void pakfire_progress_free(struct pakfire_progress* p) {
66 // Ensure this is finished
67 pakfire_progress_finish(p);
68
69 // Call the free callback
70 if (p->callbacks.free)
71 p->callbacks.free(p->pakfire, p, p->callbacks.data);
72
73 if (p->title)
74 free(p->title);
75 pakfire_unref(p->pakfire);
76 free(p);
77 }
78
79 int pakfire_progress_create(struct pakfire_progress** progress,
80 struct pakfire* pakfire, int flags) {
81 struct pakfire_progress* p = NULL;
82 int r;
83
84 // Allocate a new object
85 p = calloc(1, sizeof(*p));
86 if (!p)
87 return -errno;
88
89 // Store a reference to Pakfire
90 p->pakfire = pakfire_ref(pakfire);
91
92 // Initialize the reference counter
93 p->nrefs = 1;
94
95 // Store the flags
96 p->flags = flags;
97
98 // Initialize status
99 p->status = PAKFIRE_PROGRESS_INIT;
100
101 // XXX Create a couple of default callbacks
102
103 // Call setup
104 if (!pakfire_progress_has_flag(p, PAKFIRE_PROGRESS_NO_PROGRESS)) {
105 r = pakfire_setup_progress(pakfire, p);
106 if (r)
107 goto ERROR;
108 }
109
110 // Success
111 *progress = p;
112 return 0;
113
114 ERROR:
115 if (p)
116 pakfire_progress_unref(p);
117
118 return r;
119 }
120
121 struct pakfire_progress* pakfire_progress_ref(struct pakfire_progress* p) {
122 ++p->nrefs;
123
124 return p;
125 }
126
127 struct pakfire_progress* pakfire_progress_unref(struct pakfire_progress* p) {
128 if (--p->nrefs > 0)
129 return p;
130
131 pakfire_progress_free(p);
132 return NULL;
133 }
134
135 PAKFIRE_EXPORT int pakfire_progress_has_flag(struct pakfire_progress* p, int flag) {
136 return p->flags & flag;
137 }
138
139 /*
140 Callback Configuration
141 */
142
143 PAKFIRE_EXPORT void pakfire_progress_set_callback_data(struct pakfire_progress* p, void* data) {
144 p->callbacks.data = data;
145 }
146
147 PAKFIRE_EXPORT void pakfire_progress_set_start_callback(
148 struct pakfire_progress* p, pakfire_progress_start_callback callback) {
149 p->callbacks.start = callback;
150 }
151
152 PAKFIRE_EXPORT void pakfire_progress_set_finish_callback(
153 struct pakfire_progress* p, pakfire_progress_finish_callback callback) {
154 p->callbacks.finish = callback;
155 }
156
157 PAKFIRE_EXPORT void pakfire_progress_set_update_callback(
158 struct pakfire_progress* p, pakfire_progress_update_callback callback) {
159 p->callbacks.update = callback;
160 }
161
162 PAKFIRE_EXPORT void pakfire_progress_set_free_callback(
163 struct pakfire_progress* p, pakfire_progress_free_callback callback) {
164 p->callbacks.free = callback;
165 }
166
167 int pakfire_progress_start(struct pakfire_progress* p, unsigned long int value) {
168 int r;
169
170 // This can only be called once
171 if (p->status == PAKFIRE_PROGRESS_RUNNING)
172 return -EINVAL;
173
174 // We are now running...
175 p->status = PAKFIRE_PROGRESS_RUNNING;
176
177 // Store the max value
178 p->max_value = value;
179
180 // Set start time
181 r = clock_gettime(CLOCK_REALTIME, &p->time_start);
182 if (r)
183 return r;
184
185 // No-op
186 if (pakfire_progress_has_flag(p, PAKFIRE_PROGRESS_NO_PROGRESS))
187 return 0;
188
189 // Call the start callback
190 if (p->callbacks.start) {
191 r = p->callbacks.start(p->pakfire, p, p->callbacks.data, value);
192 if (r)
193 return r;
194 }
195
196 // Call the first update
197 return pakfire_progress_update(p, 0);
198 }
199
200 int pakfire_progress_finish(struct pakfire_progress* p) {
201 int r;
202
203 // Do nothing if already finished
204 if (p->status == PAKFIRE_PROGRESS_FINISHED)
205 return 0;
206
207 // No-op
208 if (pakfire_progress_has_flag(p, PAKFIRE_PROGRESS_NO_PROGRESS))
209 return 0;
210
211 // Set finished time
212 r = clock_gettime(CLOCK_REALTIME, &p->time_finished);
213 if (r)
214 return r;
215
216 // Call the finish callback
217 if (p->callbacks.finish) {
218 r = p->callbacks.finish(p->pakfire, p, p->callbacks.data);
219 if (r)
220 return r;
221 }
222
223 return 0;
224 }
225
226 int pakfire_progress_update(struct pakfire_progress* p, unsigned long int value) {
227 int r;
228
229 // Store the new value
230 p->value = value;
231
232 // No-op
233 if (pakfire_progress_has_flag(p, PAKFIRE_PROGRESS_NO_PROGRESS))
234 return 0;
235
236 // Call the update callback
237 if (p->callbacks.update) {
238 r = p->callbacks.update(p->pakfire, p, p->callbacks.data, value);
239 if (r)
240 return r;
241 }
242
243 return r;
244 }
245
246 PAKFIRE_EXPORT unsigned long int pakfire_progress_get_value(struct pakfire_progress* p) {
247 return p->value;
248 }
249
250 PAKFIRE_EXPORT unsigned long int pakfire_progress_get_max_value(struct pakfire_progress* p) {
251 return p->max_value;
252 }
253
254 PAKFIRE_EXPORT const char* pakfire_progress_get_title(struct pakfire_progress* p) {
255 return p->title;
256 }
257
258 int pakfire_progress_set_title(struct pakfire_progress* p, const char* format, ...) {
259 va_list args;
260 int r;
261
262 // Format the title
263 va_start(args, format);
264 r = vasprintf(&p->title, format, args);
265 va_end(args);
266
267 // Fail
268 if (r < 0)
269 return r;
270
271 return 0;
272 }
273
274 PAKFIRE_EXPORT double pakfire_progress_get_percentage(struct pakfire_progress* p) {
275 if (!p->max_value)
276 return 0;
277
278 return p->value * 100.0 / p->max_value;
279 }
280
281 PAKFIRE_EXPORT time_t pakfire_progress_get_elapsed_time(struct pakfire_progress* p) {
282 struct timespec now;
283 int r;
284
285 switch (p->status) {
286 case PAKFIRE_PROGRESS_INIT:
287 return 0;
288
289 case PAKFIRE_PROGRESS_RUNNING:
290 r = clock_gettime(CLOCK_REALTIME, &now);
291 if (r)
292 return -1;
293
294 return now.tv_sec - p->time_start.tv_sec;
295
296 case PAKFIRE_PROGRESS_FINISHED:
297 return p->time_finished.tv_sec - p->time_start.tv_sec;
298 }
299
300 return -1;
301 }
302
303 PAKFIRE_EXPORT time_t pakfire_progress_get_eta(struct pakfire_progress* p) {
304 const time_t t = pakfire_progress_get_elapsed_time(p);
305 if (t < 0)
306 return t;
307
308 return t * p->max_value / p->value - t;
309 }
310
311 PAKFIRE_EXPORT double pakfire_progress_get_transfer_speed(struct pakfire_progress* p) {
312 const time_t t = pakfire_progress_get_elapsed_time(p);
313 if (t <= 0)
314 return t;
315
316 return p->value / t;
317 }