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