-
Notifications
You must be signed in to change notification settings - Fork 845
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Disable http disk cache and implempent in-memory image cache (#2498)
* Disable http disk cache and implempent in-memory image cache * Add comment about removing URL scheme prefix Co-authored-by: PikachuEXE <[email protected]> * Add early return to clean up the code * Rewrite cache expiry logic with fallbacks * Move this change behind a CLI argument --experiments-disable-disk-cache * Replace CLI flag with a GUI setting * Improve warning message styling * ! Fix incompatibility with latest settings code * Use CSS instead of sass for the experimental settings * Return the error as JSON instead of throwing it * Inline restart prompt label and option names and values * Mention crash risk and recommend backups in the warning Co-authored-by: PikachuEXE <[email protected]>
- Loading branch information
1 parent
9ed5127
commit 697bed2
Showing
11 changed files
with
324 additions
and
6 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// cleanup expired images once every 5 mins | ||
const CLEANUP_INTERVAL = 300_000 | ||
|
||
// images expire after 2 hours if no expiry information is found in the http headers | ||
const FALLBACK_MAX_AGE = 7200 | ||
|
||
export class ImageCache { | ||
constructor() { | ||
this._cache = new Map() | ||
|
||
setInterval(this._cleanup.bind(this), CLEANUP_INTERVAL) | ||
} | ||
|
||
add(url, mimeType, data, expiry) { | ||
this._cache.set(url, { mimeType, data, expiry }) | ||
} | ||
|
||
has(url) { | ||
return this._cache.has(url) | ||
} | ||
|
||
get(url) { | ||
const entry = this._cache.get(url) | ||
|
||
if (!entry) { | ||
// this should never happen as the `has` method should be used to check for the existence first | ||
throw new Error(`No image cache entry for ${url}`) | ||
} | ||
|
||
return { | ||
data: entry.data, | ||
mimeType: entry.mimeType | ||
} | ||
} | ||
|
||
_cleanup() { | ||
// seconds since 1970-01-01 00:00:00 | ||
const now = Math.trunc(Date.now() / 1000) | ||
|
||
for (const [key, entry] of this._cache.entries()) { | ||
if (entry.expiry <= now) { | ||
this._cache.delete(key) | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Extracts the cache expiry timestamp of image from HTTP headers | ||
* @param {Record<string, string>} headers | ||
* @returns a timestamp in seconds | ||
*/ | ||
export function extractExpiryTimestamp(headers) { | ||
const maxAgeRegex = /max-age=([0-9]+)/ | ||
|
||
const cacheControl = headers['cache-control'] | ||
if (cacheControl && maxAgeRegex.test(cacheControl)) { | ||
let maxAge = parseInt(cacheControl.match(maxAgeRegex)[1]) | ||
|
||
if (headers.age) { | ||
maxAge -= parseInt(headers.age) | ||
} | ||
|
||
// we don't need millisecond precision, so we can store it as seconds to use less memory | ||
return Math.trunc(Date.now() / 1000) + maxAge | ||
} else if (headers.expires) { | ||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires | ||
|
||
return Math.trunc(Date.parse(headers.expires) / 1000) | ||
} else { | ||
return Math.trunc(Date.now() / 1000) + FALLBACK_MAX_AGE | ||
} | ||
} |
This file contains 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
6 changes: 6 additions & 0 deletions
6
src/renderer/components/experimental-settings/experimental-settings.css
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.experimental-warning { | ||
text-align: center; | ||
font-weight: bold; | ||
padding-left: 4%; | ||
padding-right: 4% | ||
} |
73 changes: 73 additions & 0 deletions
73
src/renderer/components/experimental-settings/experimental-settings.js
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { closeSync, existsSync, openSync, rmSync } from 'fs' | ||
import Vue from 'vue' | ||
import { mapActions } from 'vuex' | ||
import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue' | ||
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue' | ||
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue' | ||
import FtPrompt from '../ft-prompt/ft-prompt.vue' | ||
|
||
export default Vue.extend({ | ||
name: 'ExperimentalSettings', | ||
components: { | ||
'ft-settings-section': FtSettingsSection, | ||
'ft-flex-box': FtFlexBox, | ||
'ft-toggle-switch': FtToggleSwitch, | ||
'ft-prompt': FtPrompt | ||
}, | ||
data: function () { | ||
return { | ||
replaceHttpCacheLoading: true, | ||
replaceHttpCache: false, | ||
replaceHttpCachePath: '', | ||
showRestartPrompt: false | ||
} | ||
}, | ||
mounted: function () { | ||
this.getUserDataPath().then((userData) => { | ||
this.replaceHttpCachePath = `${userData}/experiment-replace-http-cache` | ||
|
||
this.replaceHttpCache = existsSync(this.replaceHttpCachePath) | ||
this.replaceHttpCacheLoading = false | ||
}) | ||
}, | ||
methods: { | ||
updateReplaceHttpCache: function () { | ||
this.replaceHttpCache = !this.replaceHttpCache | ||
|
||
if (this.replaceHttpCache) { | ||
// create an empty file | ||
closeSync(openSync(this.replaceHttpCachePath, 'w')) | ||
} else { | ||
rmSync(this.replaceHttpCachePath) | ||
} | ||
}, | ||
|
||
handleRestartPrompt: function (value) { | ||
this.replaceHttpCache = value | ||
this.showRestartPrompt = true | ||
}, | ||
|
||
handleReplaceHttpCache: function (value) { | ||
this.showRestartPrompt = false | ||
|
||
if (value === null || value === 'no') { | ||
this.replaceHttpCache = !this.replaceHttpCache | ||
return | ||
} | ||
|
||
if (this.replaceHttpCache) { | ||
// create an empty file | ||
closeSync(openSync(this.replaceHttpCachePath, 'w')) | ||
} else { | ||
rmSync(this.replaceHttpCachePath) | ||
} | ||
|
||
const { ipcRenderer } = require('electron') | ||
ipcRenderer.send('relaunchRequest') | ||
}, | ||
|
||
...mapActions([ | ||
'getUserDataPath' | ||
]) | ||
} | ||
}) |
30 changes: 30 additions & 0 deletions
30
src/renderer/components/experimental-settings/experimental-settings.vue
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<template> | ||
<ft-settings-section | ||
:title="$t('Settings.Experimental Settings.Experimental Settings')" | ||
> | ||
<p class="experimental-warning"> | ||
{{ $t('Settings.Experimental Settings.Warning') }} | ||
</p> | ||
<ft-flex-box> | ||
<ft-toggle-switch | ||
tooltip-position="top" | ||
:label="$t('Settings.Experimental Settings.Replace HTTP Cache')" | ||
:compact="true" | ||
:default-value="replaceHttpCache" | ||
:disabled="replaceHttpCacheLoading" | ||
:tooltip="$t('Tooltips.Experimental Settings.Replace HTTP Cache')" | ||
@change="handleRestartPrompt" | ||
/> | ||
</ft-flex-box> | ||
<ft-prompt | ||
v-if="showRestartPrompt" | ||
:label="$t('Settings[\'The app needs to restart for changes to take effect. Restart and apply change?\']')" | ||
:option-names="[$t('Yes'), $t('No')]" | ||
:option-values="['yes', 'no']" | ||
@click="handleReplaceHttpCache" | ||
/> | ||
</ft-settings-section> | ||
</template> | ||
|
||
<script src="./experimental-settings.js" /> | ||
<style scoped src="./experimental-settings.css" /> |
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Oops, something went wrong.