mirror of
https://github.com/servo/servo.git
synced 2025-09-30 08:39:16 +01:00
script: Move WebRTC DOM interfaces to script/dom/webrtc/ (#39023)
Move interfaces defined by the WebRTC specification to the `script/dom/webrtc/` module from `script/dom/`. `script/dom/rtc*.rs -> script/dom/webrtc/` Testing: No changes, just a refactoring Fixes (partially): #38901 Signed-off-by: Andrei Volykhin <volykhin.andrei@huawei.com> Co-authored-by: Andrei Volykhin <volykhin.andrei@huawei.com>
This commit is contained in:
parent
66d9f957e6
commit
00d0783471
13 changed files with 17 additions and 11 deletions
424
components/script/dom/webrtc/rtcdatachannel.rs
Normal file
424
components/script/dom/webrtc/rtcdatachannel.rs
Normal file
|
@ -0,0 +1,424 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::ptr;
|
||||
|
||||
use constellation_traits::BlobImpl;
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::{JSAutoRealm, JSObject};
|
||||
use js::jsval::UndefinedValue;
|
||||
use js::rust::CustomAutoRooterGuard;
|
||||
use js::typedarray::{ArrayBuffer, ArrayBufferView, CreateWith};
|
||||
use script_bindings::conversions::SafeToJSValConvertible;
|
||||
use script_bindings::weakref::WeakRef;
|
||||
use servo_media::webrtc::{
|
||||
DataChannelId, DataChannelInit, DataChannelMessage, DataChannelState, WebRtcError,
|
||||
};
|
||||
|
||||
use crate::conversions::Convert;
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::{
|
||||
RTCDataChannelInit, RTCDataChannelMethods, RTCDataChannelState,
|
||||
};
|
||||
use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::{RTCErrorDetailType, RTCErrorInit};
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, DomObject, reflect_dom_object};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::{DOMString, USVString};
|
||||
use crate::dom::blob::Blob;
|
||||
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::messageevent::MessageEvent;
|
||||
use crate::dom::rtcerror::RTCError;
|
||||
use crate::dom::rtcerrorevent::RTCErrorEvent;
|
||||
use crate::dom::rtcpeerconnection::RTCPeerConnection;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
struct DroppableRTCDataChannel {
|
||||
#[ignore_malloc_size_of = "defined in servo-media"]
|
||||
servo_media_id: DataChannelId,
|
||||
peer_connection: WeakRef<RTCPeerConnection>,
|
||||
}
|
||||
|
||||
impl DroppableRTCDataChannel {
|
||||
fn new(peer_connection: WeakRef<RTCPeerConnection>, servo_media_id: DataChannelId) -> Self {
|
||||
DroppableRTCDataChannel {
|
||||
servo_media_id,
|
||||
peer_connection,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_servo_media_id(&self) -> DataChannelId {
|
||||
self.servo_media_id
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DroppableRTCDataChannel {
|
||||
fn drop(&mut self) {
|
||||
if let Some(root) = self.peer_connection.root() {
|
||||
root.unregister_data_channel(&self.get_servo_media_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct RTCDataChannel {
|
||||
eventtarget: EventTarget,
|
||||
label: USVString,
|
||||
ordered: bool,
|
||||
max_packet_life_time: Option<u16>,
|
||||
max_retransmits: Option<u16>,
|
||||
protocol: USVString,
|
||||
negotiated: bool,
|
||||
id: Option<u16>,
|
||||
ready_state: Cell<RTCDataChannelState>,
|
||||
binary_type: DomRefCell<DOMString>,
|
||||
peer_connection: Dom<RTCPeerConnection>,
|
||||
droppable: DroppableRTCDataChannel,
|
||||
}
|
||||
|
||||
impl RTCDataChannel {
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||
pub(crate) fn new_inherited(
|
||||
peer_connection: &RTCPeerConnection,
|
||||
label: USVString,
|
||||
options: &RTCDataChannelInit,
|
||||
servo_media_id: Option<DataChannelId>,
|
||||
) -> RTCDataChannel {
|
||||
let mut init: DataChannelInit = options.convert();
|
||||
init.label = label.to_string();
|
||||
|
||||
let controller = peer_connection.get_webrtc_controller().borrow();
|
||||
let servo_media_id = servo_media_id.unwrap_or(
|
||||
controller
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.create_data_channel(init)
|
||||
.expect("Expected data channel id"),
|
||||
);
|
||||
|
||||
RTCDataChannel {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
label,
|
||||
ordered: options.ordered,
|
||||
max_packet_life_time: options.maxPacketLifeTime,
|
||||
max_retransmits: options.maxRetransmits,
|
||||
protocol: options.protocol.clone(),
|
||||
negotiated: options.negotiated,
|
||||
id: options.id,
|
||||
ready_state: Cell::new(RTCDataChannelState::Connecting),
|
||||
binary_type: DomRefCell::new(DOMString::from("blob")),
|
||||
peer_connection: Dom::from_ref(peer_connection),
|
||||
droppable: DroppableRTCDataChannel::new(WeakRef::new(peer_connection), servo_media_id),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
global: &GlobalScope,
|
||||
peer_connection: &RTCPeerConnection,
|
||||
label: USVString,
|
||||
options: &RTCDataChannelInit,
|
||||
servo_media_id: Option<DataChannelId>,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCDataChannel> {
|
||||
let rtc_data_channel = reflect_dom_object(
|
||||
Box::new(RTCDataChannel::new_inherited(
|
||||
peer_connection,
|
||||
label,
|
||||
options,
|
||||
servo_media_id,
|
||||
)),
|
||||
global,
|
||||
can_gc,
|
||||
);
|
||||
|
||||
peer_connection
|
||||
.register_data_channel(rtc_data_channel.get_servo_media_id(), &rtc_data_channel);
|
||||
|
||||
rtc_data_channel
|
||||
}
|
||||
|
||||
pub(crate) fn get_servo_media_id(&self) -> DataChannelId {
|
||||
self.droppable.get_servo_media_id()
|
||||
}
|
||||
|
||||
pub(crate) fn on_open(&self, can_gc: CanGc) {
|
||||
let event = Event::new(
|
||||
&self.global(),
|
||||
atom!("open"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::NotCancelable,
|
||||
can_gc,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
}
|
||||
|
||||
pub(crate) fn on_close(&self, can_gc: CanGc) {
|
||||
let event = Event::new(
|
||||
&self.global(),
|
||||
atom!("close"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::NotCancelable,
|
||||
can_gc,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
|
||||
self.peer_connection
|
||||
.unregister_data_channel(&self.get_servo_media_id());
|
||||
}
|
||||
|
||||
pub(crate) fn on_error(&self, error: WebRtcError, can_gc: CanGc) {
|
||||
let global = self.global();
|
||||
let window = global.as_window();
|
||||
let cx = GlobalScope::get_cx();
|
||||
let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get());
|
||||
let init = RTCErrorInit {
|
||||
errorDetail: RTCErrorDetailType::Data_channel_failure,
|
||||
httpRequestStatusCode: None,
|
||||
receivedAlert: None,
|
||||
sctpCauseCode: None,
|
||||
sdpLineNumber: None,
|
||||
sentAlert: None,
|
||||
};
|
||||
let message = match error {
|
||||
WebRtcError::Backend(message) => DOMString::from(message),
|
||||
};
|
||||
let error = RTCError::new(window, &init, message, can_gc);
|
||||
let event = RTCErrorEvent::new(window, atom!("error"), false, false, &error, can_gc);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn on_message(&self, channel_message: DataChannelMessage, can_gc: CanGc) {
|
||||
let global = self.global();
|
||||
let cx = GlobalScope::get_cx();
|
||||
let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get());
|
||||
rooted!(in(*cx) let mut message = UndefinedValue());
|
||||
|
||||
match channel_message {
|
||||
DataChannelMessage::Text(text) => {
|
||||
text.safe_to_jsval(cx, message.handle_mut());
|
||||
},
|
||||
DataChannelMessage::Binary(data) => match &**self.binary_type.borrow() {
|
||||
"blob" => {
|
||||
let blob = Blob::new(
|
||||
&global,
|
||||
BlobImpl::new_from_bytes(data, "".to_owned()),
|
||||
can_gc,
|
||||
);
|
||||
blob.safe_to_jsval(cx, message.handle_mut());
|
||||
},
|
||||
"arraybuffer" => {
|
||||
rooted!(in(*cx) let mut array_buffer = ptr::null_mut::<JSObject>());
|
||||
unsafe {
|
||||
assert!(
|
||||
ArrayBuffer::create(
|
||||
*cx,
|
||||
CreateWith::Slice(&data),
|
||||
array_buffer.handle_mut()
|
||||
)
|
||||
.is_ok()
|
||||
)
|
||||
};
|
||||
|
||||
(*array_buffer).safe_to_jsval(cx, message.handle_mut());
|
||||
},
|
||||
_ => unreachable!(),
|
||||
},
|
||||
}
|
||||
|
||||
MessageEvent::dispatch_jsval(
|
||||
self.upcast(),
|
||||
&global,
|
||||
message.handle(),
|
||||
Some(&global.origin().immutable().ascii_serialization()),
|
||||
None,
|
||||
vec![],
|
||||
can_gc,
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn on_state_change(&self, state: DataChannelState, can_gc: CanGc) {
|
||||
if let DataChannelState::Closing = state {
|
||||
let event = Event::new(
|
||||
&self.global(),
|
||||
atom!("closing"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::NotCancelable,
|
||||
can_gc,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
};
|
||||
self.ready_state.set(state.convert());
|
||||
}
|
||||
|
||||
fn send(&self, source: &SendSource) -> Fallible<()> {
|
||||
if self.ready_state.get() != RTCDataChannelState::Open {
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
|
||||
let message = match source {
|
||||
SendSource::String(string) => DataChannelMessage::Text(string.0.clone()),
|
||||
SendSource::Blob(blob) => {
|
||||
DataChannelMessage::Binary(blob.get_bytes().unwrap_or(vec![]))
|
||||
},
|
||||
SendSource::ArrayBuffer(array) => DataChannelMessage::Binary(array.to_vec()),
|
||||
SendSource::ArrayBufferView(array) => DataChannelMessage::Binary(array.to_vec()),
|
||||
};
|
||||
|
||||
let controller = self.peer_connection.get_webrtc_controller().borrow();
|
||||
controller
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.send_data_channel_message(&self.get_servo_media_id(), message);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
enum SendSource<'a, 'b> {
|
||||
String(&'a USVString),
|
||||
Blob(&'a Blob),
|
||||
ArrayBuffer(CustomAutoRooterGuard<'b, ArrayBuffer>),
|
||||
ArrayBufferView(CustomAutoRooterGuard<'b, ArrayBufferView>),
|
||||
}
|
||||
|
||||
impl RTCDataChannelMethods<crate::DomTypeHolder> for RTCDataChannel {
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onopen
|
||||
event_handler!(open, GetOnopen, SetOnopen);
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onbufferedamountlow
|
||||
event_handler!(
|
||||
bufferedamountlow,
|
||||
GetOnbufferedamountlow,
|
||||
SetOnbufferedamountlow
|
||||
);
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onerror
|
||||
event_handler!(error, GetOnerror, SetOnerror);
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclosing
|
||||
event_handler!(closing, GetOnclosing, SetOnclosing);
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclose
|
||||
event_handler!(close, GetOnclose, SetOnclose);
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onmessage
|
||||
event_handler!(message, GetOnmessage, SetOnmessage);
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-label
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.clone()
|
||||
}
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-ordered
|
||||
fn Ordered(&self) -> bool {
|
||||
self.ordered
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-maxpacketlifetime
|
||||
fn GetMaxPacketLifeTime(&self) -> Option<u16> {
|
||||
self.max_packet_life_time
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-maxretransmits
|
||||
fn GetMaxRetransmits(&self) -> Option<u16> {
|
||||
self.max_retransmits
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-protocol
|
||||
fn Protocol(&self) -> USVString {
|
||||
self.protocol.clone()
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-negotiated
|
||||
fn Negotiated(&self) -> bool {
|
||||
self.negotiated
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-id
|
||||
fn GetId(&self) -> Option<u16> {
|
||||
self.id
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-readystate
|
||||
fn ReadyState(&self) -> RTCDataChannelState {
|
||||
self.ready_state.get()
|
||||
}
|
||||
|
||||
// XXX We need a way to know when the underlying data transport
|
||||
// actually sends data from its queue to decrease buffered amount.
|
||||
|
||||
// fn BufferedAmount(&self) -> u32;
|
||||
// fn BufferedAmountLowThreshold(&self) -> u32;
|
||||
// fn SetBufferedAmountLowThreshold(&self, value: u32) -> ();
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-close
|
||||
fn Close(&self) {
|
||||
let controller = self.peer_connection.get_webrtc_controller().borrow();
|
||||
controller
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.close_data_channel(&self.get_servo_media_id());
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-binarytype
|
||||
fn BinaryType(&self) -> DOMString {
|
||||
self.binary_type.borrow().clone()
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-binarytype
|
||||
fn SetBinaryType(&self, value: DOMString) -> Fallible<()> {
|
||||
if value != "blob" || value != "arraybuffer" {
|
||||
return Err(Error::Syntax);
|
||||
}
|
||||
*self.binary_type.borrow_mut() = value;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send
|
||||
fn Send(&self, data: USVString) -> Fallible<()> {
|
||||
self.send(&SendSource::String(&data))
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-1
|
||||
fn Send_(&self, data: &Blob) -> Fallible<()> {
|
||||
self.send(&SendSource::Blob(data))
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-2
|
||||
fn Send__(&self, data: CustomAutoRooterGuard<ArrayBuffer>) -> Fallible<()> {
|
||||
self.send(&SendSource::ArrayBuffer(data))
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-3
|
||||
fn Send___(&self, data: CustomAutoRooterGuard<ArrayBufferView>) -> Fallible<()> {
|
||||
self.send(&SendSource::ArrayBufferView(data))
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<DataChannelInit> for &RTCDataChannelInit {
|
||||
fn convert(self) -> DataChannelInit {
|
||||
DataChannelInit {
|
||||
label: String::new(),
|
||||
id: self.id,
|
||||
max_packet_life_time: self.maxPacketLifeTime,
|
||||
max_retransmits: self.maxRetransmits,
|
||||
negotiated: self.negotiated,
|
||||
ordered: self.ordered,
|
||||
protocol: self.protocol.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<RTCDataChannelState> for DataChannelState {
|
||||
fn convert(self) -> RTCDataChannelState {
|
||||
match self {
|
||||
DataChannelState::Connecting | DataChannelState::__Unknown(_) => {
|
||||
RTCDataChannelState::Connecting
|
||||
},
|
||||
DataChannelState::Open => RTCDataChannelState::Open,
|
||||
DataChannelState::Closing => RTCDataChannelState::Closing,
|
||||
DataChannelState::Closed => RTCDataChannelState::Closed,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue