community: the soulseek link proof, one message to yourself links the account and one question links anyone who answers

This commit is contained in:
KeelrLeek committed 2026-09-02 14:27:54 -05:00
1 parent cf9558cf26
commit 6ed6f5b8f8
10 files changed
+1156 -593

No files matched your search

+55 -1
View File
@@ -59,6 +59,13 @@ export const community = $state({
interests: {},
/** The server's similar-users answer, or null before it was asked. */
similar: null,
/** slsk_link_status: our own verified link and everyone we verified. */
links: null,
/** username → the last failed ask's reason. */
linkErrors: {},
/** persona key → ProfileView | {none} | {error} | {pending}: other
* people's signed profiles, read once per session when surfaced. */
remoteProfiles: {},
/** key → true while an action runs (buttons disable on it). */
busy: {},
/** The last action's error, shown where it happened. */
@@ -303,7 +310,7 @@ export async function initCommunity() {
if (p.status === 1 || p.status === 2) noteSeen(p.username);
});
}
await Promise.all([refreshFreenet(), loadContacts()]);
await Promise.all([refreshFreenet(), loadContacts(), refreshLinks()]);
await refreshPersona();
}
@@ -337,6 +344,53 @@ export async function loadSimilar(force = false) {
}
}
// ---- the Soulseek link proof ----------------------------------------------------
export async function refreshLinks() {
try {
community.links = await api.slskLinkStatus();
} catch {
// stays null: the UI treats it as "not linked"
}
}
export const linkSelf = () =>
run("linkself", async () => {
community.links = await api.slskLinkSelf();
});
export const unlinkSelf = () =>
run("linkself", async () => {
community.links = await api.slskLinkUnlink();
});
/** Ask one person over Soulseek; success is remembered on the Rust side. */
export async function checkLink(username) {
community.busy["link:" + username] = true;
delete community.linkErrors[username];
try {
const k = await api.slskLinkCheck(username);
await refreshLinks();
return k;
} catch (e) {
community.linkErrors[username] = String(e?.message ?? e);
return null;
} finally {
delete community.busy["link:" + username];
}
}
export const linkFor = (username) => {
const n = (username ?? "").trim().toLowerCase();
return community.links?.others?.find((l) => l.username_normalized === n) ?? null;
};
export async function loadRemoteProfile(key, force = false) {
if (!key) return;
if (community.remoteProfiles[key] && !force) return;
community.remoteProfiles[key] = { pending: true };
try {
community.remoteProfiles[key] = (await api.profileGet(key)) ?? { none: true };
} catch (e) {
community.remoteProfiles[key] = { error: String(e?.message ?? e) };
}
}
// Dev handle beside `__soulstream` (state.svelte.js): probes reach the store
// through this, never through a bare import (which would be a second copy).
if (import.meta.env.DEV) globalThis.__community = community;