170 lines
5.1 KiB
Rust
170 lines
5.1 KiB
Rust
use anyhow::{anyhow, Result};
|
|
use serde::{Deserialize, Serialize};
|
|
use std::str::FromStr;
|
|
use url::Url;
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
|
pub enum Cluster {
|
|
Testnet,
|
|
Mainnet,
|
|
Devnet,
|
|
Localnet,
|
|
Debug,
|
|
Custom(String, String),
|
|
}
|
|
|
|
impl Default for Cluster {
|
|
fn default() -> Self {
|
|
Cluster::Localnet
|
|
}
|
|
}
|
|
|
|
impl FromStr for Cluster {
|
|
type Err = anyhow::Error;
|
|
fn from_str(s: &str) -> Result<Cluster> {
|
|
match s.to_lowercase().as_str() {
|
|
"t" | "testnet" => Ok(Cluster::Testnet),
|
|
"m" | "mainnet" => Ok(Cluster::Mainnet),
|
|
"d" | "devnet" => Ok(Cluster::Devnet),
|
|
"l" | "localnet" => Ok(Cluster::Localnet),
|
|
"g" | "debug" => Ok(Cluster::Debug),
|
|
_ if s.starts_with("http") => {
|
|
let http_url = s;
|
|
|
|
// Taken from:
|
|
// https://github.com/solana-labs/solana/blob/aea8f0df1610248d29d8ca3bc0d60e9fabc99e31/web3.js/src/util/url.ts
|
|
|
|
let mut ws_url = Url::parse(http_url)?;
|
|
if let Some(port) = ws_url.port() {
|
|
ws_url.set_port(Some(port + 1))
|
|
.map_err(|_| anyhow!("Unable to set port"))?;
|
|
}
|
|
if ws_url.scheme() == "https" {
|
|
ws_url.set_scheme("wss")
|
|
.map_err(|_| anyhow!("Unable to set scheme"))?;
|
|
} else {
|
|
ws_url.set_scheme("ws")
|
|
.map_err(|_| anyhow!("Unable to set scheme"))?;
|
|
}
|
|
|
|
|
|
Ok(Cluster::Custom(http_url.to_string(), ws_url.to_string()))
|
|
}
|
|
_ => Err(anyhow::Error::msg(
|
|
"Cluster must be one of [localnet, testnet, mainnet, devnet] or be an http or https url\n",
|
|
)),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for Cluster {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
let clust_str = match self {
|
|
Cluster::Testnet => "testnet",
|
|
Cluster::Mainnet => "mainnet",
|
|
Cluster::Devnet => "devnet",
|
|
Cluster::Localnet => "localnet",
|
|
Cluster::Debug => "debug",
|
|
Cluster::Custom(url, _ws_url) => url,
|
|
};
|
|
write!(f, "{}", clust_str)
|
|
}
|
|
}
|
|
|
|
impl Cluster {
|
|
pub fn url(&self) -> &str {
|
|
match self {
|
|
Cluster::Devnet => "https://api.devnet.solana.com",
|
|
Cluster::Testnet => "https://api.testnet.solana.com",
|
|
Cluster::Mainnet => "https://api.mainnet-beta.solana.com",
|
|
Cluster::Localnet => "http://127.0.0.1:8899",
|
|
Cluster::Debug => "http://34.90.18.145:8899",
|
|
Cluster::Custom(url, _ws_url) => url,
|
|
}
|
|
}
|
|
pub fn ws_url(&self) -> &str {
|
|
match self {
|
|
Cluster::Devnet => "wss://api.devnet.solana.com",
|
|
Cluster::Testnet => "wss://api.testnet.solana.com",
|
|
Cluster::Mainnet => "wss://api.mainnet-beta.solana.com",
|
|
Cluster::Localnet => "ws://127.0.0.1:9000",
|
|
Cluster::Debug => "ws://34.90.18.145:9000",
|
|
Cluster::Custom(_url, ws_url) => ws_url,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
fn test_cluster(name: &str, cluster: Cluster) {
|
|
assert_eq!(Cluster::from_str(name).unwrap(), cluster);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cluster_parse() {
|
|
test_cluster("testnet", Cluster::Testnet);
|
|
test_cluster("mainnet", Cluster::Mainnet);
|
|
test_cluster("devnet", Cluster::Devnet);
|
|
test_cluster("localnet", Cluster::Localnet);
|
|
test_cluster("debug", Cluster::Debug);
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn test_cluster_bad_parse() {
|
|
let bad_url = "httq://my_custom_url.test.net";
|
|
Cluster::from_str(bad_url).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn test_http_port() {
|
|
let url = "http://my-url.com:7000/";
|
|
let cluster = Cluster::from_str(url).unwrap();
|
|
assert_eq!(
|
|
Cluster::Custom(url.to_string(), "ws://my-url.com:7001/".to_string()),
|
|
cluster
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_http_no_port() {
|
|
let url = "http://my-url.com/";
|
|
let cluster = Cluster::from_str(url).unwrap();
|
|
assert_eq!(
|
|
Cluster::Custom(url.to_string(), "ws://my-url.com/".to_string()),
|
|
cluster
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_https_port() {
|
|
let url = "https://my-url.com:7000/";
|
|
let cluster = Cluster::from_str(url).unwrap();
|
|
assert_eq!(
|
|
Cluster::Custom(url.to_string(), "wss://my-url.com:7001/".to_string()),
|
|
cluster
|
|
);
|
|
}
|
|
#[test]
|
|
fn test_https_no_port() {
|
|
let url = "https://my-url.com/";
|
|
let cluster = Cluster::from_str(url).unwrap();
|
|
assert_eq!(
|
|
Cluster::Custom(url.to_string(), "wss://my-url.com/".to_string()),
|
|
cluster
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_upper_case() {
|
|
let url = "http://my-url.com/FooBar";
|
|
let cluster = Cluster::from_str(url).unwrap();
|
|
assert_eq!(
|
|
Cluster::Custom(url.to_string(), "ws://my-url.com/FooBar".to_string()),
|
|
cluster
|
|
);
|
|
}
|
|
}
|