Skip to content

Commit 0b8f045

Browse files
committed
Update time.rs
1 parent 89f27a7 commit 0b8f045

File tree

1 file changed

+61
-19
lines changed
  • src/append/rolling_file/policy/compound/trigger

1 file changed

+61
-19
lines changed

src/append/rolling_file/policy/compound/trigger/time.rs

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
//!
33
//! Requires the `time_trigger` feature.
44
5-
#[cfg(test)]
6-
use chrono::NaiveDateTime;
75
use chrono::{DateTime, Datelike, Duration, Local, TimeZone, Timelike};
86
#[cfg(test)]
97
use mock_instant::{SystemTime, UNIX_EPOCH};
@@ -13,6 +11,7 @@ use serde::de;
1311
#[cfg(feature = "config_parsing")]
1412
use std::fmt;
1513
use std::sync::{Once, RwLock};
14+
use thiserror::Error;
1615

1716
use crate::append::rolling_file::{policy::compound::trigger::Trigger, LogFile};
1817
#[cfg(feature = "config_parsing")]
@@ -73,6 +72,12 @@ impl Default for TimeTriggerInterval {
7372
}
7473
}
7574

75+
#[derive(Debug, Error)]
76+
enum TimeTrigerError {
77+
#[error("too large interval in time trigger {0:?}")]
78+
TooLargeInterval(TimeTriggerInterval),
79+
}
80+
7681
#[cfg(feature = "config_parsing")]
7782
impl<'de> serde::Deserialize<'de> for TimeTriggerInterval {
7883
fn deserialize<D>(d: D) -> Result<Self, D::Error>
@@ -193,13 +198,14 @@ impl TimeTrigger {
193198
current: DateTime<Local>,
194199
interval: TimeTriggerInterval,
195200
modulate: bool,
196-
) -> DateTime<Local> {
201+
) -> anyhow::Result<DateTime<Local>> {
197202
let year = current.year();
198203
if let TimeTriggerInterval::Year(n) = interval {
199204
let n = n as i32;
200205
let increment = if modulate { n - year % n } else { n };
201206
let year_new = year + increment;
202-
return Local.with_ymd_and_hms(year_new, 1, 1, 0, 0, 0).unwrap();
207+
let result = Local.with_ymd_and_hms(year_new, 1, 1, 0, 0, 0).unwrap();
208+
return Ok(result);
203209
}
204210

205211
if let TimeTriggerInterval::Month(n) = interval {
@@ -210,9 +216,10 @@ impl TimeTrigger {
210216
let num_months_new = num_months + increment;
211217
let year_new = (num_months_new / 12) as i32;
212218
let month_new = (num_months_new) % 12 + 1;
213-
return Local
219+
let result = Local
214220
.with_ymd_and_hms(year_new, month_new, 1, 0, 0, 0)
215221
.unwrap();
222+
return Ok(result);
216223
}
217224

218225
let month = current.month();
@@ -222,14 +229,21 @@ impl TimeTrigger {
222229
let weekday = current.weekday().num_days_from_monday() as i64; // Monday is the first day of the week
223230
let time = Local.with_ymd_and_hms(year, month, day, 0, 0, 0).unwrap();
224231
let increment = if modulate { n - week0 % n } else { n };
225-
return time + Duration::weeks(increment) - Duration::days(weekday);
232+
let result = time
233+
+ Duration::try_weeks(increment)
234+
.ok_or(TimeTrigerError::TooLargeInterval(interval))?
235+
- Duration::try_days(weekday).unwrap();
236+
return Ok(result);
226237
}
227238

228239
if let TimeTriggerInterval::Day(n) = interval {
229240
let ordinal0 = current.ordinal0() as i64;
230241
let time = Local.with_ymd_and_hms(year, month, day, 0, 0, 0).unwrap();
231242
let increment = if modulate { n - ordinal0 % n } else { n };
232-
return time + Duration::days(increment);
243+
let result = time
244+
+ Duration::try_days(increment)
245+
.ok_or(TimeTrigerError::TooLargeInterval(interval))?;
246+
return Ok(result);
233247
}
234248

235249
let hour = current.hour();
@@ -238,7 +252,10 @@ impl TimeTrigger {
238252
.with_ymd_and_hms(year, month, day, hour, 0, 0)
239253
.unwrap();
240254
let increment = if modulate { n - (hour as i64) % n } else { n };
241-
return time + Duration::hours(increment);
255+
let result = time
256+
+ Duration::try_hours(increment)
257+
.ok_or(TimeTrigerError::TooLargeInterval(interval))?;
258+
return Ok(result);
242259
}
243260

244261
let min = current.minute();
@@ -247,7 +264,10 @@ impl TimeTrigger {
247264
.with_ymd_and_hms(year, month, day, hour, min, 0)
248265
.unwrap();
249266
let increment = if modulate { n - (min as i64) % n } else { n };
250-
return time + Duration::minutes(increment);
267+
let result = time
268+
+ Duration::try_minutes(increment)
269+
.ok_or(TimeTrigerError::TooLargeInterval(interval))?;
270+
return Ok(result);
251271
}
252272

253273
let sec = current.second();
@@ -256,48 +276,56 @@ impl TimeTrigger {
256276
.with_ymd_and_hms(year, month, day, hour, min, sec)
257277
.unwrap();
258278
let increment = if modulate { n - (sec as i64) % n } else { n };
259-
return time + Duration::seconds(increment);
279+
let result = time
280+
+ Duration::try_seconds(increment)
281+
.ok_or(TimeTrigerError::TooLargeInterval(interval))?;
282+
return Ok(result);
260283
}
261284
panic!("Should not reach here!");
262285
}
263286

264-
fn refresh_time(&self) {
287+
fn refresh_time(&self) -> anyhow::Result<()> {
265288
#[cfg(test)]
266289
let current = {
267290
let now: std::time::Duration = SystemTime::now()
268291
.duration_since(UNIX_EPOCH)
269292
.expect("system time before Unix epoch");
270-
NaiveDateTime::from_timestamp_opt(now.as_secs() as i64, now.subsec_nanos())
293+
DateTime::from_timestamp(now.as_secs() as i64, now.subsec_nanos())
271294
.unwrap()
295+
.naive_local()
272296
.and_local_timezone(Local)
273297
.unwrap()
274298
};
275299

276300
#[cfg(not(test))]
277301
let current = Local::now();
278-
let next_time = TimeTrigger::get_next_time(current, self.interval, self.modulate);
302+
let next_time = TimeTrigger::get_next_time(current, self.interval, self.modulate)?;
279303
let next_roll_time = if self.max_random_delay > 0 {
280304
let random_delay = rand::thread_rng().gen_range(0..self.max_random_delay);
281-
next_time + Duration::seconds(random_delay as i64)
305+
next_time
306+
+ Duration::try_seconds(random_delay as i64)
307+
.unwrap_or(Duration::try_milliseconds(i64::MAX).unwrap())
282308
} else {
283309
next_time
284310
};
285311
*self.next_roll_time.write().unwrap() = next_roll_time;
312+
Ok(())
286313
}
287314
}
288315

289316
impl Trigger for TimeTrigger {
290317
fn trigger(&self, _file: &LogFile) -> anyhow::Result<bool> {
291-
self.initial.call_once(|| {
292-
self.refresh_time();
293-
});
318+
let mut result = anyhow::Result::Ok(());
319+
self.initial.call_once(|| result = self.refresh_time());
320+
result?;
294321
#[cfg(test)]
295322
let current = {
296323
let now = SystemTime::now()
297324
.duration_since(UNIX_EPOCH)
298325
.expect("system time before Unix epoch");
299-
NaiveDateTime::from_timestamp_opt(now.as_secs() as i64, now.subsec_nanos())
326+
DateTime::from_timestamp(now.as_secs() as i64, now.subsec_nanos())
300327
.unwrap()
328+
.naive_local()
301329
.and_local_timezone(Local)
302330
.unwrap()
303331
};
@@ -308,7 +336,7 @@ impl Trigger for TimeTrigger {
308336
let is_trigger = current >= *next_roll_time;
309337
drop(next_roll_time);
310338
if is_trigger {
311-
self.refresh_time();
339+
self.refresh_time()?;
312340
}
313341
Ok(is_trigger)
314342
}
@@ -494,6 +522,20 @@ mod test {
494522
assert_eq!(interval, TimeTriggerInterval::Second(1));
495523
}
496524

525+
#[test]
526+
fn trigger_large_interval() {
527+
let interval = TimeTriggerInterval::Second(i64::MAX);
528+
let file = tempfile::tempdir().unwrap();
529+
let logfile = LogFile {
530+
writer: &mut None,
531+
path: file.path(),
532+
len: 0,
533+
};
534+
535+
let trigger = TimeTrigger::new(interval, false, 0);
536+
trigger.trigger(&logfile).unwrap_err();
537+
}
538+
497539
#[test]
498540
fn pre_process() {
499541
let trigger = TimeTrigger::new(TimeTriggerInterval::Minute(2), true, 0);

0 commit comments

Comments
 (0)