1use std::any::Any;
2use std::panic::AssertUnwindSafe;
3use std::ptr::NonNull;
4use std::sync::{Arc, Mutex, MutexGuard, Once, Weak};
5
6use libc::c_void;
7
8use crate::error::{UnitError, UnitInitError, UnitResult};
9use crate::nxt_unit::{
10 self, nxt_unit_ctx_t, nxt_unit_done, nxt_unit_init, nxt_unit_init_t, nxt_unit_request_done,
11 nxt_unit_request_info_t, nxt_unit_response_init, nxt_unit_run,
12};
13use crate::request::Request;
14
15unsafe extern "C" fn request_handler(req: *mut nxt_unit_request_info_t) {
16 let context_data = (*(*req).ctx).data as *mut ContextData;
19 let context_data = &mut *context_data;
20
21 let rc = nxt_unit_response_init(req, 200, 1, 0 as u32);
22
23 if rc != nxt_unit::NXT_UNIT_OK as i32 {
24 nxt_unit_request_done(req, rc);
25 return;
26 }
27
28 let rc = if let Some(service) = &mut context_data.request_handler {
29 let unit_request = Request {
30 nxt_request: &mut *req,
31 _lifetime: Default::default(),
32 };
33
34 let handler = AssertUnwindSafe(|| service.handle_request(unit_request));
37
38 match std::panic::catch_unwind(handler) {
39 Ok(Ok(())) => nxt_unit::NXT_UNIT_OK as i32,
40 Ok(Err(UnitError(rc))) => rc,
41 Err(panic_payload) => {
42 nxt_unit_request_done(req, nxt_unit::NXT_UNIT_ERROR as i32);
43
44 std::panic::resume_unwind(panic_payload)
48 }
51 }
52 } else {
53 nxt_unit::NXT_UNIT_OK as i32
54 };
55
56 nxt_unit_request_done(req, rc);
57}
58
59struct ContextData {
60 request_handler: Option<Box<dyn UnitService>>,
61 unit_is_ready: bool,
62 panic_payload: Option<Box<dyn Any + Send>>,
63}
64
65unsafe extern "C" fn ready_handler(ctx: *mut nxt_unit_ctx_t) -> i32 {
66 let context_data = (*ctx).data as *mut ContextData;
69 let context_data = &mut *context_data;
70
71 context_data.unit_is_ready = true;
72
73 nxt_unit::NXT_UNIT_OK as i32
74}
75
76static mut MAIN_CONTEXT: Option<Mutex<MainContext>> = None;
77static MAIN_CONTEXT_INIT: Once = Once::new();
78
79enum MainContext {
80 Uninitialized,
81 InitFailed(UnitInitError),
82 Initialized(Weak<UnitContextWrapper>),
83}
84
85fn main_context() -> MutexGuard<'static, MainContext> {
86 unsafe {
87 MAIN_CONTEXT_INIT.call_once(|| {
88 MAIN_CONTEXT = Some(Mutex::new(MainContext::Uninitialized));
89 });
90 MAIN_CONTEXT
91 .as_ref()
92 .expect("Initialized above")
93 .lock()
94 .expect("Main context should not be poisoned")
95 }
96}
97
98pub struct Unit {
114 context_wrapper: Option<Arc<UnitContextWrapper>>,
115 context_data: *mut ContextData,
116}
117
118impl Unit {
119 pub fn new() -> Result<Self, UnitInitError> {
129 let mut main_context = main_context();
130
131 let main_unit_context = match &*main_context {
132 MainContext::InitFailed(UnitInitError) => {
133 return Err(UnitInitError);
134 }
135 MainContext::Uninitialized => None,
136 MainContext::Initialized(main_unit_context) => {
137 match main_unit_context.upgrade() {
138 Some(context) => Some(context),
139 None => {
140 return Ok(Self {
143 context_wrapper: None,
144 context_data: std::ptr::null_mut(),
145 });
146 }
147 }
148 }
149 };
150
151 if let Some(main_unit_context) = main_unit_context {
152 let context_data = Box::new(ContextData {
155 request_handler: None,
156 unit_is_ready: false,
157 panic_payload: None,
158 });
159
160 let context_user_data = Box::into_raw(context_data);
161
162 let ctx = unsafe {
163 nxt_unit::nxt_unit_ctx_alloc(
164 main_unit_context.context.as_ptr(),
165 context_user_data as *mut c_void,
166 )
167 };
168
169 let ctx = match NonNull::new(ctx) {
170 Some(ctx) => ctx,
171 None => {
172 return Err(UnitInitError);
173 }
174 };
175
176 let context_wrapper = UnitContextWrapper {
177 parent_context: Some(main_unit_context.clone()),
178 context: ctx,
179 };
180
181 Ok(Self {
182 context_wrapper: Some(Arc::new(context_wrapper)),
183 context_data: context_user_data,
184 })
185 } else {
186 let context_data = Box::new(ContextData {
189 request_handler: None,
190 unit_is_ready: false,
191 panic_payload: None,
192 });
193
194 let context_user_data = Box::into_raw(context_data);
195
196 let ctx = unsafe {
197 let mut init: nxt_unit_init_t = std::mem::zeroed();
198 init.callbacks.request_handler = Some(request_handler);
199 init.callbacks.ready_handler = Some(ready_handler);
200
201 init.ctx_data = context_user_data as *mut c_void;
202
203 nxt_unit_init(&mut init)
204 };
205
206 let ctx = match NonNull::new(ctx) {
207 Some(ctx) => ctx,
208 None => {
209 *main_context = MainContext::InitFailed(UnitInitError);
210 return Err(UnitInitError);
211 }
212 };
213
214 loop {
216 let rc = unsafe { nxt_unit::nxt_unit_run_once(ctx.as_ptr()) };
217
218 if rc != nxt_unit::NXT_UNIT_OK as i32 {
219 *main_context = MainContext::InitFailed(UnitInitError);
220 return Err(UnitInitError);
221 }
222
223 unsafe {
227 let context_data = (*ctx.as_ptr()).data as *mut ContextData;
228 let context_data = &mut *context_data;
229
230 if context_data.unit_is_ready {
231 break;
232 }
233 }
234 }
235
236 let context_wrapper = Arc::new(UnitContextWrapper {
237 parent_context: None,
238 context: ctx,
239 });
240
241 *main_context = MainContext::Initialized(Arc::downgrade(&context_wrapper));
244
245 Ok(Self {
246 context_wrapper: Some(context_wrapper),
247 context_data: context_user_data,
248 })
249 }
250 }
251
252 fn context_data_mut(&mut self) -> &mut ContextData {
253 unsafe { &mut *self.context_data }
256 }
257
258 pub fn set_request_handler(&mut self, f: impl UnitService + 'static) {
266 if self.context_wrapper.is_none() {
267 return;
268 }
269 self.context_data_mut().request_handler = Some(Box::new(f))
270 }
271
272 pub fn run(&mut self) {
278 if let Some(context_wrapper) = &self.context_wrapper {
279 unsafe {
283 nxt_unit_run(context_wrapper.context.as_ptr());
284 }
285
286 if let Some(panic_payload) = self.context_data_mut().panic_payload.take() {
289 std::panic::resume_unwind(panic_payload);
290 }
291 }
292 }
293}
294
295struct UnitContextWrapper {
297 parent_context: Option<Arc<UnitContextWrapper>>,
298 context: NonNull<nxt_unit_ctx_t>,
299}
300
301impl Drop for UnitContextWrapper {
302 fn drop(&mut self) {
303 unsafe {
309 nxt_unit_done(self.context.as_ptr());
310 }
311
312 drop(self.parent_context.take());
314 }
315}
316
317impl Drop for Unit {
318 fn drop(&mut self) {
319 unsafe {
322 drop(Box::from_raw(self.context_data));
323 }
324
325 drop(self.context_wrapper.take());
327 }
328}
329
330pub trait UnitService {
336 fn handle_request(&mut self, req: Request) -> UnitResult<()>;
337}
338
339impl<F> UnitService for F
340where
341 F: FnMut(Request) -> UnitResult<()> + 'static,
342{
343 fn handle_request(&mut self, req: Request) -> UnitResult<()> {
344 self(req)
345 }
346}