nakama_rs/
async_client.rs

1use super::api;
2use quad_net::http_request::{HttpError, Method, Request, RequestBuilder};
3
4#[derive(Debug)]
5pub enum Error {
6    IOError(std::io::Error),
7    JsonError(nanoserde::DeJsonErr),
8    HttpError(HttpError),
9}
10
11impl From<std::io::Error> for Error {
12    fn from(error: std::io::Error) -> Error {
13        Error::IOError(error)
14    }
15}
16
17impl From<nanoserde::DeJsonErr> for Error {
18    fn from(error: nanoserde::DeJsonErr) -> Error {
19        Error::JsonError(error)
20    }
21}
22
23impl From<HttpError> for Error {
24    fn from(error: HttpError) -> Error {
25        Error::HttpError(error)
26    }
27}
28
29pub struct AsyncRequest<T: nanoserde::DeJson> {
30    _marker: std::marker::PhantomData<T>,
31    request: Request,
32    on_success: Option<Box<dyn FnMut(T) -> ()>>,
33    on_error: Option<Box<dyn FnMut(Error) -> ()>>,
34}
35
36pub trait AsyncRequestTick {
37    fn tick(&mut self) -> bool;
38}
39
40impl<T: nanoserde::DeJson> AsyncRequestTick for AsyncRequest<T> {
41    fn tick(&mut self) -> bool {
42        match self.try_recv() {
43            Some(Ok(response)) => {
44                if let Some(on_success) = self.on_success.as_mut() {
45                    on_success(response);
46                }
47                true
48            }
49            Some(Err(err)) => {
50                if let Some(on_error) = self.on_error.as_mut() {
51                    on_error(err);
52                }
53                true
54            }
55            None => false,
56        }
57    }
58}
59
60impl<T: nanoserde::DeJson> AsyncRequest<T> {
61    pub fn on_success<F: FnMut(T) -> () + 'static>(&mut self, f: F) {
62        self.on_success = Some(Box::new(f));
63    }
64    pub fn on_error<F: FnMut(Error) -> () + 'static>(&mut self, f: F) {
65        self.on_error = Some(Box::new(f));
66    }
67
68    pub fn try_recv(&mut self) -> Option<Result<T, Error>> {
69        if let Some(response) = self.request.try_recv() {
70            return Some(response.map_err(|err| err.into()).and_then(|response| {
71                nanoserde::DeJson::deserialize_json(&response).map_err(|err| err.into())
72            }));
73        }
74
75        None
76    }
77}
78
79pub fn make_request<T: nanoserde::DeJson>(
80    server: &str,
81    port: u32,
82    request: api::RestRequest<T>,
83) -> AsyncRequest<T> {
84    let auth_header = match request.authentication {
85        api::Authentication::Basic { username, password } => {
86            format!(
87                "Basic {}",
88                base64::encode(&format!("{}:{}", username, password))
89            )
90        }
91        api::Authentication::Bearer { token } => {
92            format!("Bearer {}", token)
93        }
94    };
95    let method = match request.method {
96        api::Method::Post => Method::Post,
97        api::Method::Put => Method::Put,
98        api::Method::Get => Method::Get,
99        api::Method::Delete => Method::Delete,
100    };
101
102    let url = format!(
103        "{}:{}{}?{}",
104        server, port, request.urlpath, request.query_params
105    );
106
107    let request = RequestBuilder::new(&url)
108        .method(method)
109        .header("Authorization", &auth_header)
110        .body(&request.body)
111        .send();
112
113    AsyncRequest {
114        request,
115        on_success: None,
116        on_error: None,
117        _marker: std::marker::PhantomData,
118    }
119}
120
121#[test]
122fn auth_async() {
123    use crate::config::DEFAULT_PORT;
124
125    let request = api::authenticate_email(
126        "defaultkey",
127        "",
128        api::ApiAccountEmail {
129            email: "super3@heroes.com".to_string(),
130            password: "batsignal2".to_string(),
131            vars: std::collections::HashMap::new(),
132        },
133        Some(false),
134        None,
135    );
136
137    let mut async_request = make_request("http://127.0.0.1", DEFAULT_PORT, request);
138    let response = loop {
139        if let Some(response) = async_request.try_recv() {
140            break response;
141        }
142    };
143
144    println!("{:?}", response);
145}