use crate::prelude::*;
use super::Cites;
use chromedriver_api::{ Session, Tab };
pub trait SearchOptions {
fn new() -> Self;
fn url(&self) -> String;
fn search(&self, query: &str) -> String;
fn parse(&self) -> String;
}
pub struct SearchEngine<O>
where
O: SearchOptions
{
params: O,
session: Arc<TokioMutex<Option<Session>>>,
tab: Arc<TokioMutex<Tab>>,
}
impl<O> SearchEngine<O>
where
O: SearchOptions
{
pub async fn new<P: Into<PathBuf>>(chrome_path: P, session_path: Option<PathBuf>, headless: bool) -> Result<Self> {
let params = O::new();
let free_port = std::net::TcpListener::bind("127.0.0.1:0")?.local_addr()?.port().to_string();
let mut session = Session::run(
&free_port,
chrome_path.into(),
session_path,
headless
).await?;
let tab = session.open(params.url()).await?;
Ok(Self {
params,
session: Arc::new(TokioMutex::new(Some(session))),
tab,
})
}
pub async fn search(&mut self, query: &str, black_list: &[&str], sleep: u64) -> Result<Cites> {
let mut tab = self.tab.lock().await;
tab.open(self.params.url()).await?;
let query = query.trim().replace("\"", "'");
let status = tab.inject::<bool>(&self.params.search(&query)).await?;
if !status {
tab.close().await.ok();
return Err(Error::FailedGetResults.into());
}
sleep2(Duration::from_millis(100 + sleep)).await;
let results = tab.inject::<Vec<String>>(&self.params.parse()).await?;
drop(tab);
Ok(Cites::new(self.tab.clone(), results, black_list))
}
pub async fn stop(self) -> Result<()> {
if let Some(session) = self.session.lock().await.take() {
session.close().await?;
}
Ok(())
}
}