flaresolverr life cycle

This commit is contained in:
Simon
2026-04-05 20:55:15 +00:00
parent 7b464fe796
commit bc2a73dd06

View File

@@ -1,10 +1,11 @@
use std::{collections::HashMap, env}; use std::{collections::HashMap, env};
use serde_json::json; use serde_json::json;
use serde_json::Value;
use wreq::{Client, Proxy}; use wreq::{Client, Proxy};
use wreq_util::Emulation; use wreq_util::Emulation;
#[derive(serde::Serialize, serde::Deserialize, Debug)] #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct FlareSolverrRequest { pub struct FlareSolverrRequest {
pub cmd: String, pub cmd: String,
pub url: String, pub url: String,
@@ -64,20 +65,16 @@ impl Flaresolverr {
self.proxy = proxy; self.proxy = proxy;
} }
pub async fn solve( async fn post_payload(
&self, &self,
request: FlareSolverrRequest, payload: Value,
) -> Result<FlareSolverrResponse, Box<dyn std::error::Error>> { ) -> Result<Value, Box<dyn std::error::Error + Send + Sync>> {
let client = Client::builder().emulation(Emulation::Firefox136).build()?; let client = Client::builder().emulation(Emulation::Firefox136).build()?;
let mut req = client let mut req = client
.post(&self.url) .post(&self.url)
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.json(&json!({ .json(&payload);
"cmd": request.cmd,
"url": request.url,
"maxTimeout": request.maxTimeout,
}));
if self.proxy { if self.proxy {
if let Ok(proxy_url) = env::var("BURP_URL") { if let Ok(proxy_url) = env::var("BURP_URL") {
@@ -93,8 +90,72 @@ impl Flaresolverr {
} }
let response = req.send().await?; let response = req.send().await?;
let body = response.json::<Value>().await?;
let body = response.json::<FlareSolverrResponse>().await?; if body
.get("status")
.and_then(Value::as_str)
.is_some_and(|status| status.eq_ignore_ascii_case("error"))
{
let message = body
.get("message")
.and_then(Value::as_str)
.unwrap_or("FlareSolverr returned status=error");
return Err(message.to_string().into());
}
Ok(body) Ok(body)
} }
async fn create_session(&self) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
let body = self.post_payload(json!({ "cmd": "sessions.create" })).await?;
let session = body
.get("session")
.and_then(Value::as_str)
.ok_or("sessions.create response missing `session`")?;
Ok(session.to_string())
}
async fn destroy_session(
&self,
session: &str,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let _ = self
.post_payload(json!({
"cmd": "sessions.destroy",
"session": session,
}))
.await?;
Ok(())
}
async fn solve_with_session(
&self,
request: FlareSolverrRequest,
session: &str,
) -> Result<FlareSolverrResponse, Box<dyn std::error::Error + Send + Sync>> {
let body = self
.post_payload(json!({
"cmd": request.cmd,
"url": request.url,
"maxTimeout": request.maxTimeout,
"session": session,
}))
.await?;
let typed = serde_json::from_value::<FlareSolverrResponse>(body)?;
Ok(typed)
}
pub async fn solve(
&self,
request: FlareSolverrRequest,
) -> Result<FlareSolverrResponse, Box<dyn std::error::Error + Send + Sync>> {
let session = self.create_session().await?;
let result = self.solve_with_session(request, &session).await;
if let Err(error) = self.destroy_session(&session).await {
eprintln!(
"FlareSolverr session cleanup failed for session '{}': {}",
session, error
);
}
result
}
} }