extern crate bytes;
extern crate futures;
extern crate hyper;
extern crate hyper_tls;
use crate::component::{ParseError, Profile, Request, Task};
use crate::engine::{App, AppArg};
use crate::plugin::{MiddleWare, Spider};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::{Arc, Mutex};
pub struct ParseResult<E, T, P>
where
T: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug + Clone,
P: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug + Clone,
E: Serialize + std::fmt::Debug + Clone,
{
pub req: Vec<Request<T, P>>,
pub task: Vec<Task<T>>,
pub profile: Vec<Profile<P>>,
pub entities: Vec<E>,
pub yield_err: Vec<String>,
}
unsafe impl<E, T, P> Sync for ParseResult<E, T, P>
where
T: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug + Clone,
P: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug + Clone,
E: Serialize + std::fmt::Debug + Clone,
{
}
unsafe impl<E, T, P> Send for ParseResult<E, T, P>
where
T: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug + Clone,
P: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug + Clone,
E: Serialize + std::fmt::Debug + Clone,
{
}
#[derive(Clone, Debug)]
pub struct Response<T, P>
where
T: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug + Clone,
P: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug + Clone,
{
pub task: Task<T>,
pub profile: Profile<P>,
pub status: usize,
pub content: Option<String>,
pub headers: HashMap<String, String>,
pub msg: Option<String>,
}
unsafe impl<T, P> Sync for Response<T, P>
where
T: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug + Clone,
P: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug + Clone,
{
}
unsafe impl<T, P> Send for Response<T, P>
where
T: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug + Clone,
P: Serialize + for<'a> Deserialize<'a> + std::fmt::Debug + Clone,
{
}
impl<'t, T, P> Response<T, P>
where
T: Serialize + for<'a> Deserialize<'a> + Debug + Clone + Send,
P: Serialize + for<'a> Deserialize<'a> + Debug + Clone,
{
pub async fn parse<'b, E>(
res: Response<T, P>,
spd: &'static dyn Spider<E, T, P>,
mware: &'t MiddleWare<'b, E, T, P>,
arg: Arc<Mutex<AppArg>>,
) -> Result<ParseResult<E, T, P>, ParseError>
where
E: Serialize + std::fmt::Debug + Clone + Send,
{
let status = res.status;
if status <= 299 && status >= 200 {
log::debug!(
"recycle profile, successful Response: uri: {}",
&res.task.uri[0..77]
);
let content = res.content.clone().unwrap();
let uri = res.task.uri.clone();
let pfile = res.profile.clone();
let ind = (&res.task.parser).to_string();
let parser = spd
.get_parser(ind)
.expect(&format!("parser {} not found.", &res.task.parser));
let data = (parser)(res);
match data {
Ok(prs) => Ok(prs),
Err(_) => {
log::error!("cannot parse Response");
let mut r = ParseResult {
req: vec![],
task: vec![],
profile: vec![pfile],
entities: vec![],
yield_err: vec![],
};
let s = format!("{}\n{}", uri, content);
r.yield_err.push(s);
Ok(r)
}
}
} else {
log::error!("failed Response: {:?}", res);
let r = (mware.hand_err)(&mut vec![res], arg).await;
Ok(ParseResult {
task: r.0,
profile: r.1,
req: r.2,
entities: vec![],
yield_err: r.3,
})
}
}
pub async fn parse_all<'b, E>(
app: &'t mut App<E, T, P>,
round: usize,
spd: &'static dyn Spider<E, T, P>,
mware: &'t MiddleWare<'b, E, T, P>,
) where
E: Serialize + std::fmt::Debug + Clone + Send,
{
let mut v = Vec::new();
let len = app.res.lock().unwrap().len();
vec![0; len.min(round)].iter().for_each(|_| {
let t = app.res.lock().unwrap().remove(0);
v.push(t);
});
(mware.hand_res)(&mut v, app.rt_args.clone()).await;
while let Some(res) = v.pop() {
let fut = Response::parse(res, spd, &mware, app.rt_args.clone());
match fut.await {
Ok(mut prs) => {
if !prs.req.is_empty() {
let (task, pfile) =
(mware.hand_req)(&mut prs.req, app.rt_args.clone()).await;
prs.profile.extend(pfile);
prs.task.extend(task);
app.req.lock().unwrap().extend(prs.req);
}
if !prs.profile.is_empty() {
(mware.hand_profile)(&mut prs.profile, app.rt_args.clone()).await;
app.profile.lock().unwrap().extend(prs.profile);
}
if !prs.task.is_empty() {
(mware.hand_task)(&mut prs.task, app.rt_args.clone()).await;
app.task_tmp.lock().unwrap().extend(prs.task);
}
if !prs.entities.is_empty() {
(mware.hand_item)(&mut prs.entities, app.rt_args.clone()).await;
app.result.lock().unwrap().extend(prs.entities);
}
if !prs.yield_err.is_empty() {
app.yield_err.lock().unwrap().extend(prs.yield_err);
};
let mut rate = &mut app.rt_args.lock().unwrap().rate;
if rate.active == true && rate.uptime >= 0.5 * rate.interval {
rate.active = false;
rate.uptime = 0.0;
}
}
Err(_) => {
log::error!("parse response failed.");
}
}
}
}
}
impl<T, P> Response<T, P>
where
T: Serialize + for<'a> Deserialize<'a> + Debug + Clone,
P: Serialize + for<'a> Deserialize<'a> + Debug + Clone,
{
pub fn default(req: Option<&Request<T, P>>) -> Response<T, P> {
let r = match req {
Some(r) => r.clone(),
None => Request::default(),
};
Response {
task: r.task,
profile: r.profile,
msg: None,
content: None,
headers: std::collections::HashMap::new(),
status: 0,
}
}
}