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::weakref::WeakRef;
16use servo_media::webrtc::{
17 DataChannelId, DataChannelInit, DataChannelMessage, DataChannelState, WebRtcError,
18};
19
20use crate::conversions::Convert;
21use crate::dom::bindings::cell::DomRefCell;
22use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::{
23 RTCDataChannelInit, RTCDataChannelMethods, RTCDataChannelState,
24};
25use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::{RTCErrorDetailType, RTCErrorInit};
26use crate::dom::bindings::error::{Error, Fallible};
27use crate::dom::bindings::inheritance::Castable;
28use crate::dom::bindings::reflector::{DomGlobal, DomObject, reflect_dom_object};
29use crate::dom::bindings::root::{Dom, DomRoot};
30use crate::dom::bindings::str::{DOMString, USVString};
31use crate::dom::blob::Blob;
32use crate::dom::event::{Event, EventBubbles, EventCancelable};
33use crate::dom::eventtarget::EventTarget;
34use crate::dom::globalscope::GlobalScope;
35use crate::dom::messageevent::MessageEvent;
36use crate::dom::rtcerror::RTCError;
37use crate::dom::rtcerrorevent::RTCErrorEvent;
38use crate::dom::rtcpeerconnection::RTCPeerConnection;
39use crate::script_runtime::CanGc;
40
41#[derive(JSTraceable, MallocSizeOf)]
42struct DroppableRTCDataChannel {
43 #[ignore_malloc_size_of = "defined in servo-media"]
44 servo_media_id: DataChannelId,
45 peer_connection: WeakRef<RTCPeerConnection>,
46}
47
48impl DroppableRTCDataChannel {
49 fn new(peer_connection: WeakRef<RTCPeerConnection>, servo_media_id: DataChannelId) -> Self {
50 DroppableRTCDataChannel {
51 servo_media_id,
52 peer_connection,
53 }
54 }
55
56 pub(crate) fn get_servo_media_id(&self) -> DataChannelId {
57 self.servo_media_id
58 }
59}
60
61impl Drop for DroppableRTCDataChannel {
62 fn drop(&mut self) {
63 if let Some(root) = self.peer_connection.root() {
64 root.unregister_data_channel(&self.get_servo_media_id());
65 }
66 }
67}
68
69#[dom_struct]
70pub(crate) struct RTCDataChannel {
71 eventtarget: EventTarget,
72 label: USVString,
73 ordered: bool,
74 max_packet_life_time: Option<u16>,
75 max_retransmits: Option<u16>,
76 protocol: USVString,
77 negotiated: bool,
78 id: Option<u16>,
79 ready_state: Cell<RTCDataChannelState>,
80 binary_type: DomRefCell<DOMString>,
81 peer_connection: Dom<RTCPeerConnection>,
82 droppable: DroppableRTCDataChannel,
83}
84
85impl RTCDataChannel {
86 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
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 #[allow(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());
206 },
207 DataChannelMessage::Binary(data) => match &**self.binary_type.borrow() {
208 "blob" => {
209 let blob = Blob::new(
210 &global,
211 BlobImpl::new_from_bytes(data, "".to_owned()),
212 can_gc,
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,
222 CreateWith::Slice(&data),
223 array_buffer.handle_mut()
224 )
225 .is_ok()
226 )
227 };
228
229 (*array_buffer).safe_to_jsval(cx, message.handle_mut());
230 },
231 _ => unreachable!(),
232 },
233 }
234
235 MessageEvent::dispatch_jsval(
236 self.upcast(),
237 &global,
238 message.handle(),
239 Some(&global.origin().immutable().ascii_serialization()),
240 None,
241 vec![],
242 can_gc,
243 );
244 }
245
246 pub(crate) fn on_state_change(&self, state: DataChannelState, can_gc: CanGc) {
247 if let DataChannelState::Closing = state {
248 let event = Event::new(
249 &self.global(),
250 atom!("closing"),
251 EventBubbles::DoesNotBubble,
252 EventCancelable::NotCancelable,
253 can_gc,
254 );
255 event.upcast::<Event>().fire(self.upcast(), can_gc);
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);
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}