use crate::tlv;
use anyhow;
use serde_json;
use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum DatastoreAccessControlEntryAuthMode {
Pase = 1,
Case = 2,
Group = 3,
}
impl DatastoreAccessControlEntryAuthMode {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
1 => Some(DatastoreAccessControlEntryAuthMode::Pase),
2 => Some(DatastoreAccessControlEntryAuthMode::Case),
3 => Some(DatastoreAccessControlEntryAuthMode::Group),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<DatastoreAccessControlEntryAuthMode> for u8 {
fn from(val: DatastoreAccessControlEntryAuthMode) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum DatastoreAccessControlEntryPrivilege {
View = 1,
Proxyview = 2,
Operate = 3,
Manage = 4,
Administer = 5,
}
impl DatastoreAccessControlEntryPrivilege {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
1 => Some(DatastoreAccessControlEntryPrivilege::View),
2 => Some(DatastoreAccessControlEntryPrivilege::Proxyview),
3 => Some(DatastoreAccessControlEntryPrivilege::Operate),
4 => Some(DatastoreAccessControlEntryPrivilege::Manage),
5 => Some(DatastoreAccessControlEntryPrivilege::Administer),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<DatastoreAccessControlEntryPrivilege> for u8 {
fn from(val: DatastoreAccessControlEntryPrivilege) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum DatastoreGroupKeyMulticastPolicy {
Pergroupid = 0,
Allnodes = 1,
}
impl DatastoreGroupKeyMulticastPolicy {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(DatastoreGroupKeyMulticastPolicy::Pergroupid),
1 => Some(DatastoreGroupKeyMulticastPolicy::Allnodes),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<DatastoreGroupKeyMulticastPolicy> for u8 {
fn from(val: DatastoreGroupKeyMulticastPolicy) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum DatastoreGroupKeySecurityPolicy {
Trustfirst = 0,
}
impl DatastoreGroupKeySecurityPolicy {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(DatastoreGroupKeySecurityPolicy::Trustfirst),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<DatastoreGroupKeySecurityPolicy> for u8 {
fn from(val: DatastoreGroupKeySecurityPolicy) -> Self {
val as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum DatastoreState {
Pending = 0,
Committed = 1,
Deletepending = 2,
Commitfailed = 3,
}
impl DatastoreState {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(DatastoreState::Pending),
1 => Some(DatastoreState::Committed),
2 => Some(DatastoreState::Deletepending),
3 => Some(DatastoreState::Commitfailed),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl From<DatastoreState> for u8 {
fn from(val: DatastoreState) -> Self {
val as u8
}
}
#[derive(Debug, serde::Serialize)]
pub struct DatastoreACLEntry {
pub node_id: Option<u64>,
pub list_id: Option<u16>,
pub acl_entry: Option<DatastoreAccessControlEntry>,
pub status_entry: Option<DatastoreStatusEntry>,
}
#[derive(Debug, serde::Serialize)]
pub struct DatastoreAccessControlEntry {
pub privilege: Option<DatastoreAccessControlEntryPrivilege>,
pub auth_mode: Option<DatastoreAccessControlEntryAuthMode>,
pub subjects: Option<Vec<u64>>,
pub targets: Option<Vec<DatastoreAccessControlTarget>>,
}
#[derive(Debug, serde::Serialize)]
pub struct DatastoreAccessControlTarget {
pub cluster: Option<u32>,
pub endpoint: Option<u16>,
pub device_type: Option<u32>,
}
#[derive(Debug, serde::Serialize)]
pub struct DatastoreAdministratorInformationEntry {
pub node_id: Option<u64>,
pub friendly_name: Option<String>,
pub vendor_id: Option<u16>,
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub icac: Option<Vec<u8>>,
}
#[derive(Debug, serde::Serialize)]
pub struct DatastoreBindingTarget {
pub node: Option<u64>,
pub group: Option<u8>,
pub endpoint: Option<u16>,
pub cluster: Option<u32>,
}
#[derive(Debug, serde::Serialize)]
pub struct DatastoreEndpointBindingEntry {
pub node_id: Option<u64>,
pub endpoint_id: Option<u16>,
pub list_id: Option<u16>,
pub binding: Option<DatastoreBindingTarget>,
pub status_entry: Option<DatastoreStatusEntry>,
}
#[derive(Debug, serde::Serialize)]
pub struct DatastoreEndpointEntry {
pub endpoint_id: Option<u16>,
pub node_id: Option<u64>,
pub friendly_name: Option<String>,
pub status_entry: Option<DatastoreStatusEntry>,
}
#[derive(Debug, serde::Serialize)]
pub struct DatastoreEndpointGroupIDEntry {
pub node_id: Option<u64>,
pub endpoint_id: Option<u16>,
pub group_id: Option<u8>,
pub status_entry: Option<DatastoreStatusEntry>,
}
#[derive(Debug, serde::Serialize)]
pub struct DatastoreGroupInformationEntry {
pub group_id: Option<u64>,
pub friendly_name: Option<String>,
pub group_key_set_id: Option<u16>,
pub group_cat: Option<u16>,
pub group_cat_version: Option<u16>,
pub group_permission: Option<DatastoreAccessControlEntryPrivilege>,
}
#[derive(Debug, serde::Serialize)]
pub struct DatastoreGroupKeySet {
pub group_key_set_id: Option<u16>,
pub group_key_security_policy: Option<DatastoreGroupKeySecurityPolicy>,
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub epoch_key0: Option<Vec<u8>>,
pub epoch_start_time0: Option<u64>,
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub epoch_key1: Option<Vec<u8>>,
pub epoch_start_time1: Option<u64>,
#[serde(serialize_with = "serialize_opt_bytes_as_hex")]
pub epoch_key2: Option<Vec<u8>>,
pub epoch_start_time2: Option<u64>,
pub group_key_multicast_policy: Option<DatastoreGroupKeyMulticastPolicy>,
}
#[derive(Debug, serde::Serialize)]
pub struct DatastoreNodeInformationEntry {
pub node_id: Option<u64>,
pub friendly_name: Option<String>,
pub commissioning_status_entry: Option<DatastoreStatusEntry>,
}
#[derive(Debug, serde::Serialize)]
pub struct DatastoreNodeKeySetEntry {
pub node_id: Option<u64>,
pub group_key_set_id: Option<u16>,
pub status_entry: Option<DatastoreStatusEntry>,
}
#[derive(Debug, serde::Serialize)]
pub struct DatastoreStatusEntry {
pub state: Option<DatastoreState>,
pub update_timestamp: Option<u64>,
pub failure_code: Option<u8>,
}
pub fn encode_add_key_set(group_key_set: DatastoreGroupKeySet) -> anyhow::Result<Vec<u8>> {
let mut group_key_set_fields = Vec::new();
if let Some(x) = group_key_set.group_key_set_id { group_key_set_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
if let Some(x) = group_key_set.group_key_security_policy { group_key_set_fields.push((1, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
if let Some(x) = group_key_set.epoch_key0 { group_key_set_fields.push((2, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
if let Some(x) = group_key_set.epoch_start_time0 { group_key_set_fields.push((3, tlv::TlvItemValueEnc::UInt64(x)).into()); }
if let Some(x) = group_key_set.epoch_key1 { group_key_set_fields.push((4, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
if let Some(x) = group_key_set.epoch_start_time1 { group_key_set_fields.push((5, tlv::TlvItemValueEnc::UInt64(x)).into()); }
if let Some(x) = group_key_set.epoch_key2 { group_key_set_fields.push((6, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
if let Some(x) = group_key_set.epoch_start_time2 { group_key_set_fields.push((7, tlv::TlvItemValueEnc::UInt64(x)).into()); }
if let Some(x) = group_key_set.group_key_multicast_policy { group_key_set_fields.push((8, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::StructInvisible(group_key_set_fields)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_update_key_set(group_key_set: DatastoreGroupKeySet) -> anyhow::Result<Vec<u8>> {
let mut group_key_set_fields = Vec::new();
if let Some(x) = group_key_set.group_key_set_id { group_key_set_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
if let Some(x) = group_key_set.group_key_security_policy { group_key_set_fields.push((1, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
if let Some(x) = group_key_set.epoch_key0 { group_key_set_fields.push((2, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
if let Some(x) = group_key_set.epoch_start_time0 { group_key_set_fields.push((3, tlv::TlvItemValueEnc::UInt64(x)).into()); }
if let Some(x) = group_key_set.epoch_key1 { group_key_set_fields.push((4, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
if let Some(x) = group_key_set.epoch_start_time1 { group_key_set_fields.push((5, tlv::TlvItemValueEnc::UInt64(x)).into()); }
if let Some(x) = group_key_set.epoch_key2 { group_key_set_fields.push((6, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
if let Some(x) = group_key_set.epoch_start_time2 { group_key_set_fields.push((7, tlv::TlvItemValueEnc::UInt64(x)).into()); }
if let Some(x) = group_key_set.group_key_multicast_policy { group_key_set_fields.push((8, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::StructInvisible(group_key_set_fields)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_remove_key_set(group_key_set_id: u16) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt16(group_key_set_id)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_add_group(group_id: u8, friendly_name: String, group_key_set_id: Option<u16>, group_cat: Option<u16>, group_cat_version: Option<u16>, group_permission: DatastoreAccessControlEntryPrivilege) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
(1, tlv::TlvItemValueEnc::String(friendly_name)).into(),
(2, tlv::TlvItemValueEnc::UInt16(group_key_set_id.unwrap_or(0))).into(),
(3, tlv::TlvItemValueEnc::UInt16(group_cat.unwrap_or(0))).into(),
(4, tlv::TlvItemValueEnc::UInt16(group_cat_version.unwrap_or(0))).into(),
(5, tlv::TlvItemValueEnc::UInt8(group_permission.to_u8())).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_update_group(group_id: u8, friendly_name: Option<String>, group_key_set_id: Option<u16>, group_cat: Option<u16>, group_cat_version: Option<u16>, group_permission: Option<DatastoreAccessControlEntryPrivilege>) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
(1, tlv::TlvItemValueEnc::String(friendly_name.unwrap_or("".to_string()))).into(),
(2, tlv::TlvItemValueEnc::UInt16(group_key_set_id.unwrap_or(0))).into(),
(3, tlv::TlvItemValueEnc::UInt16(group_cat.unwrap_or(0))).into(),
(4, tlv::TlvItemValueEnc::UInt16(group_cat_version.unwrap_or(0))).into(),
(5, tlv::TlvItemValueEnc::UInt8(group_permission.map(|e| e.to_u8()).unwrap_or(0))).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_remove_group(group_id: u8) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_add_admin(node_id: u64, friendly_name: String, vendor_id: u16, icac: Vec<u8>) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(1, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
(2, tlv::TlvItemValueEnc::String(friendly_name)).into(),
(3, tlv::TlvItemValueEnc::UInt16(vendor_id)).into(),
(4, tlv::TlvItemValueEnc::OctetString(icac)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_update_admin(node_id: Option<u64>, friendly_name: Option<String>, icac: Option<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt64(node_id.unwrap_or(0))).into(),
(1, tlv::TlvItemValueEnc::String(friendly_name.unwrap_or("".to_string()))).into(),
(2, tlv::TlvItemValueEnc::OctetString(icac.unwrap_or(vec![]))).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_remove_admin(node_id: u64) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_add_pending_node(node_id: u64, friendly_name: String) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
(1, tlv::TlvItemValueEnc::String(friendly_name)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_refresh_node(node_id: u64) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_update_node(node_id: u64, friendly_name: String) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
(1, tlv::TlvItemValueEnc::String(friendly_name)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_remove_node(node_id: u64) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_update_endpoint_for_node(endpoint_id: u16, node_id: u64, friendly_name: String) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
(1, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
(2, tlv::TlvItemValueEnc::String(friendly_name)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_add_group_id_to_endpoint_for_node(node_id: u64, endpoint_id: u16, group_id: u8) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
(1, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
(2, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_remove_group_id_from_endpoint_for_node(node_id: u64, endpoint_id: u16, group_id: u8) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
(1, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
(2, tlv::TlvItemValueEnc::UInt8(group_id)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_add_binding_to_endpoint_for_node(node_id: u64, endpoint_id: u16, binding: DatastoreBindingTarget) -> anyhow::Result<Vec<u8>> {
let mut binding_fields = Vec::new();
if let Some(x) = binding.node { binding_fields.push((1, tlv::TlvItemValueEnc::UInt64(x)).into()); }
if let Some(x) = binding.endpoint { binding_fields.push((3, tlv::TlvItemValueEnc::UInt16(x)).into()); }
if let Some(x) = binding.cluster { binding_fields.push((4, tlv::TlvItemValueEnc::UInt32(x)).into()); }
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
(1, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
(2, tlv::TlvItemValueEnc::StructInvisible(binding_fields)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_remove_binding_from_endpoint_for_node(list_id: u16, endpoint_id: u16, node_id: u64) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt16(list_id)).into(),
(1, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
(2, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_add_acl_to_node(node_id: u64, acl_entry: DatastoreAccessControlEntry) -> anyhow::Result<Vec<u8>> {
let mut acl_entry_fields = Vec::new();
if let Some(x) = acl_entry.privilege { acl_entry_fields.push((1, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
if let Some(x) = acl_entry.auth_mode { acl_entry_fields.push((2, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
if let Some(listv) = acl_entry.subjects { acl_entry_fields.push((3, tlv::TlvItemValueEnc::StructAnon(listv.into_iter().map(|x| (0, tlv::TlvItemValueEnc::UInt64(x)).into()).collect())).into()); }
if let Some(listv) = acl_entry.targets {
let inner_vec: Vec<_> = listv.into_iter().map(|inner| {
let mut nested_fields = Vec::new();
if let Some(x) = inner.cluster { nested_fields.push((0, tlv::TlvItemValueEnc::UInt32(x)).into()); }
if let Some(x) = inner.endpoint { nested_fields.push((1, tlv::TlvItemValueEnc::UInt16(x)).into()); }
if let Some(x) = inner.device_type { nested_fields.push((2, tlv::TlvItemValueEnc::UInt32(x)).into()); }
(0, tlv::TlvItemValueEnc::StructAnon(nested_fields)).into()
}).collect();
acl_entry_fields.push((4, tlv::TlvItemValueEnc::Array(inner_vec)).into());
}
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
(1, tlv::TlvItemValueEnc::StructInvisible(acl_entry_fields)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn encode_remove_acl_from_node(list_id: u16, node_id: u64) -> anyhow::Result<Vec<u8>> {
let tlv = tlv::TlvItemEnc {
tag: 0,
value: tlv::TlvItemValueEnc::StructInvisible(vec![
(0, tlv::TlvItemValueEnc::UInt16(list_id)).into(),
(1, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
]),
};
Ok(tlv.encode()?)
}
pub fn decode_anchor_root_ca(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<u8>> {
if let tlv::TlvItemValue::OctetString(v) = inp {
Ok(v.clone())
} else {
Err(anyhow::anyhow!("Expected OctetString"))
}
}
pub fn decode_anchor_node_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u64> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v)
} else {
Err(anyhow::anyhow!("Expected UInt64"))
}
}
pub fn decode_anchor_vendor_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
if let tlv::TlvItemValue::Int(v) = inp {
Ok(*v as u16)
} else {
Err(anyhow::anyhow!("Expected UInt16"))
}
}
pub fn decode_friendly_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
if let tlv::TlvItemValue::String(v) = inp {
Ok(v.clone())
} else {
Err(anyhow::anyhow!("Expected String"))
}
}
pub fn decode_group_key_set_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreGroupKeySet>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(DatastoreGroupKeySet {
group_key_set_id: item.get_int(&[0]).map(|v| v as u16),
group_key_security_policy: item.get_int(&[1]).and_then(|v| DatastoreGroupKeySecurityPolicy::from_u8(v as u8)),
epoch_key0: item.get_octet_string_owned(&[2]),
epoch_start_time0: item.get_int(&[3]),
epoch_key1: item.get_octet_string_owned(&[4]),
epoch_start_time1: item.get_int(&[5]),
epoch_key2: item.get_octet_string_owned(&[6]),
epoch_start_time2: item.get_int(&[7]),
group_key_multicast_policy: item.get_int(&[8]).and_then(|v| DatastoreGroupKeyMulticastPolicy::from_u8(v as u8)),
});
}
}
Ok(res)
}
pub fn decode_group_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreGroupInformationEntry>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(DatastoreGroupInformationEntry {
group_id: item.get_int(&[0]),
friendly_name: item.get_string_owned(&[1]),
group_key_set_id: item.get_int(&[2]).map(|v| v as u16),
group_cat: item.get_int(&[3]).map(|v| v as u16),
group_cat_version: item.get_int(&[4]).map(|v| v as u16),
group_permission: item.get_int(&[5]).and_then(|v| DatastoreAccessControlEntryPrivilege::from_u8(v as u8)),
});
}
}
Ok(res)
}
pub fn decode_node_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreNodeInformationEntry>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(DatastoreNodeInformationEntry {
node_id: item.get_int(&[1]),
friendly_name: item.get_string_owned(&[2]),
commissioning_status_entry: {
if let Some(nested_tlv) = item.get(&[3]) {
if let tlv::TlvItemValue::List(_) = nested_tlv {
let nested_item = tlv::TlvItem { tag: 3, value: nested_tlv.clone() };
Some(DatastoreStatusEntry {
state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
update_timestamp: nested_item.get_int(&[1]),
failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
})
} else {
None
}
} else {
None
}
},
});
}
}
Ok(res)
}
pub fn decode_admin_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreAdministratorInformationEntry>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(DatastoreAdministratorInformationEntry {
node_id: item.get_int(&[1]),
friendly_name: item.get_string_owned(&[2]),
vendor_id: item.get_int(&[3]).map(|v| v as u16),
icac: item.get_octet_string_owned(&[4]),
});
}
}
Ok(res)
}
pub fn decode_status(inp: &tlv::TlvItemValue) -> anyhow::Result<DatastoreStatusEntry> {
if let tlv::TlvItemValue::List(_fields) = inp {
let item = tlv::TlvItem { tag: 0, value: inp.clone() };
Ok(DatastoreStatusEntry {
state: item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
update_timestamp: item.get_int(&[1]),
failure_code: item.get_int(&[2]).map(|v| v as u8),
})
} else {
Err(anyhow::anyhow!("Expected struct fields"))
}
}
pub fn decode_endpoint_group_id_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreEndpointGroupIDEntry>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(DatastoreEndpointGroupIDEntry {
node_id: item.get_int(&[0]),
endpoint_id: item.get_int(&[1]).map(|v| v as u16),
group_id: item.get_int(&[2]).map(|v| v as u8),
status_entry: {
if let Some(nested_tlv) = item.get(&[3]) {
if let tlv::TlvItemValue::List(_) = nested_tlv {
let nested_item = tlv::TlvItem { tag: 3, value: nested_tlv.clone() };
Some(DatastoreStatusEntry {
state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
update_timestamp: nested_item.get_int(&[1]),
failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
})
} else {
None
}
} else {
None
}
},
});
}
}
Ok(res)
}
pub fn decode_endpoint_binding_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreEndpointBindingEntry>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(DatastoreEndpointBindingEntry {
node_id: item.get_int(&[0]),
endpoint_id: item.get_int(&[1]).map(|v| v as u16),
list_id: item.get_int(&[2]).map(|v| v as u16),
binding: {
if let Some(nested_tlv) = item.get(&[3]) {
if let tlv::TlvItemValue::List(_) = nested_tlv {
let nested_item = tlv::TlvItem { tag: 3, value: nested_tlv.clone() };
Some(DatastoreBindingTarget {
node: nested_item.get_int(&[1]),
group: nested_item.get_int(&[2]).map(|v| v as u8),
endpoint: nested_item.get_int(&[3]).map(|v| v as u16),
cluster: nested_item.get_int(&[4]).map(|v| v as u32),
})
} else {
None
}
} else {
None
}
},
status_entry: {
if let Some(nested_tlv) = item.get(&[4]) {
if let tlv::TlvItemValue::List(_) = nested_tlv {
let nested_item = tlv::TlvItem { tag: 4, value: nested_tlv.clone() };
Some(DatastoreStatusEntry {
state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
update_timestamp: nested_item.get_int(&[1]),
failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
})
} else {
None
}
} else {
None
}
},
});
}
}
Ok(res)
}
pub fn decode_node_key_set_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreNodeKeySetEntry>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(DatastoreNodeKeySetEntry {
node_id: item.get_int(&[0]),
group_key_set_id: item.get_int(&[1]).map(|v| v as u16),
status_entry: {
if let Some(nested_tlv) = item.get(&[2]) {
if let tlv::TlvItemValue::List(_) = nested_tlv {
let nested_item = tlv::TlvItem { tag: 2, value: nested_tlv.clone() };
Some(DatastoreStatusEntry {
state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
update_timestamp: nested_item.get_int(&[1]),
failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
})
} else {
None
}
} else {
None
}
},
});
}
}
Ok(res)
}
pub fn decode_node_acl_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreACLEntry>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(DatastoreACLEntry {
node_id: item.get_int(&[0]),
list_id: item.get_int(&[1]).map(|v| v as u16),
acl_entry: {
if let Some(nested_tlv) = item.get(&[2]) {
if let tlv::TlvItemValue::List(_) = nested_tlv {
let nested_item = tlv::TlvItem { tag: 2, value: nested_tlv.clone() };
Some(DatastoreAccessControlEntry {
privilege: nested_item.get_int(&[1]).and_then(|v| DatastoreAccessControlEntryPrivilege::from_u8(v as u8)),
auth_mode: nested_item.get_int(&[2]).and_then(|v| DatastoreAccessControlEntryAuthMode::from_u8(v as u8)),
subjects: {
if let Some(tlv::TlvItemValue::List(l)) = nested_item.get(&[3]) {
let items: Vec<u64> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v) } else { None } }).collect();
Some(items)
} else {
None
}
},
targets: {
if let Some(tlv::TlvItemValue::List(l)) = nested_item.get(&[4]) {
let mut items = Vec::new();
for list_item in l {
items.push(DatastoreAccessControlTarget {
cluster: list_item.get_int(&[0]).map(|v| v as u32),
endpoint: list_item.get_int(&[1]).map(|v| v as u16),
device_type: list_item.get_int(&[2]).map(|v| v as u32),
});
}
Some(items)
} else {
None
}
},
})
} else {
None
}
} else {
None
}
},
status_entry: {
if let Some(nested_tlv) = item.get(&[3]) {
if let tlv::TlvItemValue::List(_) = nested_tlv {
let nested_item = tlv::TlvItem { tag: 3, value: nested_tlv.clone() };
Some(DatastoreStatusEntry {
state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
update_timestamp: nested_item.get_int(&[1]),
failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
})
} else {
None
}
} else {
None
}
},
});
}
}
Ok(res)
}
pub fn decode_node_endpoint_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreEndpointEntry>> {
let mut res = Vec::new();
if let tlv::TlvItemValue::List(v) = inp {
for item in v {
res.push(DatastoreEndpointEntry {
endpoint_id: item.get_int(&[0]).map(|v| v as u16),
node_id: item.get_int(&[1]),
friendly_name: item.get_string_owned(&[2]),
status_entry: {
if let Some(nested_tlv) = item.get(&[3]) {
if let tlv::TlvItemValue::List(_) = nested_tlv {
let nested_item = tlv::TlvItem { tag: 3, value: nested_tlv.clone() };
Some(DatastoreStatusEntry {
state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
update_timestamp: nested_item.get_int(&[1]),
failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
})
} else {
None
}
} else {
None
}
},
});
}
}
Ok(res)
}
pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
if cluster_id != 0x0752 {
return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0752, got {}\"}}", cluster_id);
}
match attribute_id {
0x0000 => {
match decode_anchor_root_ca(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0001 => {
match decode_anchor_node_id(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0002 => {
match decode_anchor_vendor_id(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0003 => {
match decode_friendly_name(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0004 => {
match decode_group_key_set_list(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0005 => {
match decode_group_list(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0006 => {
match decode_node_list(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0007 => {
match decode_admin_list(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0008 => {
match decode_status(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x0009 => {
match decode_endpoint_group_id_list(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x000A => {
match decode_endpoint_binding_list(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x000B => {
match decode_node_key_set_list(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x000C => {
match decode_node_acl_list(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
0x000D => {
match decode_node_endpoint_list(tlv_value) {
Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
Err(e) => format!("{{\"error\": \"{}\"}}", e),
}
}
_ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
}
}
pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
vec![
(0x0000, "AnchorRootCA"),
(0x0001, "AnchorNodeID"),
(0x0002, "AnchorVendorID"),
(0x0003, "FriendlyName"),
(0x0004, "GroupKeySetList"),
(0x0005, "GroupList"),
(0x0006, "NodeList"),
(0x0007, "AdminList"),
(0x0008, "Status"),
(0x0009, "EndpointGroupIDList"),
(0x000A, "EndpointBindingList"),
(0x000B, "NodeKeySetList"),
(0x000C, "NodeACLList"),
(0x000D, "NodeEndpointList"),
]
}