diff options
| author | Teddy Wing | 2018-10-23 06:56:08 +0200 | 
|---|---|---|
| committer | Teddy Wing | 2018-10-23 06:56:08 +0200 | 
| commit | adc4a2f7a84967541d9da3c2f8edb2814a59ab59 (patch) | |
| tree | 3c8a1afccbae5b2ea993912745733b5e7cf80f4a | |
| parent | aaca041a3eb0938ca00314aeb0ca1799d3804ba5 (diff) | |
| download | dome-key-map-adc4a2f7a84967541d9da3c2f8edb2814a59ab59.tar.bz2 | |
trial: Implement `do_trial()`
This function serves as the entry point to all trial functionality. When
called, it will try to determine the number of days remaining in the
trial.
* If the trial period is in progress, the number of days remaining will
  be printed.
* If an error is encountered involving the trial file, or the trial has
  expired, an error message is printed and the program exits.
* Finally, if an unrelated error occurs, print the error without
  exiting.
Change `DateTime<Local>`s to `DateTime<FixedOffset>`s in order to have
uniform date types. Otherwise we run into trouble when comparing dates
and when querying functions with different date typs.
TODO: This fails the tests (unless your local timezone is UTC
presumably) because the local time gets stripped of its offset and the
correct offset gets reapplied, incorrectly shifting the time. Figure out
a way to have uniform datetime types without muffing up the timezone
offsets.
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/lib.rs | 1 | ||||
| -rw-r--r-- | src/trial.rs | 107 | 
3 files changed, 90 insertions, 19 deletions
@@ -9,6 +9,7 @@ cocoa = "0.18.0"  combine = "3.4.0"  core-graphics = "0.17.2"  error-chain = "0.12.0" +exitcode = "1.1.2"  foreign-types = "0.3.2"  getopts = "0.2.18"  libc = "0.2.43" @@ -10,6 +10,7 @@ extern crate core_graphics;  #[macro_use]  extern crate error_chain; +extern crate exitcode;  extern crate foreign_types;  extern crate getopts;  extern crate libc; diff --git a/src/trial.rs b/src/trial.rs index c37cd1f..5e398fe 100644 --- a/src/trial.rs +++ b/src/trial.rs @@ -3,6 +3,7 @@ use std::io::{self, Read, Write};  use std::result;  use chrono::{DateTime, FixedOffset, Local, TimeZone}; +use exitcode;  use magic_crypt::{self, MagicCrypt};  use xdg; @@ -17,10 +18,47 @@ const KEY: &'static str = "TODO SECRET";  /// Entry point to the trial handler.  fn do_trial() { +    // Try to read trial start from file +    let date = match get_trial_start() { +        Ok(date) => date, +        Err(e) => { +            match e.kind() { +                ErrorKind::Io(e) if e.kind() == io::ErrorKind::NotFound => +                    match initialize_trial_start() { +                        Ok(date) => date, +                        Err(e) => { +                            eprintln!("{}", e); +                            ::std::process::exit(exitcode::IOERR); +                        }, +                    }, +                DurationError => return trial_expired(), +                e => { +                    eprintln!("{}", e); +                    ::std::process::exit(exitcode::SOFTWARE); +                }, +            } +        } +    }; +    // If the file doesn't exist, create it +    // Print the number of days remaining +    // If no more days remain, exit the program with error EX_NOPERM + +    match days_remaining_from_now(date) { +        Ok(remaining) => print_trial_days(remaining), +        DurationError => trial_expired(), +        Err(e) => (), +    } +} + +fn trial_expired() { +    println!("Your trial has expired"); + +    ::std::process::exit(exitcode::NOPERM)  } -fn initialize_trial_start() -> Result<()> { -    let encoded_time = encode_datetime(Local::now()); +fn initialize_trial_start() -> Result<DateTime<FixedOffset>> { +    let now = datetime_local_to_fixed_offset(Local::now()); +    let encoded_time = encode_datetime(now);      let xdg_dirs = xdg::BaseDirectories::with_prefix("dome-key")          .chain_err(|| "failed to get XDG base directories")?; @@ -32,7 +70,7 @@ fn initialize_trial_start() -> Result<()> {          .open(trial_path)      {          Ok(f) => Ok(f), -        Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(()), +        Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(now),          Err(e) => Err(e),      }          .chain_err(|| "failed to create trial file")?; @@ -40,7 +78,12 @@ fn initialize_trial_start() -> Result<()> {      write!(&mut trial_file, "{}", encoded_time)          .chain_err(|| "failed to write to trial file")?; -    Ok(()) +    Ok(now) +} + +fn datetime_local_to_fixed_offset(d: DateTime<Local>) -> DateTime<FixedOffset> { +    let offset = FixedOffset::from_offset(d.offset()); +    DateTime::<FixedOffset>::from_utc(d.naive_local(), offset)  }  /// Decrypts the time string from the trial file and returns it as a @@ -60,11 +103,13 @@ fn get_trial_start() -> Result<DateTime<FixedOffset>> {  }  fn print_trial_days(days: u8) { +    // TODO: Come up with a label +    println!("{}", days);  }  fn days_remaining( -    start: DateTime<Local>, -    now: DateTime<Local>, +    start: DateTime<FixedOffset>, +    now: DateTime<FixedOffset>,      days_available: u8,  ) -> result::Result<u8, DurationError> {      let duration = (now.date() - start.date()).num_days() as u8; @@ -79,12 +124,16 @@ fn days_remaining(  }  fn days_remaining_from_now( -    start: DateTime<Local> +    start: DateTime<FixedOffset>  ) -> result::Result<u8, DurationError> { -    days_remaining(start, Local::now(), DAYS_REMAINING) +    days_remaining( +        start, +        datetime_local_to_fixed_offset(Local::now()), +        DAYS_REMAINING +    )  } -fn encode_datetime(d: DateTime<Local>) -> String { +fn encode_datetime(d: DateTime<FixedOffset>) -> String {      let iv = initialization_vector();      let mut mc = MagicCrypt::new(KEY, magic_crypt::SecureBit::Bit64, Some(&iv)); @@ -128,8 +177,12 @@ mod tests {      #[test]      fn days_remaining_counts_days_remaining_from_start_date() {          let remaining = days_remaining( -            Local.ymd(2018, 10, 1).and_hms(23, 1, 0), -            Local.ymd(2018, 10, 1).and_hms(23, 30, 0), +            datetime_local_to_fixed_offset( +                Local.ymd(2018, 10, 1).and_hms(23, 1, 0) +            ), +            datetime_local_to_fixed_offset( +                Local.ymd(2018, 10, 1).and_hms(23, 30, 0) +            ),              30,          ); @@ -139,8 +192,12 @@ mod tests {      #[test]      fn days_remaining_with_middle_date() {          let remaining = days_remaining( -            Local.ymd(2018, 10, 1).and_hms(23, 1, 0), -            Local.ymd(2018, 10, 22).and_hms(15, 0, 0), +            datetime_local_to_fixed_offset( +                Local.ymd(2018, 10, 1).and_hms(23, 1, 0) +            ), +            datetime_local_to_fixed_offset( +                Local.ymd(2018, 10, 22).and_hms(15, 0, 0) +            ),              30,          ); @@ -150,8 +207,12 @@ mod tests {      #[test]      fn days_remaining_on_last_day_is_0() {          let remaining = days_remaining( -            Local.ymd(2018, 10, 1).and_hms(23, 1, 0), -            Local.ymd(2018, 10, 31).and_hms(23, 30, 0), +            datetime_local_to_fixed_offset( +                Local.ymd(2018, 10, 1).and_hms(23, 1, 0) +            ), +            datetime_local_to_fixed_offset( +                Local.ymd(2018, 10, 31).and_hms(23, 30, 0) +            ),              30,          ); @@ -161,8 +222,12 @@ mod tests {      #[test]      fn days_remaining_on_day_following_last_day_is_negative_duration_error() {          let remaining = days_remaining( -            Local.ymd(2018, 10, 1).and_hms(23, 1, 0), -            Local.ymd(2018, 11, 1).and_hms(0, 0, 0), +            datetime_local_to_fixed_offset( +                Local.ymd(2018, 10, 1).and_hms(23, 1, 0) +            ), +            datetime_local_to_fixed_offset( +                Local.ymd(2018, 11, 1).and_hms(0, 0, 0) +            ),              30,          ); @@ -172,8 +237,12 @@ mod tests {      #[test]      fn days_remaining_after_last_day_is_negative_duration_error() {          let remaining = days_remaining( -            Local.ymd(2018, 10, 1).and_hms(23, 1, 0), -            Local.ymd(2018, 11, 5).and_hms(0, 0, 0), +            datetime_local_to_fixed_offset( +                Local.ymd(2018, 10, 1).and_hms(23, 1, 0) +            ), +            datetime_local_to_fixed_offset( +                Local.ymd(2018, 11, 5).and_hms(0, 0, 0) +            ),              30,          );  | 
