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,
        v4::notification::internal::{
            api::internal_notification,
            models::{
                InternalNotificationRequestBuilder,
                InternalNotificationRequest,
            },
        },
    },
    extensions::botx_api_context::IBotXApiContextExt,
};
use botx_api_framework::{
    contexts::{BotXApiFrameworkContext, RequestContext},
    extensions::actix::IActixHandlersExt,
    handlers::message::IMessageHandler,
    results::{CommandOk, CommandResult},
};
use env_logger::Env;
use serde::Serialize;

#[derive(Serialize, Clone)]
pub struct InternalBotMessageData {
    pub message: String
}

#[derive(Serialize, Clone)]
pub struct InternalBotMessageOption {
    pub internal_data: String
}

#[derive(constructor)]
pub struct MessageHandler {
    #[resolve]
    api: Arc<RwLock<BotXApiContext>>,
}

#[async_trait_with_sync::async_trait]
impl IMessageHandler for MessageHandler {
    async fn handle(&mut self, _message: String, request: RequestContext) -> CommandResult {
        let request: InternalNotificationRequest<InternalBotMessageData, InternalBotMessageOption> = InternalNotificationRequestBuilder::default()
            .with_group_chat_id(request.from.group_chat_id.unwrap())
            .with_data(InternalBotMessageData { message: "test message data".to_string() })
            .with_opts(InternalBotMessageOption { internal_data: "internal message option".to_string() })
            .build()
            .unwrap();

        internal_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_type::<MessageHandler>(LifeCycle::Transient)
        .await?
        .map_as::<dyn IMessageHandler>()
        .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)
}