proxy_sdk/
hostcalls.rs

1#![allow(clippy::type_complexity)]
2
3use std::ptr::{null, null_mut, NonNull};
4use std::time::{Duration, SystemTime, UNIX_EPOCH};
5
6use crate::Status;
7
8#[repr(u32)]
9#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
10pub enum LogLevel {
11    Trace = 0,
12    Debug = 1,
13    Info = 2,
14    Warn = 3,
15    Error = 4,
16    Critical = 5,
17}
18
19#[repr(u32)]
20#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
21#[non_exhaustive]
22pub enum StreamType {
23    HttpRequest = 0,
24    HttpResponse = 1,
25    Downstream = 2,
26    Upstream = 3,
27}
28
29#[repr(u32)]
30#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
31#[non_exhaustive]
32pub enum BufferType {
33    HttpRequestBody = 0,
34    HttpResponseBody = 1,
35    DownstreamData = 2,
36    UpstreamData = 3,
37    HttpCallResponseBody = 4,
38    GrpcReceiveBuffer = 5,
39    VmConfiguration = 6,
40    PluginConfiguration = 7,
41    #[allow(dead_code)]
42    CallData = 8,
43}
44
45#[repr(u32)]
46#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
47#[non_exhaustive]
48#[allow(dead_code)]
49pub enum MapType {
50    HttpRequestHeaders = 0,
51    HttpRequestTrailers = 1,
52    HttpResponseHeaders = 2,
53    HttpResponseTrailers = 3,
54    GrpcReceiveInitialMetadata = 4,
55    GrpcReceiveTrailingMetadata = 5,
56    HttpCallResponseHeaders = 6,
57    HttpCallResponseTrailers = 7,
58}
59
60#[repr(u32)]
61#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
62#[non_exhaustive]
63pub enum MetricType {
64    Counter = 0,
65    Gauge = 1,
66    Histogram = 2,
67}
68
69extern "C" {
70    pub fn proxy_log(level: LogLevel, message_data: *const u8, message_size: usize) -> Status;
71    pub fn proxy_get_log_level(return_level: *mut LogLevel) -> Status;
72    pub fn proxy_get_current_time_nanoseconds(return_time: *mut u64) -> Status;
73    pub fn proxy_set_tick_period_milliseconds(period: u32) -> Status;
74    pub fn proxy_get_buffer_bytes(
75        buffer_type: BufferType,
76        start: usize,
77        max_size: usize,
78        return_buffer_data: *mut *mut u8,
79        return_buffer_size: *mut usize,
80    ) -> Status;
81    pub fn proxy_set_buffer_bytes(
82        buffer_type: BufferType,
83        start: usize,
84        size: usize,
85        buffer_data: *const u8,
86        buffer_size: usize,
87    ) -> Status;
88    pub fn proxy_get_header_map_pairs(
89        map_type: MapType,
90        return_map_data: *mut *mut u8,
91        return_map_size: *mut usize,
92    ) -> Status;
93    pub fn proxy_set_header_map_pairs(
94        map_type: MapType,
95        map_data: *const u8,
96        map_size: usize,
97    ) -> Status;
98    pub fn proxy_get_header_map_value(
99        map_type: MapType,
100        key_data: *const u8,
101        key_size: usize,
102        return_value_data: *mut *mut u8,
103        return_value_size: *mut usize,
104    ) -> Status;
105    pub fn proxy_replace_header_map_value(
106        map_type: MapType,
107        key_data: *const u8,
108        key_size: usize,
109        value_data: *const u8,
110        value_size: usize,
111    ) -> Status;
112    pub fn proxy_remove_header_map_value(
113        map_type: MapType,
114        key_data: *const u8,
115        key_size: usize,
116    ) -> Status;
117    pub fn proxy_add_header_map_value(
118        map_type: MapType,
119        key_data: *const u8,
120        key_size: usize,
121        value_data: *const u8,
122        value_size: usize,
123    ) -> Status;
124    pub fn proxy_get_property(
125        path_data: *const u8,
126        path_size: usize,
127        return_value_data: *mut *mut u8,
128        return_value_size: *mut usize,
129    ) -> Status;
130    pub fn proxy_set_property(
131        path_data: *const u8,
132        path_size: usize,
133        value_data: *const u8,
134        value_size: usize,
135    ) -> Status;
136    pub fn proxy_get_shared_data(
137        key_data: *const u8,
138        key_size: usize,
139        return_value_data: *mut *mut u8,
140        return_value_size: *mut usize,
141        return_cas: *mut u32,
142    ) -> Status;
143    pub fn proxy_set_shared_data(
144        key_data: *const u8,
145        key_size: usize,
146        value_data: *const u8,
147        value_size: usize,
148        cas: u32,
149    ) -> Status;
150    pub fn proxy_register_shared_queue(
151        name_data: *const u8,
152        name_size: usize,
153        return_id: *mut u32,
154    ) -> Status;
155    pub fn proxy_resolve_shared_queue(
156        vm_id_data: *const u8,
157        vm_id_size: usize,
158        name_data: *const u8,
159        name_size: usize,
160        return_id: *mut u32,
161    ) -> Status;
162    pub fn proxy_dequeue_shared_queue(
163        queue_id: u32,
164        return_value_data: *mut *mut u8,
165        return_value_size: *mut usize,
166    ) -> Status;
167    pub fn proxy_enqueue_shared_queue(
168        queue_id: u32,
169        value_data: *const u8,
170        value_size: usize,
171    ) -> Status;
172    pub fn proxy_continue_stream(stream_type: StreamType) -> Status;
173    pub fn proxy_close_stream(stream_type: StreamType) -> Status;
174    pub fn proxy_send_local_response(
175        status_code: u32,
176        status_code_details_data: *const u8,
177        status_code_details_size: usize,
178        body_data: *const u8,
179        body_size: usize,
180        headers_data: *const u8,
181        headers_size: usize,
182        grpc_status: i32,
183    ) -> Status;
184    pub fn proxy_http_call(
185        upstream_data: *const u8,
186        upstream_size: usize,
187        headers_data: *const u8,
188        headers_size: usize,
189        body_data: *const u8,
190        body_size: usize,
191        trailers_data: *const u8,
192        trailers_size: usize,
193        timeout: u32,
194        return_token: *mut u32,
195    ) -> Status;
196    pub fn proxy_grpc_call(
197        upstream_data: *const u8,
198        upstream_size: usize,
199        service_name_data: *const u8,
200        service_name_size: usize,
201        method_name_data: *const u8,
202        method_name_size: usize,
203        initial_metadata_data: *const u8,
204        initial_metadata_size: usize,
205        message_data_data: *const u8,
206        message_data_size: usize,
207        timeout: u32,
208        return_callout_id: *mut u32,
209    ) -> Status;
210    pub fn proxy_grpc_stream(
211        upstream_data: *const u8,
212        upstream_size: usize,
213        service_name_data: *const u8,
214        service_name_size: usize,
215        method_name_data: *const u8,
216        method_name_size: usize,
217        initial_metadata_data: *const u8,
218        initial_metadata_size: usize,
219        return_stream_id: *mut u32,
220    ) -> Status;
221    pub fn proxy_grpc_send(
222        token: u32,
223        message_ptr: *const u8,
224        message_len: usize,
225        end_stream: bool,
226    ) -> Status;
227    pub fn proxy_grpc_cancel(token_id: u32) -> Status;
228    pub fn proxy_grpc_close(token_id: u32) -> Status;
229    pub fn proxy_get_status(
230        return_code: *mut u32,
231        return_message_data: *mut *mut u8,
232        return_message_size: *mut usize,
233    ) -> Status;
234    pub fn proxy_set_effective_context(context_id: u32) -> Status;
235    pub fn proxy_call_foreign_function(
236        function_name_data: *const u8,
237        function_name_size: usize,
238        arguments_data: *const u8,
239        arguments_size: usize,
240        results_data: *mut *mut u8,
241        results_size: *mut usize,
242    ) -> Status;
243    pub fn proxy_done() -> Status;
244    pub fn proxy_define_metric(
245        metric_type: MetricType,
246        name_data: *const u8,
247        name_size: usize,
248        return_id: *mut u32,
249    ) -> Status;
250    pub fn proxy_get_metric(metric_id: u32, return_value: *mut u64) -> Status;
251    pub fn proxy_record_metric(metric_id: u32, value: u64) -> Status;
252    pub fn proxy_increment_metric(metric_id: u32, offset: i64) -> Status;
253}
254
255pub fn log(level: LogLevel, message: &str) -> Result<(), Status> {
256    unsafe {
257        match proxy_log(level, message.as_ptr(), message.len()) {
258            Status::Ok => Ok(()),
259            e => Err(e),
260        }
261    }
262}
263
264#[allow(dead_code)]
265pub fn get_log_level() -> Result<LogLevel, Status> {
266    let mut return_level = LogLevel::Trace;
267    unsafe {
268        match proxy_get_log_level(&mut return_level) {
269            Status::Ok => Ok(return_level),
270            e => Err(e),
271        }
272    }
273}
274
275pub fn get_current_time() -> Result<SystemTime, Status> {
276    let mut return_time = 0;
277    unsafe {
278        match proxy_get_current_time_nanoseconds(&mut return_time) {
279            Status::Ok => Ok(UNIX_EPOCH + Duration::from_nanos(return_time)),
280            e => Err(e),
281        }
282    }
283}
284
285pub fn set_tick_period(period: Duration) -> Result<(), Status> {
286    unsafe {
287        match proxy_set_tick_period_milliseconds(period.as_millis() as u32) {
288            Status::Ok => Ok(()),
289            e => Err(e),
290        }
291    }
292}
293
294pub fn get_buffer(
295    buffer_type: BufferType,
296    start: usize,
297    max_size: usize,
298) -> Result<Option<Vec<u8>>, Status> {
299    let mut return_data = null_mut();
300    let mut return_size = 0;
301    unsafe {
302        match proxy_get_buffer_bytes(
303            buffer_type,
304            start,
305            max_size,
306            &mut return_data,
307            &mut return_size,
308        ) {
309            Status::Ok => Ok(NonNull::new(return_data).map(|return_data| {
310                Vec::from_raw_parts(return_data.as_ptr(), return_size, return_size)
311            })),
312            Status::NotFound => Ok(None),
313            e => Err(e),
314        }
315    }
316}
317
318pub fn set_buffer(
319    buffer_type: BufferType,
320    start: usize,
321    size: usize,
322    value: &[u8],
323) -> Result<(), Status> {
324    unsafe {
325        match proxy_set_buffer_bytes(buffer_type, start, size, value.as_ptr(), value.len()) {
326            Status::Ok => Ok(()),
327            e => Err(e),
328        }
329    }
330}
331
332pub fn get_map(map_type: MapType) -> Result<Option<Vec<(String, Vec<u8>)>>, Status> {
333    unsafe {
334        let mut return_data = null_mut();
335        let mut return_size = 0;
336        match proxy_get_header_map_pairs(map_type, &mut return_data, &mut return_size) {
337            Status::Ok => NonNull::new(return_data)
338                .map(|return_data| {
339                    let serialized_map =
340                        Vec::from_raw_parts(return_data.as_ptr(), return_size, return_size);
341                    utils::deserialize_map_bytes(&serialized_map)
342                })
343                .transpose(),
344            Status::NotFound => Ok(None),
345            e => Err(e),
346        }
347    }
348}
349
350pub fn set_map(map_type: MapType, map: &[(&str, &[u8])]) -> Result<(), Status> {
351    let serialized_map = utils::serialize_map(map);
352    unsafe {
353        match proxy_set_header_map_pairs(map_type, serialized_map.as_ptr(), serialized_map.len()) {
354            Status::Ok => Ok(()),
355            e => Err(e),
356        }
357    }
358}
359
360pub fn get_map_value(map_type: MapType, key: &str) -> Result<Option<Vec<u8>>, Status> {
361    let mut return_data = null_mut();
362    let mut return_size = 0;
363    unsafe {
364        match proxy_get_header_map_value(
365            map_type,
366            key.as_ptr(),
367            key.len(),
368            &mut return_data,
369            &mut return_size,
370        ) {
371            Status::Ok => Ok(NonNull::new(return_data).map(|return_data| {
372                Vec::from_raw_parts(return_data.as_ptr(), return_size, return_size)
373            })),
374            Status::NotFound => Ok(None),
375            e => Err(e),
376        }
377    }
378}
379
380pub fn set_map_value(map_type: MapType, key: &str, value: Option<&[u8]>) -> Result<(), Status> {
381    unsafe {
382        if let Some(value) = value {
383            match proxy_replace_header_map_value(
384                map_type,
385                key.as_ptr(),
386                key.len(),
387                value.as_ptr(),
388                value.len(),
389            ) {
390                Status::Ok => Ok(()),
391                e => Err(e),
392            }
393        } else {
394            match proxy_remove_header_map_value(map_type, key.as_ptr(), key.len()) {
395                Status::Ok => Ok(()),
396                e => Err(e),
397            }
398        }
399    }
400}
401
402pub fn add_map_value(map_type: MapType, key: &str, value: &[u8]) -> Result<(), Status> {
403    unsafe {
404        match proxy_add_header_map_value(
405            map_type,
406            key.as_ptr(),
407            key.len(),
408            value.as_ptr(),
409            value.len(),
410        ) {
411            Status::Ok => Ok(()),
412            e => Err(e),
413        }
414    }
415}
416
417pub fn get_property<S: AsRef<str>>(
418    path: impl IntoIterator<Item = S>,
419) -> Result<Option<Vec<u8>>, Status> {
420    let serialized_path = utils::serialize_property_path(path);
421    let mut return_data = null_mut();
422    let mut return_size = 0;
423    unsafe {
424        match proxy_get_property(
425            serialized_path.as_ptr(),
426            serialized_path.len(),
427            &mut return_data,
428            &mut return_size,
429        ) {
430            Status::Ok => Ok(NonNull::new(return_data).map(|return_data| {
431                Vec::from_raw_parts(return_data.as_ptr(), return_size, return_size)
432            })),
433            Status::NotFound => Ok(None),
434            e => Err(e),
435        }
436    }
437}
438
439pub fn set_property<S: AsRef<str>>(
440    path: impl IntoIterator<Item = S>,
441    value: Option<impl AsRef<[u8]>>,
442) -> Result<(), Status> {
443    let serialized_path = utils::serialize_property_path(path);
444    let value = value.as_ref().map(|x| x.as_ref());
445    unsafe {
446        match proxy_set_property(
447            serialized_path.as_ptr(),
448            serialized_path.len(),
449            value.map_or(null(), |value| value.as_ptr()),
450            value.map_or(0, |value| value.len()),
451        ) {
452            Status::Ok => Ok(()),
453            e => Err(e),
454        }
455    }
456}
457
458pub fn get_shared_data(key: impl AsRef<str>) -> Result<(Option<Vec<u8>>, Option<u32>), Status> {
459    let mut return_data = null_mut();
460    let mut return_size = 0;
461    let mut return_cas = 0;
462    let key = key.as_ref();
463    unsafe {
464        match proxy_get_shared_data(
465            key.as_ptr(),
466            key.len(),
467            &mut return_data,
468            &mut return_size,
469            &mut return_cas,
470        ) {
471            Status::Ok => {
472                let cas = match return_cas {
473                    0 => None,
474                    cas => Some(cas),
475                };
476                Ok((
477                    NonNull::new(return_data).map(|return_data| {
478                        Vec::from_raw_parts(return_data.as_ptr(), return_size, return_size)
479                    }),
480                    cas,
481                ))
482            }
483            Status::NotFound => Ok((None, None)),
484            e => Err(e),
485        }
486    }
487}
488
489pub fn set_shared_data(
490    key: impl AsRef<str>,
491    value: Option<impl AsRef<[u8]>>,
492    cas: Option<u32>,
493) -> Result<(), Status> {
494    let key = key.as_ref();
495    let value = value.as_ref().map(|x| x.as_ref());
496    unsafe {
497        match proxy_set_shared_data(
498            key.as_ptr(),
499            key.len(),
500            value.map_or(null(), |value| value.as_ptr()),
501            value.map_or(0, |value| value.len()),
502            cas.unwrap_or(0),
503        ) {
504            Status::Ok => Ok(()),
505            e => Err(e),
506        }
507    }
508}
509
510pub fn register_shared_queue(name: impl AsRef<str>) -> Result<u32, Status> {
511    let name = name.as_ref();
512    unsafe {
513        let mut return_id = 0;
514        match proxy_register_shared_queue(name.as_ptr(), name.len(), &mut return_id) {
515            Status::Ok => Ok(return_id),
516            e => Err(e),
517        }
518    }
519}
520
521pub fn resolve_shared_queue(
522    vm_id: impl AsRef<str>,
523    name: impl AsRef<str>,
524) -> Result<Option<u32>, Status> {
525    let vm_id = vm_id.as_ref();
526    let name = name.as_ref();
527    let mut return_id = 0;
528    unsafe {
529        match proxy_resolve_shared_queue(
530            vm_id.as_ptr(),
531            vm_id.len(),
532            name.as_ptr(),
533            name.len(),
534            &mut return_id,
535        ) {
536            Status::Ok => Ok(Some(return_id)),
537            Status::NotFound => Ok(None),
538            e => Err(e),
539        }
540    }
541}
542
543pub fn dequeue_shared_queue(queue_id: u32) -> Result<Option<Vec<u8>>, Status> {
544    let mut return_data = null_mut();
545    let mut return_size = 0;
546    unsafe {
547        match proxy_dequeue_shared_queue(queue_id, &mut return_data, &mut return_size) {
548            Status::Ok => Ok(Some(Vec::from_raw_parts(
549                return_data,
550                return_size,
551                return_size,
552            ))),
553            Status::Empty => Ok(None),
554            e => Err(e),
555        }
556    }
557}
558
559pub fn enqueue_shared_queue(queue_id: u32, value: impl AsRef<[u8]>) -> Result<(), Status> {
560    let value = value.as_ref();
561    unsafe {
562        match proxy_enqueue_shared_queue(queue_id, value.as_ptr(), value.len()) {
563            Status::Ok => Ok(()),
564            e => Err(e),
565        }
566    }
567}
568
569pub fn resume_downstream() -> Result<(), Status> {
570    unsafe {
571        match proxy_continue_stream(StreamType::Downstream) {
572            Status::Ok => Ok(()),
573            e => Err(e),
574        }
575    }
576}
577
578pub fn resume_upstream() -> Result<(), Status> {
579    unsafe {
580        match proxy_continue_stream(StreamType::Upstream) {
581            Status::Ok => Ok(()),
582            e => Err(e),
583        }
584    }
585}
586
587pub fn resume_http_request() -> Result<(), Status> {
588    unsafe {
589        match proxy_continue_stream(StreamType::HttpRequest) {
590            Status::Ok => Ok(()),
591            e => Err(e),
592        }
593    }
594}
595
596pub fn resume_http_response() -> Result<(), Status> {
597    unsafe {
598        match proxy_continue_stream(StreamType::HttpResponse) {
599            Status::Ok => Ok(()),
600            e => Err(e),
601        }
602    }
603}
604
605pub fn close_downstream() -> Result<(), Status> {
606    unsafe {
607        match proxy_close_stream(StreamType::Downstream) {
608            Status::Ok => Ok(()),
609            e => Err(e),
610        }
611    }
612}
613pub fn close_upstream() -> Result<(), Status> {
614    unsafe {
615        match proxy_close_stream(StreamType::Upstream) {
616            Status::Ok => Ok(()),
617            e => Err(e),
618        }
619    }
620}
621
622pub fn reset_http_request() -> Result<(), Status> {
623    unsafe {
624        match proxy_close_stream(StreamType::HttpRequest) {
625            Status::Ok => Ok(()),
626            e => Err(e),
627        }
628    }
629}
630
631pub fn reset_http_response() -> Result<(), Status> {
632    unsafe {
633        match proxy_close_stream(StreamType::HttpResponse) {
634            Status::Ok => Ok(()),
635            e => Err(e),
636        }
637    }
638}
639
640pub fn send_http_response(
641    status_code: u32,
642    headers: &[(&str, &[u8])],
643    body: Option<&[u8]>,
644) -> Result<(), Status> {
645    let serialized_headers = utils::serialize_map(headers);
646    unsafe {
647        match proxy_send_local_response(
648            status_code,
649            null(),
650            0,
651            body.map_or(null(), |body| body.as_ptr()),
652            body.map_or(0, |body| body.len()),
653            serialized_headers.as_ptr(),
654            serialized_headers.len(),
655            -1,
656        ) {
657            Status::Ok => Ok(()),
658            e => Err(e),
659        }
660    }
661}
662
663pub fn dispatch_http_call(
664    upstream: &[u8],
665    headers: &[(&str, &[u8])],
666    body: Option<&[u8]>,
667    trailers: &[(&str, &[u8])],
668    timeout: Duration,
669) -> Result<u32, Status> {
670    let serialized_headers = utils::serialize_map(headers);
671    let serialized_trailers = utils::serialize_map(trailers);
672    let mut return_token = 0;
673    unsafe {
674        match proxy_http_call(
675            upstream.as_ptr(),
676            upstream.len(),
677            serialized_headers.as_ptr(),
678            serialized_headers.len(),
679            body.map_or(null(), |body| body.as_ptr()),
680            body.map_or(0, |body| body.len()),
681            serialized_trailers.as_ptr(),
682            serialized_trailers.len(),
683            timeout.as_millis() as u32,
684            &mut return_token,
685        ) {
686            Status::Ok => Ok(return_token),
687            e => Err(e),
688        }
689    }
690}
691
692pub fn dispatch_grpc_call(
693    upstream_name: &[u8],
694    service_name: &str,
695    method_name: &str,
696    initial_metadata: &[(&str, &[u8])],
697    message: Option<&[u8]>,
698    timeout: Duration,
699) -> Result<u32, Status> {
700    let mut return_callout_id = 0;
701    let serialized_initial_metadata = utils::serialize_map(initial_metadata);
702    unsafe {
703        match proxy_grpc_call(
704            upstream_name.as_ptr(),
705            upstream_name.len(),
706            service_name.as_ptr(),
707            service_name.len(),
708            method_name.as_ptr(),
709            method_name.len(),
710            serialized_initial_metadata.as_ptr(),
711            serialized_initial_metadata.len(),
712            message.map_or(null(), |message| message.as_ptr()),
713            message.map_or(0, |message| message.len()),
714            timeout.as_millis() as u32,
715            &mut return_callout_id,
716        ) {
717            Status::Ok => Ok(return_callout_id),
718            e => Err(e),
719        }
720    }
721}
722
723pub fn open_grpc_stream(
724    upstream_name: &[u8],
725    service_name: &str,
726    method_name: &str,
727    initial_metadata: &[(&str, &[u8])],
728) -> Result<u32, Status> {
729    let mut return_stream_id = 0;
730    let serialized_initial_metadata = utils::serialize_map(initial_metadata);
731    unsafe {
732        match proxy_grpc_stream(
733            upstream_name.as_ptr(),
734            upstream_name.len(),
735            service_name.as_ptr(),
736            service_name.len(),
737            method_name.as_ptr(),
738            method_name.len(),
739            serialized_initial_metadata.as_ptr(),
740            serialized_initial_metadata.len(),
741            &mut return_stream_id,
742        ) {
743            Status::Ok => Ok(return_stream_id),
744            e => Err(e),
745        }
746    }
747}
748
749pub fn send_grpc_stream_message(
750    token: u32,
751    message: Option<&[u8]>,
752    end_stream: bool,
753) -> Result<(), Status> {
754    unsafe {
755        match proxy_grpc_send(
756            token,
757            message.map_or(null(), |message| message.as_ptr()),
758            message.map_or(0, |message| message.len()),
759            end_stream,
760        ) {
761            Status::Ok => Ok(()),
762            e => Err(e),
763        }
764    }
765}
766
767pub fn cancel_grpc_call(token_id: u32) -> Result<(), Status> {
768    unsafe {
769        match proxy_grpc_cancel(token_id) {
770            Status::Ok => Ok(()),
771            e => Err(e),
772        }
773    }
774}
775
776pub fn cancel_grpc_stream(token_id: u32) -> Result<(), Status> {
777    unsafe {
778        match proxy_grpc_cancel(token_id) {
779            Status::Ok => Ok(()),
780            e => Err(e),
781        }
782    }
783}
784
785pub fn close_grpc_stream(token_id: u32) -> Result<(), Status> {
786    unsafe {
787        match proxy_grpc_close(token_id) {
788            Status::Ok => Ok(()),
789            e => Err(e),
790        }
791    }
792}
793
794pub fn get_grpc_status() -> Result<(u32, Option<String>), Status> {
795    let mut return_code = 0;
796    let mut return_data = null_mut();
797    let mut return_size = 0;
798    unsafe {
799        match proxy_get_status(&mut return_code, &mut return_data, &mut return_size) {
800            Status::Ok => Ok((
801                return_code,
802                NonNull::new(return_data).and_then(|return_data| {
803                    String::from_utf8(Vec::from_raw_parts(
804                        return_data.as_ptr(),
805                        return_size,
806                        return_size,
807                    ))
808                    .ok()
809                }),
810            )),
811            e => Err(e),
812        }
813    }
814}
815
816pub fn set_effective_context(context_id: u32) -> Result<(), Status> {
817    unsafe {
818        match proxy_set_effective_context(context_id) {
819            Status::Ok => Ok(()),
820            e => Err(e),
821        }
822    }
823}
824
825/// Calls a foreign function as defined by the proxy.
826pub fn call_foreign_function(
827    function_name: impl AsRef<str>,
828    arguments: Option<impl AsRef<[u8]>>,
829) -> Result<Option<Vec<u8>>, Status> {
830    let mut return_data = null_mut();
831    let mut return_size = 0;
832    let function_name = function_name.as_ref();
833    let arguments = arguments.as_ref().map(|x| x.as_ref());
834    unsafe {
835        match proxy_call_foreign_function(
836            function_name.as_ptr(),
837            function_name.len(),
838            arguments.map_or(null(), |arguments| arguments.as_ptr()),
839            arguments.map_or(0, |arguments| arguments.len()),
840            &mut return_data,
841            &mut return_size,
842        ) {
843            Status::Ok => Ok(NonNull::new(return_data).map(|return_data| {
844                Vec::from_raw_parts(return_data.as_ptr(), return_size, return_size)
845            })),
846            e => Err(e),
847        }
848    }
849}
850
851#[cfg(not(target_arch = "wasm32"))]
852lazy_static::lazy_static! {
853    static ref LIBRARY: libloading::os::unix::Library = libloading::os::unix::Library::this();
854    static ref PROXY_WRITE_UPSTREAM: Option<libloading::os::unix::Symbol<unsafe extern "C" fn(*const u8, usize) -> Status>> = unsafe { LIBRARY.get(b"proxy_write_upstream").ok() };
855    static ref PROXY_WRITE_DOWNSTREAM: Option<libloading::os::unix::Symbol<unsafe extern "C" fn(*const u8, usize) -> Status>> = unsafe { LIBRARY.get(b"proxy_write_downstream").ok() };
856}
857
858#[cfg(not(target_arch = "wasm32"))]
859pub fn write_upstream(buffer: &[u8]) -> Result<(), Status> {
860    let Some(proxy_write_upstream) = &*PROXY_WRITE_UPSTREAM else {
861        return Err(Status::InternalFailure);
862    };
863    match unsafe { proxy_write_upstream(buffer.as_ptr(), buffer.len()) } {
864        Status::Ok => Ok(()),
865        e => Err(e),
866    }
867}
868
869#[cfg(not(target_arch = "wasm32"))]
870pub fn write_downstream(buffer: &[u8]) -> Result<(), Status> {
871    let Some(proxy_write_downstream) = &*PROXY_WRITE_DOWNSTREAM else {
872        return Err(Status::InternalFailure);
873    };
874    match unsafe { proxy_write_downstream(buffer.as_ptr(), buffer.len()) } {
875        Status::Ok => Ok(()),
876        e => Err(e),
877    }
878}
879
880pub fn done() -> Result<(), Status> {
881    unsafe {
882        match proxy_done() {
883            Status::Ok => Ok(()),
884            e => Err(e),
885        }
886    }
887}
888
889pub fn define_metric(metric_type: MetricType, name: &str) -> Result<u32, Status> {
890    let mut return_id = 0;
891    unsafe {
892        match proxy_define_metric(metric_type, name.as_ptr(), name.len(), &mut return_id) {
893            Status::Ok => Ok(return_id),
894            e => Err(e),
895        }
896    }
897}
898
899pub fn get_metric(metric_id: u32) -> Result<u64, Status> {
900    let mut return_value = 0;
901    unsafe {
902        match proxy_get_metric(metric_id, &mut return_value) {
903            Status::Ok => Ok(return_value),
904            e => Err(e),
905        }
906    }
907}
908
909pub fn record_metric(metric_id: u32, value: u64) -> Result<(), Status> {
910    unsafe {
911        match proxy_record_metric(metric_id, value) {
912            Status::Ok => Ok(()),
913            e => Err(e),
914        }
915    }
916}
917
918pub fn increment_metric(metric_id: u32, offset: i64) -> Result<(), Status> {
919    unsafe {
920        match proxy_increment_metric(metric_id, offset) {
921            Status::Ok => Ok(()),
922            e => Err(e),
923        }
924    }
925}
926
927mod utils {
928    use super::Status;
929    use std::ops::Range;
930
931    pub(super) fn serialize_property_path<S: AsRef<str>>(
932        path: impl IntoIterator<Item = S>,
933    ) -> Vec<u8> {
934        let mut out = Vec::new();
935        for part in path {
936            out.extend_from_slice(part.as_ref().as_bytes());
937            out.push(0);
938        }
939        if !out.is_empty() {
940            out.pop();
941        }
942        out
943    }
944
945    pub(super) fn serialize_map(map: &[(&str, &[u8])]) -> Vec<u8> {
946        let mut size: usize = 4;
947        for (name, value) in map {
948            size += name.len() + value.len() + 10;
949        }
950        let mut bytes = Vec::with_capacity(size);
951        bytes.extend_from_slice(&(map.len() as u32).to_le_bytes());
952        for (name, value) in map {
953            bytes.extend_from_slice(&(name.len() as u32).to_le_bytes());
954            bytes.extend_from_slice(&(value.len() as u32).to_le_bytes());
955        }
956        for (name, value) in map {
957            bytes.extend_from_slice(name.as_bytes());
958            bytes.push(0);
959            bytes.extend_from_slice(value);
960            bytes.push(0);
961        }
962        bytes
963    }
964
965    pub(super) fn deserialize_map_bytes(bytes: &[u8]) -> Result<Vec<(String, Vec<u8>)>, Status> {
966        let mut map = Vec::new();
967        if bytes.is_empty() {
968            return Ok(map);
969        }
970        let get = |r: Range<usize>| bytes.get(r).ok_or(Status::ParseFailure);
971
972        let size = u32::from_le_bytes(get(0..4)?.try_into().unwrap()) as usize;
973        let mut p = 4 + size * 8;
974        for n in 0..size {
975            let s = 4 + n * 8;
976            let size = u32::from_le_bytes(get(s..s + 4)?.try_into().unwrap()) as usize;
977            let key = get(p..p + size)?;
978            p += size + 1;
979            let size = u32::from_le_bytes(get(s + 4..s + 8)?.try_into().unwrap()) as usize;
980            let value = get(p..p + size)?;
981            p += size + 1;
982            map.push((String::from_utf8(key.to_vec()).unwrap(), value.to_vec()));
983        }
984        Ok(map)
985    }
986}