use url::Url;
use crate::phoenix_rise_types::PhoenixWsError;
pub(crate) const PHOENIX_WS_URL_ENV: &str = "PHOENIX_WS_URL";
pub(crate) const PHOENIX_API_URL_ENV: &str = "PHOENIX_API_URL";
pub(crate) const DEFAULT_PHOENIX_API_URL: &str = "https://perp-api.phoenix.trade";
pub(crate) const DEFAULT_WS_PATH: &str = "/v1/ws";
fn default_ws_url() -> String {
ws_url_from_api_url(DEFAULT_PHOENIX_API_URL)
.unwrap_or_else(|_| format!("wss://perp-api.phoenix.trade{}", DEFAULT_WS_PATH))
}
#[derive(Debug, Clone)]
pub struct PhoenixEnv {
pub api_url: String,
pub ws_url: String,
}
impl PhoenixEnv {
pub fn load() -> Self {
let api_url = std::env::var(PHOENIX_API_URL_ENV)
.unwrap_or_else(|_| DEFAULT_PHOENIX_API_URL.to_string());
let ws_url = std::env::var(PHOENIX_WS_URL_ENV)
.unwrap_or_else(|_| ws_url_from_api_url(&api_url).unwrap_or_else(|_| default_ws_url()));
Self { api_url, ws_url }
}
}
impl Default for PhoenixEnv {
fn default() -> Self {
Self {
api_url: DEFAULT_PHOENIX_API_URL.to_string(),
ws_url: default_ws_url(),
}
}
}
pub(crate) fn ws_url_from_api_url(api_url: &str) -> Result<String, PhoenixWsError> {
let mut url = Url::parse(api_url)?;
let scheme = url.scheme();
if let Some(ws_scheme) = scheme.strip_prefix("http") {
let new_scheme = format!("ws{}", ws_scheme);
let _ = url.set_scheme(&new_scheme);
} else if scheme != "ws" && scheme != "wss" {
return Err(PhoenixWsError::UnsupportedUrlScheme(scheme.to_string()));
}
url.set_path(DEFAULT_WS_PATH);
url.set_query(None);
url.set_fragment(None);
Ok(url.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_load() {
let env = PhoenixEnv::load();
assert!(!env.api_url.is_empty());
assert!(!env.ws_url.is_empty());
}
#[test]
fn test_default_env() {
let env = PhoenixEnv::default();
assert_eq!(env.api_url, "https://perp-api.phoenix.trade");
assert_eq!(env.ws_url, "wss://perp-api.phoenix.trade/v1/ws");
}
#[test]
fn test_ws_url_from_https_api_url_appends_ws() {
let ws_url = ws_url_from_api_url("https://perp-api.phoenix.trade").unwrap();
assert_eq!(ws_url, "wss://perp-api.phoenix.trade/v1/ws");
}
#[test]
fn test_ws_url_from_http_api_url_appends_ws() {
let ws_url = ws_url_from_api_url("http://localhost:8080").unwrap();
assert_eq!(ws_url, "ws://localhost:8080/v1/ws");
}
#[test]
fn test_ws_url_preserves_path() {
let ws_url = ws_url_from_api_url("https://api.phoenix.trade/v1").unwrap();
assert_eq!(ws_url, "wss://api.phoenix.trade/v1/ws");
}
#[test]
fn test_ws_url_handles_trailing_slash() {
let ws_url = ws_url_from_api_url("https://perp-api.phoenix.trade/").unwrap();
assert_eq!(ws_url, "wss://perp-api.phoenix.trade/v1/ws");
}
#[test]
fn test_ws_url_does_not_double_append_ws() {
let ws_url = ws_url_from_api_url("https://perp-api.phoenix.trade/ws").unwrap();
assert_eq!(ws_url, "wss://perp-api.phoenix.trade/v1/ws");
}
}