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"] }
|
irc = { version = "0.15", default-features = false, features = ["tls-rust"] }
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
regex = "1.6.0"
|
regex = "1.6.0"
|
||||||
|
hyper = { version = "0.14", features = ["server"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# debug IRC commands
|
# debug IRC commands
|
||||||
|
|
|
@ -19,3 +19,5 @@ search_limit = 5 # optional, default: 3
|
||||||
client_id = ""
|
client_id = ""
|
||||||
client_secret = ""
|
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;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -6,6 +8,7 @@ pub struct UberConfig {
|
||||||
pub irc: IrcConfig,
|
pub irc: IrcConfig,
|
||||||
pub spotify: Option<SpotifyConfig>,
|
pub spotify: Option<SpotifyConfig>,
|
||||||
pub bot: BotConfig,
|
pub bot: BotConfig,
|
||||||
|
pub web: Option<HttpConfig>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -32,3 +35,8 @@ pub struct BotConfig {
|
||||||
pub history_depth: usize,
|
pub history_depth: usize,
|
||||||
pub search_limit: Option<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::spotify::Spotify;
|
||||||
use crate::commands::title::Title;
|
use crate::commands::title::Title;
|
||||||
use crate::commands::waifu::Waifu;
|
use crate::commands::waifu::Waifu;
|
||||||
|
use crate::web::HttpContext;
|
||||||
use futures_util::stream::StreamExt;
|
use futures_util::stream::StreamExt;
|
||||||
use irc::client::prelude::Config;
|
use irc::client::prelude::Config;
|
||||||
use irc::client::{Client, ClientStream};
|
use irc::client::{Client, ClientStream};
|
||||||
|
@ -28,6 +29,7 @@ use tracing::Level;
|
||||||
use crate::config::UberConfig;
|
use crate::config::UberConfig;
|
||||||
use crate::database::{DbExecutor, ExecutorConnection};
|
use crate::database::{DbExecutor, ExecutorConnection};
|
||||||
|
|
||||||
|
mod web;
|
||||||
mod bot;
|
mod bot;
|
||||||
mod commands;
|
mod commands;
|
||||||
mod config;
|
mod config;
|
||||||
|
@ -98,10 +100,21 @@ async fn main() -> anyhow::Result<()> {
|
||||||
let (ctx, _) = broadcast::channel(1);
|
let (ctx, _) = broadcast::channel(1);
|
||||||
let (etx, mut erx) = unbounded_channel();
|
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();
|
let client = client.clone();
|
||||||
move |target, msg| Ok(client.send_privmsg(target, msg)?)
|
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("help".into(), Help);
|
||||||
bot.add_command("waifu".into(), Waifu::default());
|
bot.add_command("waifu".into(), Waifu::default());
|
||||||
|
@ -154,13 +167,13 @@ async fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
tracing::info!("Closing services...");
|
tracing::info!("Closing services...");
|
||||||
let _ = ctx.send(());
|
let _ = ctx.send(());
|
||||||
message_loop_task
|
message_loop_task.await.unwrap();
|
||||||
.await
|
|
||||||
.unwrap_or_else(|e| tracing::warn!("Couldn't join the web service: {:?}", e));
|
|
||||||
tracing::info!("Message loop finished");
|
tracing::info!("Message loop finished");
|
||||||
exec_thread
|
if let Some(t) = http_task {
|
||||||
.join()
|
t.await.unwrap();
|
||||||
.unwrap_or_else(|e| tracing::warn!("Couldn't join the database: {:?}", e));
|
tracing::info!("Web service finished");
|
||||||
|
}
|
||||||
|
exec_thread.join().unwrap();
|
||||||
tracing::info!("DB Executor thread finished");
|
tracing::info!("DB Executor thread finished");
|
||||||
tracing::info!("Shutdown complete!");
|
tracing::info!("Shutdown complete!");
|
||||||
|
|
||||||
|
|
49
src/web.rs
Normal file
49
src/web.rs
Normal 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
|
||||||
|
}
|
Loading…
Reference in a new issue