1use std::path::PathBuf;
20use tinyjson::JsonValue;
21
22use darkfi::{
23 geode::hash_to_string,
24 rpc::util::{json_map, json_str},
25};
26
27use crate::{dht::FudSeeder, resource::Resource};
28
29#[derive(Clone, Debug)]
30pub struct DownloadStarted {
31 pub hash: blake3::Hash,
32 pub resource: Resource,
33}
34#[derive(Clone, Debug)]
35pub struct ChunkDownloadCompleted {
36 pub hash: blake3::Hash,
37 pub chunk_hash: blake3::Hash,
38 pub resource: Resource,
39}
40#[derive(Clone, Debug)]
41pub struct MetadataDownloadCompleted {
42 pub hash: blake3::Hash,
43 pub resource: Resource,
44}
45#[derive(Clone, Debug)]
46pub struct DownloadCompleted {
47 pub hash: blake3::Hash,
48 pub resource: Resource,
49}
50#[derive(Clone, Debug)]
51pub struct ResourceUpdated {
52 pub hash: blake3::Hash,
53 pub resource: Resource,
54}
55#[derive(Clone, Debug)]
56pub struct ResourceRemoved {
57 pub hash: blake3::Hash,
58}
59#[derive(Clone, Debug)]
60pub struct ChunkNotFound {
61 pub hash: blake3::Hash,
62 pub chunk_hash: blake3::Hash,
63}
64#[derive(Clone, Debug)]
65pub struct MetadataNotFound {
66 pub hash: blake3::Hash,
67 pub resource: Resource,
68}
69#[derive(Clone, Debug)]
70pub struct MissingChunks {
71 pub hash: blake3::Hash,
72 pub resource: Resource,
73}
74#[derive(Clone, Debug)]
75pub struct DownloadError {
76 pub hash: blake3::Hash,
77 pub error: String,
78}
79#[derive(Clone, Debug)]
80pub struct InsertCompleted {
81 pub hash: blake3::Hash,
82 pub path: PathBuf,
83}
84#[derive(Clone, Debug)]
85pub struct InsertError {
86 pub path: PathBuf,
87 pub error: String,
88}
89#[derive(Clone, Debug)]
90pub struct SeedersFound {
91 pub hash: blake3::Hash,
92 pub seeders: Vec<FudSeeder>,
93}
94
95#[derive(Clone, Debug)]
96pub enum FudEvent {
97 Ready,
98 DownloadStarted(DownloadStarted),
99 ChunkDownloadCompleted(ChunkDownloadCompleted),
100 MetadataDownloadCompleted(MetadataDownloadCompleted),
101 DownloadCompleted(DownloadCompleted),
102 ResourceUpdated(ResourceUpdated),
103 ResourceRemoved(ResourceRemoved),
104 ChunkNotFound(ChunkNotFound),
105 MetadataNotFound(MetadataNotFound),
106 MissingChunks(MissingChunks),
107 DownloadError(DownloadError),
108 InsertCompleted(InsertCompleted),
109 InsertError(InsertError),
110 SeedersFound(SeedersFound),
111}
112
113impl From<DownloadStarted> for JsonValue {
114 fn from(info: DownloadStarted) -> JsonValue {
115 json_map([
116 ("hash", JsonValue::String(hash_to_string(&info.hash))),
117 ("resource", info.resource.into()),
118 ])
119 }
120}
121impl From<ChunkDownloadCompleted> for JsonValue {
122 fn from(info: ChunkDownloadCompleted) -> JsonValue {
123 json_map([
124 ("hash", JsonValue::String(hash_to_string(&info.hash))),
125 ("chunk_hash", JsonValue::String(hash_to_string(&info.chunk_hash))),
126 ("resource", info.resource.into()),
127 ])
128 }
129}
130impl From<MetadataDownloadCompleted> for JsonValue {
131 fn from(info: MetadataDownloadCompleted) -> JsonValue {
132 json_map([
133 ("hash", JsonValue::String(hash_to_string(&info.hash))),
134 ("resource", info.resource.into()),
135 ])
136 }
137}
138impl From<DownloadCompleted> for JsonValue {
139 fn from(info: DownloadCompleted) -> JsonValue {
140 json_map([
141 ("hash", JsonValue::String(hash_to_string(&info.hash))),
142 ("resource", info.resource.into()),
143 ])
144 }
145}
146impl From<ResourceUpdated> for JsonValue {
147 fn from(info: ResourceUpdated) -> JsonValue {
148 json_map([
149 ("hash", JsonValue::String(hash_to_string(&info.hash))),
150 ("resource", info.resource.into()),
151 ])
152 }
153}
154impl From<ResourceRemoved> for JsonValue {
155 fn from(info: ResourceRemoved) -> JsonValue {
156 json_map([("hash", JsonValue::String(hash_to_string(&info.hash)))])
157 }
158}
159impl From<ChunkNotFound> for JsonValue {
160 fn from(info: ChunkNotFound) -> JsonValue {
161 json_map([
162 ("hash", JsonValue::String(hash_to_string(&info.hash))),
163 ("chunk_hash", JsonValue::String(hash_to_string(&info.chunk_hash))),
164 ])
165 }
166}
167impl From<MetadataNotFound> for JsonValue {
168 fn from(info: MetadataNotFound) -> JsonValue {
169 json_map([
170 ("hash", JsonValue::String(hash_to_string(&info.hash))),
171 ("resource", info.resource.into()),
172 ])
173 }
174}
175impl From<MissingChunks> for JsonValue {
176 fn from(info: MissingChunks) -> JsonValue {
177 json_map([
178 ("hash", JsonValue::String(hash_to_string(&info.hash))),
179 ("resource", info.resource.into()),
180 ])
181 }
182}
183impl From<DownloadError> for JsonValue {
184 fn from(info: DownloadError) -> JsonValue {
185 json_map([
186 ("hash", JsonValue::String(hash_to_string(&info.hash))),
187 ("error", JsonValue::String(info.error)),
188 ])
189 }
190}
191impl From<InsertCompleted> for JsonValue {
192 fn from(info: InsertCompleted) -> JsonValue {
193 json_map([
194 ("hash", JsonValue::String(hash_to_string(&info.hash))),
195 ("path", JsonValue::String(info.path.to_string_lossy().to_string())),
196 ])
197 }
198}
199impl From<InsertError> for JsonValue {
200 fn from(info: InsertError) -> JsonValue {
201 json_map([
202 ("path", JsonValue::String(info.path.to_string_lossy().to_string())),
203 ("error", JsonValue::String(info.error)),
204 ])
205 }
206}
207impl From<SeedersFound> for JsonValue {
208 fn from(info: SeedersFound) -> JsonValue {
209 json_map([
210 ("hash", JsonValue::String(hash_to_string(&info.hash))),
211 (
212 "seeders",
213 JsonValue::Array(info.seeders.iter().map(|seeder| seeder.clone().into()).collect()),
214 ),
215 ])
216 }
217}
218impl From<FudEvent> for JsonValue {
219 fn from(event: FudEvent) -> JsonValue {
220 match event {
221 FudEvent::Ready => json_map([("event", json_str("ready"))]),
222 FudEvent::DownloadStarted(info) => {
223 json_map([("event", json_str("download_started")), ("info", info.into())])
224 }
225 FudEvent::ChunkDownloadCompleted(info) => {
226 json_map([("event", json_str("chunk_download_completed")), ("info", info.into())])
227 }
228 FudEvent::MetadataDownloadCompleted(info) => json_map([
229 ("event", json_str("metadata_download_completed")),
230 ("info", info.into()),
231 ]),
232 FudEvent::DownloadCompleted(info) => {
233 json_map([("event", json_str("download_completed")), ("info", info.into())])
234 }
235 FudEvent::ResourceUpdated(info) => {
236 json_map([("event", json_str("resource_updated")), ("info", info.into())])
237 }
238 FudEvent::ResourceRemoved(info) => {
239 json_map([("event", json_str("resource_removed")), ("info", info.into())])
240 }
241 FudEvent::ChunkNotFound(info) => {
242 json_map([("event", json_str("chunk_not_found")), ("info", info.into())])
243 }
244 FudEvent::MetadataNotFound(info) => {
245 json_map([("event", json_str("metadata_not_found")), ("info", info.into())])
246 }
247 FudEvent::MissingChunks(info) => {
248 json_map([("event", json_str("missing_chunks")), ("info", info.into())])
249 }
250 FudEvent::DownloadError(info) => {
251 json_map([("event", json_str("download_error")), ("info", info.into())])
252 }
253 FudEvent::InsertCompleted(info) => {
254 json_map([("event", json_str("insert_completed")), ("info", info.into())])
255 }
256 FudEvent::InsertError(info) => {
257 json_map([("event", json_str("insert_error")), ("info", info.into())])
258 }
259 FudEvent::SeedersFound(info) => {
260 json_map([("event", json_str("seeders_found")), ("info", info.into())])
261 }
262 }
263 }
264}
265
266macro_rules! notify_event {
268 ($fud:expr, $event:ident, { $($fields:tt)* }) => {
270 $fud
271 .event_publisher
272 .notify(FudEvent::$event(event::$event {
273 $($fields)*
274 }))
275 .await;
276 };
277 ($fud:expr, $event:ident, $resource:expr) => {
279 $fud
280 .event_publisher
281 .notify(FudEvent::$event(event::$event {
282 hash: $resource.hash,
283 resource: $resource.clone(),
284 }))
285 .await;
286 };
287 ($fud:expr, $event:ident) => {
289 $fud
290 .event_publisher
291 .notify(FudEvent::$event)
292 .await;
293 };
294}
295pub(crate) use notify_event;