use std::time::Duration;
use serde::de::DeserializeOwned;
use serde::Deserialize;
use serde_json::Value;
use crate::error::{Error, Result};
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct Response<T> {
pub request_id: Option<String>,
pub credits_used: Option<i64>,
pub credits_remaining: Option<i64>,
pub data: T,
}
#[derive(Debug, Clone, Deserialize)]
pub struct LinkInfo {
pub url: Option<String>,
pub text: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct PageMetadata {
pub title: Option<String>,
pub description: Option<String>,
pub language: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ScrapeData {
pub request_id: Option<String>,
pub html: Option<String>,
pub content_type: Option<String>,
pub cleaned: Option<bool>,
pub links: Option<Vec<LinkInfo>>,
pub metadata: Option<PageMetadata>,
pub structured_data: Option<Value>,
pub latency_ms: Option<i64>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SmartScraperData {
pub request_id: Option<String>,
pub result: Option<Value>,
pub latency_ms: Option<i64>,
}
impl SmartScraperData {
pub fn result_as<T: DeserializeOwned>(&self) -> Result<T> {
match &self.result {
Some(v) => serde_json::from_value(v.clone())
.map_err(|e| Error::Decode(format!("failed to decode smartscraper result: {e}"))),
None => Err(Error::Decode("smartscraper result was null".to_string())),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum RunStatus {
Queued,
Running,
Completed,
Failed,
Cancelled,
#[serde(other)]
Unknown,
}
impl RunStatus {
pub fn is_terminal(&self) -> bool {
matches!(
self,
RunStatus::Completed | RunStatus::Failed | RunStatus::Cancelled
)
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct SmartBrowseDispatch {
pub run_id: String,
pub recipe_id: String,
pub run_status: RunStatus,
pub poll_url: Option<String>,
pub created_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SmartBrowseRun {
pub id: String,
pub recipe_id: String,
pub run_status: RunStatus,
pub pages_extracted: Option<i64>,
pub items_extracted: Option<i64>,
pub credits_used: Option<i64>,
pub started_at: Option<String>,
pub completed_at: Option<String>,
pub error: Option<String>,
pub result: Option<Value>,
pub created_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SmartBrowseLastRun {
pub id: String,
pub status: RunStatus,
pub pages_extracted: Option<i64>,
pub effective_cap: Option<i64>,
pub clamped_by_credits: Option<bool>,
pub created_at: Option<String>,
pub completed_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SmartBrowseUsage {
pub runs_used_30d: Option<i64>,
pub runs_per_month_cap: Option<i64>,
pub pages_per_run_cap: Option<i64>,
pub cost_per_page: Option<i64>,
pub schedules_count: Option<i64>,
pub schedules_allowed: Option<bool>,
pub last_run: Option<SmartBrowseLastRun>,
}
#[derive(Debug, Clone, Copy)]
pub struct WaitOptions {
pub poll_interval: Duration,
pub timeout: Duration,
}
impl Default for WaitOptions {
fn default() -> Self {
Self {
poll_interval: Duration::from_secs(2),
timeout: Duration::from_secs(900),
}
}
}
impl WaitOptions {
pub fn new() -> Self {
Self::default()
}
pub fn poll_interval(mut self, interval: Duration) -> Self {
self.poll_interval = interval;
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
}