#![allow(dead_code)] use std::path::Path; use std::time::Duration; use frxd::config::{Config, IndexSection, NodeSection, QuerySection}; use frxd::crypto::Keypair; use frxd::index::Collection; use frxd::message::{Envelope, QueryBody, TYPE_QUERY}; use frxd::relay; use serde_json::Value; pub fn config_for(dir: &Path, name: &str, relay_url: &str) -> Config { let config = Config { node: NodeSection { name: name.to_string(), id: None, listen: "127.0.0.1:0".to_string(), relays: vec![relay_url.to_string()], registry: None, ma_key: None, dev_bootstrap: true, responder: true, }, query: QuerySection { max_results: 5, timeout_ms: 700, }, index: IndexSection { data_dir: dir.join("data").display().to_string(), }, }; config.save_key(&Keypair::generate()).unwrap(); config } pub fn collection(name: &str, path: &Path, shared: bool, exposure: &str) -> Collection { Collection { name: name.to_string(), path: path.display().to_string(), shared, exposure: exposure.to_string(), } } pub async fn spawn_relay() -> String { spawn_relay_with_capacity(256).await } pub async fn spawn_relay_with_capacity(capacity: usize) -> String { let (listener, addr) = relay::bind("127.0.0.1:0").await.unwrap(); tokio::spawn(async move { let _ = relay::run(listener, capacity).await; }); format!("http://{addr}") } pub fn free_port() -> u16 { let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); listener.local_addr().unwrap().port() } pub fn query_envelope(key: &Keypair, text: &str, max_results: usize) -> Envelope { let body = QueryBody::new(text, max_results); Envelope::new(key, TYPE_QUERY, serde_json::to_value(&body).unwrap()) } pub async fn challenge(client: &reqwest::Client, relay_url: &str, member: &str) -> Option { let response = client .get(format!("{relay_url}/v1/challenge?member={member}")) .send() .await .unwrap(); if !response.status().is_success() { return None; } let payload: Value = response.json().await.unwrap(); payload .get("nonce") .and_then(Value::as_str) .map(str::to_string) } pub async fn register(client: &reqwest::Client, relay_url: &str, key: &Keypair) { poll(client, relay_url, key, 30).await; } pub async fn poll_messages( client: &reqwest::Client, relay_url: &str, key: &Keypair, timeout_ms: u64, ) -> Vec { let response = poll(client, relay_url, key, timeout_ms).await; if response.status() == reqwest::StatusCode::NO_CONTENT { return Vec::new(); } let payload: Value = response.json().await.unwrap(); payload .get("messages") .and_then(Value::as_array) .cloned() .unwrap_or_default() } pub fn messages_of_type(messages: &[Value], msg_type: &str) -> Vec { messages .iter() .filter(|m| m.get("type").and_then(Value::as_str) == Some(msg_type)) .cloned() .collect() } pub fn client() -> reqwest::Client { reqwest::Client::builder() .timeout(Duration::from_secs(10)) .build() .unwrap() } pub async fn ask( client: &reqwest::Client, addr: &str, text: &str, max: usize, ) -> (reqwest::StatusCode, String, Value) { let response = client .post(format!("http://{addr}/v1/local/query")) .json(&serde_json::json!({ "text": text, "max_results": max, "timeout_ms": 700, })) .send() .await .unwrap(); let status = response.status(); let raw = response.text().await.unwrap(); let value: Value = serde_json::from_str(&raw).unwrap(); (status, raw, value) } pub async fn publish( client: &reqwest::Client, relay_url: &str, envelope: &Envelope, ) -> reqwest::Response { client .post(format!("{relay_url}/v1/publish")) .json(envelope) .send() .await .unwrap() } pub async fn unicast( client: &reqwest::Client, relay_url: &str, to: &str, envelope: &Envelope, ) -> reqwest::Response { client .post(format!("{relay_url}/v1/unicast?to={to}")) .json(envelope) .send() .await .unwrap() } pub async fn poll( client: &reqwest::Client, relay_url: &str, key: &Keypair, timeout_ms: u64, ) -> reqwest::Response { let member = key.public_hex(); let nonce = challenge(client, relay_url, &member) .await .expect("relay challenge"); let sig = key.sign(&frxd::crypto::poll_signing_bytes(&member, &nonce)); client .get(format!( "{relay_url}/v1/poll?member={member}&nonce={nonce}&sig={sig}&timeout_ms={timeout_ms}" )) .send() .await .unwrap() }