//! The browser client's connection logic ([`Driver`]) on native: against a scripted socket with a //! made-up clock (hello, holding presence until the welcome, throttling, pings, a silent host, //! reconnecting as the same client, refusals, giving up), and against a real host over loopback through //! a small blocking socket, which checks that what the browser sends is what the host speaks. use std::net::TcpStream; use std::sync::Arc; use std::time::{Duration, Instant}; use figcraft_collab::message::{self, ClientMsg, Presence, ServerMsg}; use figcraft_collab::{Client, Limits, Outgoing, Server}; use figcraft_doc::{Document, NodeId}; use figcraft_engine::live::{Event, Status}; use tungstenite::protocol::WebSocket; use tungstenite::{Bytes, Message}; use crate::driver::{Driver, Socket}; use crate::guest::GuestConfig; use crate::host::{ENDED, Host, HostConfig}; use crate::inbox::Inbox; use crate::invite::Invite; use crate::loopback_tests::fast_limits; const TOKEN: &str = "AbCdEfGhIjKlMnOpQrStUv"; const FILE: &str = "0123456789abcdef"; /// A socket that records what the driver does. #[derive(Default)] struct Script { opened: Vec, sent: Vec, closes: usize, /// `open` fails (the browser refused the URL). refuse: bool, /// `send` fails (the connection broke). broken: bool, } impl Socket for Script { fn open(&mut self, url: &str) -> Result<(), String> { if self.refuse { return Err("SecurityError".into()); } self.opened.push(url.to_string()); Ok(()) } fn send(&mut self, bytes: &[u8]) -> bool { if self.broken { return false; } self.sent.push(message::decode(bytes, usize::MAX).unwrap()); true } fn close(&mut self) { self.closes += 1; } } fn invite() -> Invite { Invite::new("127.0.0.1:47900", FILE, TOKEN) } fn start(sock: Script, t0: Instant) -> (Driver