feat: TTL eviction, disk guard, debug logging, and extended cache API#3
Closed
chanphiromsok wants to merge 6 commits into
Closed
feat: TTL eviction, disk guard, debug logging, and extended cache API#3chanphiromsok wants to merge 6 commits into
chanphiromsok wants to merge 6 commits into
Conversation
…ail, URL encoding Four bugs were causing blank video when no internet connection: 1. serveFileFromDisk returned 200 OK for all range requests instead of 206 Partial Content with Content-Range. AVPlayer sees a different status code offline vs online and fails to render cached segments correctly. 2. ClientConnectionHandler dropped the TCP connection with no HTTP response when a network fetch failed (content not cached + offline). AVPlayer treats a connection drop as a connect error rather than an HTTP error, giving up immediately instead of retrying or showing a useful state. Now returns HTTP 502 Bad Gateway when no headers have been sent yet. 3. sendRewrittenManifest omitted Content-Length, forcing AVPlayer to wait for connection close to determine manifest end, causing stalls. 4. addingPercentEncoding with .urlQueryAllowed left & and # unencoded in segment URLs embedded as query-parameter values. A URL such as segment.m4s?token=abc&sig=xyz was silently truncated to segment.m4s?token=abc, causing cache key mismatches on playback. Fixed in both convertUrl (HlsCache.swift) and rewriteLineToProxy (DataSource.swift) using a stricter character set. https://claude.ai/code/session_016aKiYNJycuCWkNYogZNqsY
- New `cacheTTLDays` param in `startServer()` (default: 2 days) — files
older than the TTL are evicted on server start, fitting daily-feed use
cases where yesterday's segments are always stale.
- New `debugLogging` param in `startServer()` — enables `[HLSCache]`
prefixed log lines (HIT/MISS/SAVED/FAIL, manifest rewrites, prune
stats, connection count). Gated by `#if DEBUG` in CacheLogger.swift so
the flag is a no-op in release builds with zero runtime overhead.
- `VideoCacheStorage.prune()` now runs three passes in order:
1. TTL — delete files older than `cacheTTLDays`
2. Disk guard — evict oldest files when free disk < 500 MB
3. LRU — trim to `maxCacheSize` as before
- New `ios/CacheLogger.swift` — lightweight singleton logger that
compiles out entirely in release builds.
- Android stub updated to match the new `startServer` signature (no-op).
Note: run `yarn nitrogen` to regenerate the Nitro bridge boilerplate
after this interface change.
https://claude.ai/code/session_016aKiYNJycuCWkNYogZNqsY
…GUIDE
New API surface (all platforms — Android stubs return resolved no-ops):
- stopServer() — gracefully stop the proxy and all active connections
- isRunning — synchronous boolean property (Nitro getter)
- invalidateUrl(url) — remove cached file for a single remote URL
- getCacheStats() — returns { fileCount, totalSizeBytes, freeDiskSpaceBytes }
Implementation details:
- VideoCacheStorage.getStats() reads the cache directory once and sums
file sizes without holding any locks — lightweight enough to call on demand
- VideoProxyServer.storage promoted from private to internal so HybridHlsCache
can access it directly for invalidateUrl / getCacheStats without an extra
indirection layer
- CacheStats is defined as a plain Nitro interface (generates a C++ struct
after yarn nitrogen); Android stub constructs it with zero values
Also adds FLOW_GUIDE.md — a full technical reference covering:
request lifecycle (hit / miss / manifest paths), eviction flow (TTL →
disk guard → LRU), design pattern map, API reference, and debug log table.
Note: run yarn nitrogen to regenerate the Nitro bridge after the interface
changes in src/HlsCache.nitro.ts.
https://claude.ai/code/session_016aKiYNJycuCWkNYogZNqsY
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.
Summary
cacheTTLDays(default 2) are deleted on server start; fits daily-feed use cases where yesterday's segments are always staleprune()debugLogging: truetostartServer()to enable[HLSCache]stdout logs; gated by#if DEBUGso the flag is a compile-time no-op in release buildsstopServer(),isRunning,invalidateUrl(url),getCacheStats()(fills gaps from CLAUDE.md TODO list)New API
Design patterns applied
DataSource.start()prune()— TTL / disk guard / LRU passesDispatchSemaphore(value: 32)inNetworkDownloaderCacheLogger.shared,NetworkDownloader.sharedProxyConnectionDelegate → DataSourceDelegate → NetworkDownloaderDelegateTest plan
startServer()withdebugLogging: true— verify[HLSCache]lines appear in Xcode consolestartServer()with release build — verify no log output and no binary stringsgetCacheStats()— verifyfileCount > 0andtotalSizeBytes > 0invalidateUrl(url)on a cached URL, replay — verifyMISSlog on next requeststopServer(), verifyisServerRunning()returnsfalsestopServer()— verify playback resumes normallycacheTTLDays: 0.00001, restart — verify all old files pruned on nextstartServer()yarn nitrogento verify bridge regenerates cleanly with new interfacehttps://claude.ai/code/session_016aKiYNJycuCWkNYogZNqsY