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
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 call_execution_failed(msg: &str, id: Id) -> String {
format!(
r#"{{"jsonrpc":"2.0","error":{{"code":-32000,"message":"{}"}},"id":{}}}"#,
msg,
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()
)
}
pub fn server_error(id: Id) -> String {
format!(
r#"{{"jsonrpc":"2.0","error":{{"code":-32000,"message":"Server 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()
)
}
/// Server originated notification
pub fn server_notification(method: &str, params: Value) -> String {
format!(r#"{{"jsonrpc":"2.0","method":"{}", "params":{} }}"#, method, serde_json::to_string(¶ms).unwrap())
}
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
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()
}