1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
use crate::dsnp::dsnp_types::{
	DsnpInnerGraph, DsnpPublicKey, DsnpUserPrivateGraphChunk, DsnpUserPublicGraphChunk,
};
use apache_avro::{from_avro_datum, from_value, to_avro_datum, to_value, Schema};
use dsnp_graph_config::errors::DsnpGraphResult;
use log::Level;
use log_result_proc_macro::log_result_err;
use serde::{Deserialize, Serialize};

/// A utility to handle serialization and deserialization on specified schemas
pub struct SchemaHandler;

impl SchemaHandler {
	/// Reads a public key from a byte array
	#[log_result_err(Level::Info)]
	pub fn read_public_key(data: &[u8]) -> DsnpGraphResult<DsnpPublicKey> {
		Self::read(data, &dsnp_graph_config::PUBLIC_KEY_SCHEMA)
	}

	/// Writes a public key to a byte array
	#[log_result_err(Level::Info)]
	pub fn write_public_key(key: &DsnpPublicKey) -> DsnpGraphResult<Vec<u8>> {
		Self::write(key, &dsnp_graph_config::PUBLIC_KEY_SCHEMA)
	}

	/// Reads a public graph chunk from a byte array
	#[log_result_err(Level::Info)]
	pub fn read_public_graph_chunk(data: &[u8]) -> DsnpGraphResult<DsnpUserPublicGraphChunk> {
		Self::read(data, &dsnp_graph_config::PUBLIC_GRAPH_CHUNK_SCHEMA)
	}

	/// Writes a public graph chunk to a byte array
	#[log_result_err(Level::Info)]
	pub fn write_public_graph_chunk(chunk: &DsnpUserPublicGraphChunk) -> DsnpGraphResult<Vec<u8>> {
		Self::write(chunk, &dsnp_graph_config::PUBLIC_GRAPH_CHUNK_SCHEMA)
	}

	/// Reads an inner graph from a byte array
	#[log_result_err(Level::Info)]
	pub fn read_inner_graph(data: &[u8]) -> DsnpGraphResult<DsnpInnerGraph> {
		Self::read(data, &dsnp_graph_config::PUBLIC_GRAPH_SCHEMA)
	}

	/// Writes an inner graph to a byte array
	#[log_result_err(Level::Info)]
	pub fn write_inner_graph(inner_graph: &DsnpInnerGraph) -> DsnpGraphResult<Vec<u8>> {
		Self::write(inner_graph, &dsnp_graph_config::PUBLIC_GRAPH_SCHEMA)
	}

	/// Reads a private graph chunk from a byte array
	#[log_result_err(Level::Info)]
	pub fn read_private_graph_chunk(data: &[u8]) -> DsnpGraphResult<DsnpUserPrivateGraphChunk> {
		Self::read(data, &dsnp_graph_config::PRIVATE_GRAPH_CHUNK_SCHEMA)
	}

	/// Writes a private graph chunk to a byte array
	#[log_result_err(Level::Info)]
	pub fn write_private_graph_chunk(
		chunk: &DsnpUserPrivateGraphChunk,
	) -> DsnpGraphResult<Vec<u8>> {
		Self::write(chunk, &dsnp_graph_config::PRIVATE_GRAPH_CHUNK_SCHEMA)
	}

	#[log_result_err(Level::Info)]
	fn read<Output>(data: &[u8], schema: &Schema) -> DsnpGraphResult<Output>
	where
		Output: for<'a> Deserialize<'a>,
	{
		let reader = from_avro_datum(schema, &mut &data[..], None)?;
		Ok(from_value::<Output>(&reader)?)
	}

	#[log_result_err(Level::Info)]
	fn write<Input>(input: &Input, schema: &Schema) -> DsnpGraphResult<Vec<u8>>
	where
		Input: Serialize,
	{
		let val = to_value(input)?;
		Ok(to_avro_datum(schema, val)?)
	}
}

#[cfg(test)]
mod test {
	use super::*;
	use crate::dsnp::dsnp_types::{DsnpGraphEdge, DsnpPrid};
	use apache_avro::Error as AvroError;
	use dryoc::keypair::StackKeyPair;
	use dsnp_graph_config::errors::DsnpGraphError;

	#[test]
	fn public_key_read_and_write_using_valid_input_should_succeed() {
		let key = DsnpPublicKey { key_id: None, key: StackKeyPair::gen().public_key.to_vec() };

		let serialized = SchemaHandler::write_public_key(&key).expect("should serialize");
		let deserialized = SchemaHandler::read_public_key(&serialized).expect("should deserialize");

		assert_eq!(deserialized, key);
	}

	#[test]
	fn public_key_read_using_invalid_input_should_fail() {
		let key = DsnpPublicKey { key_id: None, key: b"217678127812871812334324".to_vec() };

		let mut serialized = SchemaHandler::write_public_key(&key).expect("should serialize");
		serialized[0] = !serialized[0]; // corrupting the input
		let deserialized = SchemaHandler::read_public_key(&serialized);

		assert!(deserialized.is_err());
		assert!(matches!(
			deserialized.unwrap_err(),
			DsnpGraphError::AvroError(AvroError::ConvertI64ToUsize(_, _))
		));
	}

	#[test]
	fn public_graph_chunk_read_and_write_using_valid_input_should_succeed() {
		let chunk = DsnpUserPublicGraphChunk {
			compressed_public_graph: b"shugdua781262876euwsdgjdgjay981613789y1278eywhgdjhs"
				.to_vec(),
		};

		let serialized = SchemaHandler::write_public_graph_chunk(&chunk).expect("should serialize");
		let deserialized =
			SchemaHandler::read_public_graph_chunk(&serialized).expect("should deserialize");

		assert_eq!(deserialized, chunk);
	}

	#[test]
	fn inner_graph_read_and_write_using_valid_input_should_succeed() {
		let inner_graph: DsnpInnerGraph = vec![
			DsnpGraphEdge { user_id: 7, since: 12638718 },
			DsnpGraphEdge { user_id: 167282, since: 28638718 },
		];

		let serialized = SchemaHandler::write_inner_graph(&inner_graph).expect("should serialize");
		let deserialized =
			SchemaHandler::read_inner_graph(&serialized).expect("should deserialize");

		assert_eq!(deserialized, inner_graph);
	}

	#[test]
	fn private_graph_chunk_read_and_write_using_valid_input_should_succeed() {
		let chunk = DsnpUserPrivateGraphChunk {
			encrypted_compressed_private_graph:
				b"shugdua781262876euwsdgjdgjay981613789y1278eywhgdjhs".to_vec(),
			key_id: 26783,
			prids: vec![
				DsnpPrid::new(27737272u64.to_le_bytes().as_slice()),
				DsnpPrid::new(17237271u64.to_le_bytes().as_slice()),
			],
		};

		let serialized =
			SchemaHandler::write_private_graph_chunk(&chunk).expect("should serialize");
		let deserialized =
			SchemaHandler::read_private_graph_chunk(&serialized).expect("should deserialize");

		assert_eq!(deserialized, chunk);
	}
}