1use dom_struct::dom_struct;
6use js::context::JSContext;
7use js::jsapi::{Heap, JSObject};
8use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue};
9use script_bindings::error::ErrorResult;
10use script_bindings::reflector::{Reflector, reflect_dom_object};
11use script_bindings::root::DomRoot;
12use script_bindings::script_runtime::CanGc;
13use servo_base::generic_channel::GenericSender;
14use servo_base::id::ServiceWorkerId;
15use servo_constellation_traits::ServiceWorkerMsg;
16use servo_url::ServoUrl;
17
18use crate::dom::bindings::codegen::Bindings::ClientBinding::{ClientMethods, FrameType};
19use crate::dom::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
20use crate::dom::bindings::error::Error;
21use crate::dom::bindings::reflector::DomGlobal;
22use crate::dom::bindings::str::{DOMString, USVString};
23use crate::dom::bindings::structuredclone;
24use crate::dom::bindings::trace::RootedTraceableBox;
25use crate::dom::globalscope::GlobalScope;
26
27#[dom_struct]
28pub(crate) struct Client {
29 reflector_: Reflector,
30
31 #[no_trace]
34 swmanager_sender: GenericSender<ServiceWorkerMsg>,
35
36 #[no_trace]
37 url: ServoUrl,
38
39 frame_type: FrameType,
41
42 #[no_trace]
43 worker_id: ServiceWorkerId,
44}
45
46impl Client {
47 fn new_inherited(
48 swmanager_sender: GenericSender<ServiceWorkerMsg>,
49 url: ServoUrl,
50 frame_type: FrameType,
51 worker_id: ServiceWorkerId,
52 ) -> Client {
53 Client {
54 reflector_: Reflector::new(),
55 swmanager_sender,
56 url,
57 frame_type,
58 worker_id,
59 }
60 }
61
62 pub(crate) fn new(
63 global: &GlobalScope,
64 swmanager_sender: GenericSender<ServiceWorkerMsg>,
65 url: ServoUrl,
66 frame_type: FrameType,
67 worker_id: ServiceWorkerId,
68 can_gc: CanGc,
69 ) -> DomRoot<Client> {
70 reflect_dom_object(
71 Box::new(Client::new_inherited(
72 swmanager_sender,
73 url,
74 frame_type,
75 worker_id,
76 )),
77 global,
78 can_gc,
79 )
80 }
81
82 fn post_message_impl(
84 &self,
85 cx: &mut JSContext,
86 message: HandleValue,
87 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
88 ) -> ErrorResult {
89 let global = self.reflector_.global();
94
95 let origin = global.origin();
98
99 let data = structuredclone::write(cx, message, Some(transfer))?;
100 self.swmanager_sender
101 .send(ServiceWorkerMsg::ForwardWorkerMessage {
102 data,
103 source: self.worker_id,
104 url: self.url.clone(),
105 origin: origin.immutable().clone(),
106 })
107 .map_err(|_| {
108 Error::Type(c"Failed to send message to service worker manager".to_owned())
109 })
110 }
111}
112
113impl ClientMethods<crate::DomTypeHolder> for Client {
114 fn PostMessage(
116 &self,
117 cx: &mut JSContext,
118 message: HandleValue,
119 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
120 ) -> ErrorResult {
121 self.post_message_impl(cx, message, transfer)
122 }
123
124 fn PostMessage_(
126 &self,
127 cx: &mut JSContext,
128 message: HandleValue,
129 options: RootedTraceableBox<StructuredSerializeOptions>,
130 ) -> ErrorResult {
131 let mut rooted = CustomAutoRooter::new(
132 options
133 .transfer
134 .iter()
135 .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
136 .collect(),
137 );
138 #[expect(unsafe_code)]
139 let guard = unsafe { CustomAutoRooterGuard::new(cx.raw_cx(), &mut rooted) };
140 self.post_message_impl(cx, message, guard)
141 }
142
143 fn Url(&self) -> USVString {
145 USVString(self.url.as_str().to_owned())
146 }
147
148 fn FrameType(&self) -> FrameType {
150 self.frame_type
151 }
152
153 fn Id(&self) -> DOMString {
155 format!("{}", self.worker_id).into()
156 }
157}