Add basic web service

This commit is contained in:
lemonsh 2022-07-20 23:08:35 +02:00
parent cbbdcb145c
commit 4a19c2ce5a
5 changed files with 80 additions and 7 deletions

View File

@ -26,6 +26,7 @@ futures-util = "0.3"
irc = { version = "0.15", default-features = false, features = ["tls-rust"] }
async-trait = "0.1"
regex = "1.6.0"
hyper = { version = "0.14", features = ["server"] }
[features]
# debug IRC commands

View File

@ -19,3 +19,5 @@ search_limit = 5 # optional, default: 3
client_id = ""
client_secret = ""
[web] # optional, web service disabled if missing
listen = "127.0.0.1:8080"

View File

@ -1,3 +1,5 @@
use std::net::SocketAddr;
use serde::Deserialize;
#[derive(Deserialize)]
@ -6,6 +8,7 @@ pub struct UberConfig {
pub irc: IrcConfig,
pub spotify: Option<SpotifyConfig>,
pub bot: BotConfig,
pub web: Option<HttpConfig>
}
#[derive(Deserialize)]
@ -32,3 +35,8 @@ pub struct BotConfig {
pub history_depth: usize,
pub search_limit: Option<usize>,
}
#[derive(Deserialize)]
pub struct HttpConfig {
pub listen: SocketAddr,
}

View File

@ -15,6 +15,7 @@ use crate::commands::sed::Sed;
use crate::commands::spotify::Spotify;
use crate::commands::title::Title;
use crate::commands::waifu::Waifu;
use crate::web::HttpContext;
use futures_util::stream::StreamExt;
use irc::client::prelude::Config;
use irc::client::{Client, ClientStream};
@ -28,6 +29,7 @@ use tracing::Level;
use crate::config::UberConfig;
use crate::database::{DbExecutor, ExecutorConnection};
mod web;
mod bot;
mod commands;
mod config;
@ -98,10 +100,21 @@ async fn main() -> anyhow::Result<()> {
let (ctx, _) = broadcast::channel(1);
let (etx, mut erx) = unbounded_channel();
let mut bot = Bot::new(cfg.irc.prefix, db_conn, cfg.bot.history_depth, {
let sf = {
let client = client.clone();
move |target, msg| Ok(client.send_privmsg(target, msg)?)
};
let http_task = cfg.web.map(|http| {
let http_ctx = ctx.subscribe();
let context = HttpContext { cfg: http, sendmsg: sf.clone() };
tokio::spawn(async move {
if let Err(e) = web::run(context, http_ctx).await {
tracing::error!("Fatal error in web service: {}", e);
}
})
});
let mut bot = Bot::new(cfg.irc.prefix, db_conn, cfg.bot.history_depth, sf);
bot.add_command("help".into(), Help);
bot.add_command("waifu".into(), Waifu::default());
@ -154,13 +167,13 @@ async fn main() -> anyhow::Result<()> {
tracing::info!("Closing services...");
let _ = ctx.send(());
message_loop_task
.await
.unwrap_or_else(|e| tracing::warn!("Couldn't join the web service: {:?}", e));
message_loop_task.await.unwrap();
tracing::info!("Message loop finished");
exec_thread
.join()
.unwrap_or_else(|e| tracing::warn!("Couldn't join the database: {:?}", e));
if let Some(t) = http_task {
t.await.unwrap();
tracing::info!("Web service finished");
}
exec_thread.join().unwrap();
tracing::info!("DB Executor thread finished");
tracing::info!("Shutdown complete!");

49
src/web.rs Normal file
View File

@ -0,0 +1,49 @@
use std::{convert::Infallible, sync::Arc};
use hyper::{
service::{make_service_fn, service_fn},
Body, Request, Response, Server, StatusCode,
};
use tokio::sync::broadcast;
use crate::config::HttpConfig;
pub struct HttpContext<SF>
where
SF: Fn(String, String) -> anyhow::Result<()>,
{
pub cfg: HttpConfig,
pub sendmsg: SF,
}
async fn handle<SF>(_ctx: Arc<HttpContext<SF>>, _req: Request<Body>) -> anyhow::Result<Response<Body>>
where
SF: Fn(String, String) -> anyhow::Result<()> + Send + Sync + 'static,
{
let resp = Response::builder()
.status(StatusCode::OK)
.body(Body::empty())?;
Ok(resp)
}
pub async fn run<SF>(context: HttpContext<SF>, mut shutdown: broadcast::Receiver<()>) -> hyper::Result<()>
where
SF: Fn(String, String) -> anyhow::Result<()> + Send + Sync + 'static,
{
let ctx = Arc::new(context);
let make_service = make_service_fn({
let ctx = ctx.clone();
move |_conn| {
let ctx = ctx.clone();
let service = service_fn(move |req| handle(ctx.clone(), req));
async move { Ok::<_, Infallible>(service) }
}
});
let server = Server::bind(&ctx.cfg.listen).serve(make_service);
server
.with_graceful_shutdown(async {
shutdown.recv().await.unwrap();
})
.await
}