botx-api-framework 0.1.8

Фреймворк для реализации ботов под платформу eXpress
Documentation
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)
}