1#![doc = document_features::document_features!()]
5#![allow(clippy::unwrap_used)]
9
10#[cfg(feature = "client")]
11mod client;
12use std::{fmt::Display, str::FromStr};
13
14#[cfg(feature = "client")]
15pub use client::viewer_to_server;
16
17#[cfg(feature = "server")]
18mod server;
19#[cfg(feature = "server")]
20pub use server::RerunServer;
21
22use re_log_types::LogMsg;
23
24pub const DEFAULT_WS_SERVER_PORT: u16 = 9877;
25
26#[cfg(feature = "tls")]
27pub const PROTOCOL: &str = "wss";
28
29#[cfg(not(feature = "tls"))]
30pub const PROTOCOL: &str = "ws";
31
32#[derive(thiserror::Error, Debug)]
36pub enum RerunServerError {
37 #[error("Failed to bind to WebSocket port {0}: {1}")]
38 BindFailed(RerunServerPort, std::io::Error),
39
40 #[error("Failed to bind to WebSocket port {0} since the address is already in use. Use port 0 to let the OS choose a free port.")]
41 BindFailedAddrInUse(RerunServerPort),
42
43 #[error("Received an invalid message")]
44 InvalidMessagePrefix,
45
46 #[error("Received an invalid message")]
47 InvalidMessage(#[from] bincode::Error),
48
49 #[cfg(feature = "server")]
50 #[error("IO error: {0}")]
51 IoError(#[from] std::io::Error),
52}
53
54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55pub struct RerunServerPort(pub u16);
57
58impl Default for RerunServerPort {
59 fn default() -> Self {
60 Self(DEFAULT_WS_SERVER_PORT)
61 }
62}
63
64impl Display for RerunServerPort {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 write!(f, "{}", self.0)
67 }
68}
69
70impl FromStr for RerunServerPort {
72 type Err = String;
73
74 fn from_str(s: &str) -> Result<Self, Self::Err> {
75 match s.parse::<u16>() {
76 Ok(port) => Ok(Self(port)),
77 Err(err) => Err(format!("Failed to parse port: {err}")),
78 }
79 }
80}
81
82pub fn server_url(local_addr: &std::net::SocketAddr) -> String {
84 if local_addr.ip().is_unspecified() {
85 format!("{PROTOCOL}://localhost:{}", local_addr.port())
87 } else {
88 format!("{PROTOCOL}://{local_addr}")
89 }
90}
91
92const PREFIX: [u8; 4] = *b"RR00";
93
94pub fn encode_log_msg(log_msg: &LogMsg) -> Vec<u8> {
95 re_tracing::profile_function!();
96 use bincode::Options as _;
97 let mut bytes = PREFIX.to_vec();
98 bincode::DefaultOptions::new()
99 .serialize_into(&mut bytes, log_msg)
100 .unwrap();
101 bytes
102}
103
104pub fn decode_log_msg(data: &[u8]) -> Result<LogMsg, RerunServerError> {
105 re_tracing::profile_function!();
106 let payload = data
107 .strip_prefix(&PREFIX)
108 .ok_or(RerunServerError::InvalidMessagePrefix)?;
109
110 use bincode::Options as _;
111 Ok(bincode::DefaultOptions::new().deserialize(payload)?)
112}