fix: slotsfull is occupancy, not free slots, and cover it end to end
Running the e2e suite against a real soulfind showed the per-member slots field was implemented backwards. The wire field is `slotsfull` -- a boolean that is true when the member's upload slots are all occupied -- not a count of free ones. `slots_free: u32` named it, documented it and printed it as the opposite of what the server means, so a caller reading it would pick the busiest peer to download from. - types: `slots_full: bool`, with the wire name in the doc comment - the DTO, the `room users` output and SKILL.md follow - a new e2e test joins a room with a member sharing a known three files and asserts the counts, the roster alignment and the slot flag against soulfind, so the parsing is checked against a real server rather than only against frames this repo wrote itself
This commit is contained in:
@@ -632,7 +632,7 @@ fn room_member_stats_are_returned_sorted_and_scoped_to_their_room() {
|
||||
average_speed: 1,
|
||||
shared_files: 2,
|
||||
shared_folders: 3,
|
||||
slots_free: 1,
|
||||
slots_full: true,
|
||||
country: None,
|
||||
};
|
||||
|
||||
@@ -660,7 +660,7 @@ fn rejoining_replaces_the_previous_member_stats() {
|
||||
average_speed: 1,
|
||||
shared_files: 2,
|
||||
shared_folders: 3,
|
||||
slots_free: 0,
|
||||
slots_full: false,
|
||||
country: None,
|
||||
};
|
||||
|
||||
|
||||
@@ -59,7 +59,8 @@ fn read_int32s(message: &mut Message) -> Vec<u32> {
|
||||
|
||||
/// Parse the per-member statistics that follow the membership list of a
|
||||
/// `JoinRoom` (code 14) reply: statuses, then a record of share statistics per
|
||||
/// member, then free upload slots, then country codes.
|
||||
/// member, then whether each member's upload slots are full, then country
|
||||
/// codes.
|
||||
///
|
||||
/// Each vector is independently length-prefixed and a server may send fewer
|
||||
/// entries than there are members (or, on an older server, omit the country
|
||||
@@ -87,7 +88,7 @@ fn parse_member_stats(
|
||||
shares.push((average_speed, shared_files, shared_folders));
|
||||
}
|
||||
|
||||
let slots_free = read_int32s(message);
|
||||
let slots_full = read_int32s(message);
|
||||
let countries = read_strings(message);
|
||||
|
||||
users
|
||||
@@ -104,7 +105,7 @@ fn parse_member_stats(
|
||||
average_speed,
|
||||
shared_files,
|
||||
shared_folders,
|
||||
slots_free: slots_free.get(i).copied().unwrap_or(0),
|
||||
slots_full: slots_full.get(i).copied().unwrap_or(0) != 0,
|
||||
country: countries.get(i).cloned().filter(|c| !c.is_empty()),
|
||||
}
|
||||
})
|
||||
@@ -156,7 +157,7 @@ mod tests {
|
||||
.write_int64(0)
|
||||
.write_int32(10)
|
||||
.write_int32(2)
|
||||
// free slots
|
||||
// slots full
|
||||
.write_int32(2)
|
||||
.write_int32(1)
|
||||
.write_int32(0)
|
||||
@@ -188,7 +189,7 @@ mod tests {
|
||||
average_speed: 1024,
|
||||
shared_files: 4321,
|
||||
shared_folders: 77,
|
||||
slots_free: 1,
|
||||
slots_full: true,
|
||||
country: Some("NL".to_string()),
|
||||
},
|
||||
RoomUserStats {
|
||||
@@ -197,7 +198,7 @@ mod tests {
|
||||
average_speed: 50,
|
||||
shared_files: 10,
|
||||
shared_folders: 2,
|
||||
slots_free: 0,
|
||||
slots_full: false,
|
||||
country: None,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -341,8 +341,10 @@ pub struct RoomUserStats {
|
||||
pub average_speed: u32,
|
||||
pub shared_files: u32,
|
||||
pub shared_folders: u32,
|
||||
/// Upload slots the member has free; zero means they are busy.
|
||||
pub slots_free: u32,
|
||||
/// True when the member's upload slots are all occupied, so a download
|
||||
/// from them will queue. The wire field is `slotsfull`, a boolean — not a
|
||||
/// count, and not a count of *free* slots.
|
||||
pub slots_full: bool,
|
||||
/// Two-letter country code, when the server reports one.
|
||||
pub country: Option<String>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user