feat(directory): update peer profile to include public key and improve placeholder handling in user directory
This commit is contained in:
parent
718bd9557e
commit
42f3f86f08
|
|
@ -730,8 +730,46 @@ pub async fn start(
|
|||
continue;
|
||||
}
|
||||
|
||||
// never expose relay infrastructure in the user directory
|
||||
if Some(discovered_peer) == relay_peer {
|
||||
continue;
|
||||
}
|
||||
|
||||
log::info!("discovered peer {} via rendezvous", discovered_peer);
|
||||
|
||||
// cache a placeholder entry so global discovery is visible
|
||||
// before we receive the peer's signed profile announcement
|
||||
let now = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis() as u64;
|
||||
let discovered_peer_str = discovered_peer.to_string();
|
||||
let already_known = storage
|
||||
.load_directory()
|
||||
.ok()
|
||||
.map(|d| d.contains_key(&discovered_peer_str))
|
||||
.unwrap_or(false);
|
||||
|
||||
// add a lightweight placeholder if we have not learned this peer's profile yet
|
||||
if !already_known {
|
||||
let placeholder = DirectoryEntry {
|
||||
peer_id: discovered_peer_str.clone(),
|
||||
display_name: "discovered peer".to_string(),
|
||||
bio: String::new(),
|
||||
public_key: String::new(),
|
||||
last_seen: now,
|
||||
is_friend: false,
|
||||
};
|
||||
let _ = storage.save_directory_entry(&placeholder);
|
||||
|
||||
let _ = app_handle.emit("dusk-event", DuskEvent::ProfileReceived {
|
||||
peer_id: placeholder.peer_id,
|
||||
display_name: placeholder.display_name,
|
||||
bio: placeholder.bio,
|
||||
public_key: placeholder.public_key,
|
||||
});
|
||||
}
|
||||
|
||||
// connect through the relay circuit so neither peer reveals their IP
|
||||
if let Some(ref relay_addr) = relay_multiaddr {
|
||||
let circuit_addr = relay_addr.clone()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import {
|
|||
createSignal,
|
||||
createMemo,
|
||||
createEffect,
|
||||
onCleanup,
|
||||
For,
|
||||
Show,
|
||||
} from "solid-js";
|
||||
|
|
@ -29,6 +30,7 @@ import { identity } from "../../stores/identity";
|
|||
import { setActiveDM } from "../../stores/dms";
|
||||
import { addDMConversation } from "../../stores/dms";
|
||||
import * as tauri from "../../lib/tauri";
|
||||
import type { DirectoryEntry } from "../../lib/types";
|
||||
|
||||
interface UserDirectoryModalProps {
|
||||
isOpen: boolean;
|
||||
|
|
@ -41,10 +43,18 @@ const UserDirectoryModal: Component<UserDirectoryModalProps> = (props) => {
|
|||
const [searchQuery, setSearchQuery] = createSignal("");
|
||||
const [activeTab, setActiveTab] = createSignal<DirectoryTab>("all");
|
||||
const [copiedId, setCopiedId] = createSignal<string | null>(null);
|
||||
const [isSearching, setIsSearching] = createSignal(false);
|
||||
const [searchResults, setSearchResults] = createSignal<DirectoryEntry[] | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
// reload directory from disk and trigger fresh discovery when modal opens
|
||||
createEffect(() => {
|
||||
if (props.isOpen) {
|
||||
setSearchQuery("");
|
||||
setIsSearching(false);
|
||||
setSearchResults(null);
|
||||
|
||||
// refresh the in-memory peer list from disk so any profiles received
|
||||
// while the modal was closed are visible immediately
|
||||
tauri.getKnownPeers().then((peers) => {
|
||||
|
|
@ -59,13 +69,46 @@ const UserDirectoryModal: Component<UserDirectoryModalProps> = (props) => {
|
|||
}
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
if (!props.isOpen) return;
|
||||
|
||||
const query = searchQuery().trim();
|
||||
if (!query) {
|
||||
setIsSearching(false);
|
||||
setSearchResults(null);
|
||||
return;
|
||||
}
|
||||
|
||||
let cancelled = false;
|
||||
setIsSearching(true);
|
||||
const searchTimeout = window.setTimeout(async () => {
|
||||
try {
|
||||
const results = await tauri.searchDirectory(query);
|
||||
if (!cancelled) {
|
||||
setSearchResults(results);
|
||||
setIsSearching(false);
|
||||
}
|
||||
} catch {
|
||||
if (!cancelled) {
|
||||
setIsSearching(false);
|
||||
setSearchResults(null);
|
||||
}
|
||||
}
|
||||
}, 180);
|
||||
|
||||
onCleanup(() => {
|
||||
cancelled = true;
|
||||
window.clearTimeout(searchTimeout);
|
||||
});
|
||||
});
|
||||
|
||||
// filter out our own peer id from the directory
|
||||
const filteredPeers = createMemo(() => {
|
||||
const myId = identity()?.peer_id;
|
||||
const query = searchQuery().toLowerCase().trim();
|
||||
const tab = activeTab();
|
||||
|
||||
let peers = knownPeers();
|
||||
let peers = (searchResults() ?? knownPeers()).filter((p) => p.peer_id !== myId);
|
||||
|
||||
if (tab === "friends") {
|
||||
peers = peers.filter((p) => p.is_friend);
|
||||
|
|
@ -77,9 +120,6 @@ const UserDirectoryModal: Component<UserDirectoryModalProps> = (props) => {
|
|||
p.display_name.toLowerCase().includes(query) ||
|
||||
p.peer_id.toLowerCase().includes(query),
|
||||
);
|
||||
} else {
|
||||
// if not searching, hide self from the list to avoid confusion
|
||||
peers = peers.filter((p) => p.peer_id !== myId);
|
||||
}
|
||||
|
||||
return peers;
|
||||
|
|
@ -195,6 +235,11 @@ const UserDirectoryModal: Component<UserDirectoryModalProps> = (props) => {
|
|||
onInput={(e) => setSearchQuery(e.currentTarget.value)}
|
||||
/>
|
||||
</div>
|
||||
<Show when={isSearching() && searchQuery().trim().length > 0}>
|
||||
<p class="mt-2 text-[11px] font-mono text-white/35">
|
||||
searching directory...
|
||||
</p>
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
<Divider class="mx-6" />
|
||||
|
|
@ -207,8 +252,10 @@ const UserDirectoryModal: Component<UserDirectoryModalProps> = (props) => {
|
|||
<div class="flex flex-col items-center justify-center py-16">
|
||||
<Users size={48} class="text-white/10 mb-4" />
|
||||
<p class="text-[16px] text-white/30 mb-1">
|
||||
{searchQuery()
|
||||
? "no peers matching your search"
|
||||
{searchQuery().trim().length > 0
|
||||
? isSearching()
|
||||
? "searching directory"
|
||||
: "no peers matching your search"
|
||||
: activeTab() === "friends"
|
||||
? "no friends added yet"
|
||||
: "no peers discovered yet"}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,13 @@ export function updatePeerProfile(
|
|||
// update existing peer
|
||||
return prev.map((p) =>
|
||||
p.peer_id === peerId
|
||||
? { ...p, display_name: displayName, bio, last_seen: now }
|
||||
? {
|
||||
...p,
|
||||
display_name: displayName,
|
||||
bio,
|
||||
public_key: publicKey || p.public_key,
|
||||
last_seen: now,
|
||||
}
|
||||
: p,
|
||||
);
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in New Issue