Newer
Older
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
use crate::types::{Body, HttpResponse, Id, Uri};
use hyper::service::{make_service_fn, service_fn};
use hyper::{Request, Response, Server};
use serde_json::Value;
use std::convert::Infallible;
use std::net::SocketAddr;
pub const PARSE_ERROR: &str = "Parse error";
pub const INTERNAL_ERROR: &str = "Internal error";
pub const INVALID_PARAMS: &str = "Invalid params";
pub const INVALID_REQUEST: &str = "Invalid request";
pub const METHOD_NOT_FOUND: &str = "Method not found";
/// Converts a sockaddress to a WebSocket URI.
pub fn to_ws_uri_string(addr: SocketAddr) -> String {
let mut s = String::new();
s.push_str("ws://");
s.push_str(&addr.to_string());
s
}
/// Converts a sockaddress to a HTTP URI.
pub fn to_http_uri(sockaddr: SocketAddr) -> Uri {
let s = sockaddr.to_string();
Uri::builder().scheme("http").authority(s.as_str()).path_and_query("/").build().unwrap()
}
pub fn ok_response(result: Value, id: Id) -> String {
format!(r#"{{"jsonrpc":"2.0","result":{},"id":{}}}"#, result, serde_json::to_string(&id).unwrap())
}
pub fn method_not_found(id: Id) -> String {
format!(
r#"{{"jsonrpc":"2.0","error":{{"code":-32601,"message":"Method not found"}},"id":{}}}"#,
serde_json::to_string(&id).unwrap()
)
}
pub fn parse_error(id: Id) -> String {
format!(
r#"{{"jsonrpc":"2.0","error":{{"code":-32700,"message":"Parse error"}},"id":{}}}"#,
serde_json::to_string(&id).unwrap()
)
}
pub fn invalid_request(id: Id) -> String {
format!(
r#"{{"jsonrpc":"2.0","error":{{"code":-32600,"message":"Invalid request"}},"id":{}}}"#,
serde_json::to_string(&id).unwrap()
)
}
pub fn invalid_params(id: Id) -> String {
format!(
r#"{{"jsonrpc":"2.0","error":{{"code":-32602,"message":"Invalid params"}},"id":{}}}"#,
serde_json::to_string(&id).unwrap()
)
}
pub fn internal_error(id: Id) -> String {
format!(
r#"{{"jsonrpc":"2.0","error":{{"code":-32603,"message":"Internal error"}},"id":{}}}"#,
serde_json::to_string(&id).unwrap()
)
}
/// Hardcoded server response when a client initiates a new subscription.
///
/// NOTE: works only for one subscription because the subscription ID is hardcoded.
pub fn server_subscription_id_response(id: Id) -> String {
format!(
r#"{{"jsonrpc":"2.0","result":"D3wwzU6vvoUUYehv4qoFzq42DZnLoAETeFzeyk8swH4o","id":{}}}"#,
serde_json::to_string(&id).unwrap()
)
}
/// Server response to a hardcoded pending subscription
pub fn server_subscription_response(result: Value) -> String {
format!(
r#"{{"jsonrpc":"2.0","method":"bar","params":{{"subscription":"D3wwzU6vvoUUYehv4qoFzq42DZnLoAETeFzeyk8swH4o","result":{}}}}}"#,
serde_json::to_string(&result).unwrap()
)
}
pub async fn http_request(body: Body, uri: Uri) -> Result<HttpResponse, String> {
let client = hyper::Client::new();
let r = hyper::Request::post(uri)
.header(hyper::header::CONTENT_TYPE, hyper::header::HeaderValue::from_static("application/json"))
.body(body)
.expect("uri and request headers are valid; qed");
let res = client.request(r).await.map_err(|e| format!("{:?}", e))?;
let (parts, body) = res.into_parts();
let bytes = hyper::body::to_bytes(body).await.unwrap();
Ok(HttpResponse { status: parts.status, header: parts.headers, body: String::from_utf8(bytes.to_vec()).unwrap() })
}
/// Spawn HTTP server that responds with a hardcoded response.
//
// NOTE: This must be spawned on tokio because hyper only works with tokio.
pub async fn http_server_with_hardcoded_response(response: String) -> SocketAddr {
async fn process_request(_req: Request<Body>, response: String) -> Result<Response<Body>, Infallible> {
Ok(Response::new(hyper::Body::from(response)))
}
let make_service = make_service_fn(move |_| {
let response = response.clone();
async move {
Ok::<_, Infallible>(service_fn(move |req| {
let response = response.clone();
async move { Ok::<_, Infallible>(process_request(req, response).await.unwrap()) }
}))
}
});
let (tx, rx) = futures_channel::oneshot::channel::<SocketAddr>();
tokio::spawn(async {
let addr = SocketAddr::from(([127, 0, 0, 1], 0));
let server = Server::bind(&addr).serve(make_service);
tx.send(server.local_addr()).unwrap();
server.await.unwrap()
});
rx.await.unwrap()
}