use std::fmt::Debug;
use webcore::value::{Reference, Value, ConversionError};
use webcore::try_from::{TryFrom, TryInto};
use webapi::blob::Blob;
use webapi::array_buffer::ArrayBuffer;
use webapi::web_socket::SocketCloseCode;
use webapi::event::{IEvent, Event};
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "CloseEvent")]
#[reference(event = "close")]
#[reference(subclass_of(Event))]
pub struct SocketCloseEvent( Reference );
impl SocketCloseEvent {
#[inline]
pub fn code( &self ) -> SocketCloseCode {
SocketCloseCode(js!(
return @{self.as_ref()}.code;
).try_into().unwrap())
}
#[inline]
pub fn reason( &self ) -> String {
js!(
return @{self.as_ref()}.reason;
).try_into().unwrap()
}
#[inline]
pub fn was_clean( &self ) -> bool {
js!(
return @{self.as_ref()}.wasClean;
).try_into().unwrap()
}
}
impl IEvent for SocketCloseEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Event")]
#[reference(event = "error")]
#[reference(subclass_of(Event))]
pub struct SocketErrorEvent( Reference );
impl IEvent for SocketErrorEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Event")]
#[reference(event = "open")]
#[reference(subclass_of(Event))]
pub struct SocketOpenEvent( Reference );
impl IEvent for SocketOpenEvent {}
#[derive(Debug, Clone)]
pub enum SocketMessageData {
Text(String),
Blob(Blob),
ArrayBuffer(ArrayBuffer),
}
impl SocketMessageData {
pub fn into_text(self) -> Option<String> {
if let SocketMessageData::Text(s) = self { Some(s) } else { None }
}
pub fn into_blob(self) -> Option<Blob> {
if let SocketMessageData::Blob(b) = self { Some(b) } else { None }
}
pub fn into_array_buffer(self) -> Option<ArrayBuffer> {
if let SocketMessageData::ArrayBuffer(b) = self { Some(b) } else { None }
}
}
impl TryFrom<Value> for SocketMessageData {
type Error = ConversionError;
fn try_from(v: Value) -> Result<SocketMessageData, ConversionError> {
match v {
Value::String(s) => Ok(SocketMessageData::Text(s)),
Value::Reference(ref r) => {
if let Ok(b) = r.clone().try_into() {
Ok(SocketMessageData::Blob(b))
} else if let Ok(b) = r.clone().try_into() {
Ok(SocketMessageData::ArrayBuffer(b))
} else {
Err(ConversionError::Custom(format!("Unknown message event data: {:?}", r)))
}
},
other => Err(ConversionError::Custom(format!("Unknown message event data: {:?}", other)))
}
}
}
pub trait IMessageEvent: IEvent where <Self::Data as TryFrom<Value>>::Error: Debug {
type Data: TryFrom<Value>;
#[inline]
fn data( &self ) -> Self::Data {
js!(
return @{self.as_ref()}.data;
).try_into().unwrap()
}
#[inline]
fn origin( &self ) -> String {
js!(
return @{self.as_ref()}.origin;
).try_into().unwrap()
}
#[inline]
fn last_event_id( &self ) -> String {
js!(
return @{self.as_ref()}.lastEventId;
).try_into().unwrap()
}
#[inline]
fn source( &self ) -> Option<Reference> {
js!(
return @{self.as_ref()}.source;
).try_into().ok()
}
#[inline]
fn ports( &self ) -> Vec<Reference> {
js!(
return @{self.as_ref()}.ports;
).try_into().unwrap()
}
}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "MessageEvent")]
#[reference(event = "message")]
#[reference(subclass_of(Event))]
pub struct SocketMessageEvent( Reference );
impl IMessageEvent for SocketMessageEvent {
type Data = SocketMessageData;
}
impl IEvent for SocketMessageEvent {}
#[cfg(all(test, feature = "web_test"))]
mod tests {
use super::*;
use webapi::event::ConcreteEvent;
#[test]
fn test_close_event() {
let event: SocketCloseEvent = js!(
return new CloseEvent(
@{SocketCloseEvent::EVENT_TYPE},
{
code: 1000,
reason: "WebSocket was closed normally",
wasClean: true
}
);
).try_into().unwrap();
assert_eq!( event.event_type(), SocketCloseEvent::EVENT_TYPE );
assert_eq!( event.code(), SocketCloseCode::NORMAL_CLOSURE );
assert_eq!( event.reason(), "WebSocket was closed normally" );
assert!( event.was_clean() );
}
}