use crate::types::{ApiAndOptOneshot, ApiOneshotReceiver, ApiOneshotSender};
use super::{ApiReturn, Bot, SendApi};
use log::error;
use parking_lot::RwLock;
use serde_json::Value;
use std::sync::Weak;
use tokio::sync::{mpsc, oneshot};
pub mod kovi_api;
pub use kovi_api::SetAdmin;
#[derive(Clone)]
pub struct RuntimeBot {
pub(crate) bot: Weak<RwLock<Bot>>,
pub(crate) plugin_name: String,
pub api_tx: mpsc::Sender<ApiAndOptOneshot>,
}
pub fn send_api_request_with_response(
api_tx: &mpsc::Sender<ApiAndOptOneshot>,
send_api: SendApi,
) -> impl std::future::Future<Output = Result<ApiReturn, ApiReturn>> {
let api_rx = send_api_request(api_tx, send_api);
send_api_await_response(api_rx)
}
pub fn send_api_request(
api_tx: &mpsc::Sender<ApiAndOptOneshot>,
send_api: SendApi,
) -> ApiOneshotReceiver {
let (api_tx_, api_rx): (ApiOneshotSender, ApiOneshotReceiver) = oneshot::channel();
if let Err(e) = api_tx.try_send((send_api, Some(api_tx_))) {
match e {
mpsc::error::TrySendError::Full(v) => {
log::trace!("RuntimeBot Api Queue Full, spawn new task to send");
let api_tx = api_tx.clone();
tokio::task::spawn(async move {
if let Err(e) = api_tx.send(v).await {
error!("The mpsc sender failed to send API request: {e}");
}
});
}
mpsc::error::TrySendError::Closed(_) => {
log::error!("RuntimeBot Api Queue Closed");
}
}
};
api_rx
}
pub fn send_api_request_with_forget(api_tx: &mpsc::Sender<ApiAndOptOneshot>, send_api: SendApi) {
if let Err(e) = api_tx.try_send((send_api, None)) {
match e {
mpsc::error::TrySendError::Full(v) => {
log::trace!("RuntimeBot Api Queue Full, spawn new task to send");
let api_tx = api_tx.clone();
tokio::task::spawn(async move {
if let Err(e) = api_tx.send(v).await {
error!("The mpsc sender failed to send API request: {e}");
}
});
}
mpsc::error::TrySendError::Closed(_) => {
log::error!("RuntimeBot Api Queue Closed");
}
}
};
}
pub async fn send_api_await_response(api_rx: ApiOneshotReceiver) -> Result<ApiReturn, ApiReturn> {
match api_rx.await {
Ok(v) => v,
Err(e) => {
error!("{e}");
panic!()
}
}
}
pub trait CanSendApi {
fn __get_api_tx(&self) -> &mpsc::Sender<ApiAndOptOneshot>;
fn send_api(&self, action: &str, params: Value) {
let send_api = SendApi::new(action, params);
send_api_request_with_forget(self.__get_api_tx(), send_api)
}
fn send_api_return(
&self,
action: &str,
params: Value,
) -> impl std::future::Future<Output = Result<ApiReturn, ApiReturn>> {
let send_api = SendApi::new(action, params);
send_api_request_with_response(self.__get_api_tx(), send_api)
}
}
impl CanSendApi for RuntimeBot {
fn __get_api_tx(&self) -> &mpsc::Sender<ApiAndOptOneshot> {
&self.api_tx
}
}