Initial commit in new repo with new history.
This commit is contained in:
73
src/main.rs
Normal file
73
src/main.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
#![cfg_attr(debug_assertions, allow(dead_code, unused_imports))]
|
||||
mod weather;
|
||||
mod redsox;
|
||||
use tabled::Table;
|
||||
use tabled::settings::{
|
||||
peaker::Priority, Width, Style, Alignment, object::Columns
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tabled::Tabled;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Tabled)]
|
||||
#[tabled(rename_all = "UPPERCASE")]
|
||||
struct TableRow {
|
||||
date: String,
|
||||
time_of_day: String,
|
||||
temp: u64,
|
||||
red_sox: String,
|
||||
forecast: String,
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
fn main() {
|
||||
let baseball_diamond = '\u{f15ec}';
|
||||
let sunny = '\u{f0599}';
|
||||
// Set the weather location here.
|
||||
let location = weather::WeatherOfficeLocation {
|
||||
x: 75,
|
||||
y: 59,
|
||||
code: "GYX".to_string(),
|
||||
};
|
||||
// @todo - add a way to configure which teams to add
|
||||
// @todo - add a way to get news articles?
|
||||
let entire_forecast: Vec<weather::WeatherPeriod> = weather::get_full_forecast(location);
|
||||
let sox_games: Vec<redsox::Game> = redsox::get_upcoming_games();
|
||||
let mut table_rows: Vec<TableRow> = vec![];
|
||||
for i in 0..entire_forecast.len() {
|
||||
let item = &entire_forecast[i];
|
||||
let date = &item.start_time[0..10];
|
||||
let mut sox_status = String::new();
|
||||
// Check if there is a sox game and print opp.
|
||||
for sox_game in &sox_games {
|
||||
if sox_game.date == date {
|
||||
let mut opp_str = String::new();
|
||||
opp_str.push(baseball_diamond);
|
||||
opp_str.push_str(" ");
|
||||
opp_str.push_str(&sox_game.opponent);
|
||||
sox_status = opp_str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
let mut forecast_w_icon = String::new();
|
||||
forecast_w_icon.push(sunny);
|
||||
forecast_w_icon.push_str(" ");
|
||||
forecast_w_icon.push_str(&item.detailed_forecast);
|
||||
let row = TableRow {
|
||||
date: date.to_string(),
|
||||
time_of_day: item.name.clone(),
|
||||
temp: item.temperature,
|
||||
red_sox: sox_status,
|
||||
forecast: forecast_w_icon,
|
||||
};
|
||||
table_rows.push(row);
|
||||
}
|
||||
let mut table = Table::new(table_rows);
|
||||
table.with(Style::modern());
|
||||
table.with((
|
||||
Width::wrap(210).priority(Priority::max(true)),
|
||||
Width::increase(50).priority(Priority::min(true)),
|
||||
));
|
||||
table.modify(Columns::first(), Alignment::right());
|
||||
println!("{}", table);
|
||||
}
|
||||
|
||||
72
src/redsox/mod.rs
Normal file
72
src/redsox/mod.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_alias::serde_alias;
|
||||
use std::fs;
|
||||
|
||||
const SOX_ID: i32 = 111;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde_alias(CamelCase,SnakeCase)]
|
||||
pub struct Schedule {
|
||||
pub games: Vec<Game>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde_alias(CamelCase,SnakeCase)]
|
||||
pub struct Game {
|
||||
// pub teams: Teams,
|
||||
pub date: String,
|
||||
// pub start_time: String,
|
||||
pub opponent: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde_alias(CamelCase,SnakeCase)]
|
||||
pub struct Teams {
|
||||
away: Team,
|
||||
home: Team,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde_alias(CamelCase,SnakeCase)]
|
||||
pub struct Team {
|
||||
team: TeamInfo,
|
||||
league_record: TeamRecord,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde_alias(CamelCase,SnakeCase)]
|
||||
pub struct TeamInfo {
|
||||
id: i32,
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde_alias(CamelCase,SnakeCase)]
|
||||
pub struct TeamRecord {
|
||||
wins: i32,
|
||||
losses: i32,
|
||||
}
|
||||
|
||||
pub fn get_upcoming_games() -> Vec<Game> {
|
||||
// @todo - change this to be a dynamic request from the API endpoint instead of a local file.
|
||||
let schedule_json: String = fs::read_to_string("/Users/danchadwick/Projects/rust/weather/assets/sox-schedule.json").expect("Unable to read file").to_owned();
|
||||
let json: Vec<Game> = serde_json::from_str(&schedule_json).expect("Something not good?");
|
||||
let upcoming_games: &Vec<Game> = &json.into_iter().take(7).collect();
|
||||
upcoming_games.to_owned()
|
||||
}
|
||||
|
||||
// Gets the full forecast from the response.
|
||||
pub fn get_schedule() -> Schedule {
|
||||
let url = "https://statsapi.mlb.com/api/v1/schedule?sportId=1&teamId=111&startDate=2025-04-01&endDate=2025-09-30".to_string();
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let schedule_string: String = client.get(&url).send().expect("Unable to get data").text().unwrap().to_string();
|
||||
let json: Schedule = serde_json::from_str(&schedule_string).expect("JSON was not well-formatted");
|
||||
|
||||
dbg!(json);
|
||||
let schedule = Schedule {
|
||||
games: vec![],
|
||||
};
|
||||
|
||||
schedule
|
||||
// json
|
||||
}
|
||||
54
src/weather/mod.rs
Normal file
54
src/weather/mod.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
use reqwest::header::USER_AGENT;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_alias::serde_alias;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ForecastWrapper {
|
||||
properties: Properties,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct Properties {
|
||||
periods: Vec<WeatherPeriod>,
|
||||
}
|
||||
|
||||
#[serde_alias(CamelCase,SnakeCase)]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct WeatherPeriod {
|
||||
pub name: String,
|
||||
pub temperature: u64,
|
||||
pub wind_direction: String,
|
||||
pub wind_speed: String,
|
||||
pub detailed_forecast: String,
|
||||
pub start_time: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct WeatherOfficeLocation {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub code: String,
|
||||
}
|
||||
|
||||
impl WeatherOfficeLocation {
|
||||
pub fn build_url(&self) -> String {
|
||||
format!(
|
||||
"https://api.weather.gov/gridpoints/{}/{},{}/forecast",
|
||||
self.code,
|
||||
self.x,
|
||||
self.y
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the full forecast from the response.
|
||||
pub fn get_full_forecast(location: WeatherOfficeLocation) -> Vec<WeatherPeriod> {
|
||||
let url = WeatherOfficeLocation::build_url(&location);
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let forecast = client.get(&url).header(USER_AGENT, "My SuperAwesome Weather App").send().expect("Unable to get data").text().unwrap().to_string();
|
||||
let json: ForecastWrapper = serde_json::from_str(&forecast).expect("JSON was not well-formatted");
|
||||
let periods: Vec<WeatherPeriod> = json.properties.periods.into_iter().collect();
|
||||
|
||||
periods
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user