dexr 0.4.3

A directory indexer with thumbnails, previews, and slideshow functionality.
use std::path::Path;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};

use anyhow::{Context as _, Result};
use axum::{Router, Server};
use bindable::BindableAddr;
use tokio::net::{UnixListener, UnixStream};

use crate::config::Config;

struct UnixAccept {
	stream: UnixListener,
}

impl UnixAccept {
	fn new(path: &Path) -> std::io::Result<Self> {
		UnixListener::bind(path).map(|stream| Self { stream })
	}
}

impl hyper::server::accept::Accept for UnixAccept {
	type Conn = UnixStream;
	type Error = std::io::Error;

	fn poll_accept(
		self: Pin<&mut Self>,
		ctx: &mut Context<'_>,
	) -> Poll<Option<Result<Self::Conn, Self::Error>>> {
		self
			.stream
			.poll_accept(ctx)
			.map(|result| Some(result.map(|(stream, _addr)| stream)))
	}
}

#[derive(Clone)]
struct UnixConnectInfo;

impl<'a> axum::extract::connect_info::Connected<&'a UnixStream> for UnixConnectInfo {
	fn connect_info(_stream: &'a UnixStream) -> Self {
		Self
	}
}

pub async fn serve(mut app: Router, config: Config) -> Result<()> {
	tracing::info!(address = %config.address, "serving app");
	let config = Arc::new(config);
	app = app.layer(axum::Extension(Arc::clone(&config)));
	match &config.address {
		BindableAddr::Tcp(addr) => Server::bind(addr)
			.serve(app.into_make_service())
			.await
			.context("starting server"),
		BindableAddr::Unix(addr) => Server::builder(UnixAccept::new(addr)?)
			.serve(app.into_make_service_with_connect_info::<UnixConnectInfo>())
			.await
			.context("starting server"),
	}
}