Setup CI/CD

This commit is contained in:
2025-02-27 23:29:02 +01:00
parent 6339336135
commit f6df6c7c56
6 changed files with 132 additions and 38 deletions

7
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,7 @@
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

50
.github/workflows/build-and-deploy.yml vendored Normal file
View File

@@ -0,0 +1,50 @@
name: Build docker image
on:
push:
branches:
- 'main'
jobs:
Build-Docker-Image:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- id: repository_name
uses: ASzc/change-string-case-action@v6
with:
string: ${{ github.repository }}
-
name: Login to ghcr.io
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
-
name: Build and push
id: docker_build
uses: docker/build-push-action@v6
env:
IMAGE: ${{ steps.repository_name.outputs.lowercase }}
with:
push: true
platforms: linux/amd64
tags: ghcr.io/${{ env.IMAGE }}:latest
context: .
file: ./docker/Dockerfile
-
name: Invoke deployment hook
uses: joelwmale/webhook-action@master
with:
url: ${{ secrets.WEBHOOK_URL }}

23
docker/Dockerfile Normal file
View File

@@ -0,0 +1,23 @@
FROM rust:bullseye AS builder
WORKDIR /app
COPY . .
RUN cargo build --release --bin telegram-twitch-notifier
FROM debian:bullseye-slim
RUN apt-get update \
&& apt-get install -y openssl ca-certificates curl jq \
&& rm -rf /var/lib/apt/lists/*
RUN update-ca-certificates
WORKDIR /app
COPY --from=builder /app/target/release/telegram-twitch-notifier /usr/local/bin
CMD ["/usr/local/bin/telegram-twitch-notifier"]

View File

@@ -1,12 +1,12 @@
pub mod bot;
pub mod config; pub mod config;
pub mod subscription_manager; pub mod subscription_manager;
pub mod telegram_bot;
pub mod twitch_webhook; pub mod twitch_webhook;
use std::sync::Arc; use std::sync::Arc;
use bot::start_bot;
use subscription_manager::SubscriptionManager; use subscription_manager::SubscriptionManager;
use telegram_bot::start_telegram_bot;
use twitch_webhook::start_twitch_webhook; use twitch_webhook::start_twitch_webhook;
#[tokio::main] #[tokio::main]
@@ -15,8 +15,10 @@ async fn main() {
subscription_manager.init().await; subscription_manager.init().await;
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
let (_, webhook_result) = tokio::join!( let (_, webhook_result) = tokio::join!(
start_bot(subscription_manager.clone()), start_telegram_bot(subscription_manager.clone()),
start_twitch_webhook(subscription_manager) start_twitch_webhook(subscription_manager)
); );

View File

@@ -1,18 +1,20 @@
use std::{error::Error, sync::Arc}; use std::{error::Error, sync::Arc};
use teloxide::{ use teloxide::{
Bot, Bot as OriginBot,
adaptors::throttle::Limits, adaptors::{CacheMe, Throttle, throttle::Limits},
dispatching::{HandlerExt, dialogue::GetChatId}, dispatching::{HandlerExt, UpdateFilterExt as _, dialogue::GetChatId},
dptree::{self, Handler}, dptree::{self, Handler},
macros::BotCommands, macros::BotCommands,
prelude::{Dispatcher, LoggingErrorHandler, Requester, RequesterExt}, prelude::{Dispatcher, LoggingErrorHandler, Requester, RequesterExt},
types::{BotCommand, Message}, types::{BotCommand, Message, Update},
update_listeners::webhooks, update_listeners::webhooks,
}; };
use crate::{config::CONFIG, subscription_manager::SubscriptionManager}; use crate::{config::CONFIG, subscription_manager::SubscriptionManager};
pub type Bot = CacheMe<Throttle<OriginBot>>;
pub type BotHandlerInternal = Result<(), Box<dyn Error + Send + Sync>>; pub type BotHandlerInternal = Result<(), Box<dyn Error + Send + Sync>>;
type BotHandler = Handler< type BotHandler = Handler<
'static, 'static,
@@ -32,11 +34,11 @@ enum Command {
} }
pub async fn help_message_handler(bot: Bot, message: Message) -> BotHandlerInternal { pub async fn help_message_handler(bot: Bot, message: Message) -> BotHandlerInternal {
const HELP_MESSAGE: &str = r#""" const HELP_MESSAGE: &str = r#"
Welcome! Welcome!
This bot allow you to subscribe to receive start stream notifications. This bot allow you to subscribe to receive start stream notifications.
"""#; "#;
match bot match bot
.send_message(message.chat_id().unwrap(), HELP_MESSAGE) .send_message(message.chat_id().unwrap(), HELP_MESSAGE)
@@ -86,11 +88,10 @@ pub async fn unsubscribe_handler(
} }
pub async fn get_handler() -> BotHandler { pub async fn get_handler() -> BotHandler {
dptree::entry().branch(dptree::entry().filter_command::<Command>().endpoint( dptree::entry().branch(
|bot: Bot, Update::filter_message()
message: Message, .filter_command::<Command>()
command: Command, .endpoint(|bot, message, command, subscription_manager| async move {
subscription_manager: Arc<SubscriptionManager>| async move {
match command { match command {
Command::Start | Command::Help => help_message_handler(bot, message).await, Command::Start | Command::Help => help_message_handler(bot, message).await,
Command::Subscribe(username) => { Command::Subscribe(username) => {
@@ -100,8 +101,8 @@ pub async fn get_handler() -> BotHandler {
unsubscribe_handler(bot, message, subscription_manager, username).await unsubscribe_handler(bot, message, subscription_manager, username).await
} }
} }
}, }),
)) )
} }
pub async fn get_commands() -> Vec<BotCommand> { pub async fn get_commands() -> Vec<BotCommand> {
@@ -125,8 +126,8 @@ pub async fn get_commands() -> Vec<BotCommand> {
] ]
} }
pub async fn start_bot(subscription_manager: Arc<SubscriptionManager>) { pub async fn start_telegram_bot(subscription_manager: Arc<SubscriptionManager>) {
let bot = Bot::new(CONFIG.bot_token.clone()) let bot = OriginBot::new(CONFIG.bot_token.clone())
.throttle(Limits::default()) .throttle(Limits::default())
.cache_me(); .cache_me();
@@ -141,7 +142,10 @@ pub async fn start_bot(subscription_manager: Arc<SubscriptionManager>) {
let addr = ([0, 0, 0, 0], CONFIG.telegram_webhook_port).into(); let addr = ([0, 0, 0, 0], CONFIG.telegram_webhook_port).into();
let url = CONFIG.telegram_webhook_url.parse().unwrap(); let url = CONFIG.telegram_webhook_url.parse().unwrap();
let update_listener = webhooks::axum(bot, webhooks::Options::new(addr, url)) let update_listener = webhooks::axum(
bot,
webhooks::Options::new(addr, url).path("/telegram/".to_string()),
)
.await .await
.expect("Couldn't setup webhook"); .expect("Couldn't setup webhook");

View File

@@ -194,13 +194,20 @@ impl TwitchWebhookServer {
.await; .await;
} }
pub async fn subscribe(&self, streamer: String) { pub async fn subscribe(&self, streamer: String) -> bool {
let _ = eventsub_register( match eventsub_register(
self.app_access_token.clone(), self.app_access_token.clone(),
streamer, streamer.clone(),
format!("{}/twitch/eventsub/", CONFIG.twitch_webhook_url), format!("{}/twitch/eventsub/", CONFIG.twitch_webhook_url),
) )
.await; .await
{
Ok(_) => true,
Err(err) => {
eprintln!("Error subscribing to {}: {}", streamer, err);
false
}
}
} }
pub async fn check_subscriptions(&self) { pub async fn check_subscriptions(&self) {
@@ -218,12 +225,13 @@ impl TwitchWebhookServer {
let is_subscribed = self.subscribed_to.read().await.contains(&streamer); let is_subscribed = self.subscribed_to.read().await.contains(&streamer);
if !is_subscribed { if !is_subscribed {
self.subscribe(streamer.clone()).await; if self.subscribe(streamer.clone()).await {
self.subscribed_to.write().await.push(streamer); self.subscribed_to.write().await.push(streamer);
} }
} }
}
tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
} }
} }