use std::{ collections::hash_map::DefaultHasher, hash::{Hash, Hasher}, }; use anyhow::Error; use base64::{engine::general_purpose::STANDARD, Engine as _}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use sqlx::PgPool; use crate::{ messages::discovery::{DiscoveryMessage, DiscoveryMessageKind}, model::{discovery::DiscoveryItem, repository::Repository}, }; use super::DiscoveryBackend; pub struct GiteratedDiscoveryProtocol { pub pool: PgPool, } #[derive(Debug, Hash, Serialize, Deserialize, Clone, sqlx::Type)] #[sqlx(type_name = "discovery_type", rename_all = "lowercase")] pub enum DiscoveryType { Instance, Repository, } #[async_trait::async_trait] impl DiscoveryBackend for GiteratedDiscoveryProtocol { async fn try_handle(&mut self, request: &DiscoveryMessage) -> Result { if request .message .validate(&request.message.instance) .await .is_err() { return Ok(false); } let inner = request.message.inner().await.clone(); match inner { DiscoveryMessageKind::Discoveries(mut discoveries) => { let discoveries = discoveries.discoveries.drain(..).map(|discovery| { let hash = { let mut hasher = DefaultHasher::new(); discovery.hash(&mut hasher); STANDARD.encode(hasher.finish().to_be_bytes()) }; let (discovery_type, discovery) = match discovery { DiscoveryItem::Instance { instance, signature, } => (DiscoveryType::Instance, instance.to_string()), DiscoveryItem::Repository { repository, signature, } => (DiscoveryType::Repository, repository.to_string()), }; DiscoveriesRow { discovery_hash: hash, discovery_time: Utc::now(), discovery_type, discovery, } }); for row in discoveries { let result = sqlx::query!( r#"INSERT INTO discoveries VALUES ($1, $2, $3, $4)"#, row.discovery_hash, row.discovery_time.to_string(), row.discovery_type as _, row.discovery ) .execute(&self.pool) .await; match result { Ok(_) => {}, Err(err) => { error!("Error inserting discovery. {:?}", err); } } } Ok(true) } DiscoveryMessageKind::Offer(offer) => Ok(true), DiscoveryMessageKind::Request(request) => Ok(true), } } async fn search(&mut self, _search: &str) -> Result, Error> { todo!() } } #[derive(Debug, sqlx::FromRow, sqlx::Type)] pub struct DiscoveriesRow { discovery_hash: String, discovery_time: DateTime, discovery_type: DiscoveryType, discovery: String, }