86 lines
2.2 KiB
Rust
86 lines
2.2 KiB
Rust
use tokio::io::{self, AsyncReadExt};
|
|
|
|
use bytes::BytesMut;
|
|
use chrono::{DateTime, Datelike, Timelike};
|
|
use reqwest;
|
|
use serde::{Deserialize, Serialize};
|
|
use tokio::time::error::Error;
|
|
use tokio::time::{sleep, Duration};
|
|
use webbrowser::open_browser;
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
struct Appointment {
|
|
locationId: u32,
|
|
startTimestamp: String,
|
|
endTimestamp: String,
|
|
active: bool,
|
|
duration: u32,
|
|
remoteInd: bool,
|
|
}
|
|
|
|
const TIME: u64 = 3000;
|
|
const CHARLOTTE: u32 = 14321;
|
|
// const TESTING: u32 = 5023;
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
let mut location_id: u32 = CHARLOTTE;
|
|
let mut buf = [0, 0, 0, 0];
|
|
|
|
println!(
|
|
"Enter a location id to override the default (Charlotte, NC, {:?}): ",
|
|
CHARLOTTE
|
|
);
|
|
io::stdin().read(&mut buf).await.unwrap();
|
|
|
|
let loc = String::from_utf8(buf.to_vec()).unwrap().trim().parse();
|
|
if loc.is_ok() {
|
|
location_id = loc.unwrap();
|
|
}
|
|
|
|
println!("Looking for appointments at location id: {}", location_id);
|
|
loop {
|
|
look_for_appointments(location_id).await;
|
|
println!(
|
|
"No appointments found, trying again in {} seconds",
|
|
TIME / 1000
|
|
);
|
|
sleep(Duration::from_millis(TIME)).await;
|
|
}
|
|
}
|
|
|
|
async fn look_for_appointments(location_id: u32) {
|
|
let data = get_data(location_id).await.unwrap();
|
|
|
|
for appointment in data {
|
|
let time = appointment.startTimestamp + ":00-05:00";
|
|
let at = DateTime::parse_from_rfc3339(&time).unwrap();
|
|
|
|
println!(
|
|
"Appointment found on {}/{}/{} at {}:{}",
|
|
at.day(),
|
|
at.month(),
|
|
at.year(),
|
|
at.hour(),
|
|
at.minute(),
|
|
);
|
|
open_browser(webbrowser::Browser::Default, "https://ttp.cbp.dhs.gov/credential/v1/login?app=GOES-prod&lang=en&state=en:IonIgXB4I9qt02S6cgKydMVA9HXHC1vq").unwrap();
|
|
|
|
println!("Press any key to continue...");
|
|
io::stdin()
|
|
.read_buf(&mut BytesMut::with_capacity(10))
|
|
.await
|
|
.unwrap();
|
|
}
|
|
}
|
|
|
|
async fn get_data(location_id: u32) -> Result<Vec<Appointment>, Error> {
|
|
let res = reqwest::get(format!(
|
|
"https://ttp.cbp.dhs.gov/schedulerapi/slots?orderBy=soonest&limit=3&locationId={}&minimum=1",
|
|
location_id
|
|
))
|
|
.await;
|
|
let body: Vec<Appointment> = res.unwrap().json().await.unwrap();
|
|
Ok(body)
|
|
}
|