-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add compile time EOP data fetch and refactor
EOPData
and `EOPManage…
…r` (#4)
- Loading branch information
1 parent
a1bf2d4
commit 8699264
Showing
7 changed files
with
272 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
use reqwest::blocking::Client; | ||
use std::env; | ||
use std::error::Error; | ||
use std::fs::{self, File}; | ||
use std::io::Write; | ||
use std::path::PathBuf; | ||
use std::time::{Duration, SystemTime}; | ||
|
||
const CELESTRAK_URL: &str = "https://celestrak.org/SpaceData/EOP-All.csv"; | ||
const CACHE_FILE: &str = "eop_cache.csv"; | ||
const CACHE_EXPIRATION_HOURS: u64 = 6; // CelesTrak updates every 6 hours | ||
|
||
fn main() { | ||
// Get Cargo's OUT_DIR (temporary build directory) | ||
let out_dir = env::var("OUT_DIR").expect("Cargo should set OUT_DIR"); | ||
let cache_path = PathBuf::from(out_dir).join(CACHE_FILE); | ||
|
||
// Download and store the EOP data | ||
match fetch_eop_data(&cache_path) { | ||
Ok(_) => println!("EOP data fetched successfully!"), | ||
Err(e) => panic!("Failed to fetch EOP data: {}", e), | ||
} | ||
} | ||
|
||
fn fetch_eop_data(cache_path: &PathBuf) -> Result<(), Box<dyn Error>> { | ||
// Check last modified time of cache | ||
if let Ok(metadata) = fs::metadata(cache_path) { | ||
if let Ok(modified) = metadata.modified() { | ||
let now = SystemTime::now(); | ||
let age = now.duration_since(modified).unwrap_or(Duration::ZERO); | ||
|
||
// Skip download if the cache is still fresh | ||
if age < Duration::from_secs(CACHE_EXPIRATION_HOURS * 3600) { | ||
eprintln!( | ||
"Skipping download: Cached EOP data is still fresh ({} minutes old).", | ||
age.as_secs() / 60 | ||
); | ||
return Ok(()); | ||
} | ||
} | ||
} | ||
|
||
eprintln!("Fetching new EOP data from: {}", CELESTRAK_URL); | ||
|
||
let client = Client::new(); | ||
let response = client.get(CELESTRAK_URL).send()?; | ||
let status = response.status(); | ||
|
||
if !status.is_success() { | ||
let response_body = response | ||
.text() | ||
.unwrap_or_else(|_| "Failed to read response body".to_string()); | ||
return Err(format!( | ||
"HTTP request failed: {} - Response: {}", | ||
status, response_body | ||
) | ||
.into()); | ||
} | ||
|
||
let bytes = response.bytes()?; | ||
eprintln!("Downloaded {} bytes of EOP data.", bytes.len()); | ||
|
||
let mut file = File::create(cache_path)?; | ||
file.write_all(&bytes)?; | ||
|
||
eprintln!("EOP data successfully written to {:?}", cache_path); | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
use reqwest; | ||
use std::{error::Error, fmt, io, num::ParseFloatError}; | ||
|
||
#[derive(Debug)] | ||
pub enum EOPErrors { | ||
IoError(std::io::Error), | ||
ReqwestError(reqwest::Error), | ||
CsvError(csv::Error), | ||
ParseFloatError(ParseFloatError), | ||
InvalidEpoch(hifitime::errors::Errors), | ||
MissingEOPData, | ||
DataInterpolationError, | ||
HttpForbidden, | ||
} | ||
|
||
impl fmt::Display for EOPErrors { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
match self { | ||
EOPErrors::IoError(e) => write!(f, "I/O error: {}", e), | ||
EOPErrors::ReqwestError(e) => write!(f, "Request error: {}", e), | ||
EOPErrors::CsvError(e) => write!(f, "CSV parsing error: {}", e), | ||
EOPErrors::ParseFloatError(e) => write!(f, "Float parsing error: {}", e), | ||
EOPErrors::InvalidEpoch(e) => write!(f, "Invalid epoch {}", e), | ||
EOPErrors::MissingEOPData => write!(f, "EOP data is missing"), | ||
EOPErrors::DataInterpolationError => write!(f, "Failed to interpolate EOP data"), | ||
EOPErrors::HttpForbidden => write!(f, "HTTP 403 Forbidden"), | ||
} | ||
} | ||
} | ||
|
||
impl Error for EOPErrors {} | ||
|
||
// Implement `From<T>` conversions for automatic error mapping | ||
impl From<io::Error> for EOPErrors { | ||
fn from(err: io::Error) -> Self { | ||
EOPErrors::IoError(err) | ||
} | ||
} | ||
|
||
impl From<reqwest::Error> for EOPErrors { | ||
fn from(err: reqwest::Error) -> Self { | ||
EOPErrors::ReqwestError(err) | ||
} | ||
} | ||
|
||
impl From<csv::Error> for EOPErrors { | ||
fn from(err: csv::Error) -> Self { | ||
EOPErrors::CsvError(err) | ||
} | ||
} | ||
|
||
impl From<ParseFloatError> for EOPErrors { | ||
fn from(err: ParseFloatError) -> Self { | ||
EOPErrors::ParseFloatError(err) | ||
} | ||
} |
Oops, something went wrong.