139 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
/*
 | 
						|
 * bingservice main.rs
 | 
						|
 * - entrypoint for the asklyphe bing backend
 | 
						|
 *
 | 
						|
 * Copyright (C) 2025 Real Microsoft, LLC
 | 
						|
 *
 | 
						|
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
						|
*/
 | 
						|
 | 
						|
mod process;
 | 
						|
mod bing;
 | 
						|
pub mod proxy;
 | 
						|
 | 
						|
use std::io::Read;
 | 
						|
use std::str::FromStr;
 | 
						|
use std::sync::Arc;
 | 
						|
use std::sync::atomic::{AtomicI64, AtomicU64, AtomicUsize, Ordering};
 | 
						|
use asklyphe_common::nats::authservice::AuthServiceResponse;
 | 
						|
use asklyphe_common::nats::bingservice::BingServiceResponse;
 | 
						|
use asklyphe_common::nats::comms;
 | 
						|
use async_nats::jetstream;
 | 
						|
use isahc::{Request, RequestExt};
 | 
						|
use log::{debug, error, info};
 | 
						|
use once_cell::sync::{Lazy, OnceCell};
 | 
						|
use crate::bing::BingQueryError;
 | 
						|
use crate::proxy::Proxy;
 | 
						|
 | 
						|
pub static PROXIES: Lazy<Vec<Proxy>> = Lazy::new(|| {
 | 
						|
    if let Ok(proxy_file) = std::env::var("PROXY_FILE") {
 | 
						|
        let contents = std::fs::read_to_string(proxy_file);
 | 
						|
        let mut proxies = vec![];
 | 
						|
 | 
						|
        for line in contents.expect("FAILED TO READ FILE").lines().filter(|l| l.len() > 0) {
 | 
						|
            proxies.push(Proxy::from_str(line).expect("INVALID PROXY"));
 | 
						|
        }
 | 
						|
 | 
						|
        info!("loaded {} proxies", proxies.len());
 | 
						|
 | 
						|
        proxies
 | 
						|
    } else {
 | 
						|
        vec![]
 | 
						|
    }
 | 
						|
});
 | 
						|
 | 
						|
pub static NEXT_PROXY: AtomicUsize = AtomicUsize::new(0);
 | 
						|
 | 
						|
pub static NATS_URL: Lazy<String> = Lazy::new(|| std::env::var("NATS_URL").expect("NO NATS DEFINED"));
 | 
						|
pub static NATS_CERT: Lazy<String> = Lazy::new(|| std::env::var("NATS_CERT").expect("NO NATS_CERT DEFINED"));
 | 
						|
pub static NATS_KEY: Lazy<String> = Lazy::new(|| std::env::var("NATS_KEY").expect("NO NATS_KEY DEFINED"));
 | 
						|
pub static DB_URL: Lazy<String> = Lazy::new(|| std::env::var("DB_URL").expect("NO DB_URL DEFINED"));
 | 
						|
pub static BING_KEY: Lazy<String> = Lazy::new(|| std::env::var("BING_KEY").expect("NO BING_KEY DEFINED"));
 | 
						|
pub static PROCESSES_HANDLED: AtomicU64 = AtomicU64::new(0);
 | 
						|
pub static LAST_MESSAGE: AtomicI64 = AtomicI64::new(0);
 | 
						|
 | 
						|
/*
 | 
						|
fn main() {
 | 
						|
    let mut args: Vec<String> = std::env::args().collect();
 | 
						|
    // remove first argument (path)
 | 
						|
    args.remove(0);
 | 
						|
    let query = args.join(" ");
 | 
						|
    let query = url_encoded_data::stringify(&[("q", query.as_str())]);
 | 
						|
 | 
						|
    let mut res = Request::get(format!("https://api.bing.microsoft.com/v7.0/search?{query}&safeSearch=Off"))
 | 
						|
        .header("user-agent", USER_AGENT.as_str())
 | 
						|
        .header("Ocp-Apim-Subscription-Key", BING_KEY.as_str())
 | 
						|
        .body(()).unwrap().send().expect("FAILED TO SEND REQUEST");
 | 
						|
 | 
						|
    let mut str = "".to_string();
 | 
						|
 | 
						|
    res.body_mut().read_to_string(&mut str).unwrap();
 | 
						|
 | 
						|
    println!("{str}");
 | 
						|
}
 | 
						|
*/
 | 
						|
 | 
						|
static CVID: OnceCell<Arc<String>> = OnceCell::new();
 | 
						|
 | 
						|
#[tokio::main]
 | 
						|
async fn main() {
 | 
						|
    env_logger::init();
 | 
						|
    info!("bingservice began at {}", chrono::Utc::now().to_string());
 | 
						|
 | 
						|
    let cvid = bing::generate_cvid().await;
 | 
						|
    if let Err(e) = cvid {
 | 
						|
        match e {
 | 
						|
            BingQueryError::CouldNotSendRequest => {
 | 
						|
                error!("EXITING DUE TO FAILED CVID GENERATION: COULDN'T SEND REQUEST");
 | 
						|
            }
 | 
						|
            BingQueryError::CouldNotDeserialize => {
 | 
						|
                error!("EXITING DUE TO FAILED CVID GENERATION: COULDN'T FIND CVID");
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    let cvid = Arc::new(cvid.unwrap());
 | 
						|
    info!("cvid: {cvid}");
 | 
						|
    CVID.set(cvid.clone()).unwrap();
 | 
						|
 | 
						|
    let nats = async_nats::ConnectOptions::new()
 | 
						|
        .add_client_certificate(NATS_CERT.as_str().into(), NATS_KEY.as_str().into())
 | 
						|
        .connect(NATS_URL.as_str())
 | 
						|
        .await;
 | 
						|
    if let Err(e) = nats {
 | 
						|
        error!("FATAL ERROR, COULDN'T CONNECT TO NATS: {}", e);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    let nats = nats.unwrap();
 | 
						|
    let nats = jetstream::new(nats);
 | 
						|
 | 
						|
    async fn on_recv(query: comms::Query) -> comms::ServiceResponse {
 | 
						|
        debug!("recv");
 | 
						|
        let cvid = CVID.get().unwrap().clone();
 | 
						|
        let now = chrono::Utc::now().timestamp();
 | 
						|
        LAST_MESSAGE.store(now, Ordering::Relaxed);
 | 
						|
 | 
						|
        let response = match query {
 | 
						|
            comms::Query::BingService(query) => {
 | 
						|
                process::process(query, cvid).await
 | 
						|
            }
 | 
						|
            _ => {
 | 
						|
                BingServiceResponse::InvalidRequest
 | 
						|
            }
 | 
						|
        };
 | 
						|
 | 
						|
        if PROCESSES_HANDLED.load(Ordering::Relaxed) % 100 == 0 {
 | 
						|
            info!("handled {} requests!", PROCESSES_HANDLED.load(Ordering::Relaxed));
 | 
						|
        }
 | 
						|
        PROCESSES_HANDLED.fetch_add(1, Ordering::Relaxed);
 | 
						|
        comms::ServiceResponse::BingService(response)
 | 
						|
    }
 | 
						|
 | 
						|
    if let Err(e) = comms::subscribe_service(comms::Service::BingService, &nats, Arc::new(on_recv)).await {
 | 
						|
        error!("failed to subscribe to bingservice nats! reason {:?}", e);
 | 
						|
    }
 | 
						|
}
 |