feat(daemon): say what to do next on startup, and prove multiple clients agree
Starting the daemon printed 'ready' and nothing else, so the token and the next step were both somewhere else. It now prints what other commands can do from here, and when --bind is given, the token itself with the two config commands a remote client needs. All on stderr, so stdout stays empty and daemon still composes in a pipeline. Adds the guarantee daemon mode is for as a test: eight clients connected at once are each answered correctly, none has its replies crossed with another's, and the daemon still counts all eight. Plus 250 connect-and-drop cycles, well past the connection cap, to catch a per-connection resource that is not released — the shape a daemon that works for a while and then refuses everybody would take. A connection the daemon drops before it can be served now logs why at warning level. A client only ever sees 'the connection closed', so that line is the only account of the reason.
This commit is contained in:
@@ -199,7 +199,7 @@ pub fn run(
|
||||
downloads: Arc::clone(&downloads),
|
||||
download_dir: ctx.download_dir.clone(),
|
||||
server: ctx.settings.server_address.to_string(),
|
||||
token,
|
||||
token: token.clone(),
|
||||
started: Instant::now(),
|
||||
stop: Arc::clone(&stop),
|
||||
open: Arc::new(std::sync::atomic::AtomicUsize::new(0)),
|
||||
@@ -225,7 +225,7 @@ pub fn run(
|
||||
"logged in as {}, sharing {files} files in {folders} folders",
|
||||
session.client.username()
|
||||
));
|
||||
ctx.out.status("ready");
|
||||
ready(ctx, bind, &token);
|
||||
|
||||
// The listeners run on their own threads; this one only has to notice a
|
||||
// `daemon.stop` and write state back on the way past.
|
||||
@@ -247,6 +247,57 @@ pub fn run(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Say what is now possible, once, on stderr.
|
||||
///
|
||||
/// The token goes here rather than only into a file because the moment you
|
||||
/// need it is the moment you bind a port, and hunting for `daemon token`
|
||||
/// afterwards is a poor first experience. stdout stays empty either way, so
|
||||
/// `daemon` still composes in a pipeline.
|
||||
fn ready(ctx: &Ctx, bind: Option<&str>, token: &str) {
|
||||
ctx.out.status("");
|
||||
ctx.out.status("ready — leave this running.");
|
||||
ctx.out.status("");
|
||||
ctx.out
|
||||
.status(" On this machine, nothing else to do. Other commands find");
|
||||
ctx.out
|
||||
.status(" it on their own and share this one login:");
|
||||
ctx.out.status("");
|
||||
ctx.out.status(" soulseek-rs search 'aphex twin'");
|
||||
ctx.out
|
||||
.status(" soulseek-rs (the TUI attaches)");
|
||||
ctx.out.status(" soulseek-rs daemon status");
|
||||
ctx.out.status(" soulseek-rs daemon stop");
|
||||
ctx.out.status("");
|
||||
|
||||
let Some(address) = bind else {
|
||||
ctx.out.status(
|
||||
" To drive it from another machine, restart with --bind ADDR;",
|
||||
);
|
||||
ctx.out
|
||||
.status(" `soulseek-rs daemon token` prints the secret it needs.");
|
||||
ctx.out.status("");
|
||||
return;
|
||||
};
|
||||
|
||||
ctx.out.status(&format!(
|
||||
" From another machine, point a client at {address} with"
|
||||
));
|
||||
ctx.out.status(" this token:");
|
||||
ctx.out.status("");
|
||||
ctx.out.status(&format!(" {token}"));
|
||||
ctx.out.status("");
|
||||
ctx.out
|
||||
.status(" soulseek-rs config set daemon <this-host>:PORT");
|
||||
ctx.out
|
||||
.status(" soulseek-rs config set daemon_token <token above>");
|
||||
ctx.out.status("");
|
||||
ctx.out.status(
|
||||
" That port has no encryption. Keep it off the open internet and \
|
||||
reach it over SSH instead.",
|
||||
);
|
||||
ctx.out.status("");
|
||||
}
|
||||
|
||||
/// Remove the socket file so the next start does not have to reason about
|
||||
/// whether it is stale.
|
||||
fn cleanup() {
|
||||
|
||||
Reference in New Issue
Block a user