79 lines
2.7 KiB
Rust
79 lines
2.7 KiB
Rust
use crate::TopLevelError;
|
|
use error_stack::ResultExt;
|
|
use tokio::net::{UnixListener, UnixStream};
|
|
use tracing::Instrument;
|
|
|
|
pub struct SocketServer {
|
|
name: String,
|
|
path: String,
|
|
num_sessions_run: u64,
|
|
listener: UnixListener,
|
|
}
|
|
|
|
#[allow(unused)]
|
|
impl SocketServer {
|
|
/// Create a new server that will handle inputs from the client program.
|
|
///
|
|
/// This function will just generate the function required, without starting the
|
|
/// underlying task. To start the task, use [`SocketServer::start`], although that
|
|
/// method will take ownership of the object.
|
|
pub fn new(name: String, listener: UnixListener) -> Self {
|
|
let path = listener
|
|
.local_addr()
|
|
.map(|x| x.as_pathname().map(|p| format!("{}", p.display())))
|
|
.unwrap_or_else(|_| None)
|
|
.unwrap_or_else(|| "<unknown>".to_string());
|
|
|
|
tracing::trace!(%name, %path, "Creating new socket listener");
|
|
|
|
SocketServer {
|
|
name,
|
|
path,
|
|
num_sessions_run: 0,
|
|
listener,
|
|
}
|
|
}
|
|
|
|
/// Start running the service, returning a handle that will pass on an error if
|
|
/// one occurs in the core of this task.
|
|
///
|
|
/// Typically, errors shouldn't happen in the core task, as all it does is listen
|
|
/// for new connections and then spawn other tasks based on them. If errors occur
|
|
/// there, the core task should be unaffected.
|
|
pub async fn start(mut self) -> error_stack::Result<(), TopLevelError> {
|
|
loop {
|
|
let (stream, addr) = self
|
|
.listener
|
|
.accept()
|
|
.await
|
|
.change_context(TopLevelError::SocketHandlerFailure)?;
|
|
let remote_addr = addr
|
|
.as_pathname()
|
|
.map(|x| x.display())
|
|
.map(|x| format!("{}", x))
|
|
.unwrap_or("<unknown>".to_string());
|
|
|
|
let span = tracing::debug_span!(
|
|
"unix socket handler",
|
|
socket_name = %self.name,
|
|
socket_path = %self.path,
|
|
session_no = %self.num_sessions_run,
|
|
%remote_addr,
|
|
);
|
|
|
|
self.num_sessions_run += 1;
|
|
|
|
tokio::task::spawn(Self::run_session(stream).instrument(span))
|
|
.await
|
|
.change_context(TopLevelError::SocketHandlerFailure)?;
|
|
}
|
|
}
|
|
|
|
/// Run a session.
|
|
///
|
|
/// This is here because it's convenient, not because it shares state (obviously,
|
|
/// given the type signature). But it's somewhat logically associated with this type,
|
|
/// so it seems reasonable to make it an associated function.
|
|
async fn run_session(handle: UnixStream) {}
|
|
}
|