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 pub(crate) fn new_inherited(
88 peer_connection: &RTCPeerConnection,
89 label: USVString,
90 options: &RTCDataChannelInit,
91 servo_media_id: Option<DataChannelId>,
92 ) -> RTCDataChannel {
93 let mut init: DataChannelInit = options.convert();
94 init.label = label.to_string();
95
96 let controller = peer_connection.get_webrtc_controller().borrow();
97 let servo_media_id = servo_media_id.unwrap_or(
98 controller
99 .as_ref()
100 .unwrap()
101 .create_data_channel(init)
102 .expect("Expected data channel id"),
103 );
104
105 RTCDataChannel {
106 eventtarget: EventTarget::new_inherited(),
107 label,
108 ordered: options.ordered,
109 max_packet_life_time: options.maxPacketLifeTime,
110 max_retransmits: options.maxRetransmits,
111 protocol: options.protocol.clone(),
112 negotiated: options.negotiated,
113 id: options.id,
114 ready_state: Cell::new(RTCDataChannelState::Connecting),
115 binary_type: DomRefCell::new(DOMString::from("blob")),
116 peer_connection: Dom::from_ref(peer_connection),
117 droppable: DroppableRTCDataChannel::new(WeakRef::new(peer_connection), servo_media_id),
118 }
119 }
120
121 pub(crate) fn new(
122 global: &GlobalScope,
123 peer_connection: &RTCPeerConnection,
124 label: USVString,
125 options: &RTCDataChannelInit,
126 servo_media_id: Option<DataChannelId>,
127 can_gc: CanGc,
128 ) -> DomRoot<RTCDataChannel> {
129 let rtc_data_channel = reflect_dom_object(
130 Box::new(RTCDataChannel::new_inherited(
131 peer_connection,
132 label,
133 options,
134 servo_media_id,
135 )),
136 global,
137 can_gc,
138 );
139
140 peer_connection
141 .register_data_channel(rtc_data_channel.get_servo_media_id(), &rtc_data_channel);
142
143 rtc_data_channel
144 }
145
146 pub(crate) fn get_servo_media_id(&self) -> DataChannelId {
147 self.droppable.get_servo_media_id()
148 }
149
150 pub(crate) fn on_open(&self, can_gc: CanGc) {
151 let event = Event::new(
152 &self.global(),
153 atom!("open"),
154 EventBubbles::DoesNotBubble,
155 EventCancelable::NotCancelable,
156 can_gc,
157 );
158 event.upcast::<Event>().fire(self.upcast(), can_gc);
159 }
160
161 pub(crate) fn on_close(&self, can_gc: CanGc) {
162 let event = Event::new(
163 &self.global(),
164 atom!("close"),
165 EventBubbles::DoesNotBubble,
166 EventCancelable::NotCancelable,
167 can_gc,
168 );
169 event.upcast::<Event>().fire(self.upcast(), can_gc);
170
171 self.peer_connection
172 .unregister_data_channel(&self.get_servo_media_id());
173 }
174
175 pub(crate) fn on_error(&self, error: WebRtcError, can_gc: CanGc) {
176 let global = self.global();
177 let window = global.as_window();
178 let cx = GlobalScope::get_cx();
179 let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get());
180 let init = RTCErrorInit {
181 errorDetail: RTCErrorDetailType::Data_channel_failure,
182 httpRequestStatusCode: None,
183 receivedAlert: None,
184 sctpCauseCode: None,
185 sdpLineNumber: None,
186 sentAlert: None,
187 };
188 let message = match error {
189 WebRtcError::Backend(message) => DOMString::from(message),
190 };
191 let error = RTCError::new(window, &init, message, can_gc);
192 let event = RTCErrorEvent::new(window, atom!("error"), false, false, &error, can_gc);
193 event.upcast::<Event>().fire(self.upcast(), can_gc);
194 }
195
196 #[expect(unsafe_code)]
197 pub(crate) fn on_message(&self, channel_message: DataChannelMessage, can_gc: CanGc) {
198 let global = self.global();
199 let cx = GlobalScope::get_cx();
200 let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get());
201 rooted!(in(*cx) let mut message = UndefinedValue());
202
203 match channel_message {
204 DataChannelMessage::Text(text) => {
205 text.safe_to_jsval(cx, message.handle_mut(), can_gc);
206 },
207 DataChannelMessage::Binary(data) => {
208 let binary_type = self.binary_type.borrow();
209 match_domstring_ascii!(binary_type,
210 "blob" => {
211 let blob = Blob::new(
212 &global,
213 BlobImpl::new_from_bytes(data, "".to_owned()),
214 can_gc,
215 );
216 blob.safe_to_jsval(cx, message.handle_mut(), can_gc);
217 },
218 "arraybuffer" => {
219 rooted!(in(*cx) let mut array_buffer = ptr::null_mut::<JSObject>());
220 unsafe {
221 assert!(
222 ArrayBuffer::create(
223 *cx,
224 CreateWith::Slice(&data),
225 array_buffer.handle_mut()
226 )
227 .is_ok()
228 )
229 };
230 (*array_buffer).safe_to_jsval(cx, message.handle_mut(), can_gc);
231 },
232 _ => unreachable!(),)
233 },
234 }
235
236 MessageEvent::dispatch_jsval(
237 self.upcast(),
238 &global,
239 message.handle(),
240 Some(&global.origin().immutable().ascii_serialization()),
241 None,
242 vec![],
243 can_gc,
244 );
245 }
246
247 pub(crate) fn on_state_change(&self, state: DataChannelState, can_gc: CanGc) {
248 if let DataChannelState::Closing = state {
249 let event = Event::new(
250 &self.global(),
251 atom!("closing"),
252 EventBubbles::DoesNotBubble,
253 EventCancelable::NotCancelable,
254 can_gc,
255 );
256 event.upcast::<Event>().fire(self.upcast(), can_gc);
257 };
258 self.ready_state.set(state.convert());
259 }
260
261 fn send(&self, source: &SendSource) -> Fallible<()> {
262 if self.ready_state.get() != RTCDataChannelState::Open {
263 return Err(Error::InvalidState(None));
264 }
265
266 let message = match source {
267 SendSource::String(string) => DataChannelMessage::Text(string.0.clone()),
268 SendSource::Blob(blob) => {
269 DataChannelMessage::Binary(blob.get_bytes().unwrap_or(vec![]))
270 },
271 SendSource::ArrayBuffer(array) => DataChannelMessage::Binary(array.to_vec()),
272 SendSource::ArrayBufferView(array) => DataChannelMessage::Binary(array.to_vec()),
273 };
274
275 let controller = self.peer_connection.get_webrtc_controller().borrow();
276 controller
277 .as_ref()
278 .unwrap()
279 .send_data_channel_message(&self.get_servo_media_id(), message);
280
281 Ok(())
282 }
283}
284
285enum SendSource<'a, 'b> {
286 String(&'a USVString),
287 Blob(&'a Blob),
288 ArrayBuffer(CustomAutoRooterGuard<'b, ArrayBuffer>),
289 ArrayBufferView(CustomAutoRooterGuard<'b, ArrayBufferView>),
290}
291
292impl RTCDataChannelMethods<crate::DomTypeHolder> for RTCDataChannel {
293 event_handler!(open, GetOnopen, SetOnopen);
295 event_handler!(
297 bufferedamountlow,
298 GetOnbufferedamountlow,
299 SetOnbufferedamountlow
300 );
301 event_handler!(error, GetOnerror, SetOnerror);
303 event_handler!(closing, GetOnclosing, SetOnclosing);
305 event_handler!(close, GetOnclose, SetOnclose);
307 event_handler!(message, GetOnmessage, SetOnmessage);
309
310 fn Label(&self) -> USVString {
312 self.label.clone()
313 }
314 fn Ordered(&self) -> bool {
316 self.ordered
317 }
318
319 fn GetMaxPacketLifeTime(&self) -> Option<u16> {
321 self.max_packet_life_time
322 }
323
324 fn GetMaxRetransmits(&self) -> Option<u16> {
326 self.max_retransmits
327 }
328
329 fn Protocol(&self) -> USVString {
331 self.protocol.clone()
332 }
333
334 fn Negotiated(&self) -> bool {
336 self.negotiated
337 }
338
339 fn GetId(&self) -> Option<u16> {
341 self.id
342 }
343
344 fn ReadyState(&self) -> RTCDataChannelState {
346 self.ready_state.get()
347 }
348
349 fn Close(&self) {
358 let controller = self.peer_connection.get_webrtc_controller().borrow();
359 controller
360 .as_ref()
361 .unwrap()
362 .close_data_channel(&self.get_servo_media_id());
363 }
364
365 fn BinaryType(&self) -> DOMString {
367 self.binary_type.borrow().clone()
368 }
369
370 fn SetBinaryType(&self, value: DOMString) -> Fallible<()> {
372 if value != "blob" || value != "arraybuffer" {
373 return Err(Error::Syntax(None));
374 }
375 *self.binary_type.borrow_mut() = value;
376 Ok(())
377 }
378
379 fn Send(&self, data: USVString) -> Fallible<()> {
381 self.send(&SendSource::String(&data))
382 }
383
384 fn Send_(&self, data: &Blob) -> Fallible<()> {
386 self.send(&SendSource::Blob(data))
387 }
388
389 fn Send__(&self, data: CustomAutoRooterGuard<ArrayBuffer>) -> Fallible<()> {
391 self.send(&SendSource::ArrayBuffer(data))
392 }
393
394 fn Send___(&self, data: CustomAutoRooterGuard<ArrayBufferView>) -> Fallible<()> {
396 self.send(&SendSource::ArrayBufferView(data))
397 }
398}
399
400impl Convert<DataChannelInit> for &RTCDataChannelInit {
401 fn convert(self) -> DataChannelInit {
402 DataChannelInit {
403 label: String::new(),
404 id: self.id,
405 max_packet_life_time: self.maxPacketLifeTime,
406 max_retransmits: self.maxRetransmits,
407 negotiated: self.negotiated,
408 ordered: self.ordered,
409 protocol: self.protocol.to_string(),
410 }
411 }
412}
413
414impl Convert<RTCDataChannelState> for DataChannelState {
415 fn convert(self) -> RTCDataChannelState {
416 match self {
417 DataChannelState::Connecting | DataChannelState::__Unknown(_) => {
418 RTCDataChannelState::Connecting
419 },
420 DataChannelState::Open => RTCDataChannelState::Open,
421 DataChannelState::Closing => RTCDataChannelState::Closing,
422 DataChannelState::Closed => RTCDataChannelState::Closed,
423 }
424 }
425}