use rustybook_extractor::html::extract_user_name;
use rustybook_http::client::Client as HttpClient;
use tracing::{
debug,
trace,
warn,
};
use super::extract::{
extract_client_revision,
extract_fb_dtsg,
extract_jazoest,
extract_lsd,
extract_mqtt_config,
};
use super::http::build_http_client;
use super::{
DEFAULT_USER_AGENT,
State,
};
use crate::auth::load_cookies;
use crate::error::MessengerError;
impl State {
pub async fn from_cookies_file(
path: &str,
user_agent: Option<&str>,
proxy: Option<&str>,
) -> Result<Self, MessengerError> {
let auth = load_cookies(path)?;
let user_agent = user_agent.unwrap_or(DEFAULT_USER_AGENT).to_string();
let http = build_http_client(&auth.cookie_header, &user_agent, proxy)?;
let mut state = State {
user_id: auth.user_id.clone(),
user_agent,
cookie_header: auth.cookie_header,
http: Some(http),
..State::default()
};
state.bootstrap().await?;
Ok(state)
}
pub async fn from_shared(
user_id: String,
cookie_header: String,
http: HttpClient,
user_agent: Option<&str>,
) -> Result<Self, MessengerError> {
let user_agent = user_agent.unwrap_or(DEFAULT_USER_AGENT).to_string();
let mut state = State {
user_id,
user_agent,
cookie_header,
http: Some(http),
..State::default()
};
state.bootstrap().await?;
Ok(state)
}
async fn bootstrap(&mut self) -> Result<(), MessengerError> {
let html = self.fetch_bootstrap_html().await?;
self.user_name = extract_user_name(&html).map_err(|error| {
MessengerError::State(format!("failed to extract user name from html: {error}"))
})?;
self.fb_dtsg = extract_fb_dtsg(&html)?;
self.lsd = extract_lsd(&html)?;
self.jazoest = extract_jazoest(&html)?;
self.client_revision = extract_client_revision(&html);
let mqtt_config = extract_mqtt_config(&html).ok_or_else(|| {
MessengerError::State("failed to extract mqtt config from bootstrap html".to_string())
})?;
self.mqtt_client_id = mqtt_config.client_id;
self.mqtt_app_id = mqtt_config.app_id;
self.region = mqtt_config.region;
if self.user_name.is_none() {
trace!("user name token not found in bootstrap html");
}
match self.fetch_sequence_id().await {
Ok(sequence_id) => {
self.sequence_id = Some(sequence_id);
}
Err(error) => {
warn!(?error, "failed to fetch initial sequence id");
self.sequence_id = None;
}
}
debug!(
user_name = self.user_name.as_deref().unwrap_or(""),
has_fb_dtsg = self.fb_dtsg.is_some(),
has_lsd = self.lsd.is_some(),
has_jazoest = self.jazoest.is_some(),
client_revision = self.client_revision,
region = self.region,
mqtt_client_id = self.mqtt_client_id,
sequence_id = self.sequence_id,
mqtt_app_id = self.mqtt_app_id,
ls_app_id = self.ls_app_id,
ls_version_id = self.ls_version_id,
"messenger bootstrap state"
);
Ok(())
}
}