1 /* Downloads progression stuff. */
9 #include "network/progress.h"
10 #include "util/error.h"
11 #include "util/memory.h"
12 #include "util/time.h"
14 #define SPD_DISP_TIME ((milliseconds_T) 100)
15 #define CURRENT_SPD_AFTER ((milliseconds_T) 100)
19 has_progress(struct progress
*progress
)
21 timeval_T current_speed_after
;
23 timeval_from_milliseconds(¤t_speed_after
, CURRENT_SPD_AFTER
);
25 return (timeval_cmp(&progress
->elapsed
, ¤t_speed_after
) >= 0);
29 init_progress(off_t start
)
31 struct progress
*progress
= mem_calloc(1, sizeof(*progress
));
34 progress
->start
= start
;
35 progress
->timer
= TIMER_ID_UNDEF
;
42 done_progress(struct progress
*progress
)
44 assert(progress
->timer
== TIMER_ID_UNDEF
);
48 /* Called from the timer callback of @progress->timer. This function
49 * erases the expired timer ID on behalf of the actual callback. */
51 update_progress(struct progress
*progress
, off_t loaded
, off_t size
, off_t pos
)
54 timeval_T now
, elapsed
, dis_b_max
, dis_b_interval
;
57 timeval_sub(&elapsed
, &progress
->last_time
, &now
);
58 timeval_copy(&progress
->last_time
, &now
);
60 progress
->loaded
= loaded
;
61 bytes_delta
= progress
->loaded
- progress
->last_loaded
;
62 progress
->last_loaded
= progress
->loaded
;
64 timeval_add_interval(&progress
->elapsed
, &elapsed
);
66 timeval_add_interval(&progress
->dis_b
, &elapsed
);
67 timeval_from_milliseconds(&dis_b_max
, mult_ms(SPD_DISP_TIME
, CURRENT_SPD_SEC
));
68 timeval_from_milliseconds(&dis_b_interval
, SPD_DISP_TIME
);
70 while (timeval_cmp(&progress
->dis_b
, &dis_b_max
) >= 0) {
71 progress
->cur_loaded
-= progress
->data_in_secs
[0];
72 memmove(progress
->data_in_secs
, progress
->data_in_secs
+ 1,
73 sizeof(*progress
->data_in_secs
) * (CURRENT_SPD_SEC
- 1));
74 progress
->data_in_secs
[CURRENT_SPD_SEC
- 1] = 0;
75 timeval_sub_interval(&progress
->dis_b
, &dis_b_interval
);
77 progress
->data_in_secs
[CURRENT_SPD_SEC
- 1] += bytes_delta
;
78 progress
->cur_loaded
+= bytes_delta
;
80 progress
->current_speed
= progress
->cur_loaded
/ (CURRENT_SPD_SEC
* ((long) SPD_DISP_TIME
) / 1000);
83 progress
->size
= size
;
84 if (progress
->size
!= -1 && progress
->size
< progress
->pos
)
85 progress
->size
= progress
->pos
;
87 progress
->average_speed
= timeval_div_off_t(progress
->loaded
, &progress
->elapsed
);
88 if (progress
->average_speed
) /* Division by zero risk */
89 timeval_from_seconds(&progress
->estimated_time
,
90 (progress
->size
- progress
->pos
) / progress
->average_speed
);
92 install_timer(&progress
->timer
, SPD_DISP_TIME
, progress
->timer_func
, progress
->timer_func_data
);
93 /* The expired timer ID has now been erased. */
96 /* As in @install_timer, @timer_func should erase the expired timer ID
97 * from @progress->timer. The usual way to ensure this is to make
98 * @timer_func call @update_progress, which sets a new timer. */
100 start_update_progress(struct progress
*progress
, void (*timer_func
)(void *),
101 void *timer_func_data
)
103 if (!progress
->valid
) {
106 /* Just copy useful fields from invalid progress. */
107 memset(&tmp
, 0, sizeof(tmp
));
108 tmp
.start
= progress
->start
;
109 tmp
.seek
= progress
->seek
;
112 memcpy(progress
, &tmp
, sizeof(*progress
));
114 timeval_now(&progress
->last_time
);
115 progress
->last_loaded
= progress
->loaded
;
116 progress
->timer_func
= timer_func
;
117 progress
->timer_func_data
= timer_func_data
;