1use std::cell::Cell;
6use std::ptr;
7
8use constellation_traits::BlobImpl;
9use dom_struct::dom_struct;
10use js::jsapi::{JSAutoRealm, JSObject};
11use js::jsval::UndefinedValue;
12use js::rust::CustomAutoRooterGuard;
13use js::typedarray::{ArrayBuffer, ArrayBufferView, CreateWith};
14use script_bindings::conversions::SafeToJSValConvertible;
15use script_bindings::match_domstring_ascii;
16use script_bindings::weakref::WeakRef;
17use servo_media::webrtc::{
18 DataChannelId, DataChannelInit, DataChannelMessage, DataChannelState, WebRtcError,
19};
20
21use crate::conversions::Convert;
22use crate::dom::bindings::cell::DomRefCell;
23use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::{
24 RTCDataChannelInit, RTCDataChannelMethods, RTCDataChannelState,
25};
26use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::{RTCErrorDetailType, RTCErrorInit};
27use crate::dom::bindings::error::{Error, Fallible};
28use crate::dom::bindings::inheritance::Castable;
29use crate::dom::bindings::reflector::{DomGlobal, DomObject, reflect_dom_object};
30use crate::dom::bindings::root::{Dom, DomRoot};
31use crate::dom::bindings::str::{DOMString, USVString};
32use crate::dom::blob::Blob;
33use crate::dom::event::{Event, EventBubbles, EventCancelable};
34use crate::dom::eventtarget::EventTarget;
35use crate::dom::globalscope::GlobalScope;
36use crate::dom::messageevent::MessageEvent;
37use crate::dom::rtcerror::RTCError;
38use crate::dom::rtcerrorevent::RTCErrorEvent;
39use crate::dom::rtcpeerconnection::RTCPeerConnection;
40use crate::script_runtime::CanGc;
41
42#[derive(JSTraceable, MallocSizeOf)]
43struct DroppableRTCDataChannel {
44 #[ignore_malloc_size_of = "defined in servo-media"]
45 servo_media_id: DataChannelId,
46 peer_connection: WeakRef<RTCPeerConnection>,
47}
48
49impl DroppableRTCDataChannel {
50 fn new(peer_connection: WeakRef<RTCPeerConnection>, servo_media_id: DataChannelId) -> Self {
51 DroppableRTCDataChannel {
52 servo_media_id,
53 peer_connection,
54 }
55 }
56
57 pub(crate) fn get_servo_media_id(&self) -> DataChannelId {
58 self.servo_media_id
59 }
60}
61
62impl Drop for DroppableRTCDataChannel {
63 fn drop(&mut self) {
64 if let Some(root) = self.peer_connection.root() {
65 root.unregister_data_channel(&self.get_servo_media_id());
66 }
67 }
68}
69
70#[dom_struct]
71pub(crate) struct RTCDataChannel {
72 eventtarget: EventTarget,
73 label: USVString,
74 ordered: bool,
75 max_packet_life_time: Option<u16>,
76 max_retransmits: Option<u16>,
77 protocol: USVString,
78 negotiated: bool,
79 id: Option<u16>,
80 ready_state: Cell<RTCDataChannelState>,
81 binary_type: DomRefCell<DOMString>,
82 peer_connection: Dom<RTCPeerConnection>,
83 droppable: DroppableRTCDataChannel,
84}
85
86impl RTCDataChannel {
87 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
88 pub(crate) fn new_inherited(
89 peer_connection: &RTCPeerConnection,
90 label: USVString,
91 options: &RTCDataChannelInit,
92 servo_media_id: Option<DataChannelId>,
93 ) -> RTCDataChannel {
94 let mut init: DataChannelInit = options.convert();
95 init.label = label.to_string();
96
97 let controller = peer_connection.get_webrtc_controller().borrow();
98 let servo_media_id = servo_media_id.unwrap_or(
99 controller
100 .as_ref()
101 .unwrap()
102 .create_data_channel(init)
103 .expect("Expected data channel id"),
104 );
105
106 RTCDataChannel {
107 eventtarget: EventTarget::new_inherited(),
108 label,
109 ordered: options.ordered,
110 max_packet_life_time: options.maxPacketLifeTime,
111 max_retransmits: options.maxRetransmits,
112 protocol: options.protocol.clone(),
113 negotiated: options.negotiated,
114 id: options.id,
115 ready_state: Cell::new(RTCDataChannelState::Connecting),
116 binary_type: DomRefCell::new(DOMString::from("blob")),
117 peer_connection: Dom::from_ref(peer_connection),
118 droppable: DroppableRTCDataChannel::new(WeakRef::new(peer_connection), servo_media_id),
119 }
120 }
121
122 pub(crate) fn new(
123 global: &GlobalScope,
124 peer_connection: &RTCPeerConnection,
125 label: USVString,
126 options: &RTCDataChannelInit,
127 servo_media_id: Option<DataChannelId>,
128 can_gc: CanGc,
129 ) -> DomRoot<RTCDataChannel> {
130 let rtc_data_channel = reflect_dom_object(
131 Box::new(RTCDataChannel::new_inherited(
132 peer_connection,
133 label,
134 options,
135 servo_media_id,
136 )),
137 global,
138 can_gc,
139 );
140
141 peer_connection
142 .register_data_channel(rtc_data_channel.get_servo_media_id(), &rtc_data_channel);
143
144 rtc_data_channel
145 }
146
147 pub(crate) fn get_servo_media_id(&self) -> DataChannelId {
148 self.droppable.get_servo_media_id()
149 }
150
151 pub(crate) fn on_open(&self, can_gc: CanGc) {
152 let event = Event::new(
153 &self.global(),
154 atom!("open"),
155 EventBubbles::DoesNotBubble,
156 EventCancelable::NotCancelable,
157 can_gc,
158 );
159 event.upcast::<Event>().fire(self.upcast(), can_gc);
160 }
161
162 pub(crate) fn on_close(&self, can_gc: CanGc) {
163 let event = Event::new(
164 &self.global(),
165 atom!("close"),
166 EventBubbles::DoesNotBubble,
167 EventCancelable::NotCancelable,
168 can_gc,
169 );
170 event.upcast::<Event>().fire(self.upcast(), can_gc);
171
172 self.peer_connection
173 .unregister_data_channel(&self.get_servo_media_id());
174 }
175
176 pub(crate) fn on_error(&self, error: WebRtcError, can_gc: CanGc) {
177 let global = self.global();
178 let window = global.as_window();
179 let cx = GlobalScope::get_cx();
180 let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get());
181 let init = RTCErrorInit {
182 errorDetail: RTCErrorDetailType::Data_channel_failure,
183 httpRequestStatusCode: None,
184 receivedAlert: None,
185 sctpCauseCode: None,
186 sdpLineNumber: None,
187 sentAlert: None,
188 };
189 let message = match error {
190 WebRtcError::Backend(message) => DOMString::from(message),
191 };
192 let error = RTCError::new(window, &init, message, can_gc);
193 let event = RTCErrorEvent::new(window, atom!("error"), false, false, &error, can_gc);
194 event.upcast::<Event>().fire(self.upcast(), can_gc);
195 }
196
197 #[expect(unsafe_code)]
198 pub(crate) fn on_message(&self, channel_message: DataChannelMessage, can_gc: CanGc) {
199 let global = self.global();
200 let cx = GlobalScope::get_cx();
201 let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get());
202 rooted!(in(*cx) let mut message = UndefinedValue());
203
204 match channel_message {
205 DataChannelMessage::Text(text) => {
206 text.safe_to_jsval(cx, message.handle_mut(), can_gc);
207 },
208 DataChannelMessage::Binary(data) => {
209 let binary_type = self.binary_type.borrow();
210 match_domstring_ascii!(binary_type,
211 "blob" => {
212 let blob = Blob::new(
213 &global,
214 BlobImpl::new_from_bytes(data, "".to_owned()),
215 can_gc,
216 );
217 blob.safe_to_jsval(cx, message.handle_mut(), can_gc);
218 },
219 "arraybuffer" => {
220 rooted!(in(*cx) let mut array_buffer = ptr::null_mut::<JSObject>());
221 unsafe {
222 assert!(
223 ArrayBuffer::create(
224 *cx,
225 CreateWith::Slice(&data),
226 array_buffer.handle_mut()
227 )
228 .is_ok()
229 )
230 };
231 (*array_buffer).safe_to_jsval(cx, message.handle_mut(), can_gc);
232 },
233 _ => unreachable!(),)
234 },
235 }
236
237 MessageEvent::dispatch_jsval(
238 self.upcast(),
239 &global,
240 message.handle(),
241 Some(&global.origin().immutable().ascii_serialization()),
242 None,
243 vec![],
244 can_gc,
245 );
246 }
247
248 pub(crate) fn on_state_change(&self, state: DataChannelState, can_gc: CanGc) {
249 if let DataChannelState::Closing = state {
250 let event = Event::new(
251 &self.global(),
252 atom!("closing"),
253 EventBubbles::DoesNotBubble,
254 EventCancelable::NotCancelable,
255 can_gc,
256 );
257 event.upcast::<Event>().fire(self.upcast(), can_gc);
258 };
259 self.ready_state.set(state.convert());
260 }
261
262 fn send(&self, source: &SendSource) -> Fallible<()> {
263 if self.ready_state.get() != RTCDataChannelState::Open {
264 return Err(Error::InvalidState(None));
265 }
266
267 let message = match source {
268 SendSource::String(string) => DataChannelMessage::Text(string.0.clone()),
269 SendSource::Blob(blob) => {
270 DataChannelMessage::Binary(blob.get_bytes().unwrap_or(vec![]))
271 },
272 SendSource::ArrayBuffer(array) => DataChannelMessage::Binary(array.to_vec()),
273 SendSource::ArrayBufferView(array) => DataChannelMessage::Binary(array.to_vec()),
274 };
275
276 let controller = self.peer_connection.get_webrtc_controller().borrow();
277 controller
278 .as_ref()
279 .unwrap()
280 .send_data_channel_message(&self.get_servo_media_id(), message);
281
282 Ok(())
283 }
284}
285
286enum SendSource<'a, 'b> {
287 String(&'a USVString),
288 Blob(&'a Blob),
289 ArrayBuffer(CustomAutoRooterGuard<'b, ArrayBuffer>),
290 ArrayBufferView(CustomAutoRooterGuard<'b, ArrayBufferView>),
291}
292
293impl RTCDataChannelMethods<crate::DomTypeHolder> for RTCDataChannel {
294 event_handler!(open, GetOnopen, SetOnopen);
296 event_handler!(
298 bufferedamountlow,
299 GetOnbufferedamountlow,
300 SetOnbufferedamountlow
301 );
302 event_handler!(error, GetOnerror, SetOnerror);
304 event_handler!(closing, GetOnclosing, SetOnclosing);
306 event_handler!(close, GetOnclose, SetOnclose);
308 event_handler!(message, GetOnmessage, SetOnmessage);
310
311 fn Label(&self) -> USVString {
313 self.label.clone()
314 }
315 fn Ordered(&self) -> bool {
317 self.ordered
318 }
319
320 fn GetMaxPacketLifeTime(&self) -> Option<u16> {
322 self.max_packet_life_time
323 }
324
325 fn GetMaxRetransmits(&self) -> Option<u16> {
327 self.max_retransmits
328 }
329
330 fn Protocol(&self) -> USVString {
332 self.protocol.clone()
333 }
334
335 fn Negotiated(&self) -> bool {
337 self.negotiated
338 }
339
340 fn GetId(&self) -> Option<u16> {
342 self.id
343 }
344
345 fn ReadyState(&self) -> RTCDataChannelState {
347 self.ready_state.get()
348 }
349
350 fn Close(&self) {
359 let controller = self.peer_connection.get_webrtc_controller().borrow();
360 controller
361 .as_ref()
362 .unwrap()
363 .close_data_channel(&self.get_servo_media_id());
364 }
365
366 fn BinaryType(&self) -> DOMString {
368 self.binary_type.borrow().clone()
369 }
370
371 fn SetBinaryType(&self, value: DOMString) -> Fallible<()> {
373 if value != "blob" || value != "arraybuffer" {
374 return Err(Error::Syntax(None));
375 }
376 *self.binary_type.borrow_mut() = value;
377 Ok(())
378 }
379
380 fn Send(&self, data: USVString) -> Fallible<()> {
382 self.send(&SendSource::String(&data))
383 }
384
385 fn Send_(&self, data: &Blob) -> Fallible<()> {
387 self.send(&SendSource::Blob(data))
388 }
389
390 fn Send__(&self, data: CustomAutoRooterGuard<ArrayBuffer>) -> Fallible<()> {
392 self.send(&SendSource::ArrayBuffer(data))
393 }
394
395 fn Send___(&self, data: CustomAutoRooterGuard<ArrayBufferView>) -> Fallible<()> {
397 self.send(&SendSource::ArrayBufferView(data))
398 }
399}
400
401impl Convert<DataChannelInit> for &RTCDataChannelInit {
402 fn convert(self) -> DataChannelInit {
403 DataChannelInit {
404 label: String::new(),
405 id: self.id,
406 max_packet_life_time: self.maxPacketLifeTime,
407 max_retransmits: self.maxRetransmits,
408 negotiated: self.negotiated,
409 ordered: self.ordered,
410 protocol: self.protocol.to_string(),
411 }
412 }
413}
414
415impl Convert<RTCDataChannelState> for DataChannelState {
416 fn convert(self) -> RTCDataChannelState {
417 match self {
418 DataChannelState::Connecting | DataChannelState::__Unknown(_) => {
419 RTCDataChannelState::Connecting
420 },
421 DataChannelState::Open => RTCDataChannelState::Open,
422 DataChannelState::Closing => RTCDataChannelState::Closing,
423 DataChannelState::Closed => RTCDataChannelState::Closed,
424 }
425 }
426}