Skip to content

Commit 53c1621

Browse files
Simplify download logic by omitting callback
1 parent 6c26748 commit 53c1621

File tree

6 files changed

+125
-107
lines changed

6 files changed

+125
-107
lines changed

Diff for: src/components/mixins/DownloadMixin.vue

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ export default class DownloadMixin extends Vue {
2121
this.$store.commit("closeDownloadModModal");
2222
}
2323
24+
setIsModProgressModalOpen(open: boolean): void {
25+
this.$store.commit('download/setIsModProgressModalOpen', open);
26+
}
27+
2428
get isOpen(): boolean {
2529
return this.$store.state.modals.isDownloadModModalOpen;
2630
}

Diff for: src/components/views/DownloadModModal.vue

+61-42
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div>
33
<div id='downloadProgressModal' :class="['modal', {'is-active':$store.state.download.isModProgressModalOpen}]" v-if="$store.getters['download/currentDownload'] !== null">
4-
<div class="modal-background" @click="$store.commit('download/setIsModProgressModalOpen', false);"></div>
4+
<div class="modal-background" @click="setIsModProgressModalOpen(false);"></div>
55
<div class='modal-content'>
66
<div class='notification is-info'>
77
<h3 class='title'>Downloading {{$store.getters['download/currentDownload'].modName}}</h3>
@@ -13,7 +13,7 @@
1313
/>
1414
</div>
1515
</div>
16-
<button class="modal-close is-large" aria-label="close" @click="$store.commit('download/setIsModProgressModalOpen', false);"></button>
16+
<button class="modal-close is-large" aria-label="close" @click="setIsModProgressModalOpen(false);"></button>
1717
</div>
1818
<DownloadModVersionSelectModal @download-mod="downloadHandler" />
1919
<UpdateAllInstalledModsModal />
@@ -60,31 +60,30 @@ import ProfileModList from '../../r2mm/mods/ProfileModList';
6060
store: Store<any>
6161
): Promise<void> {
6262
return new Promise(async (resolve, reject) => {
63-
const tsMod = combo.getMod();
64-
const tsVersion = combo.getVersion();
6563
6664
const assignId = await store.dispatch(
6765
'download/addDownload',
68-
[`${tsMod.getName()} (${tsVersion.getVersionNumber().toString()})`]
66+
[`${combo.getMod().getName()} (${combo.getVersion().getVersionNumber().toString()})`]
6967
);
7068
71-
setTimeout(() => {
72-
ThunderstoreDownloaderProvider.instance.download(profile.asImmutableProfile(), tsMod, tsVersion, ignoreCache, (progress: number, modName: string, status: number, err: R2Error | null) => {
73-
try {
74-
if (status === StatusEnum.FAILURE) {
75-
store.commit('download/updateDownload', {assignId, failed: true});
76-
if (err !== null) {
77-
DownloadMixin.addSolutionsToError(err);
78-
return reject(err);
69+
setTimeout(async () => {
70+
try {
71+
const downloadedMods = await ThunderstoreDownloaderProvider.instance.download(profile.asImmutableProfile(), combo, ignoreCache, (progress: number, modName: string, status: number, err: R2Error | null) => {
72+
try {
73+
if (status === StatusEnum.FAILURE) {
74+
store.commit('download/updateDownload', {assignId, failed: true});
75+
if (err !== null) {
76+
DownloadMixin.addSolutionsToError(err);
77+
return reject(err);
78+
}
79+
} else if (status === StatusEnum.PENDING) {
80+
store.commit('download/updateDownload', {assignId, progress, modName});
7981
}
80-
} else if (status === StatusEnum.PENDING) {
81-
store.commit('download/updateDownload', {assignId, progress, modName});
82+
} catch (e) {
83+
return reject(e);
8284
}
83-
} catch (e) {
84-
return reject(e);
85-
}
86-
}, async (downloadedMods: ThunderstoreCombo[]) => {
87-
ProfileModList.requestLock(async () => {
85+
});
86+
await ProfileModList.requestLock(async () => {
8887
for (const combo of downloadedMods) {
8988
try {
9089
await DownloadModModal.installModAfterDownload(profile, combo.getMod(), combo.getVersion());
@@ -103,7 +102,9 @@ import ProfileModList from '../../r2mm/mods/ProfileModList';
103102
}
104103
return resolve();
105104
});
106-
});
105+
} catch (e) {
106+
store.commit('error/handleError', R2Error.fromThrownValue(e));
107+
}
107108
}, 1);
108109
});
109110
}
@@ -116,30 +117,48 @@ import ProfileModList from '../../r2mm/mods/ProfileModList';
116117
[`${tsMod.getName()} (${tsVersion.getVersionNumber().toString()})`]
117118
);
118119
119-
this.$store.commit('download/setIsModProgressModalOpen', true);
120-
setTimeout(() => {
121-
ThunderstoreDownloaderProvider.instance.download(this.profile.asImmutableProfile(), tsMod, tsVersion, this.ignoreCache, (progress: number, modName: string, status: number, err: R2Error | null) => {
122-
try {
123-
if (status === StatusEnum.FAILURE) {
124-
this.$store.commit('download/setIsModProgressModalOpen', false);
125-
this.$store.commit('download/updateDownload', {assignId, failed: true});
126-
if (err !== null) {
127-
DownloadMixin.addSolutionsToError(err);
128-
throw err;
129-
}
130-
} else if (status === StatusEnum.PENDING) {
131-
this.$store.commit('download/updateDownload', {assignId, progress, modName});
132-
}
133-
} catch (e) {
134-
this.$store.commit('error/handleError', R2Error.fromThrownValue(e));
135-
}
136-
}, async (downloadedMods) => {
137-
await this.downloadCompletedCallback(downloadedMods);
138-
this.$store.commit('download/setIsModProgressModalOpen', false);
139-
});
120+
this.setIsModProgressModalOpen(true);
121+
122+
const tsCombo = new ThunderstoreCombo();
123+
tsCombo.setMod(tsMod);
124+
tsCombo.setVersion(tsVersion);
125+
126+
setTimeout(async () => {
127+
let downloadedMods: ThunderstoreCombo[] = [];
128+
try {
129+
downloadedMods = await ThunderstoreDownloaderProvider.instance.download(
130+
this.profile.asImmutableProfile(),
131+
tsCombo,
132+
this.ignoreCache,
133+
(progress, modName, status, err) => { this.downloadProgressCallback(assignId, progress, modName, status, err); }
134+
);
135+
} catch (e) {
136+
this.setIsModProgressModalOpen(false);
137+
this.$store.commit('error/handleError', R2Error.fromThrownValue(e));
138+
}
139+
await this.downloadCompletedCallback(downloadedMods);
140+
this.setIsModProgressModalOpen(false);
140141
}, 1);
142+
141143
}
142144
145+
downloadProgressCallback(assignId: number, progress: number, modName: string, status: number, err: R2Error | null) {
146+
try {
147+
if (status === StatusEnum.FAILURE) {
148+
this.setIsModProgressModalOpen(false);
149+
this.$store.commit('download/updateDownload', {assignId, failed: true});
150+
if (err !== null) {
151+
DownloadMixin.addSolutionsToError(err);
152+
throw err;
153+
}
154+
} else if (status === StatusEnum.PENDING) {
155+
this.$store.commit('download/updateDownload', {assignId, progress, modName});
156+
}
157+
} catch (e) {
158+
this.$store.commit('error/handleError', R2Error.fromThrownValue(e));
159+
}
160+
};
161+
143162
static async installModAfterDownload(profile: Profile, mod: ThunderstoreMod, version: ThunderstoreVersion): Promise<R2Error | void> {
144163
return new Promise(async (resolve, reject) => {
145164
const manifestMod: ManifestV2 = new ManifestV2().fromThunderstoreMod(mod, version);

Diff for: src/components/views/DownloadModVersionSelectModal.vue

-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ import ModalCard from "../ModalCard.vue";
6060
import DownloadMixin from "../../components/mixins/DownloadMixin.vue";
6161
import R2Error from "../../model/errors/R2Error";
6262
import ManifestV2 from "../../model/ManifestV2";
63-
import ThunderstoreMod from "../../model/ThunderstoreMod";
6463
import ThunderstoreVersion from "../../model/ThunderstoreVersion";
6564
import { MOD_LOADER_VARIANTS } from "../../r2mm/installing/profile_installers/ModLoaderVariantRecord";
6665
import * as PackageDb from "../../r2mm/manager/PackageDexieStore";

Diff for: src/components/views/UpdateAllInstalledModsModal.vue

+3-3
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ export default class UpdateAllInstalledModsModal extends mixins(DownloadMixin)
4848
modsWithUpdates.map(value => `${value.getMod().getName()} (${value.getVersion().getVersionNumber().toString()})`)
4949
);
5050
51-
this.$store.commit('download/setIsModProgressModalOpen', true);
51+
this.setIsModProgressModalOpen(true);
5252
ThunderstoreDownloaderProvider.instance.downloadLatestOfAll(modsWithUpdates, this.ignoreCache, (progress: number, modName: string, status: number, err: R2Error | null) => {
5353
try {
5454
if (status === StatusEnum.FAILURE) {
55-
this.$store.commit('download/setIsModProgressModalOpen', false);
55+
this.setIsModProgressModalOpen(false);
5656
this.$store.commit('download/updateDownload', {assignId, failed: true});
5757
if (err !== null) {
5858
DownloadMixin.addSolutionsToError(err);
@@ -66,7 +66,7 @@ export default class UpdateAllInstalledModsModal extends mixins(DownloadMixin)
6666
}
6767
}, async (downloadedMods) => {
6868
await this.downloadCompletedCallback(downloadedMods);
69-
this.$store.commit('download/setIsModProgressModalOpen', false);
69+
this.setIsModProgressModalOpen(false);
7070
});
7171
}
7272
}

Diff for: src/providers/ror2/downloading/ThunderstoreDownloaderProvider.ts

+10-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import ProviderUtils from '../../generic/ProviderUtils';
22
import ThunderstoreVersion from '../../../model/ThunderstoreVersion';
3-
import ThunderstoreMod from '../../../model/ThunderstoreMod';
43
import ThunderstoreCombo from '../../../model/ThunderstoreCombo';
54
import R2Error from '../../../model/errors/R2Error';
65
import { ImmutableProfile } from '../../../model/Profile';
@@ -49,17 +48,17 @@ export default abstract class ThunderstoreDownloaderProvider {
4948
/**
5049
* A top-level method to download the latest version of a mod including its dependencies.
5150
*
52-
* @param profile The profile the mod is downloaded for (needed to prevent dependencies from updating existing mods).
53-
* @param mod The mod to be downloaded.
54-
* @param modVersion The version of the mod to download.
55-
* @param ignoreCache Download mod even if it already exists in the cache.
56-
* @param callback Callback to show the current state of the downloads.
57-
* @param completedCallback Callback to perform final actions against. Only called if {@param callback} has not returned a failed status.
51+
* @param profile The profile the mod is downloaded for (needed to prevent dependencies from updating existing mods).
52+
* @param combo The combo to be downloaded.
53+
* @param ignoreCache Download mod even if it already exists in the cache.
54+
* @param totalProgressCallback Callback to show the combined state of all the downloads.
5855
*/
59-
public abstract download(profile: ImmutableProfile, mod: ThunderstoreMod, modVersion: ThunderstoreVersion,
60-
ignoreCache: boolean,
61-
callback: (progress: number, modName: string, status: number, err: R2Error | null) => void,
62-
completedCallback: (modList: ThunderstoreCombo[]) => void): void;
56+
public abstract download(
57+
profile: ImmutableProfile,
58+
combo: ThunderstoreCombo,
59+
ignoreCache: boolean,
60+
totalProgressCallback: (progress: number, modName: string, status: number, err: R2Error | null) => void
61+
): Promise<ThunderstoreCombo[]>;
6362

6463
/**
6564
* A top-level method to download exact versions of exported mods.

Diff for: src/r2mm/downloading/BetterThunderstoreDownloader.ts

+47-50
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import ManifestV2 from "src/model/ManifestV2";
21
import ThunderstoreVersion from '../../model/ThunderstoreVersion';
3-
import ThunderstoreMod from '../../model/ThunderstoreMod';
42
import StatusEnum from '../../model/enums/StatusEnum';
53
import axios, { AxiosResponse } from 'axios';
4+
import ManifestV2 from "../../model/ManifestV2";
65
import ThunderstoreCombo from '../../model/ThunderstoreCombo';
76
import ZipExtract from '../installing/ZipExtract';
87
import R2Error from '../../model/errors/R2Error';
@@ -83,71 +82,69 @@ export default class BetterThunderstoreDownloader extends ThunderstoreDownloader
8382
});
8483
}
8584

86-
public async download(profile: ImmutableProfile, mod: ThunderstoreMod, modVersion: ThunderstoreVersion,
87-
ignoreCache: boolean,
88-
callback: (progress: number, modName: string, status: number, err: R2Error | null) => void,
89-
completedCallback: (modList: ThunderstoreCombo[]) => void) {
85+
public async download(
86+
profile: ImmutableProfile,
87+
combo: ThunderstoreCombo,
88+
ignoreCache: boolean,
89+
totalProgressCallback: (progress: number, modName: string, status: number, err: R2Error | null) => void
90+
): Promise<ThunderstoreCombo[]> {
9091

9192
const modList = await ProfileModList.getModList(profile);
9293
if (modList instanceof R2Error) {
93-
return callback(0, mod.getName(), StatusEnum.FAILURE, modList);
94+
totalProgressCallback(0, combo.getMod().getName(), StatusEnum.FAILURE, modList);
95+
throw modList;
9496
}
9597

96-
let dependencies: ThunderstoreCombo[] = [];
97-
await this.buildDependencySet(modVersion, dependencies, DependencySetBuilderMode.USE_EXACT_VERSION);
98-
this.sortDependencyOrder(dependencies);
99-
const combo = new ThunderstoreCombo();
100-
combo.setMod(mod);
101-
combo.setVersion(modVersion);
102-
103-
dependencies = await this.determineDependencyVersions(dependencies, combo, modVersion, modList);
104-
let downloadableDependencySize = this.calculateInitialDownloadSize(dependencies);
98+
const dependencies = await this.getDependenciesWithCorrectVersions(combo, modList);
99+
const allModsToDownload = [...dependencies, combo];
105100

106101
let downloadCount = 0;
107-
await this.downloadAndSave(combo, ignoreCache, async (progress: number, status: number, err: R2Error | null) => {
102+
const singleModProgressCallback = (progress: number, status: number, err: R2Error | null) => {
108103
if (status === StatusEnum.FAILURE) {
109-
callback(0, mod.getName(), status, err);
110-
} else if (status === StatusEnum.PENDING) {
111-
callback(this.generateProgressPercentage(progress, downloadCount, downloadableDependencySize + 1), mod.getName(), status, err);
104+
throw err;
105+
}
106+
107+
let totalProgress: number;
108+
if (status === StatusEnum.PENDING) {
109+
totalProgress = this.generateProgressPercentage(progress, downloadCount, allModsToDownload.length);
112110
} else if (status === StatusEnum.SUCCESS) {
111+
totalProgress = this.generateProgressPercentage(100, downloadCount, allModsToDownload.length);
113112
downloadCount += 1;
114-
// If no dependencies, end here.
115-
if (dependencies.length === 0) {
116-
callback(100, mod.getName(), StatusEnum.PENDING, err);
117-
completedCallback([combo]);
118-
return;
119-
}
113+
} else {
114+
console.error(`Ignore unknown status code "${status}"`);
115+
return;
116+
}
117+
totalProgressCallback(totalProgress, combo.getMod().getName(), status, err);
118+
}
120119

121-
// If dependencies, queue and download.
122-
await this.queueDownloadDependencies(dependencies.entries(), ignoreCache, (progress: number, modName: string, status: number, err: R2Error | null) => {
123-
if (status === StatusEnum.FAILURE) {
124-
callback(0, modName, status, err);
125-
} else if (status === StatusEnum.PENDING) {
126-
callback(this.generateProgressPercentage(progress, downloadCount, downloadableDependencySize + 1), modName, status, err);
127-
} else if (status === StatusEnum.SUCCESS) {
128-
callback(this.generateProgressPercentage(progress, downloadCount, downloadableDependencySize + 1), modName, StatusEnum.PENDING, err);
129-
downloadCount += 1;
130-
if (downloadCount >= dependencies.length + 1) {
131-
callback(100, modName, StatusEnum.PENDING, err);
132-
completedCallback([...dependencies, combo]);
133-
}
134-
}
135-
});
120+
for (const combo of allModsToDownload) {
121+
if (!ignoreCache && await this.isVersionAlreadyDownloaded(combo)) {
122+
totalProgressCallback(100, combo.getMod().getName(), StatusEnum.SUCCESS, null);
123+
continue;
136124
}
137-
})
125+
126+
try {
127+
const response = await this._downloadCombo(combo, singleModProgressCallback);
128+
await this._saveDownloadResponse(response, combo, singleModProgressCallback);
129+
} catch(e) {
130+
throw R2Error.fromThrownValue(e, `Failed to download mod ${combo.getVersion().getFullName()}`);
131+
}
132+
}
133+
return allModsToDownload;
138134
}
139135

140136
// If combo is a modpack, use the modpack's dependency versions. If it isn't, get the latest versions.
141-
public async determineDependencyVersions(dependencies: ThunderstoreCombo[], combo: ThunderstoreCombo, modVersion: ThunderstoreVersion, modList: ManifestV2[]) {
142-
let isModpack = combo.getMod().getCategories().find(value => value === "Modpacks") !== undefined;
143-
if (isModpack) {
144-
return dependencies;
145-
}
146-
dependencies = [];
147-
await this.buildDependencySet(modVersion, dependencies, DependencySetBuilderMode.USE_LATEST_VERSION);
137+
private async getDependenciesWithCorrectVersions(combo: ThunderstoreCombo, modList: ManifestV2[]) {
138+
const dependencies: ThunderstoreCombo[] = [];
139+
const isModpack = combo.getMod().getCategories().some(value => value === "Modpacks");
140+
const versionMode = isModpack ? DependencySetBuilderMode.USE_EXACT_VERSION : DependencySetBuilderMode.USE_LATEST_VERSION;
141+
142+
await this.buildDependencySet(combo.getVersion(), dependencies, versionMode);
148143
this.sortDependencyOrder(dependencies);
149144
// #270: Remove already-installed dependencies to prevent updating.
150-
return dependencies.filter(dep => modList.find(installed => installed.getName() === dep.getMod().getFullName()) === undefined);
145+
return dependencies.filter((dep) => {
146+
return !(modList.some(installed => installed.getName() === dep.getMod().getFullName()));
147+
});
151148
}
152149

153150
public async downloadImportedMods(

0 commit comments

Comments
 (0)