argus-frontier 0.1.0

URL frontier implementations for web crawling
Documentation
use std::collections::VecDeque;
use std::sync::Arc;
use tokio::sync::Mutex;

use async_trait::async_trait;

use argus_common::CrawlJob;

use crate::frontier::Frontier;

#[derive(Clone, Default)]
pub struct InMemoryFrontier {
    queue: Arc<Mutex<VecDeque<CrawlJob>>>,
}

#[async_trait]
impl Frontier for InMemoryFrontier {
    async fn push(&self, job: CrawlJob) {
        let mut q = self.queue.lock().await;
        q.push_back(job);
    }

    async fn pop(&self) -> Option<CrawlJob> {
        let mut q = self.queue.lock().await;
        q.pop_front()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn job(url: &str, depth: u16) -> CrawlJob {
        CrawlJob {
            url: url.to_string(),
            normalized_url: url.to_string(),
            host: "example.com".to_string(),
            depth,
        }
    }

    #[tokio::test]
    async fn push_pop_fifo_order() {
        let frontier = InMemoryFrontier::default();
        frontier.push(job("https://a.com", 0)).await;
        frontier.push(job("https://b.com", 1)).await;
        let first = frontier.pop().await.unwrap();
        let second = frontier.pop().await.unwrap();
        assert_eq!(first.url, "https://a.com");
        assert_eq!(second.url, "https://b.com");
    }

    #[tokio::test]
    async fn pop_empty_returns_none() {
        let frontier = InMemoryFrontier::default();
        assert!(frontier.pop().await.is_none());
    }
}