use std::io::{BufReader, Read};
use std::sync::Arc;
use url::Url;
use crate::BYTE_LIMIT;
pub use access::AccessResult;
use inner::RobotsInner;
mod access;
mod inner;
mod lexer;
mod parser;
mod rule;
#[cfg(feature = "serde")]
use ::serde::{Deserialize, Serialize};
#[cfg(feature = "serde")]
mod serde;
pub const ALL_UAS: &str = "*";
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Robots {
#[cfg_attr(feature = "serde", serde(flatten))]
inner: Arc<RobotsInner>,
}
impl Robots {
pub fn from_bytes(robots: &[u8], user_agent: &str) -> Self {
let inner = RobotsInner::from_bytes(robots, user_agent);
Self {
inner: Arc::new(inner),
}
}
pub fn from_reader<R: Read>(reader: R, user_agent: &str) -> Result<Self, std::io::Error> {
let reader = reader.take(BYTE_LIMIT as u64);
let mut reader = BufReader::new(reader);
let mut buffer = Vec::new();
reader.read_to_end(&mut buffer)?;
let robots = buffer.as_slice();
Ok(Self::from_bytes(robots, user_agent))
}
pub fn from_access(access: AccessResult, user_agent: &str) -> Self {
use AccessResult as AR;
match access {
AR::Successful(txt) => Self::from_bytes(txt, user_agent),
AR::Redirect | AR::Unavailable => Self::from_always(true, user_agent),
AR::Unreachable => Self::from_always(false, user_agent),
}
}
pub fn from_always(always: bool, user_agent: &str) -> Self {
let inner = RobotsInner::from_always(always, None, user_agent);
Self {
inner: Arc::new(inner),
}
}
#[cfg(feature = "builder")]
#[cfg_attr(docsrs, doc(cfg(feature = "builder")))]
pub fn builder() -> crate::RobotsBuilder {
crate::RobotsBuilder::new()
}
}
impl Robots {
pub fn try_is_relative_allowed(&self, addr: &str) -> Option<bool> {
self.inner.try_is_allowed(addr)
}
pub fn is_relative_allowed(&self, addr: &str) -> bool {
self.inner.is_allowed(addr)
}
pub fn try_is_absolute_allowed(&self, addr: &Url) -> Option<bool> {
let path = addr.path().to_owned();
let query = addr
.query()
.map(|u| "?".to_owned() + u)
.unwrap_or("".to_owned());
let frag = addr
.fragment()
.map(|u| "#".to_owned() + u)
.unwrap_or("".to_owned());
let relative = path + &query + &frag;
self.inner.try_is_allowed(&relative)
}
pub fn is_absolute_allowed(&self, addr: &Url) -> bool {
self.try_is_absolute_allowed(addr).unwrap_or(true)
}
pub fn is_always(&self) -> Option<bool> {
self.inner.is_always()
}
pub fn user_agent(&self) -> &str {
self.inner.user_agent()
}
pub fn crawl_delay(&self) -> Option<std::time::Duration> {
self.inner.crawl_delay()
}
pub fn sitemaps(&self) -> &[Url] {
self.inner.sitemaps()
}
pub fn len(&self) -> Option<usize> {
self.inner.len()
}
pub fn is_empty(&self) -> Option<bool> {
self.inner.is_empty()
}
}