use crate::errors::DomainError; use crate::job::{Job, JobId, JobKind, JobSubject}; use crate::user::UserId; #[async_trait::async_trait] pub trait JobQueueCommandPort: Send + Sync { async fn enqueue(&self, kind: JobKind, subject: &JobSubject) -> Result; async fn claim(&self, kind: JobKind, most: usize) -> Result, DomainError>; async fn finish(&self, id: &JobId) -> Result<(), DomainError>; async fn release(&self, id: &JobId, reason: &str) -> Result<(), DomainError>; async fn exhaust(&self, id: &JobId, reason: &str) -> Result<(), DomainError>; async fn reclaim_stalled(&self, stalled_after_seconds: i64) -> Result; } #[async_trait::async_trait] pub trait JobQueueQueryPort: Send + Sync { async fn find_exhausted(&self, most: usize) -> Result, DomainError>; } #[async_trait::async_trait] pub trait WeatherLookupPort: Send + Sync { fn provider(&self) -> &crate::provider::ProviderName; async fn observed_at( &self, coordinates: &crate::location::Coordinates, instant: &chrono::DateTime, ) -> Result, DomainError>; } pub struct UnwatchedPlace { pub entry_id: crate::entry::MoodEntryId, pub coordinates: crate::location::Coordinates, pub logged_at: chrono::DateTime, } impl UnwatchedPlace { pub fn subject(&self) -> JobSubject { JobSubject::Entry(self.entry_id.clone()) } } #[async_trait::async_trait] pub trait WeatherBacklogQueryPort: Send + Sync { async fn find_places_without_weather( &self, most: usize, ) -> Result, DomainError>; } #[async_trait::async_trait] pub trait RecordingBackfillQueryPort: Send + Sync { async fn find_songs_without_a_recording( &self, most: usize, ) -> Result, DomainError>; async fn record_identity( &self, entry_id: &crate::entry::MoodEntryId, recording_id: &crate::song::RecordingId, ) -> Result<(), DomainError>; } pub struct UnidentifiedSong { pub entry_id: crate::entry::MoodEntryId, pub user_id: UserId, pub title: String, pub artist: String, } impl UnidentifiedSong { pub fn subject(&self) -> JobSubject { JobSubject::Entry(self.entry_id.clone()) } }