Add basic web service
This commit is contained in:
parent
cbbdcb145c
commit
4a19c2ce5a
|
@ -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
|
||||
|
|
|
@ -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"
|
|
@ -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,
|
||||
}
|
||||
|
|
27
src/main.rs
27
src/main.rs
|
@ -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!");
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue