1use crate::{Message, Session, WebsocketConnection, prelude::*};
2use glib::translate::*;
3use std::boxed::Box as Box_;
4use std::pin::Pin;
5use std::ptr;
6
7mod sealed {
8 pub trait Sealed {}
9 impl<T: super::IsA<crate::Session>> Sealed for T {}
10}
11
12pub trait SessionExtManual: IsA<Session> + sealed::Sealed + 'static {
13 #[doc(alias = "soup_session_websocket_connect_async")]
14 fn websocket_connect_async<P: FnOnce(Result<WebsocketConnection, glib::Error>) + 'static>(
15 &self,
16 msg: &Message,
17 origin: Option<&str>,
18 protocols: &[&str],
19 io_priority: glib::Priority,
20 cancellable: Option<&impl IsA<gio::Cancellable>>,
21 callback: P,
22 ) {
23 let main_context = glib::MainContext::ref_thread_default();
24 let is_main_context_owner = main_context.is_owner();
25 let has_acquired_main_context = (!is_main_context_owner)
26 .then(|| main_context.acquire().ok())
27 .flatten();
28 assert!(
29 is_main_context_owner || has_acquired_main_context.is_some(),
30 "Async operations only allowed if the thread is owning the MainContext"
31 );
32
33 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
34 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
35 unsafe extern "C" fn websocket_connect_async_trampoline<
36 P: FnOnce(Result<WebsocketConnection, glib::Error>) + 'static,
37 >(
38 _source_object: *mut glib::gobject_ffi::GObject,
39 res: *mut gio::ffi::GAsyncResult,
40 user_data: glib::ffi::gpointer,
41 ) {
42 unsafe {
43 let mut error = ptr::null_mut();
44 let ret = ffi::soup_session_websocket_connect_finish(
45 _source_object as *mut _,
46 res,
47 &mut error,
48 );
49 let result = if error.is_null() {
50 Ok(from_glib_full(ret))
51 } else {
52 Err(from_glib_full(error))
53 };
54 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
55 Box_::from_raw(user_data as *mut _);
56 let callback = callback.into_inner();
57 callback(result);
58 }
59 }
60 let callback = websocket_connect_async_trampoline::<P>;
61 unsafe {
62 ffi::soup_session_websocket_connect_async(
63 self.as_ref().to_glib_none().0,
64 msg.to_glib_none().0,
65 origin.to_glib_none().0,
66 protocols.to_glib_none().0,
67 io_priority.into_glib(),
68 cancellable.map(|p| p.as_ref()).to_glib_none().0,
69 Some(callback),
70 Box_::into_raw(user_data) as *mut _,
71 );
72 }
73 }
74
75 fn websocket_connect_async_future(
76 &self,
77 msg: &Message,
78 origin: Option<&str>,
79 protocols: &[&str],
80 io_priority: glib::Priority,
81 ) -> Pin<
82 Box_<dyn std::future::Future<Output = Result<WebsocketConnection, glib::Error>> + 'static>,
83 > {
84 let msg = msg.clone();
85 let origin = origin.map(ToOwned::to_owned);
86 let protocols = protocols
87 .iter()
88 .copied()
89 .map(String::from)
90 .collect::<Vec<_>>();
91 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
92 let protocols = protocols.iter().map(|s| s.as_str()).collect::<Vec<_>>();
93 obj.websocket_connect_async(
94 &msg,
95 origin.as_ref().map(::std::borrow::Borrow::borrow),
96 &protocols,
97 io_priority,
98 Some(cancellable),
99 move |res| {
100 send.resolve(res);
101 },
102 );
103 }))
104 }
105}
106
107impl<O: IsA<Session>> SessionExtManual for O {}