Setup CI/CD
This commit is contained in:
7
.github/dependabot.yml
vendored
Normal file
7
.github/dependabot.yml
vendored
Normal 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
50
.github/workflows/build-and-deploy.yml
vendored
Normal 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
23
docker/Dockerfile
Normal 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"]
|
||||||
@@ -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)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -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,22 +88,21 @@ 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) => {
|
subscribe_handler(bot, message, subscription_manager, username).await
|
||||||
subscribe_handler(bot, message, subscription_manager, username).await
|
}
|
||||||
|
Command::Unsubscribe(username) => {
|
||||||
|
unsubscribe_handler(bot, message, subscription_manager, username).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Command::Unsubscribe(username) => {
|
}),
|
||||||
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,9 +142,12 @@ 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(
|
||||||
.await
|
bot,
|
||||||
.expect("Couldn't setup webhook");
|
webhooks::Options::new(addr, url).path("/telegram/".to_string()),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("Couldn't setup webhook");
|
||||||
|
|
||||||
dispatcher
|
dispatcher
|
||||||
.dispatch_with_listener(
|
.dispatch_with_listener(
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user