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