rocket/local/blocking/
client.rs
1use std::fmt;
2use std::cell::RefCell;
3
4use crate::{Rocket, Phase, Orbit, Ignite, Error};
5use crate::local::{asynchronous, blocking::{LocalRequest, LocalResponse}};
6use crate::http::{Method, uri::Origin};
7
8pub struct Client {
28 pub(crate) inner: Option<asynchronous::Client>,
29 runtime: RefCell<tokio::runtime::Runtime>,
30}
31
32impl Client {
33 fn _new<P: Phase>(rocket: Rocket<P>, tracked: bool) -> Result<Client, Error> {
34 let runtime = tokio::runtime::Builder::new_multi_thread()
35 .thread_name("rocket-local-client-worker-thread")
36 .worker_threads(1)
37 .enable_all()
38 .build()
39 .expect("create tokio runtime");
40
41 let inner = Some(runtime.block_on(asynchronous::Client::_new(rocket, tracked))?);
43 Ok(Self { inner, runtime: RefCell::new(runtime) })
44 }
45
46 #[doc(hidden)]
48 pub fn _test<T, F>(f: F) -> T
49 where F: FnOnce(&Self, LocalRequest<'_>, LocalResponse<'_>) -> T + Send
50 {
51 let client = Client::debug(crate::build()).unwrap();
52 let request = client.get("/");
53 let response = request.clone().dispatch();
54 f(&client, request, response)
55 }
56
57 #[inline(always)]
58 pub(crate) fn inner(&self) -> &asynchronous::Client {
59 self.inner.as_ref().expect("internal invariant broken: self.inner is Some")
60 }
61
62 #[inline(always)]
63 pub(crate) fn block_on<F, R>(&self, fut: F) -> R
64 where F: std::future::Future<Output=R>,
65 {
66 self.runtime.borrow_mut().block_on(fut)
67 }
68
69 #[inline(always)]
70 fn _rocket(&self) -> &Rocket<Orbit> {
71 self.inner()._rocket()
72 }
73
74 #[inline(always)]
75 pub(crate) fn _with_raw_cookies<F, T>(&self, f: F) -> T
76 where F: FnOnce(&crate::http::private::cookie::CookieJar) -> T
77 {
78 self.inner()._with_raw_cookies(f)
79 }
80
81 pub(crate) fn _terminate(mut self) -> Rocket<Ignite> {
82 let runtime = tokio::runtime::Builder::new_current_thread().build().unwrap();
83 let runtime = self.runtime.replace(runtime);
84 let inner = self.inner.take().expect("invariant broken: self.inner is Some");
85 let rocket = runtime.block_on(inner._terminate());
86 runtime.shutdown_timeout(std::time::Duration::from_secs(1));
87 rocket
88 }
89
90 #[inline(always)]
91 fn _req<'c, 'u: 'c, U>(&'c self, method: Method, uri: U) -> LocalRequest<'c>
92 where U: TryInto<Origin<'u>> + fmt::Display
93 {
94 LocalRequest::new(self, method, uri)
95 }
96
97 pub_client_impl!("use rocket::local::blocking::Client;");
99}
100
101impl std::fmt::Debug for Client {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 self._rocket().fmt(f)
104 }
105}
106
107impl Drop for Client {
108 fn drop(&mut self) {
109 if let Some(client) = self.inner.take() {
110 self.block_on(async { drop(client) });
111 }
112 }
113}
114
115#[cfg(doctest)]
116mod doctest {
117 #[allow(dead_code)]
124 fn test_not_sync() {}
125}