ChatGPT Codex 5.2 xhigh refactored > 45min

This commit is contained in:
2026-01-13 18:59:12 +01:00
parent f76d59265c
commit b60dcef471
15 changed files with 1672 additions and 367 deletions
+263 -34
View File
@@ -8,16 +8,28 @@ use std::{
};
use lanspread_db::db::{Game, GameFileDescription};
use lanspread_proto::{GameSummary, LibraryDelta, LibrarySnapshot};
use crate::library::compute_library_digest;
pub type PeerId = String;
/// Information about a discovered peer.
#[derive(Clone, Debug)]
pub struct PeerInfo {
/// Stable peer identifier.
pub peer_id: PeerId,
/// Network address of the peer.
pub addr: SocketAddr,
/// Last time we heard from this peer.
pub last_seen: Instant,
/// Latest library revision advertised by the peer.
pub library_rev: u64,
/// Digest of the peer library state.
pub library_digest: u64,
/// Capability flags advertised by the peer.
pub features: Vec<String>,
/// Games this peer has available, keyed by game ID.
pub games: HashMap<String, Game>,
pub games: HashMap<String, GameSummary>,
/// File descriptions for each game, keyed by game ID.
pub files: HashMap<String, Vec<GameFileDescription>>,
}
@@ -25,7 +37,14 @@ pub struct PeerInfo {
/// Database tracking all discovered peers and their games.
#[derive(Debug)]
pub struct PeerGameDB {
peers: HashMap<SocketAddr, PeerInfo>,
peers: HashMap<PeerId, PeerInfo>,
addr_index: HashMap<SocketAddr, PeerId>,
}
#[derive(Debug, Clone, Copy)]
pub struct PeerUpsert {
pub is_new: bool,
pub addr_changed: bool,
}
impl Default for PeerGameDB {
@@ -39,59 +58,205 @@ impl PeerGameDB {
pub fn new() -> Self {
Self {
peers: HashMap::new(),
addr_index: HashMap::new(),
}
}
/// Adds a new peer to the database.
pub fn add_peer(&mut self, addr: SocketAddr) {
/// Adds a new peer to the database or updates its address.
pub fn upsert_peer(&mut self, peer_id: PeerId, addr: SocketAddr) -> PeerUpsert {
if let Some(existing_id) = self.addr_index.get(&addr).cloned()
&& existing_id != peer_id
{
self.peers.remove(&existing_id);
self.addr_index.remove(&addr);
}
if let Some(peer) = self.peers.get_mut(&peer_id) {
let addr_changed = peer.addr != addr;
if addr_changed {
self.addr_index.remove(&peer.addr);
self.addr_index.insert(addr, peer_id.clone());
peer.addr = addr;
}
peer.last_seen = Instant::now();
return PeerUpsert {
is_new: false,
addr_changed,
};
}
let peer_info = PeerInfo {
peer_id: peer_id.clone(),
addr,
last_seen: Instant::now(),
library_rev: 0,
library_digest: 0,
features: Vec::new(),
games: HashMap::new(),
files: HashMap::new(),
};
self.peers.insert(addr, peer_info);
self.peers.insert(peer_id.clone(), peer_info);
self.addr_index.insert(addr, peer_id);
log::info!("Added peer: {addr}");
PeerUpsert {
is_new: true,
addr_changed: false,
}
}
/// Removes a peer from the database.
pub fn remove_peer(&mut self, addr: &SocketAddr) -> Option<PeerInfo> {
self.peers.remove(addr)
/// Removes a peer from the database by id.
pub fn remove_peer(&mut self, peer_id: &PeerId) -> Option<PeerInfo> {
if let Some(peer) = self.peers.remove(peer_id) {
self.addr_index.remove(&peer.addr);
return Some(peer);
}
None
}
/// Removes a peer by address.
pub fn remove_peer_by_addr(&mut self, addr: &SocketAddr) -> Option<PeerInfo> {
let peer_id = self.addr_index.remove(addr)?;
self.peers.remove(&peer_id)
}
/// Returns the peer id for an address if known.
#[must_use]
pub fn peer_id_for_addr(&self, addr: &SocketAddr) -> Option<&PeerId> {
self.addr_index.get(addr)
}
/// Returns the library state for a peer if known.
#[must_use]
pub fn peer_library_state(&self, peer_id: &PeerId) -> Option<(u64, u64)> {
self.peers
.get(peer_id)
.map(|peer| (peer.library_rev, peer.library_digest))
}
/// Returns the number of games known for a peer.
#[must_use]
pub fn peer_game_count(&self, peer_id: &PeerId) -> usize {
self.peers.get(peer_id).map_or(0, |peer| peer.games.len())
}
/// Returns the feature list for a peer.
#[must_use]
pub fn peer_features(&self, peer_id: &PeerId) -> Vec<String> {
self.peers
.get(peer_id)
.map(|peer| peer.features.clone())
.unwrap_or_default()
}
/// Returns the address for a peer id.
#[must_use]
pub fn peer_addr(&self, peer_id: &PeerId) -> Option<SocketAddr> {
self.peers.get(peer_id).map(|peer| peer.addr)
}
/// Updates the games list for a peer.
pub fn update_peer_games(&mut self, addr: SocketAddr, games: Vec<Game>) {
if let Some(peer) = self.peers.get_mut(&addr) {
pub fn update_peer_games(&mut self, peer_id: &PeerId, games: Vec<GameSummary>) {
if let Some(peer) = self.peers.get_mut(peer_id) {
let mut map = HashMap::with_capacity(games.len());
for game in games {
map.insert(game.id.clone(), game);
}
peer.games = map;
peer.last_seen = Instant::now();
log::info!("Updated games for peer: {addr}");
log::info!("Updated games for peer: {}", peer.addr);
}
}
/// Updates the file descriptions for a specific game from a peer.
pub fn update_peer_game_files(
&mut self,
addr: SocketAddr,
peer_id: &PeerId,
game_id: &str,
files: Vec<GameFileDescription>,
) {
if let Some(peer) = self.peers.get_mut(&addr) {
if let Some(peer) = self.peers.get_mut(peer_id) {
peer.files.insert(game_id.to_string(), files);
peer.last_seen = Instant::now();
}
}
/// Updates the last seen timestamp for a peer.
pub fn update_last_seen(&mut self, addr: &SocketAddr) {
if let Some(peer) = self.peers.get_mut(addr) {
pub fn update_last_seen(&mut self, peer_id: &PeerId) {
if let Some(peer) = self.peers.get_mut(peer_id) {
peer.last_seen = Instant::now();
}
}
/// Updates the last seen timestamp for a peer by address.
pub fn update_last_seen_by_addr(&mut self, addr: &SocketAddr) {
if let Some(peer_id) = self.addr_index.get(addr).cloned()
&& let Some(peer) = self.peers.get_mut(&peer_id)
{
peer.last_seen = Instant::now();
}
}
/// Updates the library metadata for a peer.
pub fn update_peer_library(
&mut self,
peer_id: &PeerId,
library_rev: u64,
library_digest: u64,
features: Vec<String>,
) {
if let Some(peer) = self.peers.get_mut(peer_id) {
peer.library_rev = library_rev;
peer.library_digest = library_digest;
peer.features = features;
peer.last_seen = Instant::now();
}
}
/// Applies a full library snapshot for a peer.
pub fn apply_library_snapshot(&mut self, peer_id: &PeerId, snapshot: LibrarySnapshot) {
if let Some(peer) = self.peers.get_mut(peer_id) {
let mut map = HashMap::with_capacity(snapshot.games.len());
for game in snapshot.games {
map.insert(game.id.clone(), game);
}
let digest = compute_library_digest(&map);
peer.games = map;
peer.library_rev = snapshot.library_rev;
peer.library_digest = digest;
peer.last_seen = Instant::now();
}
}
/// Applies a library delta for a peer. Returns true when applied.
pub fn apply_library_delta(&mut self, peer_id: &PeerId, delta: LibraryDelta) -> bool {
let Some(peer) = self.peers.get_mut(peer_id) else {
return false;
};
if delta.to_rev <= peer.library_rev {
return false;
}
if delta.from_rev != peer.library_rev {
return false;
}
for game in delta.added {
peer.games.insert(game.id.clone(), game);
}
for game in delta.updated {
peer.games.insert(game.id.clone(), game);
}
for game_id in delta.removed {
peer.games.remove(&game_id);
}
peer.library_rev = delta.to_rev;
peer.library_digest = compute_library_digest(&peer.games);
peer.last_seen = Instant::now();
true
}
/// Returns all games aggregated from all peers.
#[must_use]
pub fn get_all_games(&self) -> Vec<Game> {
@@ -112,19 +277,27 @@ impl PeerGameDB {
.entry(game.id.clone())
.and_modify(|existing| {
if let (Some(new_version), Some(current)) =
(&game.eti_game_version, &existing.eti_game_version)
(&game.eti_version, &existing.eti_game_version)
{
if new_version > current {
existing.eti_game_version = Some(new_version.clone());
}
} else if existing.eti_game_version.is_none() {
existing.eti_game_version.clone_from(&game.eti_game_version);
existing.eti_game_version.clone_from(&game.eti_version);
}
// Update peer count
existing.peer_count = peer_counts[&game.id];
if game.size > existing.size {
existing.size = game.size;
}
if game.downloaded {
existing.downloaded = true;
}
if game.installed {
existing.installed = true;
}
})
.or_insert_with(|| {
let mut game_clone = game.clone();
let mut game_clone = summary_to_game(game);
game_clone.peer_count = peer_counts[&game.id];
game_clone
});
@@ -143,7 +316,7 @@ impl PeerGameDB {
for peer in self.peers.values() {
if let Some(game) = peer.games.get(game_id)
&& let Some(ref version) = game.eti_game_version
&& let Some(ref version) = game.eti_version
{
match &latest_version {
None => latest_version = Some(version.clone()),
@@ -162,13 +335,37 @@ impl PeerGameDB {
/// Returns all peer addresses.
#[must_use]
pub fn get_peer_addresses(&self) -> Vec<SocketAddr> {
self.peers.keys().copied().collect()
self.peers.values().map(|peer| peer.addr).collect()
}
/// Returns peer liveness info for ping scheduling.
#[must_use]
pub fn peer_liveness_snapshot(&self) -> Vec<(PeerId, SocketAddr, Instant)> {
self.peers
.values()
.map(|peer| (peer.peer_id.clone(), peer.addr, peer.last_seen))
.collect()
}
/// Returns peer ids with their current addresses.
#[must_use]
pub fn peer_identities(&self) -> Vec<(PeerId, SocketAddr)> {
self.peers
.values()
.map(|peer| (peer.peer_id.clone(), peer.addr))
.collect()
}
/// Checks if a peer is in the database.
#[must_use]
pub fn contains_peer(&self, addr: &SocketAddr) -> bool {
self.peers.contains_key(addr)
pub fn contains_peer(&self, peer_id: &PeerId) -> bool {
self.peers.contains_key(peer_id)
}
/// Checks if a peer address is in the database.
#[must_use]
pub fn contains_peer_addr(&self, addr: &SocketAddr) -> bool {
self.addr_index.contains_key(addr)
}
/// Returns addresses of peers that have a specific game.
@@ -177,7 +374,7 @@ impl PeerGameDB {
self.peers
.iter()
.filter(|(_, peer)| peer.games.contains_key(game_id))
.map(|(addr, _)| *addr)
.map(|(_, peer)| peer.addr)
.collect()
}
@@ -191,7 +388,7 @@ impl PeerGameDB {
.iter()
.filter(|(_, peer)| {
if let Some(game) = peer.games.get(game_id) {
if let Some(ref version) = game.eti_game_version {
if let Some(ref version) = game.eti_version {
version == latest
} else {
false
@@ -200,7 +397,7 @@ impl PeerGameDB {
false
}
})
.map(|(addr, _)| *addr)
.map(|(_, peer)| peer.addr)
.collect()
} else {
// If no version info is available, fall back to all peers with the game
@@ -213,7 +410,12 @@ impl PeerGameDB {
pub fn game_files_for(&self, game_id: &str) -> Vec<(SocketAddr, Vec<GameFileDescription>)> {
self.peers
.iter()
.filter_map(|(addr, peer)| peer.files.get(game_id).cloned().map(|files| (*addr, files)))
.filter_map(|(_, peer)| {
peer.files
.get(game_id)
.cloned()
.map(|files| (peer.addr, files))
})
.collect()
}
@@ -373,10 +575,8 @@ impl PeerGameDB {
peers: &[SocketAddr],
) -> Option<GameFileDescription> {
if let Some(first_peer) = peers.first()
&& let Some(files) = self
.peers
.get(first_peer)
.and_then(|p| p.files.get(game_id))
&& let Some(peer_id) = self.addr_index.get(first_peer)
&& let Some(files) = self.peers.get(peer_id).and_then(|p| p.files.get(game_id))
&& let Some(file_desc) = files
.iter()
.find(|f| f.relative_path == relative_path && f.size == size)
@@ -390,9 +590,19 @@ impl PeerGameDB {
#[must_use]
pub fn get_stale_peers(&self, timeout: Duration) -> Vec<SocketAddr> {
self.peers
.iter()
.filter(|(_, peer)| peer.last_seen.elapsed() > timeout)
.map(|(addr, _)| *addr)
.values()
.filter(|peer| peer.last_seen.elapsed() > timeout)
.map(|peer| peer.addr)
.collect()
}
/// Returns stale peer ids that exceeded the timeout.
#[must_use]
pub fn get_stale_peer_ids(&self, timeout: Duration) -> Vec<PeerId> {
self.peers
.values()
.filter(|peer| peer.last_seen.elapsed() > timeout)
.map(|peer| peer.peer_id.clone())
.collect()
}
}
@@ -500,3 +710,22 @@ fn create_peer_whitelist(peer_scores: HashMap<SocketAddr, usize>) -> Vec<SocketA
peers.into_iter().map(|(peer, _)| peer).collect()
}
fn summary_to_game(summary: &GameSummary) -> Game {
Game {
id: summary.id.clone(),
name: summary.name.clone(),
description: String::new(),
release_year: String::new(),
publisher: String::new(),
max_players: 1,
version: "1.0".to_string(),
genre: String::new(),
size: summary.size,
downloaded: summary.downloaded,
installed: summary.installed,
eti_game_version: summary.eti_version.clone(),
local_version: None,
peer_count: 0,
}
}