189 lines
5.0 KiB
Rust
189 lines
5.0 KiB
Rust
use crate::fat_error::{FatError, FatResult};
|
|
use crate::hal::rtc::X25;
|
|
use crate::BOARD_ACCESS;
|
|
use alloc::borrow::ToOwned;
|
|
use alloc::format;
|
|
use alloc::string::{String, ToString};
|
|
use chrono::DateTime;
|
|
use edge_http::io::server::Connection;
|
|
use edge_nal::io::{Read, Write};
|
|
use log::info;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
pub struct WebBackupHeader {
|
|
timestamp: String,
|
|
size: u16,
|
|
}
|
|
pub(crate) async fn get_backup_config<T, const N: usize>(
|
|
conn: &mut Connection<'_, T, { N }>,
|
|
) -> FatResult<Option<u32>>
|
|
where
|
|
T: Read + Write,
|
|
{
|
|
// First pass: verify checksum without sending data
|
|
let mut checksum = X25.digest();
|
|
let mut chunk = 0_usize;
|
|
loop {
|
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
|
board.board_hal.progress(chunk as u32).await;
|
|
let (buf, len, expected_crc) = board
|
|
.board_hal
|
|
.get_rtc_module()
|
|
.get_backup_config(chunk)
|
|
.await?;
|
|
|
|
// Update checksum with the actual data bytes of this chunk
|
|
checksum.update(&buf[..len]);
|
|
|
|
let is_last = len == 0 || len < buf.len();
|
|
if is_last {
|
|
let actual_crc = checksum.finalize();
|
|
if actual_crc != expected_crc {
|
|
BOARD_ACCESS
|
|
.get()
|
|
.await
|
|
.lock()
|
|
.await
|
|
.board_hal
|
|
.clear_progress()
|
|
.await;
|
|
conn.initiate_response(
|
|
409,
|
|
Some(
|
|
format!("Checksum mismatch expected {expected_crc} got {actual_crc}")
|
|
.as_str(),
|
|
),
|
|
&[],
|
|
)
|
|
.await?;
|
|
return Ok(Some(409));
|
|
}
|
|
break;
|
|
}
|
|
chunk += 1;
|
|
}
|
|
// Second pass: stream data
|
|
conn.initiate_response(
|
|
200,
|
|
Some("OK"),
|
|
&[
|
|
("Access-Control-Allow-Origin", "*"),
|
|
("Access-Control-Allow-Headers", "*"),
|
|
("Access-Control-Allow-Methods", "*"),
|
|
],
|
|
)
|
|
.await?;
|
|
|
|
let mut chunk = 0_usize;
|
|
loop {
|
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
|
board.board_hal.progress(chunk as u32).await;
|
|
let (buf, len, _expected_crc) = board
|
|
.board_hal
|
|
.get_rtc_module()
|
|
.get_backup_config(chunk)
|
|
.await?;
|
|
|
|
if len == 0 {
|
|
break;
|
|
}
|
|
|
|
conn.write_all(&buf[..len]).await?;
|
|
|
|
if len < buf.len() {
|
|
break;
|
|
}
|
|
chunk += 1;
|
|
}
|
|
BOARD_ACCESS
|
|
.get()
|
|
.await
|
|
.lock()
|
|
.await
|
|
.board_hal
|
|
.clear_progress()
|
|
.await;
|
|
Ok(Some(200))
|
|
}
|
|
|
|
pub(crate) async fn backup_config<T, const N: usize>(
|
|
conn: &mut Connection<'_, T, N>,
|
|
) -> FatResult<Option<String>>
|
|
where
|
|
T: Read + Write,
|
|
{
|
|
let mut offset = 0_usize;
|
|
let mut buf = [0_u8; 32];
|
|
|
|
let mut checksum = X25.digest();
|
|
|
|
let mut counter = 0;
|
|
loop {
|
|
let to_write = conn.read(&mut buf).await?;
|
|
if to_write == 0 {
|
|
info!("backup finished");
|
|
break;
|
|
} else {
|
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
|
board.board_hal.progress(counter).await;
|
|
|
|
counter += 1;
|
|
board
|
|
.board_hal
|
|
.get_rtc_module()
|
|
.backup_config(offset, &buf[0..to_write])
|
|
.await?;
|
|
checksum.update(&buf[0..to_write]);
|
|
}
|
|
offset += to_write;
|
|
}
|
|
|
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
|
board
|
|
.board_hal
|
|
.get_rtc_module()
|
|
.backup_config_finalize(checksum.finalize(), offset)
|
|
.await?;
|
|
board.board_hal.clear_progress().await;
|
|
conn.initiate_response(
|
|
200,
|
|
Some("OK"),
|
|
&[
|
|
("Access-Control-Allow-Origin", "*"),
|
|
("Access-Control-Allow-Headers", "*"),
|
|
("Access-Control-Allow-Methods", "*"),
|
|
],
|
|
)
|
|
.await?;
|
|
Ok(Some("saved".to_owned()))
|
|
}
|
|
|
|
pub(crate) async fn backup_info<T, const N: usize>(
|
|
_request: &mut Connection<'_, T, N>,
|
|
) -> Result<Option<String>, FatError>
|
|
where
|
|
T: Read + Write,
|
|
{
|
|
let mut board = BOARD_ACCESS.get().await.lock().await;
|
|
let header = board.board_hal.get_rtc_module().get_backup_info().await;
|
|
let json = match header {
|
|
Ok(h) => {
|
|
let timestamp = DateTime::from_timestamp_millis(h.timestamp).unwrap();
|
|
let wbh = WebBackupHeader {
|
|
timestamp: timestamp.to_rfc3339(),
|
|
size: h.size,
|
|
};
|
|
serde_json::to_string(&wbh)?
|
|
}
|
|
Err(err) => {
|
|
let wbh = WebBackupHeader {
|
|
timestamp: err.to_string(),
|
|
size: 0,
|
|
};
|
|
serde_json::to_string(&wbh)?
|
|
}
|
|
};
|
|
Ok(Some(json))
|
|
}
|