gain_localhost/
lib.rs

1// Copyright (c) 2019 Timo Savola.
2// Use of this source code is governed by the MIT
3// license that can be found in the LICENSE file.
4
5//! Access a local HTTP server.
6
7#[macro_use]
8extern crate lazy_static;
9
10use flatbuffers::{root, FlatBufferBuilder};
11use gain::service::Service;
12
13// The schema file can be found at https://gate.computer/localhost
14#[allow(unused, unused_imports)]
15#[path = "localhost_generated.rs"]
16mod flat;
17
18lazy_static! {
19    static ref SERVICE: Service = Service::register("gate.computer/localhost");
20}
21
22/// Make a GET request.
23pub async fn get(uri: &str) -> Response {
24    request("GET", uri, None, &[]).await
25}
26
27/// Make a POST request.
28pub async fn post(uri: &str, content_type: &str, body: &[u8]) -> Response {
29    request("POST", uri, Some(content_type), body).await
30}
31
32/// Make a PUT request.
33pub async fn put(uri: &str, content_type: &str, body: &[u8]) -> Response {
34    request("PUT", uri, Some(content_type), body).await
35}
36
37/// Make an HTTP request.
38pub async fn request(
39    method: &str,
40    uri: &str,
41    content_type: Option<&str>,
42    content: &[u8],
43) -> Response {
44    let mut b = FlatBufferBuilder::new();
45
46    let content = if !content.is_empty() {
47        Some(b.create_vector(content))
48    } else {
49        None
50    };
51
52    let content_type = match content_type {
53        Some(s) => Some(b.create_string(s)),
54        None => None,
55    };
56
57    let uri = b.create_string(uri);
58    let method = b.create_string(method);
59
60    let function = flat::Request::create(
61        &mut b,
62        &flat::RequestArgs {
63            method: Some(method),
64            uri: Some(uri),
65            content_type: content_type,
66            body: content,
67        },
68    );
69
70    let call = flat::Call::create(
71        &mut b,
72        &flat::CallArgs {
73            function_type: flat::Function::Request,
74            function: Some(function.as_union_value()),
75        },
76    );
77
78    b.finish_minimal(call);
79
80    SERVICE
81        .call(b.finished_data(), |reply: &[u8]| {
82            if reply.is_empty() {
83                return Response {
84                    status_code: 0,
85                    content_type: None,
86                    content: Vec::new(),
87                };
88            }
89
90            let r = root::<flat::Response>(reply).unwrap();
91
92            Response {
93                status_code: r.status_code(),
94                content_type: match r.content_type() {
95                    Some(s) => Some(s.to_owned()),
96                    None => None,
97                },
98                content: {
99                    let mut v = Vec::new();
100                    if let Some(b) = r.body() {
101                        v.reserve(b.len());
102                        v.extend_from_slice(b);
103                    }
104                    v
105                },
106            }
107        })
108        .await
109}
110
111/// HTTP response.
112pub struct Response {
113    pub status_code: u16,
114    pub content_type: Option<String>,
115    pub content: Vec<u8>,
116}
117
118#[cfg(feature = "lep")]
119pub mod lep;