1use std::ops::{Deref, DerefMut};
2
3use anyhow::Result;
4use serde::{Deserialize, Serialize};
5use shared_ids::ClientId;
6use tracing::trace;
7
8use crate::RequestPayload;
9
10#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
12pub(crate) struct ClientRequest<P> {
13 pub(crate) client: ClientId,
14 pub(crate) payload: P,
15}
16
17impl<P> Deref for ClientRequest<P> {
18 type Target = P;
19
20 fn deref(&self) -> &Self::Target {
22 &self.payload
23 }
24}
25
26impl<P> DerefMut for ClientRequest<P> {
27 fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
29 &mut self.payload
30 }
31}
32
33impl<P: RequestPayload> ClientRequest<P> {
34 pub(crate) fn validate(&self) -> Result<()> {
36 self.verify(self.client)
37 }
38}
39
40#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
42#[repr(transparent)]
43#[serde(transparent)]
44pub(crate) struct RequestBatch<P> {
45 pub(crate) batch: Box<[ClientRequest<P>]>,
47}
48
49impl<P: RequestPayload> RequestBatch<P> {
50 pub(crate) fn new(batch: Box<[ClientRequest<P>]>) -> Self {
52 Self { batch }
53 }
54
55 pub(crate) fn validate(&self) -> Result<()> {
57 trace!("Validating batch of requests ...");
58 for request in self.batch.iter() {
59 trace!(
60 "Validating client request (ID: {:?}, client ID: {:?}) contained in batch ...",
61 request.id(),
62 request.client
63 );
64 request.validate()?;
65 trace!("Successfully validated client request (ID: {:?}, client ID: {:?}) contained in batch.", request.id(), request.client);
66 }
67 trace!("Successfully validated batch of requests.");
68 Ok(())
69 }
70}
71
72impl<P> IntoIterator for RequestBatch<P> {
73 type Item = ClientRequest<P>;
74
75 type IntoIter = std::vec::IntoIter<Self::Item>;
76
77 fn into_iter(self) -> Self::IntoIter {
79 let batch = Vec::from(self.batch); batch.into_iter()
81 }
82}
83
84#[cfg(test)]
85
86pub(crate) mod test {
87 use rand::{rngs::ThreadRng, Rng};
88 use shared_ids::ClientId;
89
90 use crate::tests::DummyPayload;
91
92 use super::{ClientRequest, RequestBatch};
93
94 pub(crate) fn create_invalid_client_req(rng: &mut ThreadRng) -> ClientRequest<DummyPayload> {
95 let rand_client_id = rng.gen::<u64>();
96 let rand_req_id = rng.gen::<u64>();
97 ClientRequest {
98 client: ClientId::from_u64(rand_client_id),
99 payload: DummyPayload(rand_req_id, false),
100 }
101 }
102
103 pub(crate) fn create_batch() -> RequestBatch<DummyPayload> {
104 let mut batch = Vec::new();
105 for i in 0..10 {
106 let client_req = ClientRequest {
107 client: ClientId::from_u64(i),
108 payload: DummyPayload(i, true),
109 };
110 batch.push(client_req);
111 }
112 let batch: [ClientRequest<DummyPayload>; 10] = batch.try_into().unwrap();
113 let batch = Box::new(batch);
114 RequestBatch { batch }
115 }
116}