summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: cf4dc661ce8e174e4bc3f4a3fc57085c9d5b4730 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use serde_json::Value;
use std::error::Error;
use std::fs;
use std::path::Path;

const CONFIG_PATH: &str = "/home/adam/.config/forecast";

#[derive(Debug)]
struct WeatherInfo {
    icon: char,
    temp: i32,
}

fn main() {
    let (current_endpoint, forecast_endpoint) = init();
    let current_data = req_weather(current_endpoint).unwrap();
    let forecast_data = req_weather(forecast_endpoint).unwrap();

    let current_weather = parse_current(current_data).unwrap();
    let forecast_weather = parse_forecast(forecast_data).unwrap();
    let trend = get_trend(current_weather.temp, forecast_weather.temp);

    println!(
        "  {} {}°C {} {} {}°C  ",
        current_weather.icon,
        current_weather.temp,
        trend,
        forecast_weather.icon,
        forecast_weather.temp
    );
}

fn init() -> (String, String) {
    let city_id = read_config_file("city_id");
    let api_key = read_config_file("api_key");

    let current_endpoint: String = format!(
        "https://api.openweathermap.org/data/2.5/weather?id={}&appid={}&units=metric",
        city_id, api_key
    );
    let forecast_endpoint: String = format!(
        "https://api.openweathermap.org/data/2.5/forecast?id={}&appid={}&units=metric&cnt=1",
        city_id, api_key
    );
    (current_endpoint, forecast_endpoint)
}

fn read_config_file(file_name: &str) -> String {
    let path = Path::new(CONFIG_PATH).join(file_name);
    fs::read_to_string(path.to_string_lossy().to_string()).unwrap()
}

fn req_weather(endpoint: String) -> Result<Value, Box<dyn Error>> {
    let resp = reqwest::blocking::get(endpoint)?.text()?;
    Ok(serde_json::from_str(&resp)?)
}

fn parse_current(response: Value) -> Option<WeatherInfo> {
    let icon_code = response["weather"][0]["icon"].as_str()?;
    let temperature = response["main"]["temp"].as_f64()?.round();

    Some(WeatherInfo {
        icon: get_icon(icon_code),
        temp: temperature as i32,
    })
}

fn parse_forecast(response: Value) -> Option<WeatherInfo> {
    let icon_code = response["list"][0]["weather"][0]["icon"].as_str()?;
    let temperature = response["list"][0]["main"]["temp"].as_f64()?.round();

    Some(WeatherInfo {
        icon: get_icon(icon_code),
        temp: temperature as i32,
    })
}

fn get_icon(code: &str) -> char {
    match code {
        "01d" => '',         // Clear sky - day
        "01n" => '',         // Clear sky - night
        "02d" => '',         // Few clouds (11-25%) - day
        "02n" => '',         // Few clouds (11-25%) - night
        "03d" | "03n" => '', // Scattered clouds (25-50%) - day/night
        "04d" | "04n" => '', // Broken / Overcast clouds (51-84% / 85-100%) - day/night
        "09d" => '',         // Shower rain - day
        "09n" => '',         // Shower rain - night
        "10d" => '',         // Moderate / heavy rain - day
        "10n" => '',         // Moderate / heavy rain - night
        "11d" => '',         // Thunderstorm - day
        "11n" => '',         // Thunderstorm - night
        "13d" => '',         // Snow - day
        "13n" => '',         // Snow - night
        "50d" => '',         // Fog - day
        "50n" => '',         // Fog - night
        _ => '',             // ??
    }
}

fn get_trend(t1: i32, t2: i32) -> char {
    if t1 < t2 {
        ''
    } else if t1 > t2 {
        ''
    } else {
        ''
    }
}