Switch to fetching instances from group
Rather than having configuration file based instance list. Having both is an option but the trend is generally using group instances for events.
This commit is contained in:
parent
3ac0d13780
commit
d4cffaea0a
13
README.md
13
README.md
|
@ -13,20 +13,11 @@ Not a lot of metrics are collected at the moment. Just the ones I care about.
|
|||
Configuration is done with a `config.toml` file with the following format:
|
||||
|
||||
```toml
|
||||
instances = [
|
||||
{ name = "optional instance name"
|
||||
, url = "https://vrchat.com/home/launch?worldId=wrld_123&instanceId=123"
|
||||
},
|
||||
{ name = "another instance"
|
||||
, instance = "234"
|
||||
, world = "wrld_234"
|
||||
}
|
||||
]
|
||||
|
||||
group = "group_7f23c663-e3c5-408f-bfb3-02b164f9e921"
|
||||
vrcdn = "vrcdn_stream_name"
|
||||
```
|
||||
|
||||
Instances can either be the URL or instance and world ID seperated out, the later taking priority over the former.
|
||||
Instances will be retrieved from the group.
|
||||
|
||||
Runs on port `6534`, on all interfaces. May be configurable in the future.
|
||||
|
||||
|
|
83
src/main.rs
83
src/main.rs
|
@ -1,4 +1,3 @@
|
|||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::{env, fmt, fs};
|
||||
|
||||
|
@ -10,11 +9,10 @@ use axum::{
|
|||
routing::get,
|
||||
Router,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
use maud::html;
|
||||
use maud::Markup;
|
||||
use prometheus::{register_gauge_vec, Encoder, GaugeVec, TextEncoder};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use reqwest::header::USER_AGENT;
|
||||
use serde::Deserialize;
|
||||
use url::Url;
|
||||
|
@ -68,21 +66,21 @@ impl fmt::Display for WsError {
|
|||
#[derive(Clone, Debug, Deserialize)]
|
||||
struct Config {
|
||||
vrcdn: Option<String>,
|
||||
instances: Option<Vec<VrcInstance>>,
|
||||
group: Option<String>,
|
||||
vrchat_token: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
struct VrcInstance {
|
||||
/// Full invite URL. Takes precedence over instance and world.
|
||||
url: Option<String>,
|
||||
/// Instance ID.
|
||||
instance: Option<String>,
|
||||
/// World ID.
|
||||
world: Option<String>,
|
||||
/// Raw location
|
||||
location: Option<String>,
|
||||
/// Custom name for the instance.
|
||||
#[serde(skip)]
|
||||
name: Option<String>
|
||||
name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
|
@ -101,6 +99,11 @@ struct VrCdnRegion {
|
|||
total: f64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
struct VrcGroupInstance {
|
||||
location: String,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), ()> {
|
||||
let content = fs::read_to_string("config.toml").unwrap();
|
||||
|
@ -111,7 +114,7 @@ async fn main() -> Result<(), ()> {
|
|||
.route("/", get(homepage))
|
||||
.route("/metrics", get(metrics_handler))
|
||||
.with_state(config);
|
||||
|
||||
|
||||
let _ = axum::Server::bind(&"0.0.0.0:6534".parse().unwrap())
|
||||
.serve(app.into_make_service())
|
||||
.await;
|
||||
|
@ -143,45 +146,52 @@ async fn metrics(config: Config) -> Result<Vec<u8>, WsError> {
|
|||
let encoder = TextEncoder::new();
|
||||
let client = reqwest::Client::new();
|
||||
let auth_cookie = format!("auth={}", &config.vrchat_token.unwrap());
|
||||
let mut instances: Vec<VrcInstance> = vec![];
|
||||
|
||||
// Do work.
|
||||
for instance in config.instances.ok_or(WsError::Custom("".to_owned()))? {
|
||||
let (instance_id, world_id): (String, String) = if instance.url.is_none() {
|
||||
(
|
||||
instance.instance.ok_or(WsError::Custom("".to_owned()))?,
|
||||
instance.world.ok_or(WsError::Custom("".to_owned()))?,
|
||||
)
|
||||
} else {
|
||||
let url = Url::parse(&instance.url.unwrap_or("".to_owned()))?;
|
||||
let hash_query: HashMap<_, _> = url.query_pairs().into_owned().collect();
|
||||
(
|
||||
hash_query
|
||||
.get("instanceId")
|
||||
.ok_or(WsError::Custom("".to_owned()))?
|
||||
.to_string(),
|
||||
hash_query
|
||||
.get("worldId")
|
||||
.ok_or(WsError::Custom("".to_owned()))?
|
||||
.to_string(),
|
||||
)
|
||||
};
|
||||
// Check if we can fetch instances from a group if set.
|
||||
if config.group.is_some() {
|
||||
let api_url = format!(
|
||||
"https://api.vrchat.cloud/api/1/instances/{0}:{1}",
|
||||
world_id, instance_id
|
||||
"https://api.vrchat.cloud/api/1/groups/{}/instances",
|
||||
config.group.unwrap()
|
||||
);
|
||||
let url = Url::parse(&api_url).unwrap();
|
||||
let req = client
|
||||
.get(url)
|
||||
.header(
|
||||
USER_AGENT,
|
||||
"vr-event-tracker(git.gmem.ca/arch/vr-event-tracker)",
|
||||
)
|
||||
.header("Cookie", &auth_cookie)
|
||||
.send()
|
||||
.await?;
|
||||
let data: Vec<VrcGroupInstance> = req.json().await?;
|
||||
instances = data.into_iter().map(|f| {
|
||||
let spl: Vec<&str> = f.location.split(":").collect();
|
||||
VrcInstance{ instance: Some(spl[0].to_owned()), world: Some(spl[1].to_owned()), location: Some(f.location), name: None }
|
||||
}).collect();
|
||||
}
|
||||
|
||||
for instance in instances {
|
||||
let api_url = format!(
|
||||
"https://api.vrchat.cloud/api/1/instances/{}",
|
||||
&instance.location.clone().unwrap()
|
||||
);
|
||||
let url = Url::parse(&api_url).unwrap();
|
||||
|
||||
let req = client
|
||||
.get(url)
|
||||
.header(USER_AGENT, "vr-event-tracker(git.gmem.ca/arch/vr-event-tracker)")
|
||||
.header(
|
||||
USER_AGENT,
|
||||
"vr-event-tracker(git.gmem.ca/arch/vr-event-tracker)",
|
||||
)
|
||||
.header("Cookie", &auth_cookie)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
let data: VrcInstanceData = req.json().await?;
|
||||
let name = instance.name.unwrap_or(instance_id.clone());
|
||||
let name = instance.name.unwrap_or(instance.location.unwrap());
|
||||
PLAYER_COUNT
|
||||
.with_label_values(&[&world_id, &instance_id, &name])
|
||||
.with_label_values(&[&instance.world.unwrap(), &instance.instance.unwrap(), &name])
|
||||
.set(data.user_count.unwrap_or(0 as f64));
|
||||
}
|
||||
|
||||
|
@ -191,7 +201,10 @@ async fn metrics(config: Config) -> Result<Vec<u8>, WsError> {
|
|||
);
|
||||
let req = client
|
||||
.get(vrcdn_url)
|
||||
.header(USER_AGENT, "vr-event-tracker(git.gmem.ca/arch/vr-event-tracker)")
|
||||
.header(
|
||||
USER_AGENT,
|
||||
"vr-event-tracker(git.gmem.ca/arch/vr-event-tracker)",
|
||||
)
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
Loading…
Reference in a new issue