use std::{env, net::Ipv4Addr, sync::Arc};
use actix_web::{
middleware::Logger,
web::{self, Data},
App, HttpServer,
};
use anthill_di::*;
use anthill_di_derive::constructor;
use async_lock::RwLock;
use botx_api::{
api::{
context::BotXApiContext,
models::EventPayloadBuilder,
v4::notification::direct::{
api::direct_notification,
models::DirectNotificationRequestBuilder,
},
},
extensions::botx_api_context::IBotXApiContextExt,
};
use botx_api_framework::{
contexts::{BotXApiFrameworkContext, RequestContext},
extensions::{actix::IActixHandlersExt, anthill_di::IAnthillDiExt},
handlers::command::ICommandHandler,
results::{CommandOk, CommandResult},
};
use env_logger::Env;
use regex::Regex;
#[derive(constructor)]
pub struct EchoCommandHandler {
#[resolve]
api: Arc<RwLock<BotXApiContext>>,
}
#[async_trait_with_sync::async_trait]
impl ICommandHandler for EchoCommandHandler {
async fn handle(&mut self, command: String, request: RequestContext) -> CommandResult {
let notification = EventPayloadBuilder::default()
.with_body(command)
.build()
.unwrap();
let request = &DirectNotificationRequestBuilder::default()
.with_group_chat_id(request.from.group_chat_id.unwrap())
.with_notification(notification)
.build()
.unwrap();
direct_notification(&self.api, request).await.unwrap();
Ok(CommandOk::default())
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
dotenv::dotenv().ok();
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
let (ip, port) = get_address();
let ioc_ctx = DependencyContext::new_root();
ioc_ctx
.register_type::<BotXApiFrameworkContext>(LifeCycle::Transient)
.await?;
ioc_ctx
.register_command_handler::<EchoCommandHandler>(Regex::new("^/echo")?)
.await?;
ioc_ctx.register_botx_api_context().await?;
HttpServer::new(move || {
App::new()
.wrap(Logger::default())
.app_data(web::PayloadConfig::new(usize::MAX))
.app_data(web::JsonConfig::default().limit(usize::MAX))
.app_data(Data::new(ioc_ctx.clone()))
.add_botx_api_handlers()
})
.bind((ip.to_string(), port))?
.run()
.await?;
Ok(())
}
const BOT_HOST_ENV: &str = "BOT_HOST";
const BOT_PORT_ENV: &str = "BOT_PORT";
fn get_address() -> (Ipv4Addr, u16) {
let ip = env::var(BOT_HOST_ENV)
.expect(&*format!("Env {BOT_HOST_ENV} not found"))
.parse::<Ipv4Addr>()
.expect(&*format!("Env {BOT_HOST_ENV} must be valid ipv4"));
let port = env::var(BOT_PORT_ENV)
.expect(&*format!("Env {BOT_PORT_ENV} not found"))
.parse::<u16>()
.expect(&*format!("Env {BOT_PORT_ENV} must be valid u32"));
(ip, port)
}