use super::types::{AlarmSeverity, DropPolicy, TargetType};
use crate::{AccessMode, DataType, NGValue, PointValue, Transform};
use bytes::Bytes;
use chrono::{DateTime, Duration, Utc};
use sea_orm::FromJsonQueryResult;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fmt::Debug, sync::Arc};
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Command {
pub command_id: String,
pub key: String,
pub target_type: TargetType,
pub device_id: Option<i32>,
pub device_name: Option<String>,
pub params: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeout_ms: Option<u64>,
pub timestamp: DateTime<Utc>,
}
impl Command {
pub fn new(
command_id: String,
key: String,
target_type: TargetType,
device_id: i32,
device_name: String,
params: serde_json::Value,
) -> Self {
Self {
command_id,
key,
target_type,
device_id: Some(device_id),
device_name: Some(device_name),
params: Some(params),
timeout_ms: None,
timestamp: Utc::now(),
}
}
pub fn with_timeout(mut self, timeout_ms: u64) -> Self {
self.timeout_ms = Some(timeout_ms);
self
}
#[inline]
pub fn is_expired(&self) -> bool {
if let Some(expires_at) = self.timeout_ms {
Utc::now() > self.timestamp + Duration::milliseconds(expires_at as i64)
} else {
false
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WritePoint {
pub request_id: String,
pub point_id: i32,
pub value: NGValue,
pub timestamp: DateTime<Utc>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeout_ms: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WritePointResponse {
pub request_id: String,
pub point_id: i32,
pub device_id: i32,
#[serde(with = "arc_str_serde")]
pub device_name: Arc<str>,
#[serde(with = "arc_str_serde")]
pub point_key: Arc<str>,
pub status: WritePointStatus,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<WritePointError>,
#[serde(skip_serializing_if = "Option::is_none")]
pub applied_value: Option<NGValue>,
pub completed_at: DateTime<Utc>,
}
impl WritePointResponse {
#[inline]
pub fn success(
request_id: String,
point_id: i32,
device_id: i32,
device_name: Arc<str>,
point_key: Arc<str>,
applied_value: Option<NGValue>,
completed_at: DateTime<Utc>,
) -> Self {
Self {
request_id,
point_id,
device_id,
device_name,
point_key,
status: WritePointStatus::Success,
error: None,
applied_value,
completed_at,
}
}
#[inline]
pub fn failed(
request_id: String,
point_id: i32,
device_id: i32,
device_name: Arc<str>,
point_key: Arc<str>,
error: WritePointError,
completed_at: DateTime<Utc>,
) -> Self {
Self {
request_id,
point_id,
device_id,
device_name,
point_key,
status: WritePointStatus::Failed,
error: Some(error),
applied_value: None,
completed_at,
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum WritePointStatus {
Success,
Failed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WritePointError {
pub kind: WritePointErrorKind,
pub message: String,
}
impl WritePointError {
#[inline]
pub fn new(kind: WritePointErrorKind, message: impl Into<String>) -> Self {
Self {
kind,
message: message.into(),
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum WritePointErrorKind {
NotFound,
NotWriteable,
TypeMismatch,
OutOfRange,
NotConnected,
QueueTimeout,
DriverError,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeviceConnectedData {
pub device_id: i32,
pub device_name: String,
pub device_type: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeviceDisconnectedData {
pub device_id: i32,
pub device_name: String,
pub device_type: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TelemetryData {
pub device_id: i32,
pub device_name: String,
pub timestamp: DateTime<Utc>,
pub values: Vec<PointValue>,
#[serde(default)]
pub metadata: HashMap<String, serde_json::Value>,
}
impl TelemetryData {
pub fn new(device_id: i32, device_name: impl Into<String>, values: Vec<PointValue>) -> Self {
Self {
device_id,
device_name: device_name.into(),
timestamp: Utc::now(),
values,
metadata: HashMap::new(),
}
}
pub fn with_metadata(mut self, metadata: HashMap<String, serde_json::Value>) -> Self {
self.metadata = metadata;
self
}
pub fn to_json_bytes(&self) -> Result<Bytes, serde_json::Error> {
let json = serde_json::to_vec(self)?;
Ok(Bytes::from(json))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttributeData {
pub device_id: i32,
pub device_name: String,
pub timestamp: DateTime<Utc>,
#[serde(default)]
pub client_attributes: Vec<PointValue>,
#[serde(default)]
pub shared_attributes: Vec<PointValue>,
#[serde(default)]
pub server_attributes: Vec<PointValue>,
}
impl AttributeData {
pub fn new_client_attributes(
device_id: i32,
device_name: impl Into<String>,
attributes: Vec<PointValue>,
) -> Self {
Self {
device_id,
device_name: device_name.into(),
timestamp: Utc::now(),
client_attributes: attributes,
shared_attributes: Vec::new(),
server_attributes: Vec::new(),
}
}
pub fn new_shared_attributes(
device_id: i32,
device_name: impl Into<String>,
attributes: Vec<PointValue>,
) -> Self {
Self {
device_id,
device_name: device_name.into(),
timestamp: Utc::now(),
client_attributes: Vec::new(),
shared_attributes: attributes,
server_attributes: Vec::new(),
}
}
pub fn to_json_bytes(&self) -> Result<Bytes, serde_json::Error> {
let json = serde_json::to_vec(self)?;
Ok(Bytes::from(json))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RpcRequest {
pub target_type: TargetType,
pub request_id: Uuid,
pub device_id: i32,
pub device_name: String,
pub method: String,
pub params: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerRpcResponse {
pub request_id: String,
pub target_type: TargetType,
#[serde(skip_serializing_if = "Option::is_none")]
pub result: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
pub timestamp: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClientRpcResponse {
pub device_id: i32,
#[serde(skip_serializing_if = "Option::is_none")]
pub device_name: Option<String>,
pub request_id: String,
pub target_type: TargetType,
#[serde(skip_serializing_if = "Option::is_none")]
pub result: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
pub timestamp: DateTime<Utc>,
}
impl ClientRpcResponse {
pub fn success(
request_id: String,
target_type: TargetType,
device_id: i32,
device_name: Option<String>,
result: serde_json::Value,
) -> Self {
Self {
request_id,
target_type,
device_id,
device_name,
result: Some(result),
error: None,
timestamp: Utc::now(),
}
}
pub fn error(
request_id: String,
target_type: TargetType,
device_id: i32,
device_name: Option<String>,
error: String,
) -> Self {
Self {
request_id,
target_type,
device_id,
device_name,
result: None,
error: Some(error),
timestamp: Utc::now(),
}
}
pub fn is_success(&self) -> bool {
self.error.is_none()
}
pub fn to_json_bytes(&self) -> Result<Bytes, serde_json::Error> {
let json = serde_json::to_vec(self)?;
Ok(Bytes::from(json))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AlarmData {
pub device_id: i32,
pub device_name: String,
pub alarm_type: String,
pub severity: AlarmSeverity,
pub message: String,
pub details: HashMap<String, serde_json::Value>,
pub timestamp: DateTime<Utc>,
pub cleared: bool,
}
impl AlarmData {
pub fn new(
device_id: i32,
device_name: String,
alarm_type: String,
severity: AlarmSeverity,
message: String,
) -> Self {
Self {
device_id,
device_name,
alarm_type,
severity,
message,
details: HashMap::new(),
timestamp: Utc::now(),
cleared: false,
}
}
pub fn clear(mut self) -> Self {
self.cleared = true;
self
}
pub fn with_details(mut self, details: HashMap<String, serde_json::Value>) -> Self {
self.details = details;
self
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, FromJsonQueryResult)]
#[serde(rename_all = "camelCase")]
pub struct QueuePolicy {
#[serde(default = "QueuePolicy::default_capacity")]
pub capacity: u32,
#[serde(default = "QueuePolicy::default_drop_policy")]
pub drop_policy: DropPolicy,
#[serde(default = "QueuePolicy::default_block_duration_ms")]
pub block_duration: u64,
#[serde(default = "QueuePolicy::default_buffer_enabled")]
pub buffer_enabled: bool,
#[serde(default = "QueuePolicy::default_buffer_capacity")]
pub buffer_capacity: u32,
#[serde(default = "QueuePolicy::default_buffer_expire_ms")]
pub buffer_expire_ms: u64,
}
impl QueuePolicy {
fn default_capacity() -> u32 {
1000
}
fn default_drop_policy() -> DropPolicy {
DropPolicy::Discard
}
fn default_block_duration_ms() -> u64 {
1000
}
fn default_buffer_enabled() -> bool {
true
}
fn default_buffer_capacity() -> u32 {
1000
}
fn default_buffer_expire_ms() -> u64 {
300_000 }
}
impl sea_orm::IntoActiveValue<QueuePolicy> for QueuePolicy {
fn into_active_value(self) -> sea_orm::ActiveValue<QueuePolicy> {
sea_orm::ActiveValue::Set(self)
}
}
mod arc_str_serde {
use serde::{Deserialize, Deserializer, Serializer};
use std::sync::Arc;
pub fn serialize<S>(v: &Arc<str>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(v.as_ref())
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Arc<str>, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(Arc::<str>::from(s))
}
pub mod option {
use super::*;
use serde::Deserialize;
pub fn serialize<S>(v: &Option<Arc<str>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match v {
Some(s) => serializer.serialize_some(s.as_ref()),
None => serializer.serialize_none(),
}
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Arc<str>>, D::Error>
where
D: Deserializer<'de>,
{
let opt = Option::<String>::deserialize(deserializer)?;
Ok(opt.map(Arc::<str>::from))
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PointMeta {
pub point_id: i32,
pub channel_id: i32,
#[serde(with = "arc_str_serde")]
pub channel_name: Arc<str>,
pub device_id: i32,
#[serde(with = "arc_str_serde")]
pub device_name: Arc<str>,
#[serde(with = "arc_str_serde")]
pub point_name: Arc<str>,
#[serde(with = "arc_str_serde")]
pub point_key: Arc<str>,
pub data_type: DataType,
pub access_mode: AccessMode,
#[serde(default, with = "arc_str_serde::option")]
pub unit: Option<Arc<str>>,
pub min_value: Option<f64>,
pub max_value: Option<f64>,
#[serde(default)]
pub transform: Transform,
#[serde(default, with = "arc_str_serde::option")]
pub description: Option<Arc<str>>,
}
impl PointMeta {
#[inline]
pub fn wire_data_type(&self) -> DataType {
self.data_type
}
#[inline]
pub fn logical_data_type(&self) -> DataType {
self.transform.resolve_logical_datatype(self.data_type)
}
#[inline]
pub fn readable(&self) -> bool {
matches!(self.access_mode, AccessMode::Read | AccessMode::ReadWrite)
}
#[inline]
pub fn writable(&self) -> bool {
matches!(self.access_mode, AccessMode::Write | AccessMode::ReadWrite)
}
}