aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/db.rs16
-rw-r--r--src/main.rs4
-rw-r--r--src/ui.rs36
3 files changed, 46 insertions, 10 deletions
diff --git a/src/db.rs b/src/db.rs
index 26f0c32..5d0f627 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -5,7 +5,8 @@ use sqlx::SqlitePool;
#[derive(Clone)]
pub struct Database {
- pool : SqlitePool
+ pool : SqlitePool,
+ num_frames_received : u64,
}
#[derive(sqlx::FromRow, Debug)]
@@ -25,7 +26,16 @@ impl Database {
.await
.expect("could not run SQLx migrations");
- Self { pool }
+ let num_frames_received : i64 = sqlx::query_scalar(r#"SELECT COUNT(id) FROM frames_received"#)
+ .fetch_one(&pool)
+ .await
+ .expect("could not count frames");
+
+ Self { pool, num_frames_received: num_frames_received.try_into().unwrap() }
+ }
+
+ pub fn get_num_received_frames(&self) -> u64 {
+ self.num_frames_received
}
pub async fn store_packet(&mut self, packet: &[u8]) -> anyhow::Result<()> {
@@ -41,6 +51,8 @@ impl Database {
.await?
.last_insert_rowid();
+ self.num_frames_received += 1;
+
debug!("INSERTed row {id}");
Ok(())
}
diff --git a/src/main.rs b/src/main.rs
index fd4cc03..6b79581 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -14,6 +14,7 @@ struct AppState {
conf : config::Config,
db : db::Database,
transmit_queue : mpsc::Sender<Vec<u8>>,
+ start_time : chrono::DateTime<chrono::Utc>,
}
type SharedState = Arc<Mutex<AppState>>;
@@ -59,7 +60,8 @@ async fn main() -> std::io::Result<()> {
let shared_state = Arc::new(Mutex::new(AppState {
conf : conf.clone(),
db : db::Database::new().await,
- transmit_queue: packet_send.clone(),
+ transmit_queue : packet_send.clone(),
+ start_time : chrono::Utc::now(),
}));
if conf.freq == 0 {
diff --git a/src/ui.rs b/src/ui.rs
index 2226a43..82c8b5c 100644
--- a/src/ui.rs
+++ b/src/ui.rs
@@ -16,7 +16,7 @@ use tower_http::services::ServeDir;
use ham_cats::{
buffer::Buffer,
- whisker::Identification,
+ whisker::{Identification, Destination},
};
use crate::{config, radio::MAX_PACKET_LEN};
@@ -51,6 +51,8 @@ struct DashboardTemplate<'a> {
title: &'a str,
page: ActivePage,
conf: config::Config,
+ node_startup_time: String,
+ num_received_frames: u64,
packets: Vec<UIPacket>,
}
@@ -64,7 +66,10 @@ struct UIPacket {
}
async fn dashboard(State(state): State<SharedState>) -> DashboardTemplate<'static> {
- let mut db = state.lock().unwrap().db.clone();
+ let (conf, mut db, node_startup_time) = {
+ let st = state.lock().unwrap();
+ (st.conf.clone(), st.db.clone(), st.start_time.clone())
+ };
let packets = match db.get_most_recent_packets(10).await {
Ok(v) => v,
@@ -106,9 +111,11 @@ async fn dashboard(State(state): State<SharedState>) -> DashboardTemplate<'stati
DashboardTemplate {
title: "Dashboard",
- conf: state.lock().unwrap().conf.clone(),
+ conf,
page: ActivePage::Dashboard,
- packets
+ num_received_frames : db.get_num_received_frames(),
+ node_startup_time : node_startup_time.format("%Y-%m-%d %H:%M:%S").to_string(),
+ packets,
}
}
@@ -145,11 +152,18 @@ async fn send(State(state): State<SharedState>) -> SendTemplate<'static> {
}
#[derive(Deserialize, Debug)]
+struct ApiSendPacketDestination {
+ callsign : String,
+ ssid : u8,
+}
+
+#[derive(Deserialize, Debug)]
struct ApiSendPacket {
+ destinations : Vec<ApiSendPacketDestination>,
comment : Option<String>,
}
-fn build_packet(config: config::Config, comment: Option<String>) -> anyhow::Result<Vec<u8>> {
+fn build_packet(config: config::Config, payload: ApiSendPacket) -> anyhow::Result<Vec<u8>> {
let mut buf = [0; crate::radio::MAX_PACKET_LEN];
let mut pkt = ham_cats::packet::Packet::new(&mut buf);
pkt.add_identification(
@@ -158,11 +172,19 @@ fn build_packet(config: config::Config, comment: Option<String>) -> anyhow::Resu
)
.map_err(|e| anyhow!("Could not add identification to packet: {e}"))?;
- if let Some(c) = comment {
+ if let Some(c) = payload.comment {
pkt.add_comment(&c)
.map_err(|e| anyhow!("Could not add comment to packet: {e}"))?;
}
+ for dest in payload.destinations {
+ let dest = Destination::new(false, 0, &dest.callsign, dest.ssid)
+ .ok_or(anyhow!("Cound not create destination"))?;
+
+ pkt.add_destination(dest)
+ .map_err(|e| anyhow!("Could not add destination to packet: {e}"))?;
+ }
+
let mut buf2 = [0; crate::radio::MAX_PACKET_LEN];
let mut data = Buffer::new_empty(&mut buf2);
pkt.fully_encode(&mut data)
@@ -179,7 +201,7 @@ async fn post_packet(State(state): State<SharedState>, Json(payload): Json<ApiSe
info!("send_packet {:?}", payload);
- match build_packet(config, payload.comment) {
+ match build_packet(config, payload) {
Ok(p) => {
info!("Built packet of {} bytes", p.len());
match transmit_queue.send(p).await {