1use nnsdk::web::offlinewebsession::*;
2use std::ffi::CString;
3
4use crate::PageResult;
5
6pub use nnsdk::web::{
7 offlinewebsession::OfflineWebSession, OfflineBackgroundKind as Background,
8 OfflineBootDisplayKind as BootDisplay, WebSessionBootMode as Visibility,
9};
10
11extern "C" {
12 #[link_name = "\u{1}_ZN2nn3web17OfflineWebSession11RequestExitEv"]
13 pub fn request_exit(session: &OfflineWebSession);
14}
15
16pub struct WebSession(pub(crate) OfflineWebSession);
17
18impl WebSession {
19 pub fn send(&self, message: &str) {
21 let len = message.len() + 1;
22 let message = CString::new(message).unwrap();
23
24 while unsafe { !TrySendContentMessage(&self.0, message.as_ptr() as _, len) } {}
25 }
26
27 pub fn try_send(&self, message: &str) -> bool {
29 let len = message.len() + 1;
30 let message = CString::new(message).unwrap();
31
32 unsafe { TrySendContentMessage(&self.0, message.as_ptr() as _, len) }
33 }
34
35 pub fn recv(&self) -> String {
39 self.recv_max(0x10000)
40 }
41
42 pub fn recv_max(&self, max_size: usize) -> String {
44 let mut buffer = vec![0u8; max_size];
45
46 loop {
47 if let Some(size) = self.inner_recv(&mut buffer) {
48 if size != 0 {
49 buffer.truncate(size - 1);
50 buffer.shrink_to_fit();
51 let message = String::from_utf8(buffer).map(|string| string).unwrap();
52
53 break message;
54 }
55 }
56 }
57 }
58
59 pub fn try_recv(&self) -> Option<String> {
63 self.try_recv_max(0x10000)
64 }
65
66 pub fn try_recv_max(&self, max_size: usize) -> Option<String> {
68 let mut buffer = vec![0u8; max_size];
69
70 self.inner_recv(&mut buffer)
71 .map(|size| {
72 if size != 0 {
73 buffer.truncate(size - 1);
74 buffer.shrink_to_fit();
75 String::from_utf8(buffer).map(|string| string).ok()
76 } else {
77 None
78 }
79 })
80 .flatten()
81 }
82
83 fn inner_recv<T: AsMut<[u8]>>(&self, buffer: &mut T) -> Option<usize> {
84 let buffer = buffer.as_mut();
85 let mut out_size = 0;
86
87 unsafe {
88 if skyline::nn::web::offlinewebsession::TryReceiveContentMessage(
89 &self.0,
90 &mut out_size,
91 buffer.as_mut_ptr(),
92 buffer.len(),
93 ) != false
94 {
95 Some(out_size)
96 } else {
97 None
98 }
99 }
100 }
101
102 pub fn show(&self) {
104 unsafe { Appear(&self.0) };
105 }
106
107 pub fn wait_for_exit(&self) -> PageResult {
109 let return_value = PageResult::new();
110 unsafe { WaitForExit(&self.0, return_value.as_ref()) };
111 return_value
112 }
113
114 pub fn exit(&self) {
116 unsafe { request_exit(&self.0); }
117 }
118}
119
120
121
122#[cfg(feature = "json")]
123use serde::{de::DeserializeOwned, Serialize};
124
125#[cfg(feature = "json")]
126impl WebSession {
127 pub fn send_json<T: Serialize>(&self, obj: &T) {
129 self.send(&serde_json::to_string(obj).unwrap())
130 }
131
132 pub fn try_send_json<T: Serialize>(&self, obj: &T) -> bool {
134 self.try_send(&serde_json::to_string(obj).unwrap())
135 }
136
137 pub fn recv_json<T: DeserializeOwned>(&self) -> serde_json::Result<T> {
139 serde_json::from_str(&self.recv())
140 }
141
142 pub fn try_recv_json<T: DeserializeOwned>(&self) -> Option<serde_json::Result<T>> {
144 self.try_recv().map(|msg| serde_json::from_str(&msg))
145 }
146
147 pub fn recv_json_max<T: DeserializeOwned>(&self, max_size: usize) -> serde_json::Result<T> {
150 serde_json::from_str(&self.recv_max(max_size))
151 }
152
153 pub fn try_recv_json_max<T: DeserializeOwned>(
156 &self,
157 max_size: usize,
158 ) -> Option<serde_json::Result<T>> {
159 self.try_recv_max(max_size)
160 .map(|msg| serde_json::from_str(&msg))
161 }
162}