// bebot -- a Gitlab -> Matrix event publisher // Copyright (C) 2023-2025 Brian Tarricone // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #[macro_use(anyhow)] extern crate anyhow; #[macro_use] extern crate log; #[macro_use] extern crate serde; mod config; mod gitlab_event; mod gitlab_webhook; mod mail_archive; mod matrix; use std::{env, process::exit}; use anyhow::Context; use futures::future::join_all; use tokio::net::TcpListener; async fn run() -> anyhow::Result<()> { info!("{} v{} starting...", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); let config_path = env::args() .nth(1) .ok_or_else(|| anyhow!("Config file should be passed as only parameter"))?; let mut config = config::load(config_path).await?; let mut join_handles = Vec::default(); let matrix_client = matrix::connect(&config).await.context("Failed to connect to Matrix")?; if let Some(avatar_path) = config.avatar_image_path { let matrix_client = matrix_client.clone(); let handle = tokio::spawn(async move { if let Err(err) = matrix::set_avatar_if_needed(&matrix_client, avatar_path).await { warn!("Failed to set matrix avatar: {err}"); } }); join_handles.push(handle); } let mail_join_handles = if let Some(mail_archive) = config.mail_archive.take() { mail_archive::start_polling(mail_archive, matrix_client.clone())? } else { vec![] }; join_handles.extend(mail_join_handles); if let Some(gitlab_webhook) = config.gitlab_webhook.take() { let gitlab = gitlab_webhook::build_route(gitlab_webhook, matrix_client.clone()); let bind_addr = format!( "{}:{}", config.bind_address.as_deref().unwrap_or("127.0.0.1"), config.bind_port.unwrap_or(3000) ); let listener = TcpListener::bind(bind_addr).await?; axum::serve(listener, gitlab).await?; } join_all(join_handles).await; error!("No functionality is configured; exiting"); exit(1); } #[tokio::main] async fn main() { let lenv = env_logger::Env::new() .filter("BEBOT_LOG") .write_style("BEBOT_LOG_STYLE"); env_logger::init_from_env(lenv); if let Err(err) = run().await { error!("{err:#}"); exit(1); } }