1pub mod api;
2pub mod request;
3
4use serde::{Deserialize, Serialize};
5
6const QUERY: &str = "podping";
7pub(crate) const HIVE_API: &str = "https://api.hive.blog";
8
9#[derive(Debug)]
10pub(crate) struct HiveClient {
11 pub client: reqwest::Client,
12 block: Option<u64>,
13}
14
15impl HiveClient {
16 pub(crate) fn new(block: Option<u64>) -> Self {
17 let client = reqwest::Client::new();
18 Self { client, block }
19 }
20
21 pub(crate) async fn init(&mut self) {
22 match &self.block {
23 Some(_) => {}
24 None => {
25 let block = self.get_head_block_number();
26 self.block = Some(block.await);
27 }
28 }
29 }
30
31 pub(crate) async fn next_block(&mut self) {
32 if let Some(block) = self.block_mut() {
33 *block += 1
34 }
35 }
36
37 pub(crate) async fn get_head_block_number(&self) -> u64 {
39 self.get_dynamic_global_properties()
40 .await
41 .get_head_block_number()
42 .unwrap()
43 }
44
45 pub(crate) async fn get_dynamic_global_properties(&self) -> HiveResponse {
47 self.client
48 .post(HIVE_API)
49 .json(&HiveMessage::get_dynamic_global_properties())
50 .send()
51 .await
52 .unwrap()
53 .json::<HiveResponse>()
54 .await
55 .unwrap()
56 }
57
58 pub(crate) fn block(&self) -> Option<u64> {
59 self.block
60 }
61
62 pub(crate) fn block_mut(&mut self) -> &mut Option<u64> {
63 &mut self.block
64 }
65
66 pub(crate) fn set_block(&mut self, block: Option<u64>) {
67 self.block = block;
68 }
69
70 pub(crate) fn get_payloads(&self, operations: Vec<Operations>) -> Vec<String> {
72 let mut payloads = vec![];
74 for tr in operations {
75 let json_payload = serde_json::from_str::<OpPayload>(&tr.json.unwrap()).unwrap();
76 payloads = json_payload.iris;
77 if json_payload.reason == "live" {
79 let item = format!("live: {:?}", self.block);
80 std::process::Command::new("notify-send")
81 .arg(item)
82 .output()
83 .expect("failed to execute process");
84 }
85 }
86
87 if !payloads.is_empty() {
88 println!("block: {:?}, payloads: {:?}", self.block, payloads);
89 }
90 payloads
91 }
92 pub(crate) async fn get_operations(&self) -> Vec<Operations> {
95 let transactions = self.get_transactions().await;
96
97 let mut operations = vec![];
98 for transaction in transactions {
99 for operation in transaction.operations {
100 for op in operation {
101 match op {
102 HiveOperation::Operations(operation) => {
103 if let Some(name) = &operation.id {
104 if name == QUERY {
106 operations.push(operation);
107 }
108 }
109 }
110 HiveOperation::String(_)
112 | HiveOperation::Vote(_)
113 | HiveOperation::Transfer(_)
114 | HiveOperation::Transactions(_)
115 | HiveOperation::Comment(_) => {}
116 }
117 }
118 }
119 }
120 operations
121 }
122 pub(crate) async fn get_block(&self) -> HiveResponse {
123 let block_response = HiveMessage::get_block(self.block.unwrap());
124 let resp = self
125 .client
126 .post(HIVE_API)
127 .json(&block_response)
128 .send()
129 .await
130 .unwrap()
131 .text()
132 .await
133 .unwrap();
134 serde_json::from_str::<HiveResponse>(&resp).unwrap()
137 }
138
139 pub(crate) async fn get_transactions(&self) -> Vec<Transactions> {
140 let hive_response = &self.get_block().await;
141 if let Some(HiveResponseResult::Block(block)) = &hive_response.result {
142 block.transactions.clone()
143 } else {
144 vec![]
145 }
146 }
147}
148#[derive(Debug)]
149pub(crate) struct HiveClientBlocking {
150 pub client: reqwest::blocking::Client,
151 block: Option<u64>,
152}
153
154impl HiveClientBlocking {
155 pub(crate) fn new(block: Option<u64>) -> Self {
156 let client = reqwest::blocking::Client::new();
157 Self { client, block }
158 }
159 pub(crate) fn init(&mut self) {
160 match &self.block {
161 Some(_) => {}
162 None => {
163 let block = self.get_head_block_number();
164 self.block = Some(block);
165 }
166 }
167 }
168
169 pub(crate) fn get_head_block_number(&self) -> u64 {
170 let resp = self
171 .client
172 .post(HIVE_API)
173 .json(&HiveMessage::get_dynamic_global_properties())
174 .send()
175 .unwrap()
176 .json::<HiveResponse>()
177 .unwrap();
178 resp.get_head_block_number().unwrap()
179 }
180
181 pub(crate) fn get_operations(&self) -> Vec<Operations> {
184 let transactions = self.get_transactions();
185
186 let mut operations = vec![];
187 for transaction in transactions {
188 for operation in transaction.operations {
189 for op in operation {
190 match op {
191 HiveOperation::Operations(operation) => {
192 if let Some(name) = &operation.id {
193 if name == QUERY {
195 operations.push(operation);
196 }
197 }
198 }
199 HiveOperation::String(_)
201 | HiveOperation::Vote(_)
202 | HiveOperation::Transfer(_)
203 | HiveOperation::Transactions(_)
204 | HiveOperation::Comment(_) => {}
205 }
206 }
207 }
208 }
209 operations
210 }
211
212 pub(crate) fn get_transactions(&self) -> Vec<Transactions> {
213 let block_response = HiveMessage::get_block(self.block.unwrap());
214 let resp = self
215 .client
216 .post(HIVE_API)
217 .json(&block_response)
218 .send()
219 .unwrap()
220 .text()
221 .unwrap();
222 let hive_response = serde_json::from_str::<HiveResponse>(&resp).unwrap();
225
226 if let Some(HiveResponseResult::Block(block)) = hive_response.result {
227 block.transactions
228 } else {
229 vec![]
230 }
231 }
232
233 pub(crate) fn get_payloads(&self, operations: Vec<Operations>) -> Vec<String> {
235 let mut payloads = vec![];
237 for tr in operations {
238 let mut json_payload = serde_json::from_str::<OpPayload>(&tr.json.unwrap()).unwrap();
239 payloads.append(&mut json_payload.iris);
240 }
241 payloads
242 }
243
244 pub(crate) fn block(&self) -> Option<u64> {
245 self.block
246 }
247
248 pub(crate) fn block_mut(&mut self) -> &mut Option<u64> {
249 &mut self.block
250 }
251
252 pub(crate) fn set_block(&mut self, block: Option<u64>) {
253 self.block = block;
254 }
255
256 pub(crate) fn next_block(&mut self) {
257 if let Some(block) = self.block_mut() {
258 *block += 1
259 }
260 }
261}
262
263#[derive(Debug, Serialize, Deserialize)]
264pub(crate) struct HiveRequest {
265 jsonrpc: String,
266 method: String,
267 id: u8,
268}
269
270#[derive(Debug, Serialize, Deserialize)]
271pub(crate) struct HiveRequestParams {
272 jsonrpc: String,
273 method: String,
274 params: Vec<ParamMember>,
275 id: u8,
276}
277
278#[derive(Debug, Serialize, Deserialize)]
279#[serde(untagged)]
280pub(crate) enum HiveMessage {
281 Request(HiveRequest),
282 RequestParams(HiveRequestParams),
283 Response(HiveResponse),
284}
285
286#[derive(Debug, Serialize, Deserialize)]
287#[serde(untagged)]
288pub(crate) enum ParamMember {
289 String(String),
290 Int(u16),
291 Int128(u128),
292 Int64(u64),
293 None,
294}
295
296impl HiveMessage {
297 pub(crate) fn get_followers() -> Self {
298 Self::RequestParams(HiveRequestParams {
299 jsonrpc: "2.0".into(),
300 method: "condenser_api.get_followers".into(),
301 params: vec![
302 ParamMember::String(QUERY.into()),
303 ParamMember::None,
304 ParamMember::String("blog".into()),
305 ParamMember::Int(100),
306 ],
307 id: 1,
308 })
309 }
310 pub(crate) fn get_methods() -> Self {
311 Self::Request(HiveRequest {
312 jsonrpc: "2.0".into(),
313 method: "jsonrpc.get_methods".into(),
314 id: 1,
315 })
316 }
317 pub(crate) fn get_dynamic_global_properties() -> Self {
318 Self::Request(HiveRequest {
319 jsonrpc: "2.0".into(),
320 method: "database_api.get_dynamic_global_properties".into(),
321 id: 1,
322 })
323 }
324 pub(crate) fn get_block(block: u64) -> Self {
325 Self::RequestParams(HiveRequestParams {
326 jsonrpc: "2.0".into(),
327 method: "condenser_api.get_block".into(),
328 params: vec![ParamMember::Int64(block)],
329 id: 1,
330 })
331 }
332}
333
334#[derive(Debug, Clone, Serialize, Deserialize)]
335pub struct HiveResponse {
336 pub jsonrpc: String,
337 pub id: u16,
338 pub result: Option<HiveResponseResult>,
340}
341
342impl HiveResponse {
343 pub(crate) fn get_head_block_number(&self) -> Option<u64> {
344 if let Some(response) = &self.result {
345 response.get_head_block_number()
346 } else {
347 None
348 }
349 }
350}
351
352impl HiveResponseResult {
353 pub(crate) fn get_head_block_number(&self) -> Option<u64> {
354 match self {
355 HiveResponseResult::DynamicGlobalProperties(properties) => {
356 Some(properties.head_block_number)
357 }
358 _ => None,
359 }
360 }
361}
362
363#[derive(Clone, Debug, Serialize, Deserialize)]
364#[serde(untagged)]
365pub enum HiveResponseResult {
366 DynamicGlobalProperties(HiveDynamicGlobalProperties),
367 Block(Block),
368}
369
370#[derive(Clone, Debug, Serialize, Deserialize)]
371pub struct HiveDynamicGlobalProperties {
372 id: u16,
373 head_block_number: u64,
374 }
380
381#[derive(Clone, Debug, Serialize, Deserialize)]
382pub struct Block {
383 pub transactions: Vec<Transactions>,
387 }
395
396#[derive(Clone, Debug, Serialize, Deserialize)]
397pub struct Transactions {
399 pub(crate) operations: Vec<Vec<HiveOperation>>,
403}
404
405#[derive(Clone, Debug, Serialize, Deserialize)]
406#[serde(untagged)]
407pub enum HiveOperation {
408 Operations(Operations),
409 String(String),
410 Vote(Vote),
411 Transfer(Transfer),
412 Transactions(Transactions),
413 Comment(Comment),
414}
415
416#[derive(Clone, Debug, Serialize, Deserialize)]
417pub struct Operations {
418 required_auths: Vec<String>,
419 required_posting_auths: Vec<String>,
420 pub id: Option<String>,
421 pub json: Option<String>,
422}
423
424#[derive(Clone, Debug, Serialize, Deserialize)]
425pub struct OpPayload {
426 version: String,
427 num_urls: Option<u8>,
428 pub medium: String,
429 pub reason: String,
430 pub iris: Vec<String>,
432}
433
434#[derive(Clone, Debug, Serialize, Deserialize)]
435pub struct Vote {
436 voter: Option<String>,
437 author: Option<String>,
438 permlink: Option<String>,
439 }
441
442#[derive(Clone, Debug, Serialize, Deserialize)]
443pub struct Transfer {
444 from: Option<String>,
445 to: Option<String>,
446 amount: Option<String>,
447 memo: Option<String>,
448 }
450
451#[derive(Clone, Debug, Serialize, Deserialize)]
452pub struct Comment {
453 parent_author: Option<String>,
454 parent_permlink: Option<String>,
455 author: Option<String>,
456 title: Option<String>,
457 }