feat(directory): proper cache handling
This commit is contained in:
@@ -1,4 +1,2 @@
|
||||
VITE_APP_TITLE=AKLive2D
|
||||
VITE_VERSION=0.5.9
|
||||
VITE_APP_VOICE_URL=jp/CN_037.ogg
|
||||
VITE_SHOWCASE_VERSION=3.3.13
|
||||
VITE_APP_VOICE_URL=jp/CN_037.ogg
|
||||
@@ -1 +1 @@
|
||||
0.5.9
|
||||
0.5.12
|
||||
@@ -1,29 +1,91 @@
|
||||
import { createContext, useState, useEffect } from "react"
|
||||
import db from "@/db"
|
||||
import { createContext, useState, useEffect, useCallback } from "react"
|
||||
import db, { invalidateCache } from "@/db"
|
||||
|
||||
const versionCompare = (v1, v2) => {
|
||||
const v1Arr = v1.split(".")
|
||||
const v2Arr = v2.split(".")
|
||||
for (let i = 0; i < v1Arr.length; i++) {
|
||||
if (v1Arr[i] > v2Arr[i]) {
|
||||
return 1
|
||||
} else if (v1Arr[i] < v2Arr[i]) {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
const invalidateRules = (local, version) => {
|
||||
if (local === undefined) {
|
||||
// no local version
|
||||
return true
|
||||
}
|
||||
if (version === undefined) {
|
||||
// no remote version
|
||||
return false
|
||||
}
|
||||
return versionCompare(local, version) < 0
|
||||
}
|
||||
|
||||
export const ConfigContext = createContext()
|
||||
|
||||
export function ConfigProvider(props) {
|
||||
const [config, setConfig] = useState([])
|
||||
const [operators, setOperators] = useState([])
|
||||
const [version, setVersion] = useState({})
|
||||
|
||||
useEffect(() => {
|
||||
const fetchConfig = (version) => {
|
||||
fetch("/_assets/directory.json").then(res => res.json()).then(data => {
|
||||
setConfig(data)
|
||||
db.config.put({ key: "config", value: data })
|
||||
let operatorsList = []
|
||||
data.operators.forEach((item) => {
|
||||
operatorsList = [...operatorsList, ...item]
|
||||
})
|
||||
setOperators(operatorsList)
|
||||
resolveOperators(data)
|
||||
db.config.put({ key: "version", value: version })
|
||||
})
|
||||
}
|
||||
|
||||
const resolveOperators = useCallback((data) => {
|
||||
let operatorsList = []
|
||||
data.operators.forEach((item) => {
|
||||
operatorsList = [...operatorsList, ...item]
|
||||
})
|
||||
setOperators(operatorsList)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/_assets/version.json").then(res => res.json()).then(data => {
|
||||
db.config.put({ key: "version", value: data })
|
||||
db.config.get({ key: "version" }).then((local) => {
|
||||
if (local === undefined || invalidateRules(local.value.directory, data.directory) || invalidateRules(local.value.showcase, data.showcase)) {
|
||||
invalidateCache()
|
||||
fetchConfig(data)
|
||||
} else {
|
||||
db.config.get({ key: "config" }).then((local) => {
|
||||
if (local) {
|
||||
setConfig(local.value)
|
||||
resolveOperators(local.value)
|
||||
} else {
|
||||
fetchConfig(data)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
setVersion(data)
|
||||
})
|
||||
/*
|
||||
local.directory | version.directory | action
|
||||
--------------- | ----------------- | ------
|
||||
1.0.0 | 1.0.0 | use cache
|
||||
1.0.0 | 1.0.1 | invalidate cache
|
||||
1.0.1 | 1.0.0 | impossible
|
||||
|
||||
local.showcase | version.showcase | action
|
||||
-------------- | ---------------- | ------
|
||||
1.0.0 | 1.0.0 | use cache
|
||||
1.0.0 | 1.0.1 | invalidate cache
|
||||
1.0.1 | 1.0.0 | use cache
|
||||
*/
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<ConfigContext.Provider value={{ config, operators }}>
|
||||
<ConfigContext.Provider value={{ config, operators, version }}>
|
||||
{props.children}
|
||||
</ConfigContext.Provider>
|
||||
)
|
||||
|
||||
@@ -7,4 +7,10 @@ db.version(2).stores({
|
||||
config: '++key, value',
|
||||
});
|
||||
|
||||
export function invalidateCache() {
|
||||
db.image.clear();
|
||||
db.voice.clear();
|
||||
db.config.clear();
|
||||
}
|
||||
|
||||
export default db;
|
||||
@@ -87,15 +87,15 @@ export default function Home() {
|
||||
const loadVoice = (link) => {
|
||||
if (!voiceOn) return
|
||||
db.voice.get({ key: link }).then((v) => {
|
||||
if (v === undefined) {
|
||||
if (v) {
|
||||
playVoice(v.blob)
|
||||
} else {
|
||||
fetch(`/${link}/assets/voice/${import.meta.env.VITE_APP_VOICE_URL}`)
|
||||
.then(res => res.blob())
|
||||
.then(blob => {
|
||||
db.voice.put({ key: link, blob: blob })
|
||||
playVoice(blob)
|
||||
})
|
||||
} else {
|
||||
playVoice(v.blob)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -162,15 +162,15 @@ function ImageElement({ item, language }) {
|
||||
|
||||
useEffect(() => {
|
||||
db.image.get({ key: item.link }).then((v) => {
|
||||
if (v === undefined) {
|
||||
if (v) {
|
||||
setBlobUrl(URL.createObjectURL(v.blob))
|
||||
} else {
|
||||
fetch(`/${item.link}/assets/${item.fallback_name.replace("#", "%23")}_portrait.png`)
|
||||
.then(res => res.blob())
|
||||
.then(blob => {
|
||||
db.image.put({ key: item.link, blob: blob })
|
||||
setBlobUrl(URL.createObjectURL(blob))
|
||||
})
|
||||
} else {
|
||||
setBlobUrl(URL.createObjectURL(v.blob))
|
||||
}
|
||||
})
|
||||
}, [item.link])
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
} from "react-router-dom";
|
||||
import './root.css'
|
||||
import routes from '@/routes'
|
||||
import { ConfigContext } from '@/context/useConfigContext';
|
||||
import { HeaderContext } from '@/context/useHeaderContext';
|
||||
import { LanguageContext } from '@/context/useLanguageContext';
|
||||
import Dropdown from '@/component/dropdown';
|
||||
@@ -34,6 +35,7 @@ export default function Root(props) {
|
||||
currentTab, setCurrentTab,
|
||||
appbarExtraArea
|
||||
} = useContext(HeaderContext)
|
||||
const { version } = useContext(ConfigContext)
|
||||
const [drawerDestinations, setDrawerDestinations] = useState(null)
|
||||
const currentYear = new Date().getFullYear()
|
||||
const [headerTabs, setHeaderTabs] = useState(null)
|
||||
@@ -197,15 +199,11 @@ export default function Root(props) {
|
||||
<span>Spine Runtimes © 2013 - 2019 Esoteric Software LLC</span>
|
||||
<span>Assets © 2017 - {currentYear} Arknights/Hypergryph Co., Ltd</span>
|
||||
<span>Source Code © 2021 - {currentYear} Halyul</span>
|
||||
<span>Version: {import.meta.env.VITE_VERSION}</span>
|
||||
<span>Directory @ {version.directory}</span>
|
||||
<span>Showcase @ {version.showcase}</span>
|
||||
</section>
|
||||
</footer>
|
||||
<ScrollRestoration
|
||||
getKey={(location, matches) => {
|
||||
// default behavior
|
||||
return location.pathname;
|
||||
}}
|
||||
/>
|
||||
<ScrollRestoration />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import getConfig from './libs/config.js'
|
||||
import { rmdir, writeSync } from './libs/file.js'
|
||||
import { increase } from './libs/version.js'
|
||||
import EnvGenerator from './libs/env_generator.js'
|
||||
import directory from './libs/directory.js'
|
||||
|
||||
global.__projetRoot = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
@@ -134,21 +135,17 @@ class ViteRunner {
|
||||
get #directoryConfig() {
|
||||
if (process.env.npm_lifecycle_event === 'vite:directory:build') {
|
||||
this.#globalConfig.version.directory = increase(path.join(__projetRoot, "directory"))
|
||||
global.__config = this.#globalConfig
|
||||
directory()
|
||||
}
|
||||
const directoryDir = path.resolve(__projetRoot, 'directory')
|
||||
writeSync((new EnvGenerator()).generate([
|
||||
{
|
||||
key: "app_title",
|
||||
value: this.#globalConfig.directory.title
|
||||
}, {
|
||||
key: "version",
|
||||
value: this.#globalConfig.version.directory
|
||||
}, {
|
||||
}, {
|
||||
key: "app_voice_url",
|
||||
value: this.#globalConfig.directory.voice
|
||||
}, {
|
||||
key: "showcase_version",
|
||||
value: this.#globalConfig.version.showcase
|
||||
}
|
||||
]), path.join(directoryDir, '.env'))
|
||||
this.#mode = process.argv[3]
|
||||
|
||||
Reference in New Issue
Block a user