community: the drawer asks a peer for its card and the server for interests, and discover gets the similar-users shelf
This commit is contained in:
1 parent
64a7561750
commit
5160d97a5f
10 files changed
+412
-2
No files matched your search
@@ -1084,6 +1084,94 @@ pub struct BrowseDirDto {
|
||||
|
||||
/// Walk a user's shares. Long-running: the client lock is held only long
|
||||
/// enough to start the request.
|
||||
#[derive(Serialize)]
|
||||
pub struct UserInfoDto {
|
||||
pub username: String,
|
||||
pub description: String,
|
||||
/// The picture ONLY after the avatar pipeline's bounded decode + resize
|
||||
/// (profile.rs): a peer's bytes are hostile input, never rendered raw.
|
||||
pub picture_png_base64: Option<String>,
|
||||
pub picture_note: Option<String>,
|
||||
pub total_uploads: u32,
|
||||
pub queue_size: u32,
|
||||
pub has_free_slot: bool,
|
||||
}
|
||||
|
||||
/// A peer's native user-info card: description, picture, upload state.
|
||||
#[tauri::command]
|
||||
pub async fn slsk_user_info(
|
||||
state: State<'_, AppState>,
|
||||
username: String,
|
||||
) -> Result<UserInfoDto, String> {
|
||||
let fut = {
|
||||
let guard = state.client.lock().await;
|
||||
let client = guard.as_ref().ok_or("not connected to Soulseek")?;
|
||||
client.user_info(&username)
|
||||
};
|
||||
let info = fut.await.map_err(|e| e.to_string())?;
|
||||
let (picture_png_base64, picture_note) = match info.picture.as_deref() {
|
||||
None => (None, None),
|
||||
Some(bytes) => match crate::profile::normalize_avatar(bytes) {
|
||||
Ok(png) => {
|
||||
use base64::Engine;
|
||||
(Some(base64::engine::general_purpose::STANDARD.encode(png)), None)
|
||||
}
|
||||
Err(e) => (None, Some(format!("picture refused: {e}"))),
|
||||
},
|
||||
};
|
||||
Ok(UserInfoDto {
|
||||
username,
|
||||
description: info.description,
|
||||
picture_png_base64,
|
||||
picture_note,
|
||||
total_uploads: info.total_uploads,
|
||||
queue_size: info.queue_size,
|
||||
has_free_slot: info.has_free_slot,
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct InterestsDto {
|
||||
pub likes: Vec<String>,
|
||||
pub hates: Vec<String>,
|
||||
}
|
||||
|
||||
/// A user's declared Soulseek interests — raw likes and hates, not follows.
|
||||
#[tauri::command]
|
||||
pub async fn slsk_user_interests(
|
||||
state: State<'_, AppState>,
|
||||
username: String,
|
||||
) -> Result<InterestsDto, String> {
|
||||
let fut = {
|
||||
let guard = state.client.lock().await;
|
||||
let client = guard.as_ref().ok_or("not connected to Soulseek")?;
|
||||
client.user_interests(&username)
|
||||
};
|
||||
let (likes, hates) = fut.await.map_err(|e| e.to_string())?;
|
||||
Ok(InterestsDto { likes, hates })
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct SimilarUserDto {
|
||||
pub username: String,
|
||||
pub rating: u32,
|
||||
}
|
||||
|
||||
/// Users the server ranks as similar to us by shared interests.
|
||||
#[tauri::command]
|
||||
pub async fn slsk_similar_users(state: State<'_, AppState>) -> Result<Vec<SimilarUserDto>, String> {
|
||||
let fut = {
|
||||
let guard = state.client.lock().await;
|
||||
let client = guard.as_ref().ok_or("not connected to Soulseek")?;
|
||||
client.similar_users()
|
||||
};
|
||||
let users = fut.await.map_err(|e| e.to_string())?;
|
||||
Ok(users
|
||||
.into_iter()
|
||||
.map(|(username, rating)| SimilarUserDto { username, rating })
|
||||
.collect())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn slsk_browse_user(
|
||||
state: State<'_, AppState>,
|
||||
|
||||
@@ -120,6 +120,9 @@ pub fn run() {
|
||||
commands::slsk_message_user,
|
||||
commands::slsk_room_list,
|
||||
commands::slsk_browse_user,
|
||||
commands::slsk_user_info,
|
||||
commands::slsk_user_interests,
|
||||
commands::slsk_similar_users,
|
||||
commands::buddy_list,
|
||||
commands::buddy_add,
|
||||
commands::buddy_remove,
|
||||
|
||||
Reference in new issue
Block a user