reqrio 0.3.0-rc2

A lightweight, high-performance, fingerprint-based HTTP request library.
Documentation
mod finger;
mod response;
mod body;

use crate::export::{check_run, handle_err1, handle_err2};
use crate::time::Timeout;
use crate::{json, Body, Cookie, HlsError, Method, Proxy, ReqExt, ReqGenExt, Response, ScReq, ALPN, Url};
use crate::Fingerprint;
use std::ffi::{c_char, CStr, CString};
use std::ops::{Deref, DerefMut};
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::ptr::null_mut;
#[cfg(feature = "log")]
use crate::{logger::Logger, set_logger, set_max_level, LevelFilter};

#[cfg(feature = "log")]
const LOGER: Logger = Logger {
    module: &[],
    debug_file: None,
    info_file: None,
    warn_file: None,
    error_file: None,
    out_file: None,
};

#[unsafe(no_mangle)]
#[cfg(feature = "log")]
pub extern "system" fn init_log(level: LevelFilter) {
    let _ = set_logger(&LOGER);
    set_max_level(level);
}

#[unsafe(no_mangle)]
#[cfg(feature = "log")]
pub extern "system" fn set_max_log_level(level: LevelFilter) {
    set_max_level(level);
}


#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_new() -> *mut ScReq {
    let sc = ScReq::new();
    Box::into_raw(Box::new(sc))
}

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_set_header_json(req: *mut ScReq, header: *const c_char) -> *mut c_char {
    check_run(move || {
        let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
        let header = unsafe { CStr::from_ptr(header) }.to_bytes();
        let header = json::from_bytes(header)?;
        req.set_headers_json(header)?;
        Ok(null_mut())
    }, handle_err2)
}

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_add_header(req: *mut ScReq, key: *const c_char, value: *const c_char) -> *mut c_char {
    check_run(move || {
        let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
        let key = unsafe { CStr::from_ptr(key) }.to_str()?;
        let value = unsafe { CStr::from_ptr(value) }.to_str()?;
        req.header_mut().insert(key, value)?;
        Ok(null_mut())
    }, handle_err2)
}

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_remove_header(req: *mut ScReq, key: *const c_char) -> *mut c_char {
    check_run(move || {
        let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
        let key = unsafe { CStr::from_ptr(key) }.to_str()?;
        req.remove_header(key);
        Ok(null_mut())
    }, handle_err2)
}

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_set_alpn(req: *mut ScReq, alpn: *const c_char) -> *mut c_char {
    check_run(move || {
        let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
        let alpn = unsafe { CStr::from_ptr(alpn) }.to_bytes();
        let alpn = ALPN::from_slice(alpn);
        req.set_alpn(alpn);
        Ok(null_mut())
    }, handle_err2)
}

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_set_verify(req: *mut ScReq, verify: bool) -> *mut c_char {
    check_run(move || {
        let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
        req.set_verify(verify);
        Ok(null_mut())
    }, handle_err2)
}


#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_set_redirect(req: *mut ScReq, redirect: bool) -> *mut c_char {
    check_run(move || {
        let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
        req.set_auto_redirect(redirect);
        Ok(null_mut())
    }, handle_err2)
}

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_set_key_log(req: *mut ScReq, key_log: *const c_char) -> *mut c_char {
    check_run(move || {
        let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
        let key_log = unsafe { CStr::from_ptr(key_log) }.to_str()?;
        req.set_key_log(key_log);
        Ok(null_mut())
    }, handle_err2)
}

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_set_fingerprint(req: *mut ScReq, fingerprint: *mut Fingerprint) -> *mut c_char {
    check_run(move || {
        let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
        req.set_fingerprint(unsafe { *Box::from_raw(fingerprint) });
        Ok(null_mut())
    }, handle_err2)
}

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_set_proxy(req: *mut ScReq, addr: *const c_char) -> *mut c_char {
    check_run(move || {
        let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
        let addr = unsafe { CStr::from_ptr(addr) }.to_str()?.to_string();
        let proxy = Proxy::try_from(addr)?;
        req.set_proxy(proxy);
        Ok(null_mut())
    }, handle_err2)
}

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_set_timeout(req: *mut ScReq, timeout: *const c_char) -> *mut c_char {
    check_run(move || {
        let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
        let timeout = unsafe { CStr::from_ptr(timeout) }.to_bytes();
        let data = json::from_bytes(timeout)?;
        let timeout = Timeout::try_from(data)?;
        req.set_timeout(timeout);
        Ok(null_mut())
    }, handle_err2)
}

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_set_cookie(req: *mut ScReq, cookie: *const c_char) -> *mut c_char {
    check_run(move || {
        let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
        let cookie = unsafe { CStr::from_ptr(cookie) }.to_str()?;
        req.header_mut().set_cookie(cookie)?;
        Ok(null_mut())
    }, handle_err2)
}

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_add_cookie(req: *mut ScReq, name: *const c_char, value: *const c_char) -> *mut c_char {
    check_run(move || {
        let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
        let name = unsafe { CStr::from_ptr(name) }.to_str()?;
        let value = unsafe { CStr::from_ptr(value) }.to_str()?;
        let cookie = Cookie::new_cookie(name, value);
        req.header_mut().add_cookie(cookie);
        Ok(null_mut())
    }, handle_err2)
}


#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub unsafe extern "C" fn ScReq_stream_io(
    req: *mut ScReq,
    method: Method,
    url: *mut Url,
    body: *mut Body<'static>,
    err: *mut *mut c_char,
) -> *mut Response {
    catch_unwind(AssertUnwindSafe(|| {
        check_run(move || {
            let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
            let mut url = unsafe { Box::from_raw(url) };
            let body = unsafe { Box::from_raw(body) };
            let resp = req.stream_io(method, url.deref_mut(), body.deref())?;
            Ok(Box::into_raw(Box::new(resp)))
        }, |e| handle_err1(e, err, null_mut()))
    })).unwrap_or_else(|_| handle_err1("程序panic", err, null_mut()))
}
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_reconnect(req: *mut ScReq) -> *mut c_char {
    catch_unwind(AssertUnwindSafe(|| {
        check_run(move || {
            let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
            req.re_conn(None)?;
            Ok(null_mut())
        }, handle_err2)
    })).unwrap_or_else(|_| handle_err2("程序panic"))
}

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn ScReq_connect(req: *mut ScReq, url: *const c_char) -> *mut c_char {
    catch_unwind(AssertUnwindSafe(|| {
        check_run(move || {
            let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
            let url = unsafe { CStr::from_ptr(url) }.to_str()?.try_into()?;
            req.re_conn(Some(&url))?;
            Ok(null_mut())
        }, handle_err2)
    })).unwrap_or_else(|_| handle_err2("程序panic"))
}

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "C" fn ScReq_close_stream(req: *mut ScReq) -> *mut c_char {
    check_run(move || {
        let req = unsafe { req.as_mut() }.ok_or(HlsError::NullPointer)?;
        let _ = req.stream_mut().sync_shutdown();
        Ok(null_mut())
    }, handle_err2)
}


#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "C" fn ScReq_drop(req: *mut ScReq) {
    if req.is_null() { return; }
    let mut req = unsafe { Box::from_raw(req) };
    let _ = req.stream_mut().sync_shutdown();
    drop(req);
}

#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "system" fn char_free(ptr: *mut c_char) {
    if ptr.is_null() { return; }
    unsafe { let _ = CString::from_raw(ptr); }
}

pub type Callback = extern "C" fn(*const c_char, u32);


#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub extern "C" fn ScReq_set_callback(req: *mut ScReq, callback: Callback) -> *mut c_char {
    check_run(move || {
        let req = unsafe { req.as_mut().ok_or(HlsError::NullPointer) }?;
        req.set_callback(move |bs| {
            callback(bs.as_ptr() as *const c_char, bs.len() as u32);
            Ok(())
        });
        Ok(null_mut())
    }, handle_err2)
}