ozzy_replication/local/
configuration.rs1use super::Error;
2use crate::{Digest, Scope};
3use ozzy_proto::{GroupId, NodeId, layout::Fixed};
4
5pub const CONFIGURATION_BYTES: usize = 128;
7const DIGEST_START: usize = 88;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct Configuration {
13 scope: Scope,
14 broker: NodeId,
15 principal: Digest,
16}
17
18impl Configuration {
19 pub fn new(
21 group: GroupId,
22 epoch: u64,
23 broker: NodeId,
24 principal: Digest,
25 ) -> Result<Self, Error> {
26 if group.as_bytes() == &[0; 16]
27 || broker.as_bytes() == &[0; 16]
28 || epoch == 0
29 || principal == Digest::ZERO
30 {
31 return Err(Error::Configuration);
32 }
33 let mut configuration = Self {
34 scope: Scope {
35 group_id: group,
36 configuration_epoch: epoch,
37 configuration_digest: Digest::ZERO,
38 view: 0,
39 },
40 broker,
41 principal,
42 };
43 configuration.scope.configuration_digest = checksum(&configuration.encode());
44 Ok(configuration)
45 }
46
47 pub const fn scope(self) -> Scope {
49 self.scope
50 }
51 pub const fn broker(self) -> NodeId {
53 self.broker
54 }
55 pub const fn principal(self) -> Digest {
57 self.principal
58 }
59
60 pub fn encode(self) -> [u8; CONFIGURATION_BYTES] {
62 let mut bytes = [0; CONFIGURATION_BYTES];
63 bytes[..8].copy_from_slice(b"OZYLOCAL");
64 bytes[8..12].copy_from_slice(&[
65 ozzy_journal::integrity::PROFILE,
66 ozzy_proto::VERSION,
67 1,
68 1,
69 ]);
70 bytes[16..32].copy_from_slice(self.scope.group_id.as_bytes());
71 bytes[32..40].copy_from_slice(&self.scope.configuration_epoch.to_be_bytes());
72 bytes[40..56].copy_from_slice(self.broker.as_bytes());
73 bytes[56..88].copy_from_slice(self.principal.as_bytes());
74 bytes[DIGEST_START..120].copy_from_slice(self.scope.configuration_digest.as_bytes());
75 bytes
76 }
77
78 pub fn decode(bytes: &[u8]) -> Result<Self, Error> {
80 let bytes: &[u8; CONFIGURATION_BYTES] = bytes.try_into().map_err(|_| Error::Encoding)?;
81 let configuration = Self::new(
82 GroupId::from_bytes(bytes.array::<16, 16>()),
83 bytes.u64_at::<32>(),
84 NodeId::from_bytes(bytes.array::<40, 16>()),
85 Digest::from_bytes(bytes.array::<56, 32>()),
86 )?;
87 if *bytes != configuration.encode() {
88 return Err(Error::Encoding);
89 }
90 Ok(configuration)
91 }
92}
93
94fn checksum(bytes: &[u8; CONFIGURATION_BYTES]) -> Digest {
95 let mut hasher =
96 ozzy_journal::integrity::IntegrityHasher::new("ozzy single broker configuration");
97 hasher.update(&bytes[..DIGEST_START]);
98 hasher.update(&[0; 32]);
99 hasher.update(&bytes[120..]);
100 hasher.finish()
101}