/* wearechat - generic multiplayer game with voip Copyright (C) 2025 metamuffin This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3 of the License only. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ use crate::network::Network; use anyhow::Result; use log::debug; use std::{collections::HashSet, marker::PhantomData}; use weareshared::{ packets::{Packet, ReadWrite, Resource}, store::{ResourceStore, sha256}, }; pub struct Downloader { have: HashSet, need: HashSet, pending: HashSet, store: ResourceStore, } impl Downloader { pub fn new(store: ResourceStore) -> Self { Self { have: HashSet::new(), need: HashSet::new(), pending: HashSet::new(), store, } } pub fn try_get(&mut self, hash: Resource) -> Result> { self.try_get_raw(Resource(hash.0, PhantomData))? .map(|x| T::read(&mut x.as_slice())) .transpose() } pub fn try_get_raw(&mut self, hash: Resource) -> Result>> { if self.have.contains(&hash) { self.store.get_raw(hash) } else { self.need.insert(hash); Ok(None) } } pub fn packet(&mut self, p: &Packet) -> Result<()> { match p { Packet::RespondResource(d) => { let key = Resource(sha256(&d.0), PhantomData); self.store.set_raw(&d.0)?; self.need.remove(&key); self.pending.remove(&key); if self.have.insert(key) { debug!("have {key}"); } } _ => (), } Ok(()) } pub fn update(&mut self, network: &mut Network) -> Result<()> { let mut new_pending = Vec::new(); for n in self.need.difference(&self.pending) { network .packet_send .send(Packet::RequestResource(*n)) .unwrap(); debug!("need {n}"); new_pending.push(*n); } self.pending.extend(new_pending); Ok(()) } }