feat!: wishlist, upload-queue privilege recognition, and search filters (#20)
Closes the last two gaps in Soulseek's list of features an alternative client must implement to be tolerated, and adds the result filters Nicotine+ has had all along. Wishlist: server code 103 is sent and code 104's announced interval is kept rather than logged and discarded, so the re-search timer runs off the schedule the server set. `wish add|remove|list|run` plus `serve --wishlist`; wishes persist in config.toml as a TOML array so a comma inside a query survives. `wish run` prints search-shaped records, so it pipes into `download --stdin`. Privilege recognition: the code-69 user list is parsed instead of counted and dropped, and code 92 answers `whoami` as `privilege_seconds`. Uploads now go through a queue with a slot cap (`--upload-slots`, default 2) that serves privileged users first — the cap is what makes the ordering mean anything, so they are one change. `PlaceInQueueRequest` (peer code 51) is answered, where it previously had no handler at all, and a departed peer's slot is released so a stalled peer cannot wedge uploads shut. Search filters: `--exclude`, `--extension`, `--min-size`, `--max-size` beside the existing `--min-bitrate` and `--free-slots`, in one flattened arg group shared by `search`, `get` and `wish run`. Also serialises the library e2e suite behind the same gate `cli_e2e` already uses: the new queue tests hold peer sockets open on purpose, which starved concurrently-spawned soulfinds and failed unrelated download tests with `login: Timeout`. BREAKING CHANGE: `UploadStatus` gains a `Queued(u32)` variant, so an exhaustive match on it no longer compiles, and `cli::Commands` gains `Wish`.
This commit is contained in:
@@ -92,6 +92,9 @@ fn build_upload_info_lines(upload: &UploadInfo) -> Vec<Line<'static>> {
|
||||
lines.push(label_value("Size", &format_bytes(upload.size)));
|
||||
|
||||
let (status_text, status_style) = match &upload.status {
|
||||
UploadStatus::Queued(place) => {
|
||||
(format!("Queued (#{place})"), inactive_style())
|
||||
}
|
||||
UploadStatus::InProgress => {
|
||||
("In progress".to_string(), warning_style())
|
||||
}
|
||||
@@ -132,7 +135,9 @@ fn build_upload_info_lines(upload: &UploadInfo) -> Vec<Line<'static>> {
|
||||
)));
|
||||
lines.push(Line::from(Span::styled(reason.clone(), error_style())));
|
||||
}
|
||||
UploadStatus::Completed | UploadStatus::Cancelled => {}
|
||||
UploadStatus::Queued(_)
|
||||
| UploadStatus::Completed
|
||||
| UploadStatus::Cancelled => {}
|
||||
}
|
||||
|
||||
lines
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::models::DownloadEntry;
|
||||
use crate::ui::{
|
||||
GLYPH_ACTIVE, GLYPH_DONE, GLYPH_FAILED, HIGHLIGHT_SYMBOL, accent_style,
|
||||
body_style, dimmed_style, download_status_glyph, error_style, format_bytes,
|
||||
format_speed, header_style, inactive_style, info_style, pane_block,
|
||||
pane_title, primary_style, row_highlight_style, success_style,
|
||||
GLYPH_ACTIVE, GLYPH_DONE, GLYPH_FAILED, GLYPH_QUEUED, HIGHLIGHT_SYMBOL,
|
||||
accent_style, body_style, dimmed_style, download_status_glyph, error_style,
|
||||
format_bytes, format_speed, header_style, inactive_style, info_style,
|
||||
pane_block, pane_title, primary_style, row_highlight_style, success_style,
|
||||
warning_style,
|
||||
};
|
||||
use ratatui::{
|
||||
@@ -119,12 +119,14 @@ pub fn render_downloads_pane(
|
||||
|
||||
rows.extend(uploads.iter().map(|upload| {
|
||||
let (status_icon, status_style) = match &upload.status {
|
||||
UploadStatus::Queued(_) => (GLYPH_QUEUED, warning_style()),
|
||||
UploadStatus::InProgress => (GLYPH_ACTIVE, accent_style()),
|
||||
UploadStatus::Completed => (GLYPH_DONE, success_style()),
|
||||
UploadStatus::Cancelled => (GLYPH_FAILED, inactive_style()),
|
||||
UploadStatus::Failed(_) => (GLYPH_FAILED, error_style()),
|
||||
};
|
||||
let progress_text = match &upload.status {
|
||||
UploadStatus::Queued(place) => format!("Queued #{place}"),
|
||||
UploadStatus::InProgress => {
|
||||
let percent = if upload.size > 0 {
|
||||
(upload.bytes_sent as f64 / upload.size as f64 * 100.0)
|
||||
|
||||
Reference in New Issue
Block a user