1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use std::str;
use rand::{self, seq::SliceRandom, Rng};
use url::Url;
mod error {
use std::{error, fmt};
#[derive(Clone, Debug)]
pub enum Error {
Parse {
err: url::ParseError,
url: String,
},
WrongScheme {
scheme: String,
url: url::Url,
},
}
impl Error {
pub fn from_err(error: url::ParseError, url: String) -> Self {
Error::Parse {
err: error,
url: url,
}
}
pub fn wrong_scheme(scheme: String, url: url::Url) -> Self {
Error::WrongScheme {
url: url,
scheme: scheme,
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Parse { ref err, ref url } => {
write!(f, "URL parse error: {} | url: {}", err, url)
}
Error::WrongScheme {
ref scheme,
ref url,
} => write!(
f,
"expected HTTP or HTTPS url, found {} | url: {}",
scheme, url
),
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::Parse { .. } => "expected URL to succeed parsing, but it failed",
Error::WrongScheme { .. } => "expected HTTP or HTTPS url, found a different scheme",
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
Error::Parse { ref err, .. } => Some(err),
Error::WrongScheme { .. } => None,
}
}
}
}
pub use self::error::Error as UrlError;
pub fn default_url() -> Url {
transform_url(crate::DEFAULT_OFFICIAL_API_URL)
.expect("expected known good default URL to parse successfully.")
}
pub fn transform_url<U: AsRef<str> + ?Sized>(url: &U) -> Result<Url, UrlError> {
use std::fmt;
let mut url = match url.as_ref().parse::<Url>() {
Ok(v) => v,
Err(e) => return Err(UrlError::from_err(e, url.as_ref().to_owned())),
};
let new_scheme = match url.scheme() {
"http" => Ok("ws"),
"https" => Ok("wss"),
other => Err(other.to_string()),
};
let new_scheme = match new_scheme {
Ok(v) => v,
Err(other) => return Err(UrlError::wrong_scheme(other, url)),
};
url.set_scheme(new_scheme)
.expect("expected `ws` and `wss` to be valid url schemes.");
const VALID_CHARS: &'static [u8] = b"abcdefghijklmnopqrstuvwxyz012345";
struct GenServerAndSessionId;
impl fmt::Display for GenServerAndSessionId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut rng = rand::thread_rng();
write!(f, "../socket/{:04}/", rng.gen_range(0, 1000))?;
for _ in 0..8 {
write!(f, "{}", *VALID_CHARS.choose(&mut rng).unwrap() as char)?;
}
write!(f, "/websocket")?;
Ok(())
}
}
let result = url
.join(&GenServerAndSessionId.to_string())
.expect("expected generated string known to be correct to parse successfully");
Ok(result)
}