1mod value;
2
3use crate::ProtocolVersion;
4use derive_more::{Constructor, From, IsVariant, TryInto};
5use enum_kinds::EnumKind;
6use serde::Serialize;
7use std::{convert::TryFrom, time::SystemTime};
8
9pub use value::*;
10
11mod sealed {
12 pub trait Sealed {}
13}
14
15pub trait RequestType: Into<Request> + TryFrom<Request> + sealed::Sealed {
16 fn protocol_version(&self) -> ProtocolVersion;
17}
18
19macro_rules! impl_request_type {
20 ($t:ty => $e:expr) => {
21 impl sealed::Sealed for $t {}
22 impl RequestType for $t {
23 #[inline]
24 fn protocol_version(&self) -> ProtocolVersion {
25 $e
26 }
27 }
28 };
29}
30
31#[derive(Serialize, Debug, Constructor, Clone)]
32#[serde(rename_all = "UPPERCASE")]
33pub struct VersionReq;
34impl_request_type!(VersionReq => ProtocolVersion::ZeroZeroThree);
35
36#[derive(Serialize, Debug, Constructor, Clone)]
37#[serde(rename_all = "UPPERCASE")]
38pub struct GetChannelInfoAllReq;
39impl_request_type!(GetChannelInfoAllReq => ProtocolVersion::ZeroZeroThree);
40
41#[derive(Serialize, Debug, Constructor, Clone)]
42#[serde(rename_all = "UPPERCASE")]
43pub struct ItemValueSignInReq {
44 pub items: Vec<u32>,
45}
46impl_request_type!(ItemValueSignInReq => ProtocolVersion::ZeroZeroThree);
47
48#[derive(Serialize, Debug, Constructor, Clone)]
49#[serde(rename_all = "UPPERCASE")]
50pub struct ItemValueSignOutReq {
51 pub items: Vec<u32>,
52}
53impl_request_type!(ItemValueSignOutReq => ProtocolVersion::ZeroZeroThree);
54
55#[derive(Serialize, Debug, Constructor, Clone)]
56#[serde(rename_all = "UPPERCASE")]
57pub struct BlockListReq {
58 #[serde(rename = "LIST-RANGE")]
59 pub list_range: u32,
60}
61impl_request_type!(BlockListReq => ProtocolVersion::ZeroZeroThree);
62
63#[derive(Serialize, Debug, Constructor, Clone)]
64#[serde(rename_all = "UPPERCASE")]
65pub struct ProjectListReq;
66impl_request_type!(ProjectListReq => ProtocolVersion::ZeroZeroThree);
67
68#[derive(Serialize, Debug, Constructor, Clone)]
69#[serde(rename_all = "UPPERCASE")]
70pub struct ItemValueSetReq {
71 pub values: Vec<ItemSetValue>,
72}
73impl_request_type!(ItemValueSetReq => ProtocolVersion::ZeroZeroThree);
74
75#[derive(Debug, Serialize, From, IsVariant, TryInto, EnumKind, Clone)]
76#[enum_kind(RequestKind)]
77#[serde(tag = "CMD")]
78pub enum Request {
79 #[serde(rename = "VERSION_REQ")]
80 Version(VersionReq),
81
82 #[serde(rename = "GET_CHANNEL_INFO_ALL_REQ")]
83 GetChannelInfoAll(GetChannelInfoAllReq),
84
85 #[serde(rename = "ITEM_VALUE_SIGN_IN_REQ")]
86 ItemValueSignIn(ItemValueSignInReq),
87
88 #[serde(rename = "ITEM_VALUE_SIGN_OUT_REQ")]
89 ItemValueSignOut(ItemValueSignOutReq),
90
91 #[serde(rename = "BLOCK_LIST_REQ")]
92 BlockList(BlockListReq),
93
94 #[serde(rename = "PROJECT_LIST_GET")]
95 ProjectList(ProjectListReq),
96
97 #[serde(rename = "ITEM_VALUE_SET")]
98 ItemValueSet(ItemValueSetReq),
99}
100
101impl Request {
102 #[inline]
103 pub fn kind(&self) -> RequestKind {
104 RequestKind::from(self)
105 }
106}
107
108impl sealed::Sealed for Request {}
109impl RequestType for Request {
110 fn protocol_version(&self) -> ProtocolVersion {
111 match self {
112 Request::Version(v) => v.protocol_version(),
113 Request::GetChannelInfoAll(v) => v.protocol_version(),
114 Request::ItemValueSignIn(v) => v.protocol_version(),
115 Request::ItemValueSignOut(v) => v.protocol_version(),
116 Request::BlockList(v) => v.protocol_version(),
117 Request::ProjectList(v) => v.protocol_version(),
118 Request::ItemValueSet(v) => v.protocol_version(),
119 }
120 }
121}
122
123#[derive(Debug, Serialize)]
124#[serde(rename_all = "UPPERCASE")]
125pub struct RequestEnvelope {
126 #[serde(flatten)]
127 pub body: Request,
128 pub protocol: ProtocolVersion,
129 #[serde(serialize_with = "serialize_enet_timestamp")]
130 pub timestamp: SystemTime,
131}
132
133impl RequestEnvelope {
134 pub fn new(request: impl RequestType) -> Self {
135 let protocol = request.protocol_version();
136 Self::_new(request.into(), protocol)
137 }
138
139 #[inline(never)]
140 fn _new(request: Request, protocol: ProtocolVersion) -> Self {
141 Self {
142 body: request,
143 protocol,
144 timestamp: SystemTime::now(),
145 }
146 }
147}
148
149fn serialize_enet_timestamp<S>(value: &SystemTime, serializer: S) -> Result<S::Ok, S::Error>
150where
151 S: serde::Serializer,
152{
153 let s = value
154 .duration_since(std::time::UNIX_EPOCH)
155 .unwrap()
156 .as_secs()
157 .to_string();
158
159 s.serialize(serializer)
160}