@@ -4,7 +4,7 @@ import Component from 'vue-class-component';
4
4
5
5
import R2Error from ' ../../model/errors/R2Error' ;
6
6
import RequestItem from ' ../../model/requests/RequestItem' ;
7
- import type { PackageListChunks } from ' ../../store/modules/TsModsModule' ;
7
+ import type { PackageListChunks , PackageListIndex } from ' ../../store/modules/TsModsModule' ;
8
8
9
9
10
10
@Component
@@ -51,16 +51,19 @@ export default class SplashMixin extends Vue {
51
51
52
52
// Get the list of Thunderstore mods from API or local cache.
53
53
async getThunderstoreMods() {
54
- const packageListChunks = await this .fetchPackageListChunksIfUpdated ();
54
+ const packageListIndex = await this .fetchPackageListIndex ();
55
+ const packageListChunks = await this .fetchPackageListChunksIfUpdated (packageListIndex );
55
56
this .getRequestItem (' ThunderstoreDownload' ).setProgress (100 );
56
- await this .writeModsToPersistentCacheIfUpdated (packageListChunks );
57
+ await this .writeModsToPersistentCacheIfUpdated (packageListIndex , packageListChunks );
57
58
const isModListLoaded = await this .readModsToVuex ();
58
59
59
60
// To proceed, the loading of the mod list should result in a non-empty list.
60
61
// Empty list is allowed if that's actually what the API returned.
62
+ // API wasn't queried at all if we already had the latest index chunk.
61
63
const modListHasMods = this .$store .state .tsMods .mods .length ;
62
64
const apiReturnedEmptyList = packageListChunks && packageListChunks [0 ].length === 0 ;
63
- if (isModListLoaded && (modListHasMods || apiReturnedEmptyList )) {
65
+ const apiWasNotQueried = packageListIndex && packageListIndex .isLatest ;
66
+ if (isModListLoaded && (modListHasMods || apiReturnedEmptyList || apiWasNotQueried )) {
64
67
await this .moveToNextScreen ();
65
68
} else {
66
69
this .heroTitle = ' Failed to get the list of online mods' ;
@@ -70,18 +73,41 @@ export default class SplashMixin extends Vue {
70
73
}
71
74
72
75
/** *
73
- * Load the package list in chunks .
76
+ * Query Thunderstore API for the URLs pointing to parts of the package list .
74
77
* Fails silently to fallback reading the old values from the IndexedDB cache.
75
78
*/
76
- async fetchPackageListChunksIfUpdated(): Promise <PackageListChunks | undefined > {
79
+ async fetchPackageListIndex(): Promise <PackageListIndex | undefined > {
80
+ this .loadingText = ' Checking for mod list updates from Thunderstore' ;
77
81
78
- const showProgress = (progress : number ) => {
82
+ try {
83
+ return await this .$store .dispatch (' tsMods/fetchPackageListIndex' );
84
+ } catch (e ) {
85
+ console .error (' SplashMixin failed to fetch mod list index from API.' , e );
86
+ return undefined ;
87
+ }
88
+ }
89
+
90
+ /** *
91
+ * Load the package list in chunks pointed out by the packageListIndex.
92
+ * This step is skipped if we can't or don't need to load the chunks.
93
+ * Fails silently to fallback reading the old values from the IndexedDB cache.
94
+ */
95
+ async fetchPackageListChunksIfUpdated(packageListIndex ? : PackageListIndex ): Promise <PackageListChunks | undefined > {
96
+ // Skip loading chunks if loading index failed, or if we already have the latest data.
97
+ if (! packageListIndex || packageListIndex .isLatest ) {
98
+ return undefined ;
99
+ }
100
+
101
+ const progressCallback = (progress : number ) => {
79
102
this .loadingText = ' Loading latest mod list from Thunderstore' ;
80
103
this .getRequestItem (' ThunderstoreDownload' ).setProgress (progress );
81
104
};
82
105
83
106
try {
84
- return await this .$store .dispatch (' tsMods/fetchPackageListChunks' , showProgress );
107
+ return await this .$store .dispatch (
108
+ ' tsMods/fetchPackageListChunks' ,
109
+ {chunkUrls: packageListIndex .content , progressCallback }
110
+ );
85
111
} catch (e ) {
86
112
console .error (' SplashMixin failed to fetch mod list from API.' , e );
87
113
return undefined ;
@@ -90,15 +116,18 @@ export default class SplashMixin extends Vue {
90
116
91
117
/** *
92
118
* Update a fresh package list to the IndexedDB cache.
93
- * Done only if the package list was loaded successfully.
119
+ * Done only if there was a fresh list to load and it was loaded successfully.
94
120
* Fails silently to fallback reading the old values from the IndexedDB cache.
95
121
*/
96
- async writeModsToPersistentCacheIfUpdated(packageListChunks ? : PackageListChunks ) {
97
- if (packageListChunks ) {
122
+ async writeModsToPersistentCacheIfUpdated(packageListIndex ? : PackageListIndex , packageListChunks ? : PackageListChunks ) {
123
+ if (packageListIndex && packageListChunks ) {
98
124
this .loadingText = ' Storing the mod list into local cache' ;
99
125
100
126
try {
101
- await this .$store .dispatch (' tsMods/updatePersistentCache' , packageListChunks )
127
+ await this .$store .dispatch (
128
+ ' tsMods/updatePersistentCache' ,
129
+ {indexHash: packageListIndex .hash , chunks: packageListChunks }
130
+ );
102
131
} catch (e ) {
103
132
console .error (' SplashMixin failed to cache mod list locally.' , e );
104
133
}
@@ -117,12 +146,12 @@ export default class SplashMixin extends Vue {
117
146
* queried from the API successfully or not. This also handles the type
118
147
* casting, since mod manager expects the data to be formatted into objects.
119
148
*
149
+ * Failure at this point is no longer silently ignored, instead an error
150
+ * modal is shown.
151
+ *
120
152
* Return value is used to tell whether Vuex might contain an empty list
121
153
* after calling this because there was an error, or because the package
122
154
* list is actually empty.
123
- *
124
- * Failure at this point is no longer silently ignored, instead an error
125
- * modal is shown.
126
155
*/
127
156
async readModsToVuex(): Promise <boolean > {
128
157
let isModListLoaded = false ;
0 commit comments