1use std::time::Duration;
4
5use crate::{CallbackMessage, Context, State, Value};
6
7use crate::{ArmaCallContext, Caller, Mission, Server, Source};
8
9pub struct Extension(crate::Extension);
11
12const BUFFER_SIZE: libc::size_t = 10240; #[derive(Debug, PartialEq, Eq)]
15pub enum Result<T, E> {
17 Ok(T),
19 Err(E),
21 Continue,
23 Timeout,
25}
26
27impl<T, E> Result<T, E> {
28 pub const fn is_ok(&self) -> bool {
30 matches!(self, Self::Ok(_))
31 }
32
33 pub const fn is_err(&self) -> bool {
35 matches!(self, Self::Err(_))
36 }
37
38 pub const fn is_continue(&self) -> bool {
40 matches!(self, Self::Continue)
41 }
42
43 pub const fn is_timeout(&self) -> bool {
45 matches!(self, Self::Timeout)
46 }
47}
48
49impl Extension {
50 #[must_use]
51 pub const fn new(ext: crate::Extension) -> Self {
53 Self(ext)
54 }
55
56 #[must_use]
57 pub fn context(&self) -> Context {
59 self.0.context().with_buffer_size(BUFFER_SIZE)
60 }
61
62 #[must_use]
63 pub fn state(&self) -> &State {
65 &self.0.group.state
66 }
67
68 #[must_use]
69 #[allow(clippy::too_many_arguments)]
70 pub fn call_with_context(
75 &self,
76 function: &str,
77 args: Option<Vec<String>>,
78 caller: Caller,
79 source: Source,
80 mission: Mission,
81 server: Server,
82 remote_exec_owner: i16,
83 ) -> (String, libc::c_int) {
84 self.0.context_manager.replace(Some(ArmaCallContext::new(
85 caller,
86 source,
87 mission,
88 server,
89 remote_exec_owner,
90 )));
91 unsafe { self.handle_call(function, args) }
92 }
93
94 #[must_use]
95 pub fn call(&self, function: &str, args: Option<Vec<String>>) -> (String, libc::c_int) {
103 self.0.context_manager.replace(None);
104 unsafe { self.handle_call(function, args) }
105 }
106
107 unsafe fn handle_call(
108 &self,
109 function: &str,
110 args: Option<Vec<String>>,
111 ) -> (String, libc::c_int) {
112 let mut output = [0; BUFFER_SIZE];
113 let len = args.as_ref().map(|a| a.len().try_into().unwrap());
114 let mut args_pointer = args.map(|v| {
115 v.into_iter()
116 .map(|s| std::ffi::CString::new(s).unwrap().into_raw())
117 .collect::<Vec<*mut i8>>()
118 });
119 let res = self.0.group.handle(
120 self.context(),
121 &self.0.context_manager,
122 function,
123 output.as_mut_ptr(),
124 BUFFER_SIZE,
125 args_pointer.as_mut().map(Vec::as_mut_ptr),
126 len,
127 );
128 if let Some(args) = args_pointer {
129 for arg in args {
130 let _ = unsafe { std::ffi::CString::from_raw(arg) };
131 }
132 }
133 (
134 std::ffi::CStr::from_ptr(output.as_ptr())
135 .to_str()
136 .unwrap()
137 .to_string(),
138 res,
139 )
140 }
141
142 pub fn callback_handler<F, T, E>(&self, handler: F, timeout: Duration) -> Result<T, E>
151 where
152 F: Fn(&str, &str, Option<Value>) -> Result<T, E>,
153 {
154 let (_, rx) = &self.0.callback_channel;
155 let deadline = std::time::Instant::now() + timeout;
156 loop {
157 match rx.recv_deadline(deadline) {
158 Ok(CallbackMessage::Call(name, func, data)) => match handler(&name, &func, data) {
159 Result::Ok(value) => return Result::Ok(value),
160 Result::Err(error) => return Result::Err(error),
161 Result::Timeout => return Result::Timeout,
162 Result::Continue => {}
163 },
164 _ => return Result::Timeout,
165 }
166 }
167 }
168}