From bc2a73dd061868643bd9d6d6eca5467095a544e5 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 5 Apr 2026 20:55:15 +0000 Subject: [PATCH] flaresolverr life cycle --- src/util/flaresolverr.rs | 83 ++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 11 deletions(-) diff --git a/src/util/flaresolverr.rs b/src/util/flaresolverr.rs index d19a32c..ac001b9 100644 --- a/src/util/flaresolverr.rs +++ b/src/util/flaresolverr.rs @@ -1,10 +1,11 @@ use std::{collections::HashMap, env}; use serde_json::json; +use serde_json::Value; use wreq::{Client, Proxy}; use wreq_util::Emulation; -#[derive(serde::Serialize, serde::Deserialize, Debug)] +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct FlareSolverrRequest { pub cmd: String, pub url: String, @@ -64,20 +65,16 @@ impl Flaresolverr { self.proxy = proxy; } - pub async fn solve( + async fn post_payload( &self, - request: FlareSolverrRequest, - ) -> Result> { + payload: Value, + ) -> Result> { let client = Client::builder().emulation(Emulation::Firefox136).build()?; let mut req = client .post(&self.url) .header("Content-Type", "application/json") - .json(&json!({ - "cmd": request.cmd, - "url": request.url, - "maxTimeout": request.maxTimeout, - })); + .json(&payload); if self.proxy { if let Ok(proxy_url) = env::var("BURP_URL") { @@ -93,8 +90,72 @@ impl Flaresolverr { } let response = req.send().await?; - - let body = response.json::().await?; + let body = response.json::().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) } + + async fn create_session(&self) -> Result> { + 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> { + let _ = self + .post_payload(json!({ + "cmd": "sessions.destroy", + "session": session, + })) + .await?; + Ok(()) + } + + async fn solve_with_session( + &self, + request: FlareSolverrRequest, + session: &str, + ) -> Result> { + let body = self + .post_payload(json!({ + "cmd": request.cmd, + "url": request.url, + "maxTimeout": request.maxTimeout, + "session": session, + })) + .await?; + let typed = serde_json::from_value::(body)?; + Ok(typed) + } + + pub async fn solve( + &self, + request: FlareSolverrRequest, + ) -> Result> { + 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 + } }