use crate::{Device, Error, Transport};
use serde::Deserialize;
pub struct DiskManagement<'a, T: Transport>(&'a Device<T>, String);
impl<'a, T: Transport> DiskManagement<'a, T> {
pub(crate) fn new(device: &'a Device<T>, api_version: String) -> Self {
Self(device, api_version)
}
pub async fn list(&self) -> Result<Vec<DiskInfo>, Error<T::Error>> {
let req = http::Request::builder()
.method(http::Method::GET)
.uri(
self.0
.uri_for("/axis-cgi/disks/list.cgi?diskid=all")
.unwrap(),
)
.body(Vec::new())
.unwrap();
let (_resp, resp_body) = self.0.roundtrip(req, "text/xml").await?;
let resp_body =
std::str::from_utf8(resp_body.as_slice()).map_err(|_| Error::Other("invalid UTF-8"))?;
#[derive(Deserialize)]
struct ListResponse {
#[serde(rename = "disks")]
container: Container,
}
#[derive(Deserialize)]
struct Container {
#[serde(rename = "disk")]
disks: Vec<DiskInfo>,
}
let resp_body: ListResponse = quick_xml::de::from_str(resp_body)?;
Ok(resp_body.container.disks)
}
}
#[derive(Debug, Clone, Deserialize, Eq, PartialEq)]
pub struct DiskInfo {
#[serde(rename = "diskid")]
pub disk_id: String,
pub name: String,
#[serde(rename = "totalsize")]
pub total_size: u64,
#[serde(rename = "freesize")]
pub free_size: u64,
#[serde(rename = "cleanuplevel")]
pub cleanup_level: u16,
#[serde(rename = "cleanupmaxage")]
pub cleanup_max_age: u16,
#[serde(rename = "cleanuppolicy")]
pub cleanup_policy: CleanupPolicy,
#[serde(deserialize_with = "deserialize_yesno")]
pub locked: bool,
pub full: bool,
pub readonly: bool,
pub status: String,
pub filesystem: Filesystem,
pub group: String,
#[serde(rename = "requiredfilesystem")]
pub required_filesystem: Filesystem,
#[serde(rename = "encryptionenabled")]
pub encryption_enabled: bool,
#[serde(rename = "diskencrypted")]
pub disk_encrypted: bool,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Deserialize)]
pub enum CleanupPolicy {
#[serde(rename = "fifo")]
FIFO,
#[serde(rename = "none")]
None,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Deserialize)]
pub enum Filesystem {
#[serde(rename = "ext4")]
EXT4,
#[serde(rename = "vfat")]
VFAT,
#[serde(rename = "cifs")]
CIFS,
#[serde(rename = "none")]
None,
}
fn deserialize_yesno<'de, D>(d: D) -> Result<bool, D::Error>
where
D: serde::de::Deserializer<'de>,
{
struct V;
impl<'de> serde::de::Visitor<'de> for V {
type Value = bool;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str(r#""yes" or "no""#)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match v {
"yes" => Ok(true),
"no" => Ok(false),
other => Err(E::invalid_value(serde::de::Unexpected::Str(other), &self)),
}
}
}
d.deserialize_any(V)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn list() {
crate::test_with_devices(|test_device| async move {
let services = test_device.device.services().await?;
let disk_management = services.disk_management.ok_or(Error::UnsupportedFeature)?;
let disks = disk_management.list().await?;
assert_ne!(disks.len(), 0);
Ok(())
});
}
#[test]
fn deserialize_list() {
#[derive(Deserialize)]
struct ListResponse {
#[serde(rename = "disks")]
container: Container,
}
#[derive(Deserialize)]
struct Container {
#[serde(rename = "disk")]
disks: Vec<DiskInfo>,
}
let ListResponse { container } = quick_xml::de::from_str(r#"<?xml version="1.0"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.axis.com/vapix/http_cgi/disk/list1.xsd">
<disks numberofdisks="2">
<disk diskid="SD_DISK" name="" totalsize="116109036" freesize="75106020" cleanuplevel="99" cleanupmaxage="7" cleanuppolicy="fifo" locked="no" full="no" readonly="no" status="OK" filesystem="ext4" group="S0" requiredfilesystem="none" encryptionenabled="false" diskencrypted="false"/>
<disk diskid="NetworkShare" name="" totalsize="0" freesize="0" cleanuplevel="90" cleanupmaxage="7" cleanuppolicy="fifo" locked="no" full="no" readonly="no" status="disconnected" filesystem="cifs" group="S1" requiredfilesystem="none" encryptionenabled="false" diskencrypted="false"/>
</disks>
</root>
"#).unwrap();
assert_eq!(container.disks.len(), 2);
assert_eq!(
container.disks[0],
DiskInfo {
disk_id: "SD_DISK".to_string(),
name: "".to_string(),
total_size: 116109036,
free_size: 75106020,
cleanup_level: 99,
cleanup_max_age: 7,
cleanup_policy: CleanupPolicy::FIFO,
locked: false,
full: false,
readonly: false,
status: "OK".to_string(),
filesystem: Filesystem::EXT4,
group: "S0".to_string(),
required_filesystem: Filesystem::None,
encryption_enabled: false,
disk_encrypted: false,
}
);
}
}