-
Notifications
You must be signed in to change notification settings - Fork 193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: Callback stack refactoring and installation after download #1564
base: download-vuex-poc
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,12 +54,12 @@ export default abstract class ThunderstoreDownloaderProvider { | |
* @param modVersion The version of the mod to download. | ||
* @param ignoreCache Download mod even if it already exists in the cache. | ||
* @param callback Callback to show the current state of the downloads. | ||
* @param completedCallback Callback to perform final actions against. Only called if {@param callback} has not returned a failed status. | ||
*/ | ||
public abstract download(profile: ImmutableProfile, mod: ThunderstoreMod, modVersion: ThunderstoreVersion, | ||
ignoreCache: boolean, | ||
callback: (progress: number, modName: string, status: number, err: R2Error | null) => void, | ||
completedCallback: (modList: ThunderstoreCombo[]) => void): void; | ||
public abstract download( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
profile: ImmutableProfile, mod: ThunderstoreMod, modVersion: ThunderstoreVersion, | ||
ignoreCache: boolean, | ||
callback: (progress: number, modName: string, status: number, err: R2Error | null) => void | ||
): Promise<ThunderstoreCombo[]>; | ||
|
||
/** | ||
* A top-level method to download exact versions of exported mods. | ||
|
@@ -87,11 +87,11 @@ export default abstract class ThunderstoreDownloaderProvider { | |
* Iterate the {@class ThunderstoreCombo} array to perform the download for each mod. | ||
* Progress to the next one recursively once the callback received has been successful. | ||
* | ||
* @param entries IterableIterator of entries for {@class ThunderstoreCombo} mods to download. | ||
* @param entries The {@class ThunderstoreCombo} mods to download. | ||
* @param ignoreCache Should mod be downloaded even if it already exists in the cache? | ||
* @param callback See {@method download} | ||
*/ | ||
public abstract queueDownloadDependencies(entries: IterableIterator<[number, ThunderstoreCombo]>, ignoreCache: boolean, callback: (progress: number, modName: string, status: number, err: R2Error | null) => void): void | ||
public abstract queueDownloadDependencies(entries: ThunderstoreCombo[], ignoreCache: boolean, callback: (progress: number, modName: string, status: number, err: R2Error | null) => void): void | ||
|
||
/** | ||
* Generate the total count of mods to be downloaded. Cached mods are not included in this count unless download cache is disabled. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,7 +66,7 @@ export default class BetterThunderstoreDownloader extends ThunderstoreDownloader | |
let downloadCount = 0; | ||
const downloadableDependencySize = this.calculateInitialDownloadSize(dependencies); | ||
|
||
await this.queueDownloadDependencies(dependencies.entries(), ignoreCache, (progress: number, modName: string, status: number, err: R2Error | null) => { | ||
await this.queueDownloadDependencies(dependencies, ignoreCache, (progress: number, modName: string, status: number, err: R2Error | null) => { | ||
if (status === StatusEnum.FAILURE) { | ||
callback(0, modName, status, err); | ||
} else if (status === StatusEnum.PENDING) { | ||
|
@@ -82,10 +82,12 @@ export default class BetterThunderstoreDownloader extends ThunderstoreDownloader | |
}); | ||
} | ||
|
||
public async download(profile: ImmutableProfile, mod: ThunderstoreMod, modVersion: ThunderstoreVersion, | ||
ignoreCache: boolean, | ||
callback: (progress: number, modName: string, status: number, err: R2Error | null) => void, | ||
completedCallback: (modList: ThunderstoreCombo[]) => void) { | ||
|
||
public async download( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These comments are based on just looking at the code so there's quite a change I'm missing something, but the approach taken here doesn't seem optimal to me. I would rather:
|
||
profile: ImmutableProfile, mod: ThunderstoreMod, modVersion: ThunderstoreVersion, | ||
ignoreCache: boolean, | ||
callback: (progress: number, modName: string, status: number, err: R2Error | null) => void | ||
): Promise<ThunderstoreCombo[]> { | ||
let dependencies: ThunderstoreCombo[] = []; | ||
await this.buildDependencySet(modVersion, dependencies, DependencySetBuilderMode.USE_EXACT_VERSION); | ||
this.sortDependencyOrder(dependencies); | ||
|
@@ -94,9 +96,11 @@ export default class BetterThunderstoreDownloader extends ThunderstoreDownloader | |
combo.setVersion(modVersion); | ||
let downloadCount = 0; | ||
|
||
let downloadedModsList: ThunderstoreCombo[] = [combo]; | ||
|
||
const modList = await ProfileModList.getModList(profile); | ||
if (modList instanceof R2Error) { | ||
return callback(0, mod.getName(), StatusEnum.FAILURE, modList); | ||
throw modList; | ||
} | ||
|
||
let downloadableDependencySize = this.calculateInitialDownloadSize(dependencies); | ||
|
@@ -122,30 +126,32 @@ export default class BetterThunderstoreDownloader extends ThunderstoreDownloader | |
callback(this.generateProgressPercentage(progress, downloadCount, downloadableDependencySize + 1), mod.getName(), status, err); | ||
} else if (status === StatusEnum.SUCCESS) { | ||
downloadCount += 1; | ||
// If no dependencies, end here. | ||
if (dependencies.length === 0) { | ||
callback(100, mod.getName(), StatusEnum.PENDING, err); | ||
completedCallback([combo]); | ||
return; | ||
} | ||
} | ||
}); | ||
|
||
// If dependencies, queue and download. | ||
await this.queueDownloadDependencies(dependencies.entries(), ignoreCache, (progress: number, modName: string, status: number, err: R2Error | null) => { | ||
if (status === StatusEnum.FAILURE) { | ||
callback(0, modName, status, err); | ||
} else if (status === StatusEnum.PENDING) { | ||
callback(this.generateProgressPercentage(progress, downloadCount, downloadableDependencySize + 1), modName, status, err); | ||
} else if (status === StatusEnum.SUCCESS) { | ||
callback(this.generateProgressPercentage(progress, downloadCount, downloadableDependencySize + 1), modName, StatusEnum.PENDING, err); | ||
downloadCount += 1; | ||
if (downloadCount >= dependencies.length + 1) { | ||
callback(100, modName, StatusEnum.PENDING, err); | ||
completedCallback([...dependencies, combo]); | ||
} | ||
} | ||
}); | ||
// If no dependencies, end here. | ||
if (dependencies.length === 0) { | ||
callback(100, mod.getName(), StatusEnum.SUCCESS, null); | ||
return downloadedModsList; | ||
} | ||
|
||
// If dependencies, queue and download. | ||
let downloadedDependencies = await this.queueDownloadDependencies(dependencies, ignoreCache, (progress: number, modName: string, status: number, err: R2Error | null) => { | ||
if (status === StatusEnum.FAILURE) { | ||
callback(0, modName, status, err); | ||
} else if (status === StatusEnum.PENDING) { | ||
callback(this.generateProgressPercentage(progress, downloadCount, downloadableDependencySize + 1), modName, status, err); | ||
} else if (status === StatusEnum.SUCCESS) { | ||
callback(this.generateProgressPercentage(progress, downloadCount, downloadableDependencySize + 1), modName, StatusEnum.PENDING, err); | ||
downloadCount += 1; | ||
if (downloadCount >= dependencies.length + 1) { | ||
callback(100, modName, StatusEnum.PENDING, err); | ||
} | ||
} | ||
}) | ||
}); | ||
|
||
downloadedModsList.push(...downloadedDependencies); | ||
return downloadedModsList; | ||
} | ||
|
||
public async downloadImportedMods( | ||
|
@@ -197,20 +203,35 @@ export default class BetterThunderstoreDownloader extends ThunderstoreDownloader | |
return completedProgress + (progress * 1/total); | ||
} | ||
|
||
public async queueDownloadDependencies(entries: IterableIterator<[number, ThunderstoreCombo]>, ignoreCache: boolean, callback: (progress: number, modName: string, status: number, err: R2Error | null) => void) { | ||
const entry = entries.next(); | ||
if (!entry.done) { | ||
await this.downloadAndSave(entry.value[1] as ThunderstoreCombo, ignoreCache, async (progress: number, status: number, err: R2Error | null) => { | ||
if (status === StatusEnum.FAILURE) { | ||
callback(0, (entry.value[1] as ThunderstoreCombo).getMod().getName(), status, err); | ||
} else if (status === StatusEnum.PENDING) { | ||
callback(progress, (entry.value[1] as ThunderstoreCombo).getMod().getName(), status, err); | ||
} else if (status === StatusEnum.SUCCESS) { | ||
callback(100, (entry.value[1] as ThunderstoreCombo).getMod().getName(), status, err); | ||
await this.queueDownloadDependencies(entries, ignoreCache, callback); | ||
} | ||
public async queueDownloadDependencies( | ||
thunderstoreCombos: ThunderstoreCombo[], | ||
ignoreCache: boolean, | ||
callback: (progress: number, modName: string, status: number, err: R2Error | null) => void | ||
): Promise<ThunderstoreCombo[]> { | ||
const downloadTasks: Promise<void>[] = []; | ||
const mods: ThunderstoreCombo[] = []; | ||
|
||
thunderstoreCombos.forEach((mod) => { | ||
const task = new Promise<void>((resolve, reject) => { | ||
this.downloadAndSave(mod, ignoreCache, (progress: number, status: number, err: R2Error | null) => { | ||
if (status === StatusEnum.FAILURE) { | ||
callback(0, mod.getMod().getName(), status, err); | ||
reject(err); // Reject the promise if there's a failure | ||
} else if (status === StatusEnum.PENDING) { | ||
callback(progress, mod.getMod().getName(), status, err); | ||
} else if (status === StatusEnum.SUCCESS) { | ||
callback(100, mod.getMod().getName(), status, err); | ||
mods.push(mod); | ||
resolve(); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
downloadTasks.push(task); | ||
}); | ||
|
||
await Promise.all(downloadTasks); | ||
return mods; | ||
} | ||
|
||
public calculateInitialDownloadSize(list: ThunderstoreCombo[]): number { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Vuex implementation may return undefined as well, so using
number
as the return type here is a bug.