qvopenapi 0.1.0

wmca.dll은 윈도우 이벤트 기반으로 동작하므로 윈도우 및 기반 이벤트들을 자동으로 관리하고 주요 Tx 들을 별도 메소드로 제공
Documentation
use std::{
    collections::VecDeque,
    sync::{Arc, Mutex, RwLock},
};

use serde_json::to_string_pretty;

use crate::{error::*, models::*, window_mgr::message_const::*, *};

pub trait QvOpenApiRequest: Send + Sync {
    fn before_post(&self) -> Result<(), QvOpenApiError>;
    fn call_lib(&self, tr_index: i32, hwnd: isize) -> Result<(), QvOpenApiError>;
    fn get_tr_code(&self) -> &str;
}

pub trait AbstractQvOpenApiClient {
    fn get_handler(&self) -> Arc<QvOpenApiClientMessageHandler>;

    fn get_hwnd(&self) -> Option<isize>;

    fn set_hwnd(&self, new_hwnd: isize);

    fn on_connect(&self, callback: Box<dyn FnMut(&ConnectResponse) + Send>) {
        self.get_handler()
            .message_handler
            .lock()
            .unwrap()
            .on_connect = callback;
    }

    fn on_disconnect(&self, callback: Box<dyn FnMut() + Send>) {
        self.get_handler()
            .message_handler
            .lock()
            .unwrap()
            .on_disconnect = callback;
    }

    fn on_socket_error(&self, callback: Box<dyn FnMut() + Send>) {
        self.get_handler()
            .message_handler
            .lock()
            .unwrap()
            .on_socket_error = callback;
    }

    fn on_data(&self, callback: Box<dyn FnMut(&DataResponse) + Send>) {
        self.get_handler().message_handler.lock().unwrap().on_data = callback;
    }

    fn on_sise(&self, callback: Box<dyn FnMut(&DataResponse) + Send>) {
        self.get_handler().message_handler.lock().unwrap().on_sise = callback;
    }

    fn on_message(&self, callback: Box<dyn FnMut(&MessageResponse) + Send>) {
        self.get_handler()
            .message_handler
            .lock()
            .unwrap()
            .on_message = callback;
    }

    fn on_complete(&self, callback: Box<dyn FnMut(i32) + Send>) {
        self.get_handler()
            .message_handler
            .lock()
            .unwrap()
            .on_complete = callback;
    }

    fn on_error(&self, callback: Box<dyn FnMut(&ErrorResponse) + Send>) {
        self.get_handler().message_handler.lock().unwrap().on_error = callback;
    }

    fn connect(
        &self,
        new_hwnd: isize,
        account_type: AccountType,
        id: &str,
        password: &str,
        cert_password: &str,
    ) -> Result<(), QvOpenApiError> {
        self.set_hwnd(new_hwnd);
        self.query(
            TR_INDEX_CONNECT,
            Arc::new(ConnectRequest {
                account_type,
                id: id.into(),
                password: password.into(),
                cert_password: cert_password.into(),
            }),
        )
    }

    fn disconnect(&self) -> Result<(), QvOpenApiError> {
        self.query(-1, Arc::new(DisconnectRequest {}))
    }

    fn query(&self, tr_index: i32, req: Arc<dyn QvOpenApiRequest>) -> Result<(), QvOpenApiError>;
}

impl AbstractQvOpenApiClient for QvOpenApiClient {
    fn get_handler(&self) -> Arc<QvOpenApiClientMessageHandler> {
        self.handler.clone()
    }

    fn get_hwnd(&self) -> Option<isize> {
        *self.handler.hwnd_lock.read().unwrap()
    }

    fn set_hwnd(&self, new_hwnd: isize) {
        let mut hwnd = self.handler.hwnd_lock.write().unwrap();
        *hwnd = Some(new_hwnd);
    }

    fn query(&self, tr_index: i32, req: Arc<dyn QvOpenApiRequest>) -> Result<(), QvOpenApiError> {
        req.before_post()?;
        let hwnd = self.handler.hwnd_lock.read().unwrap();
        let mut request_queue = self.handler.request_queue_lock.lock().unwrap();
        request_queue.push_back((tr_index, req));
        window_mgr::post_message_to_window(
            hwnd.unwrap(),
            WM_WMCAEVENT,
            CA_CUSTOM_EXECUTE_POSTED_COMMAND,
            0,
        );
        Ok(())
    }
}

pub struct QvOpenApiClient {
    handler: Arc<QvOpenApiClientMessageHandler>,
}

pub struct QvOpenApiClientMessageHandler {
    hwnd_lock: RwLock<Option<isize>>,
    pub message_handler: Mutex<QvOpenApiClientMessageCallbacks>,
    request_queue_lock: Mutex<VecDeque<(i32, Arc<dyn QvOpenApiRequest>)>>,
}

impl QvOpenApiClientMessageHandler {
    pub fn new() -> QvOpenApiClientMessageHandler {
        QvOpenApiClientMessageHandler {
            hwnd_lock: RwLock::new(None),
            message_handler: Mutex::new(QvOpenApiClientMessageCallbacks {
                on_connect: Box::new(|_| {}),
                on_disconnect: Box::new(|| {}),
                on_socket_error: Box::new(|| {}),
                on_data: Box::new(|_| {}),
                on_sise: Box::new(|_| {}),
                on_message: Box::new(|_| {}),
                on_complete: Box::new(|_| {}),
                on_error: Box::new(|_| {}),
            }),
            request_queue_lock: Mutex::new(VecDeque::new()),
        }
    }
}

pub struct QvOpenApiClientMessageCallbacks {
    pub on_connect: Box<dyn FnMut(&ConnectResponse) + Send>,
    pub on_disconnect: Box<dyn FnMut() + Send>,
    pub on_socket_error: Box<dyn FnMut() + Send>,
    pub on_data: Box<dyn FnMut(&DataResponse) + Send>,
    pub on_sise: Box<dyn FnMut(&DataResponse) + Send>,
    pub on_message: Box<dyn FnMut(&MessageResponse) + Send>,
    pub on_complete: Box<dyn FnMut(i32) + Send>,
    pub on_error: Box<dyn FnMut(&ErrorResponse) + Send>,
}

impl QvOpenApiClient {
    pub fn new() -> Result<QvOpenApiClient, QvOpenApiError> {
        crate::init()?;
        Ok(QvOpenApiClient {
            handler: Arc::new(QvOpenApiClientMessageHandler::new()),
        })
    }
}

impl QvOpenApiClientMessageHandler {
    pub fn on_wmca_msg(
        &self,
        wparam: usize,
        lparam: isize,
    ) -> std::result::Result<(), QvOpenApiError> {
        debug!("on_wmca_msg {} {}", wparam, lparam);
        match u32::try_from(wparam).unwrap() {
            CA_CONNECTED => {
                let res = models::parse_connect(lparam)?;
                debug!("CA_CONNECT {}", to_string_pretty(&res)?);
                let mut handler = self.message_handler.lock().unwrap();
                (handler.on_connect)(&res);
                Ok(())
            }
            CA_DISCONNECTED => {
                debug!("CA_DISCONNECTED");
                let mut handler = self.message_handler.lock().unwrap();
                (handler.on_disconnect)();
                Ok(())
            }
            CA_SOCKETERROR => {
                debug!("CA_SOCKETERROR");
                let mut handler = self.message_handler.lock().unwrap();
                (handler.on_socket_error)();
                Ok(())
            }
            CA_RECEIVEDATA => {
                let res = models::parse_data(lparam)?;
                debug!(
                    "CA_RECEIVEDATA [TR{}] {}",
                    res.tr_index,
                    to_string_pretty(&res)?
                );
                let mut handler = self.message_handler.lock().unwrap();
                (handler.on_data)(&res);
                Ok(())
            }
            CA_RECEIVESISE => {
                let res = models::parse_sise(lparam)?;
                debug!(
                    "CA_RECEIVESISE [TR{}] {}",
                    res.tr_index,
                    to_string_pretty(&res)?
                );
                let mut handler = self.message_handler.lock().unwrap();
                (handler.on_sise)(&res);
                Ok(())
            }
            CA_RECEIVEMESSAGE => {
                let res = models::parse_message(lparam)?;
                debug!(
                    "CA_RECEIVEMESSAGE [TR{}] [{}] \"{}\"",
                    res.tr_index, res.msg_code, res.msg
                );
                let mut handler = self.message_handler.lock().unwrap();
                (handler.on_message)(&res);
                Ok(())
            }
            CA_RECEIVECOMPLETE => {
                let res = models::parse_complete(lparam)?;
                debug!("CA_RECEIVECOMPLETE [TR{}]", res);
                let mut handler = self.message_handler.lock().unwrap();
                (handler.on_complete)(res);
                Ok(())
            }
            CA_RECEIVEERROR => {
                let res = models::parse_error(lparam)?;
                debug!("CA_RECEIVEERROR [TR{}] \"{}\"", res.tr_index, res.error_msg);
                let mut handler = self.message_handler.lock().unwrap();
                (handler.on_error)(&res);
                Ok(())
            }
            CA_CUSTOM_EXECUTE_POSTED_COMMAND => {
                let mut request_queue = self.request_queue_lock.lock().unwrap();
                let hwnd = self.hwnd_lock.read().unwrap();
                while let Some((tr_index, cmd)) = request_queue.pop_front() {
                    cmd.call_lib(tr_index, hwnd.unwrap())?;
                }
                Ok(())
            }
            _ => Err(QvOpenApiError::WindowUnknownEventError { wparam }),
        }
    }

    pub fn on_destroy(&self) {
        let mut hwnd = self.hwnd_lock.write().unwrap();
        *hwnd = None;
    }
}