mirror of
https://git.srhtnin.garden/sarah/srhtnin.github.io.git
synced 2026-10-13 18:38:11 +02:00
Added catalogue version to make webpages not need to repeatedly fetch
info from API.
This commit is contained in:
1 parent
dde47ff5a6
commit
ce6dced3ad
6 files changed
+374
-85
No files matched your search
@@ -135,6 +135,7 @@ $PageSection = "Garden";
|
|||||||
<script src="/Scripts/Garden/Plants.js"></script>
|
<script src="/Scripts/Garden/Plants.js"></script>
|
||||||
<script src="/Scripts/Garden/Mutations.js"></script>
|
<script src="/Scripts/Garden/Mutations.js"></script>
|
||||||
<script src="/Scripts/Garden/Save.js"></script>
|
<script src="/Scripts/Garden/Save.js"></script>
|
||||||
|
<script src="/Scripts/Garden/Content.js"></script>
|
||||||
<script src="/Scripts/Garden/Economy.js"></script>
|
<script src="/Scripts/Garden/Economy.js"></script>
|
||||||
<script src="/Scripts/Garden/MutationEngine.js"></script>
|
<script src="/Scripts/Garden/MutationEngine.js"></script>
|
||||||
<script src="/Scripts/Garden/Users.js"></script>
|
<script src="/Scripts/Garden/Users.js"></script>
|
||||||
|
|||||||
@@ -293,6 +293,7 @@ $PageTitle = "Profile";
|
|||||||
<script src="/Scripts/Garden/Plants.js"></script>
|
<script src="/Scripts/Garden/Plants.js"></script>
|
||||||
<script src="/Scripts/Garden/Mutations.js"></script>
|
<script src="/Scripts/Garden/Mutations.js"></script>
|
||||||
<script src="/Scripts/Garden/Save.js"></script>
|
<script src="/Scripts/Garden/Save.js"></script>
|
||||||
|
<script src="/Scripts/Garden/Content.js"></script>
|
||||||
<script src="/Scripts/Garden/Users.js"></script>
|
<script src="/Scripts/Garden/Users.js"></script>
|
||||||
<script src="/Scripts/Garden/Profile.js"></script>
|
<script src="/Scripts/Garden/Profile.js"></script>
|
||||||
<script src="/Scripts/Garden/Account.js"></script>
|
<script src="/Scripts/Garden/Account.js"></script>
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ $PageSection = "Shop";
|
|||||||
<script src="/Scripts/Garden/Plants.js"></script>
|
<script src="/Scripts/Garden/Plants.js"></script>
|
||||||
<script src="/Scripts/Garden/Mutations.js"></script>
|
<script src="/Scripts/Garden/Mutations.js"></script>
|
||||||
<script src="/Scripts/Garden/Save.js"></script>
|
<script src="/Scripts/Garden/Save.js"></script>
|
||||||
|
<script src="/Scripts/Garden/Content.js"></script>
|
||||||
<script src="/Scripts/Garden/Economy.js"></script>
|
<script src="/Scripts/Garden/Economy.js"></script>
|
||||||
<script src="/Scripts/Garden/Shop.js"></script>
|
<script src="/Scripts/Garden/Shop.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -0,0 +1,361 @@
|
|||||||
|
const GameContentCacheName =
|
||||||
|
"SarahtoninGardenContent";
|
||||||
|
|
||||||
|
const GameContentCacheSchemaVersion = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Once content has been checked, page loads for the next
|
||||||
|
* five minutes can use the local cache without any API call.
|
||||||
|
* After that, only the tiny ContentVersion endpoint is needed
|
||||||
|
* unless the catalogue has actually changed.
|
||||||
|
*/
|
||||||
|
const GameContentVersionCheckInterval =
|
||||||
|
5 * 60 * 1000;
|
||||||
|
|
||||||
|
|
||||||
|
let GameContentLoadPromise = null;
|
||||||
|
|
||||||
|
|
||||||
|
async function LoadGameContent() {
|
||||||
|
if (GameContentLoadPromise === null) {
|
||||||
|
GameContentLoadPromise =
|
||||||
|
LoadGameContentInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await GameContentLoadPromise;
|
||||||
|
} catch (Error) {
|
||||||
|
GameContentLoadPromise = null;
|
||||||
|
|
||||||
|
throw Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function LoadGameContentInternal() {
|
||||||
|
const Cache =
|
||||||
|
ReadGameContentCache();
|
||||||
|
|
||||||
|
const Now = Date.now();
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
Cache !== null &&
|
||||||
|
Now - Cache.CheckedAt <
|
||||||
|
GameContentVersionCheckInterval
|
||||||
|
) {
|
||||||
|
ApplyGameContent(
|
||||||
|
Cache.Plants,
|
||||||
|
Cache.Mutations
|
||||||
|
);
|
||||||
|
|
||||||
|
return GetLoadedGameContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
const ContentVersion =
|
||||||
|
await FetchGameContentVersion();
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
Cache !== null &&
|
||||||
|
Cache.ContentVersion ===
|
||||||
|
ContentVersion
|
||||||
|
) {
|
||||||
|
Cache.CheckedAt = Now;
|
||||||
|
|
||||||
|
WriteGameContentCache(
|
||||||
|
Cache
|
||||||
|
);
|
||||||
|
|
||||||
|
ApplyGameContent(
|
||||||
|
Cache.Plants,
|
||||||
|
Cache.Mutations
|
||||||
|
);
|
||||||
|
|
||||||
|
return GetLoadedGameContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return await RefreshGameContent(
|
||||||
|
ContentVersion
|
||||||
|
);
|
||||||
|
} catch (VersionError) {
|
||||||
|
console.warn(
|
||||||
|
"Couldn't check Garden content version. " +
|
||||||
|
"Refreshing the catalogues directly.",
|
||||||
|
VersionError
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await RefreshGameContent(
|
||||||
|
null
|
||||||
|
);
|
||||||
|
} catch (RefreshError) {
|
||||||
|
if (Cache !== null) {
|
||||||
|
console.warn(
|
||||||
|
"Couldn't refresh Garden content. " +
|
||||||
|
"Using the last cached catalogue.",
|
||||||
|
RefreshError
|
||||||
|
);
|
||||||
|
|
||||||
|
ApplyGameContent(
|
||||||
|
Cache.Plants,
|
||||||
|
Cache.Mutations
|
||||||
|
);
|
||||||
|
|
||||||
|
return GetLoadedGameContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw RefreshError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function FetchGameContentVersion() {
|
||||||
|
const Response =
|
||||||
|
await fetch(
|
||||||
|
ApiUrl +
|
||||||
|
"/ContentVersion.php",
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
|
||||||
|
headers: {
|
||||||
|
"Accept":
|
||||||
|
"application/json"
|
||||||
|
},
|
||||||
|
|
||||||
|
cache: "no-store"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (!Response.ok) {
|
||||||
|
throw new Error(
|
||||||
|
"Content version API returned HTTP " +
|
||||||
|
Response.status
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Result =
|
||||||
|
await Response.json();
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
!Result.Success ||
|
||||||
|
typeof Result.Version !==
|
||||||
|
"string" ||
|
||||||
|
Result.Version.length === 0
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
Result.Error ??
|
||||||
|
"Content version API returned invalid data."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Result.Version;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function RefreshGameContent(
|
||||||
|
ContentVersion
|
||||||
|
) {
|
||||||
|
const [
|
||||||
|
FreshPlants,
|
||||||
|
FreshMutations
|
||||||
|
] =
|
||||||
|
await Promise.all([
|
||||||
|
FetchPlantsFromApi(),
|
||||||
|
FetchMutationsFromApi()
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
const Cache = {
|
||||||
|
SchemaVersion:
|
||||||
|
GameContentCacheSchemaVersion,
|
||||||
|
|
||||||
|
ContentVersion:
|
||||||
|
ContentVersion,
|
||||||
|
|
||||||
|
CheckedAt:
|
||||||
|
Date.now(),
|
||||||
|
|
||||||
|
Plants:
|
||||||
|
FreshPlants,
|
||||||
|
|
||||||
|
Mutations:
|
||||||
|
FreshMutations
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
WriteGameContentCache(
|
||||||
|
Cache
|
||||||
|
);
|
||||||
|
|
||||||
|
ApplyGameContent(
|
||||||
|
FreshPlants,
|
||||||
|
FreshMutations
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return GetLoadedGameContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ApplyGameContent(
|
||||||
|
LoadedPlants,
|
||||||
|
LoadedMutations
|
||||||
|
) {
|
||||||
|
Plants = LoadedPlants;
|
||||||
|
MutationSets = LoadedMutations;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function GetLoadedGameContent() {
|
||||||
|
return {
|
||||||
|
Plants: Plants,
|
||||||
|
Mutations: MutationSets
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ReadGameContentCache() {
|
||||||
|
let RawCache;
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
RawCache =
|
||||||
|
localStorage.getItem(
|
||||||
|
GameContentCacheName
|
||||||
|
);
|
||||||
|
} catch (Error) {
|
||||||
|
console.warn(
|
||||||
|
"Couldn't read the Garden content cache.",
|
||||||
|
Error
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (RawCache === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
const Cache =
|
||||||
|
JSON.parse(
|
||||||
|
RawCache
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
!IsValidGameContentCache(
|
||||||
|
Cache
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
RemoveGameContentCache();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Cache;
|
||||||
|
} catch (Error) {
|
||||||
|
RemoveGameContentCache();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function IsValidGameContentCache(
|
||||||
|
Cache
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
Cache !== null &&
|
||||||
|
typeof Cache === "object" &&
|
||||||
|
!Array.isArray(Cache) &&
|
||||||
|
|
||||||
|
Cache.SchemaVersion ===
|
||||||
|
GameContentCacheSchemaVersion &&
|
||||||
|
|
||||||
|
Number.isFinite(
|
||||||
|
Cache.CheckedAt
|
||||||
|
) &&
|
||||||
|
|
||||||
|
Cache.CheckedAt >= 0 &&
|
||||||
|
|
||||||
|
(
|
||||||
|
Cache.ContentVersion ===
|
||||||
|
null ||
|
||||||
|
typeof Cache.ContentVersion ===
|
||||||
|
"string"
|
||||||
|
) &&
|
||||||
|
|
||||||
|
IsGameContentObject(
|
||||||
|
Cache.Plants
|
||||||
|
) &&
|
||||||
|
|
||||||
|
IsGameContentObject(
|
||||||
|
Cache.Mutations
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function IsGameContentObject(
|
||||||
|
Value
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
Value !== null &&
|
||||||
|
typeof Value === "object" &&
|
||||||
|
!Array.isArray(Value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function WriteGameContentCache(
|
||||||
|
Cache
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(
|
||||||
|
GameContentCacheName,
|
||||||
|
JSON.stringify(
|
||||||
|
Cache
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (Error) {
|
||||||
|
console.warn(
|
||||||
|
"Couldn't write the Garden content cache.",
|
||||||
|
Error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function RemoveGameContentCache() {
|
||||||
|
try {
|
||||||
|
localStorage.removeItem(
|
||||||
|
GameContentCacheName
|
||||||
|
);
|
||||||
|
} catch (Error) {
|
||||||
|
console.warn(
|
||||||
|
"Couldn't clear the Garden content cache.",
|
||||||
|
Error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ClearGameContentCache() {
|
||||||
|
RemoveGameContentCache();
|
||||||
|
GameContentLoadPromise = null;
|
||||||
|
}
|
||||||
@@ -1,30 +1,7 @@
|
|||||||
let MutationSets = {};
|
let MutationSets = {};
|
||||||
|
|
||||||
let MutationsLoadPromise = null;
|
|
||||||
let GameContentLoadPromise = null;
|
|
||||||
|
|
||||||
|
async function FetchMutationsFromApi() {
|
||||||
async function LoadMutations() {
|
|
||||||
if (MutationsLoadPromise !== null) {
|
|
||||||
return MutationsLoadPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MutationsLoadPromise =
|
|
||||||
LoadMutationsFromApi();
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await MutationsLoadPromise;
|
|
||||||
} catch (Error) {
|
|
||||||
MutationsLoadPromise = null;
|
|
||||||
|
|
||||||
throw Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async function LoadMutationsFromApi() {
|
|
||||||
const Response =
|
const Response =
|
||||||
await fetch(
|
await fetch(
|
||||||
ApiUrl + "/Mutations.php",
|
ApiUrl + "/Mutations.php",
|
||||||
@@ -34,7 +11,9 @@ async function LoadMutationsFromApi() {
|
|||||||
headers: {
|
headers: {
|
||||||
"Accept":
|
"Accept":
|
||||||
"application/json"
|
"application/json"
|
||||||
}
|
},
|
||||||
|
|
||||||
|
cache: "no-store"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -67,35 +46,5 @@ async function LoadMutationsFromApi() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MutationSets =
|
return Result.Mutations;
|
||||||
Result.Mutations;
|
|
||||||
|
|
||||||
|
|
||||||
return MutationSets;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async function LoadGameContent() {
|
|
||||||
if (GameContentLoadPromise === null) {
|
|
||||||
GameContentLoadPromise =
|
|
||||||
Promise.all([
|
|
||||||
LoadPlants(),
|
|
||||||
LoadMutations()
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
await GameContentLoadPromise;
|
|
||||||
} catch (Error) {
|
|
||||||
GameContentLoadPromise = null;
|
|
||||||
|
|
||||||
throw Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
|
||||||
Plants: Plants,
|
|
||||||
Mutations: MutationSets
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
@@ -1,29 +1,7 @@
|
|||||||
let Plants = {};
|
let Plants = {};
|
||||||
|
|
||||||
let PlantsLoadPromise = null;
|
|
||||||
|
|
||||||
|
async function FetchPlantsFromApi() {
|
||||||
async function LoadPlants() {
|
|
||||||
if (PlantsLoadPromise !== null) {
|
|
||||||
return PlantsLoadPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PlantsLoadPromise =
|
|
||||||
LoadPlantsFromApi();
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await PlantsLoadPromise;
|
|
||||||
} catch (Error) {
|
|
||||||
PlantsLoadPromise = null;
|
|
||||||
|
|
||||||
throw Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async function LoadPlantsFromApi() {
|
|
||||||
const Response =
|
const Response =
|
||||||
await fetch(
|
await fetch(
|
||||||
ApiUrl + "/Plants.php",
|
ApiUrl + "/Plants.php",
|
||||||
@@ -33,7 +11,9 @@ async function LoadPlantsFromApi() {
|
|||||||
headers: {
|
headers: {
|
||||||
"Accept":
|
"Accept":
|
||||||
"application/json"
|
"application/json"
|
||||||
}
|
},
|
||||||
|
|
||||||
|
cache: "no-store"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -66,9 +46,5 @@ async function LoadPlantsFromApi() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Plants =
|
return Result.Plants;
|
||||||
Result.Plants;
|
|
||||||
|
|
||||||
|
|
||||||
return Plants;
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user