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