Conversation
Bug: when a Game had image_url but no image_sha256, the card rendered blank and the hash never propagated back to the config. Root cause was an interaction between two earlier commits: - deb6bcb turned CachedImage's createResource source key from a tuple into a concatenated string, converting props.hash=null into '' (empty string). - Tauri serializes '' as Some("") on the Rust side, not None. - The pre-existing fast-path at http/mod.rs did IMAGE_CACHE_DIR.join(hash); join("") is a no-op, so cache_path resolved to IMAGE_CACHE_DIR itself, which always .exists(). prepare_image returned Ok(""). - Back in TS, hash !== currentHash was '' !== '' -> false, so onHashUpdate never fired, and imageHash() was falsy so the <img> never rendered. Fix / rewrite: - http::prepare_image now validates the hash (is_valid_hash: 32 hex chars) before using it as a cache key. Empty / malformed values are treated as None. The galimg protocol handler is tightened the same way. - The single-flight dedup is rewritten using DashMap<String, broadcast::Sender> instead of DashMap<String, Arc<Mutex<Option<String>>>>. The leader does the HTTP GET, hashes the bytes, writes the cache file, broadcasts the result to all subscribers, then removes itself from the pool. Late subscribers that miss the broadcast (RecvError::Closed) fall back to the disk fast-path when sha256 is known, or loop once to become the new leader otherwise. - Dedup key is sha256 when known, falling back to the URL itself for the first load of a URL-only config (the bug case). - Renamed the IPC and internal parameter hash -> sha256 for clarity, since the value is always the content sha256 of the cached bytes. - CachedImage now passes sha256: currentHash || null so a missing hash serializes to None on the Rust side, never an empty string. The existing Cache-Control: public, max-age=31536000, immutable on the galimg protocol response already lets the webview cache content-addressed images indefinitely; no JS-side cache is needed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
close #11
Bug: when a Game had image_url but no image_sha256, the card rendered blank and the hash never propagated back to the config.
Root cause was an interaction between two earlier commits:
''(empty string).''asSome("")on the Rust side, not None.IMAGE_CACHE_DIR.join(hash);join("")is a no-op, so cache_path resolved to IMAGE_CACHE_DIR itself, which always .exists(). prepare_image returnedOk("").Fix / rewrite:
http::prepare_imagenow validates the hash (is_valid_hash: 32 hex chars) before using it as a cache key. Empty / malformed values are treated as None. The galimg protocol handler is tightened the same way.DashMap<String, broadcast::Sender>instead ofDashMap<String, Arc<Mutex<Option<String>>>>. The leader does the HTTP GET, hashes the bytes, writes the cache file, broadcasts the result to all subscribers, then removes itself from the pool. Late subscribers that miss the broadcast (RecvError::Closed) fall back to the disk fast-path when sha256 is known, or loop once to become the new leader otherwise.