nakama_rs/
async_client.rs1use 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}