playwright 0.0.20

Playwright port to Rust
Documentation
use crate::imp::{core::*, prelude::*};

#[derive(Debug)]
pub(crate) struct WebSocket {
    channel: ChannelOwner,
    url: String,
    var: Mutex<Variable>,
    tx: Mutex<Option<broadcast::Sender<Evt>>>
}

#[derive(Debug, Default)]
struct Variable {
    is_closed: bool
}

impl WebSocket {
    pub(crate) fn try_new(channel: ChannelOwner) -> Result<Self, Error> {
        let Initializer { url } = serde_json::from_value(channel.initializer.clone())?;
        Ok(Self {
            channel,
            url,
            var: Mutex::default(),
            tx: Mutex::default()
        })
    }

    pub(crate) fn url(&self) -> &str { &self.url }
}

impl WebSocket {
    pub(crate) fn is_closed(&self) -> bool { self.var.lock().unwrap().is_closed }

    fn on_frame_sent(&self, params: Map<String, Value>) -> Result<(), Error> {
        let buffer = parse_frame(params)?;
        self.emit_event(Evt::FrameSent(buffer));
        Ok(())
    }

    fn on_frame_received(&self, params: Map<String, Value>) -> Result<(), Error> {
        let buffer = parse_frame(params)?;
        self.emit_event(Evt::FrameReceived(buffer));
        Ok(())
    }
}

fn parse_frame(params: Map<String, Value>) -> Result<Buffer, Error> {
    #[derive(Deserialize)]
    struct De {
        opcode: i32,
        data: String
    }
    let De { opcode, data } = serde_json::from_value(params.into())?;
    let buffer = if opcode == 2 {
        let bytes = base64::decode(data).map_err(Error::InvalidBase64)?;
        Buffer::Bytes(bytes)
    } else {
        Buffer::String(data)
    };
    Ok(buffer)
}

impl RemoteObject for WebSocket {
    fn channel(&self) -> &ChannelOwner { &self.channel }
    fn channel_mut(&mut self) -> &mut ChannelOwner { &mut self.channel }

    fn handle_event(
        &self,
        _ctx: &Context,
        method: Str<Method>,
        params: Map<String, Value>
    ) -> Result<(), Error> {
        match method.as_str() {
            "framesent" => self.on_frame_sent(params)?,
            "framereceived" => self.on_frame_received(params)?,
            "error" => {
                let error: Value = params.get("error").cloned().unwrap_or_default();
                self.emit_event(Evt::Error(error));
            }
            "close" => {
                self.var.lock().unwrap().is_closed = true;
                self.emit_event(Evt::Close);
            }
            _ => {}
        }
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub(crate) enum Evt {
    FrameSent(Buffer),
    FrameReceived(Buffer),
    Error(Value),
    Close
}

#[derive(Debug, Clone)]
pub enum Buffer {
    Bytes(Vec<u8>),
    String(String)
}

impl EventEmitter for WebSocket {
    type Event = Evt;

    fn tx(&self) -> Option<broadcast::Sender<Self::Event>> { self.tx.lock().unwrap().clone() }

    fn set_tx(&self, tx: broadcast::Sender<Self::Event>) { *self.tx.lock().unwrap() = Some(tx); }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum EventType {
    FrameSent,
    FrameReceived,
    Error,
    Close
}

impl IsEvent for Evt {
    type EventType = EventType;

    fn event_type(&self) -> Self::EventType {
        match self {
            Evt::FrameSent(_) => EventType::FrameSent,
            Evt::FrameReceived(_) => EventType::FrameReceived,
            Evt::Error(_) => EventType::Error,
            Evt::Close => EventType::Close
        }
    }
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Initializer {
    url: String
}