Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,027 changes: 649 additions & 378 deletions Cargo.lock

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "belabot"
version = "0.3.2"
version = "0.4.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand All @@ -10,15 +10,15 @@ futures-util = "0.3"
read_input = "0.8"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
strsim = "0.10.0"
serde_with = "3.12.0"
strsim = "0.11.1"
tokio = { version = "1.20.1", features = ["full"] }
tokio-tungstenite = { version = "0.20", features = [ "native-tls" ] }
tokio-tungstenite = { version = "0.26", features = [ "native-tls" ] }
twitch-irc = "5.0"

anyhow = "1.0"
thiserror = "1.0.31"
thiserror = "2.0.12"

tracing = "0.1"
tracing-futures = "0.2"
tracing-log = { version = "0.1", features = ["env_logger"] }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ Example of the config that will be automatically generated upon running the bina
"modems": true,
"notifications": true,
"ups": true,
"network": false,
"ups_plugged_in": 5.1,
"notification_timeout": 30
"notification_timeout": 30,
"network_timeout": 30
}
},
"twitch": {
Expand Down Expand Up @@ -135,6 +137,7 @@ After running the executable successfully you can use the following commands in
| Restart | !bbrestart | Restarts the jetson nano |
| Sensor | !bbsensor | Shows the current sensor information |
| Stats | !bbs | Shows the current connected modems status and bitrate |
| Modems | !bbm | Shows the current connected modems status and bitrate |
| Start | !bbstart | Starts the stream |
| Stop | !bbstop | Stops the stream |
| Latency | !bbl (latency) | Changes the SRT latency in ms |
Expand Down
10 changes: 6 additions & 4 deletions src/belabox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ async fn run_loop(

// Authenticate
let auth_request = serde_json::to_string(&Request::Remote(auth.clone())).unwrap();
if let Err(e) = write.send(TMessage::Text(auth_request)).await {
if let Err(e) = write.send(TMessage::Text(auth_request.into())).await {
error!(?e, "error sending auth message");
continue;
};
Expand Down Expand Up @@ -211,7 +211,9 @@ async fn keepalive(write: Arc<Mutex<Option<Writer>>>, mut cancel_rx: oneshot::Re
if let Some(w) = write.lock().await.as_mut() {
if (w
.send(TMessage::Text(
serde_json::to_string(&Request::Keepalive(None)).unwrap(),
serde_json::to_string(&Request::Keepalive(None))
.unwrap()
.into(),
))
.await)
.is_err()
Expand Down Expand Up @@ -246,7 +248,7 @@ async fn handle_messages(
let text: serde_json::Value = match serde_json::from_str(text) {
Ok(o) => o,
Err(e) => {
error!(?e, text, "failed to deserialize");
error!(?e, ?text, "failed to deserialize");
continue;
}
};
Expand Down Expand Up @@ -310,7 +312,7 @@ async fn handle_requests(
let mut lock = write.lock().await;
if let Some(w) = lock.as_mut() {
let res = w
.send(TMessage::Text(request.message))
.send(TMessage::Text(request.message.into()))
.await
.map_err(BelaboxError::Send);

Expand Down
158 changes: 146 additions & 12 deletions src/belabox/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ pub enum Message {
Bitrate(Bitrate),
Pipelines(HashMap<String, Pipeline>),
Acodecs(HashMap<String, String>),
Relays(Relays),
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase", untagged)]
pub enum Remote {
RemoteAuth(RemoteAuth),
RemoteEncoder(RemoteEncoder),
RemoteRevision(RemoteRevision),
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
Expand All @@ -38,29 +40,37 @@ pub struct RemoteEncoder {
pub version: Option<i64>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct RemoteRevision {
pub revision: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct Config {
pub password_hash: String,
pub remote_key: String,
pub max_br: u32,
pub delay: i32,
pub pipeline: String,
pub srt_latency: u64,
pub srt_streamid: String,
pub srtla_addr: String,
pub srtla_port: u16,
pub bitrate_overlay: bool,
pub ssh_pass: Option<String>,
pub asrc: String,
pub acodec: String,
pub asrc: Option<String>,
pub acodec: Option<String>,
pub relay_server: Option<String>,
pub relay_account: Option<String>,
pub srt_streamid: Option<String>,
pub srtla_addr: Option<String>,
pub srtla_port: Option<u16>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct Netif {
pub ip: String,
pub txb: u64,
/// Might have been removed in newer versions
pub txb: Option<u64>,
pub tp: u64,
pub enabled: bool,
pub error: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
Expand All @@ -75,15 +85,73 @@ pub struct StreamingStatus {
pub is_streaming: bool,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
#[serde(untagged)]
#[derive(Debug, Serialize, Clone, PartialEq, Eq)]
pub enum StatusKind {
#[serde(rename = "status")]
Status(Status),
#[serde(rename = "asrcs")]
Asrcs(Asrcs),
#[serde(rename = "is_streaming")]
StreamingStatus(StreamingStatus),
#[serde(rename = "wifi")]
Wifi(WifiChange),
#[serde(rename = "available_updates")]
AvailableUpdates(AvailableUpdatesStatus),
#[serde(rename = "modems")]
Modems(Modems),
#[serde(rename = "updating")]
Updating(Updating),
}

impl<'de> serde::Deserialize<'de> for StatusKind {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
// Deserialize into a generic JSON Value first.
let val = serde_json::Value::deserialize(deserializer)?;
let obj = val.as_object().ok_or_else(|| {
serde::de::Error::custom("Expected a JSON object when deserializing StatusKind")
})?;

// If more than one key is present, choose the default detailed Status immediately.
if obj.len() > 1 {
return Status::deserialize(val)
.map(StatusKind::Status)
.map_err(serde::de::Error::custom);
}

// If there's exactly one key, use that key to decide the variant.
if let Some((key, _)) = obj.iter().next() {
return match key.as_str() {
"asrcs" => Asrcs::deserialize(val)
.map(StatusKind::Asrcs)
.map_err(serde::de::Error::custom),
"is_streaming" => StreamingStatus::deserialize(val)
.map(StatusKind::StreamingStatus)
.map_err(serde::de::Error::custom),
"wifi" => WifiChange::deserialize(val)
.map(StatusKind::Wifi)
.map_err(serde::de::Error::custom),
"available_updates" => AvailableUpdatesStatus::deserialize(val)
.map(StatusKind::AvailableUpdates)
.map_err(serde::de::Error::custom),
"modems" => Modems::deserialize(val)
.map(StatusKind::Modems)
.map_err(serde::de::Error::custom),
"updating" => Updating::deserialize(val)
.map(StatusKind::Updating)
.map_err(serde::de::Error::custom),
_ => Status::deserialize(val)
.map(StatusKind::Status)
.map_err(serde::de::Error::custom),
};
}

Err(serde::de::Error::custom(
"Expected a single key in the JSON object when deserializing StatusKind",
))
}
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
Expand All @@ -94,6 +162,7 @@ pub struct Status {
pub ssh: Ssh,
pub wifi: HashMap<String, Wifi>,
pub asrcs: Vec<String>,
pub modems: HashMap<String, Modem>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
Expand All @@ -114,9 +183,15 @@ pub struct WifiChange {
pub wifi: HashMap<String, Wifi>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct AvailableUpdatesStatus {
pub available_updates: Option<AvailableUpdates>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct AvailableUpdates {
pub package_count: u32,
pub package_count: Option<u32>,
pub download_size: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
Expand All @@ -130,8 +205,8 @@ pub struct Ssh {
pub struct Wifi {
pub ifname: String,
pub conn: Option<String>,
pub available: Vec<Available>,
pub saved: HashMap<String, String>,
pub available: Option<Vec<Available>>,
pub saved: Option<HashMap<String, String>>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
Expand All @@ -143,6 +218,49 @@ pub struct Available {
pub freq: i64,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct Modems {
pub modems: HashMap<String, Modem>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct Modem {
pub ifname: Option<String>,
pub name: Option<String>,
pub network_type: Option<NetworkType>,
pub config: Option<ModemConfig>,
/// Will be set to true when there is no config
pub no_sim: Option<bool>,
// TODO: What does this object look like?
pub available_networks: Option<serde_json::Value>,
pub status: Option<ModemStatus>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct NetworkType {
pub supported: Vec<String>,
pub active: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct ModemConfig {
pub autoconfig: Option<bool>,
pub apn: String,
pub username: String,
pub password: String,
pub roaming: bool,
pub network: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct ModemStatus {
pub connection: String,
pub network: Option<String>,
pub network_type: Option<String>,
pub signal: String,
pub roaming: bool,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct Sensors {
#[serde(rename = "SoC voltage")]
Expand Down Expand Up @@ -202,6 +320,22 @@ pub struct Asrcs {
pub asrcs: Vec<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct Relays {
pub servers: HashMap<String, Server>,
pub accounts: HashMap<String, Account>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct Server {
pub name: String,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct Account {
pub name: String,
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading