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