diff --git a/src/collectors/mod.rs b/src/collectors/mod.rs new file mode 100644 index 0000000..2e3d1e8 --- /dev/null +++ b/src/collectors/mod.rs @@ -0,0 +1,9 @@ +pub mod player_count; +// pub mod stats; + +pub trait PromMetric { + fn to_metric_string(self: &Self) -> String; +} + +pub const USER_AGENT: &str = "osrs-prometheus-exporter"; +pub const RUNELITE_API_VERSION: &str = "runelite-1.9.13"; diff --git a/src/collector/mod.rs b/src/collectors/player_count.rs similarity index 83% rename from src/collector/mod.rs rename to src/collectors/player_count.rs index dae4562..bbd7150 100644 --- a/src/collector/mod.rs +++ b/src/collectors/player_count.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Deserializer}; use std::fmt::{Display, Formatter}; use std::str; +use super::PromMetric; #[derive(Deserialize, Debug)] pub struct Worlds { @@ -18,8 +19,8 @@ pub enum WorldLocation { impl<'de> Deserialize<'de> for WorldLocation { fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, + where + D: Deserializer<'de>, { let field = i16::deserialize(deserializer)?; let world = match field { @@ -66,8 +67,8 @@ pub enum WorldType { impl<'de> Deserialize<'de> for WorldType { fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, + where + D: Deserializer<'de>, { let field = String::deserialize(deserializer)?; let res = match field.as_str() { @@ -101,15 +102,11 @@ pub struct World { pub types: Vec, } -pub trait PromMetric { - fn to_metric_string(self: &Self) -> String; -} - impl PromMetric for World { fn to_metric_string(&self) -> String { //"player_count{id=\"301\",location=\"Germany\,"isMembers=\"true\"} 123" format!( - "player_count{{id=\"{}\",location=\"{}\",isMembers=\"{:?}\"}} {}", + "osrs_world_players{{id=\"{}\",location=\"{}\",isMembers=\"{:?}\"}} {}", self.id, self.location, self.is_members(), @@ -123,3 +120,16 @@ impl World { self.types.contains(&WorldType::Members) } } + +pub async fn get_player_count() -> eyre::Result> { + let req_url = format!("https://api.runelite.net/{}/worlds.js", super::RUNELITE_API_VERSION); + let resp = reqwest::Client::new() + .get(req_url) + .header("User-Agent", super::USER_AGENT) + .send() + .await? + .json::() + .await?; + + Ok(resp.worlds) +} diff --git a/src/main.rs b/src/main.rs index bb963df..d198273 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,27 +2,34 @@ mod collector; use axum::routing::get; use axum::Router; -use collector::{PromMetric, Worlds}; +use axum::extract::Path; +use axum::http::StatusCode; +use axum::response::IntoResponse; +use collectors::PromMetric; -async fn metrics() -> String { - let resp = reqwest::get("https://api.runelite.net/runelite-1.9.13/worlds.js") - .await - .unwrap() - .json::() - .await - .unwrap(); - - let metric_strings: Vec = resp - .worlds +fn convert_into_metrics(data: Vec) -> String { + let metrics: Vec = data .into_iter() .map(|w| w.to_metric_string()) .collect(); - metric_strings.join("\n") + + metrics.join("\n") +} + +async fn worlds() -> impl IntoResponse { + let resp = match collectors::player_count::get_player_count().await { + Ok(r) => r, + Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "Nope".to_string()) + }; + + (StatusCode::OK, convert_into_metrics(resp)) } #[tokio::main] async fn main() { - let app = Router::new().route("/metrics", get(metrics)); + let app = Router::new() + .route("/worlds", get(worlds)); + // .route("/stats/:rsn", get(stats)); println!("Starting...");