Skip to content

Instantly share code, notes, and snippets.

@ldmsys
Created June 14, 2023 04:10
Show Gist options
  • Save ldmsys/ff328ab81ca99c15712b70dc2251eaed to your computer and use it in GitHub Desktop.
Save ldmsys/ff328ab81ca99c15712b70dc2251eaed to your computer and use it in GitHub Desktop.
const http = require('http');
const API_KEY = "[INSERT_API_KEY_HERE]"; // https://data.seoul.go.kr/dataList/OA-15488/S/1/datasetView.do
const url = 'http://openapi.seoul.go.kr:8088/'+API_KEY+'/json/WPOSInformationTime/1/5';
async function getTemp() {
return new Promise(function(resolve, reject) {
const req = http.request(url, {
url: url,
method: 'GET'
}, function (res) {
res.on('data', c => {
let count = 0, temp = 0.0;
let data = JSON.parse(c.toString());
for(let i of data.WPOSInformationTime.row) {
parseFloat(i.W_TEMP) && (temp += parseFloat(i.W_TEMP)) && count++;
}
resolve(temp/count);
});
});
req.end();
});
}
(async () => {
console.log(await getTemp());
})();
const a = http.createServer(async (req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': "*" });
res.end(JSON.stringify({river: "Han-gang", temp: await getTemp(), source: "Seoul Metropolitan Government"}));
});
a.listen(4264, "0.0.0.0");
@ldmsys
Copy link
Author

ldmsys commented May 2, 2024

use std::net::{TcpListener, TcpStream};
use std::io::{Read, Write};
use std::sync::{Arc, Mutex};
use std::time::{Duration, SystemTime};
use reqwest::blocking::Client;
use serde_json::Value;

const API_KEY: &str = "INSERT_API_KEY_HERE";
const URL: &str = "http://openapi.seoul.go.kr:8088/INSERT_API_KEY_HERE/json/WPOSInformationTime/1/5";

#[derive(Debug)]
struct Cache {
    last_fetched: SystemTime,
    value: f64,
}

impl Cache {
    fn new() -> Cache {
        Cache {
            last_fetched: SystemTime::now() - Duration::from_secs(301),
            value: 0.0,
        }
    }

    fn should_update(&self) -> bool {
        self.last_fetched.elapsed().unwrap_or(Duration::from_secs(301)) > Duration::from_secs(300)
    }
}

fn handle_client(mut stream: TcpStream, cache: Arc<Mutex<Cache>>) {
    let mut buffer = Vec::new();
    let mut data = [0; 512]; // Buffer for reading data
    while match stream.read(&mut data) {
        Ok(size) => {
            if size == 0 {
                false
            } else {
                buffer.extend_from_slice(&data[0..size]);
                !buffer.ends_with(b"\r\n\r\n")
            }
        },
        Err(_) => false,
    } {}

    let cache_clone = Arc::clone(&cache);
    let mut cache_guard = cache_clone.lock().unwrap();
    if cache_guard.should_update() {
        let client = Client::new();
        let response = client.get(URL).send();
        match response {
            Ok(resp) => {
                if resp.status().is_success() {
                    let json_result = resp.json::<Value>();
                    match json_result {
                        Ok(json) => {
                            if let Some(rows) = json["WPOSInformationTime"]["row"].as_array() {
                                let mut total_temp = 0.0;
                                let mut count = 0;
                                for row in rows {
                                    if let Some(temp_str) = row["W_TEMP"].as_str() {
                                        if let Ok(temp) = temp_str.parse::<f64>() {
                                            total_temp += temp;
                                            count += 1;
                                        }
                                    }
                                }
                                if count > 0 {
                                    let avg_temp = total_temp / count as f64;
                                    cache_guard.value = (avg_temp * 1000.0).round() / 1000.0; // Rounded to three decimals
                                } else {
                                    cache_guard.value = -1.00; // Error in data
                                }
                            } else {
                                cache_guard.value = -1.00; // Error in JSON structure
                            }
                        },
                        Err(_) => cache_guard.value = -1.00, // Error in parsing JSON
                    }
                } else {
                    cache_guard.value = -1.00; // HTTP request failed
                }
            },
            Err(_) => cache_guard.value = -1.00, // HTTP request error
        }
        cache_guard.last_fetched = SystemTime::now();
    }

    let response = format!(
        "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n{}",
        serde_json::json!({
            "river": "Han-gang",
            "temp": cache_guard.value,
            "source": "Seoul Metropolitan Government"
        }).to_string()
    );
    let _ = stream.write(response.as_bytes());
    let _ = stream.flush();
}

fn main() {
    let listener = TcpListener::bind("0.0.0.0:4264").unwrap();
    let cache = Arc::new(Mutex::new(Cache::new()));

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                let cache_clone = Arc::clone(&cache);
                std::thread::spawn(move || {
                    handle_client(stream, cache_clone);
                });
            }
            Err(e) => { eprintln!("Failed to accept connection: {}", e); }
        }
    }
}

Cargo.toml

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
reqwest = { version = "0.11", features = ["json", "blocking"] }
chrono = "0.4"

@ldmsys
Copy link
Author

ldmsys commented May 2, 2024

Return Only Temperature (Rust)

use std::net::{TcpListener, TcpStream};
use std::io::{Read, Write};
use std::sync::{Arc, Mutex};
use std::time::{SystemTime, Duration};
use reqwest::blocking::Client;
use serde_json::Value;

const API_KEY: &str = "INSERT_YOUR_API_KEY";
const URL: &str = &format!("http://openapi.seoul.go.kr:8088/{}/json/WPOSInformationTime/1/5", API_KEY);

struct Cache {
    last_fetched: SystemTime,
    value: f64,
}

impl Cache {
    fn new() -> Cache {
        Cache {
            last_fetched: SystemTime::now() - Duration::from_secs(301),
            value: 0.0,
        }
    }

    fn should_update(&self) -> bool {
        self.last_fetched.elapsed().unwrap_or(Duration::from_secs(301)) > Duration::from_secs(300)
    }

    fn update_temperature(&mut self) {
        let client = Client::new();
        match client.get(URL).send() {
            Ok(resp) => {
                if resp.status().is_success() {
                    match resp.json::<Value>() {
                        Ok(json) => {
                            let rows = json["WPOSInformationTime"]["row"].as_array();
                            if let Some(rows) = rows {
                                let (sum, count) = rows.iter().fold((0.0, 0), |(acc, cnt), row| {
                                    if let Some(temp_str) = row["W_TEMP"].as_str() {
                                        if let Ok(temp) = temp_str.parse::<f64>() {
                                            (acc + temp, cnt + 1)
                                        } else {
                                            (acc, cnt)
                                        }
                                    } else {
                                        (acc, cnt)
                                    }
                                });
                                if count > 0 {
                                    let avg_temp = sum / count as f64;
                                    self.value = (avg_temp * 1000.0).round() / 1000.0; // Rounded to three decimals
                                } else {
                                    self.value = -1.0;
                                }
                            } else {
                                self.value = -1.0;
                            }
                        },
                        Err(_) => self.value = -1.0,
                    }
                } else {
                    self.value = -1.0;
                }
            },
            Err(_) => self.value = -1.0,
        }
        self.last_fetched = SystemTime::now();
    }
}

fn handle_client(mut stream: TcpStream, cache: Arc<Mutex<Cache>>) {
    let mut cache_guard = cache.lock().unwrap();
    if cache_guard.should_update() {
        cache_guard.update_temperature();
    }

    let response = format!(
        "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nConnection: close\r\n\r\n{}",
        serde_json::json!({
            "river": "Han-gang",
            "temp": cache_guard.value,
            "source": "Seoul Metropolitan Government"
        }).to_string()
    );

    let _ = stream.write_all(response.as_bytes());
    let _ = stream.flush();
}

fn main() {
    let listener = TcpListener::bind("0.0.0.0:4444").unwrap();
    let cache = Arc::new(Mutex::new(Cache::new()));

    for stream in listener.incoming() {
        if let Ok(stream) = stream {
            let cache_clone = Arc::clone(&cache);
            std::thread::spawn(move || {
                handle_client(stream, cache_clone);
            });
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment