use anyhow::Result;
use log::debug;
use wacore_binary::jid::Jid;
use super::Client;
use crate::lid_pn_cache::{LearningSource, LidPnEntry};
impl Client {
pub(crate) async fn warm_up_lid_pn_cache(&self) -> Result<(), anyhow::Error> {
let backend = self.persistence_manager.backend();
let entries = backend.get_all_lid_mappings().await?;
if entries.is_empty() {
debug!("LID-PN cache warm-up: no entries found in storage");
return Ok(());
}
let cache_entries: Vec<LidPnEntry> = entries
.into_iter()
.map(|e| {
LidPnEntry::with_timestamp(
e.lid,
e.phone_number,
e.created_at,
LearningSource::parse(&e.learning_source),
)
})
.collect();
self.lid_pn_cache.warm_up(cache_entries).await;
Ok(())
}
pub(crate) async fn add_lid_pn_mapping(
&self,
lid: &str,
phone_number: &str,
source: LearningSource,
) -> Result<()> {
use anyhow::anyhow;
use wacore::store::traits::LidPnMappingEntry;
let is_new_mapping = self
.lid_pn_cache
.get_current_lid(phone_number)
.await
.is_none();
let entry = LidPnEntry::new(lid.to_string(), phone_number.to_string(), source);
self.lid_pn_cache.add(entry.clone()).await;
let backend = self.persistence_manager.backend();
let storage_entry = LidPnMappingEntry {
lid: entry.lid,
phone_number: entry.phone_number,
created_at: entry.created_at,
updated_at: entry.created_at,
learning_source: entry.learning_source.as_str().to_string(),
};
backend
.put_lid_mapping(&storage_entry)
.await
.map_err(|e| anyhow!("persisting LID-PN mapping: {e}"))?;
if is_new_mapping {
self.migrate_device_registry_on_lid_discovery(phone_number, lid)
.await;
}
Ok(())
}
pub(crate) async fn resolve_lid_mappings(&self, jids: &[Jid]) -> Vec<Jid> {
let mut resolved = Vec::with_capacity(jids.len());
for jid in jids {
if !jid.is_pn() && !jid.is_lid() {
resolved.push(jid.clone());
continue;
}
if jid.is_lid() {
resolved.push(jid.clone());
continue;
}
if let Some(lid_user) = self.lid_pn_cache.get_current_lid(&jid.user).await {
resolved.push(Jid::lid_device(lid_user, jid.device));
} else {
resolved.push(jid.clone());
}
}
resolved
}
pub(crate) async fn resolve_encryption_jid(&self, target: &Jid) -> Jid {
let pn_server = wacore_binary::jid::DEFAULT_USER_SERVER;
let lid_server = wacore_binary::jid::HIDDEN_USER_SERVER;
if target.server == lid_server {
target.clone()
} else if target.server == pn_server {
if let Some(lid_user) = self.lid_pn_cache.get_current_lid(&target.user).await {
let lid_jid = Jid {
user: lid_user,
server: wacore_binary::jid::cow_server_from_str(lid_server),
device: target.device,
agent: target.agent,
integrator: target.integrator,
};
debug!(
"[SEND-LOCK] Resolved {} to LID {} for session lock",
target, lid_jid
);
lid_jid
} else {
debug!("[SEND-LOCK] No LID mapping for {}, using PN", target);
target.clone()
}
} else {
target.clone()
}
}
pub async fn get_phone_number_from_lid(&self, lid: &str) -> Option<String> {
let lid_user = if lid.contains('@') {
lid.split('@').next().unwrap_or(lid)
} else {
lid
};
self.lid_pn_cache.get_phone_number(lid_user).await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::lid_pn_cache::LearningSource;
use crate::test_utils::create_test_client;
use std::sync::Arc;
use wacore_binary::jid::HIDDEN_USER_SERVER;
#[tokio::test]
async fn test_resolve_encryption_jid_pn_to_lid() {
let client: Arc<Client> = create_test_client().await;
let pn = "55999999999";
let lid = "100000012345678";
client
.add_lid_pn_mapping(lid, pn, LearningSource::PeerPnMessage)
.await
.unwrap();
let pn_jid = Jid::pn(pn);
let resolved = client.resolve_encryption_jid(&pn_jid).await;
assert_eq!(resolved.user, lid);
assert_eq!(resolved.server, HIDDEN_USER_SERVER);
}
#[tokio::test]
async fn test_resolve_encryption_jid_preserves_lid() {
let client: Arc<Client> = create_test_client().await;
let lid = "100000012345678";
let lid_jid = Jid::lid(lid);
let resolved = client.resolve_encryption_jid(&lid_jid).await;
assert_eq!(resolved, lid_jid);
}
#[tokio::test]
async fn test_resolve_encryption_jid_no_mapping_returns_pn() {
let client: Arc<Client> = create_test_client().await;
let pn = "55999999999";
let pn_jid = Jid::pn(pn);
let resolved = client.resolve_encryption_jid(&pn_jid).await;
assert_eq!(resolved, pn_jid);
}
}