Skip to content
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

Clean up the download state management Vuex store and it's usages #1596

Open
wants to merge 1 commit into
base: download-callback-refactor
Choose a base branch
from

Conversation

VilppeRiskidev
Copy link
Collaborator

  • Remove assignId field
  • Remove downloadObject field
  • Rename some fields and functions to be more descriptive
  • assignId is no longer passed unnecessarily when calling vuex store functions

@VilppeRiskidev VilppeRiskidev self-assigned this Dec 18, 2024
- Remove assignId field
- Remove downloadObject field
- Rename some fields and functions to be more descriptive
- assignId is no longer passed unnecessarily when calling vuex store
  functions
@VilppeRiskidev VilppeRiskidev force-pushed the cleanup-download-management branch from c71b670 to fecc3c3 Compare December 18, 2024 15:48
Copy link
Collaborator

@anttimaki anttimaki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes match mostly what was planned, so in that sense this could be approved, but I think the suggested improvements are worthy of implementing right away.

One exception is that you didn't implement a getter for "next assign id" as was planned, nor was the plan augmented. Why's that?

Also generally speaking, while it's good to stick to the plan, I consider going a bit further than the plan if further improvement changes are discovered during implementation. Scope creep needs to be kept in mind though. I guess what I'm trying to say is to beware of the mentality where the plan is executed blindly, as it doesn't necessarily lead to best outcome.

@@ -95,8 +88,9 @@ interface DownloadProgress {
const tsMod = combo.getMod();
const tsVersion = combo.getVersion();

store.commit('download/increaseAssignId');
const currentAssignId = store.state.download.assignId;
const currentAssignId = store.getters["download/currentDownload"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor+: On a further thought, there seems to be this repeated pattern of "get id, create blank progress object, add it to store". In addition to repetition, the current implementation of getting the id for example unnecessarily places the logic into component, and leaks store's internal implementation details. I suggest we combine these to an action instead, i.e. something like:

        async addDownload(state: State, initialMods: string[]): Promise<number> {
            const assignId = state.allDownloads.length;
            const downloadObject: DownloadProgress = {
                assignId,
                initialMods,
                modName: '',
                progress: 0,
                failed: false,
            };
            state.allDownloads = [...state.allDownloads, downloadObject];
            return assignId;
        },

if (status === StatusEnum.FAILURE) {
if (err !== null) {
const existing = store.state.download.allVersions[assignIndex]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor+: Similar to addDownload, it seems we can take updateDownload even further. In the store:

interface UpdateObject {
    assignId: number;
    progress?: number;
    modName?: string;
    failed?: boolean;
}

updateDownload(state: State, update: UpdateObject) {
    const downloads = [...state.allDownloads];
    const index = downloads.findIndex((old) => old.assignId === update.assignId);
    if (index === -1) {
        throw new R2Error(...);
    }
    downloads[index] = {...downloads[index], ...update};
    state.allDownloads = downloads;
},

And then on the call sites:
this.$store.commit('download/updateDownload', {assignId, failed: true}); &
this.$store.commit('download/updateDownload', {assignId, progress, modName});

As a bonus we don't need to export DownloadProgress, as the UI component doesn't care about this internal implementation detail anymore. Nevermind, it's still needed by the DownloadMonitor.

assignId: assignIndex,
downloadVersion: [currentAssignId, obj]
});
this.$store.commit('download/updateDownload', obj);
}
}, (downloadedMods) => {
this.downloadCompletedCallback(downloadedMods);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical: found a bug from previous PR: downloadCompletedCallback should be awaited on both call sites to prevent the modal closing too early.

@@ -42,10 +42,12 @@

<script lang="ts">

import Timeout = NodeJS.Timeout;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An idea for a "next" PR:

  • Test if timeouts are no longer needed now that the state is managed in Vuex
  • Add a getter, e.g. "newestFirst" that returns all downloads, in reverse order
  • I think the store getter can be used directly in the template part, but if a separate get method is needed in the Vue component, name it something else than "activeDownloads" as the list clearly includes also the completed downloads
  • See if we can stop exporting DownloadProgress from the store after the above changes (it might be needed if we need the get method to satisfy TypeScript)

newVersions[params.assignId] = params.downloadVersion;
state.allVersions = newVersions;
updateDownload(state: State, downloadObject: DownloadProgress) {
const newVersions = [...state.allDownloads];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: "versions" is still used in the variable names. E.g. in my suggestion above I used just "downloads".

state.allVersions = newVersions;
updateDownload(state: State, downloadObject: DownloadProgress) {
const newVersions = [...state.allDownloads];
const index = newVersions.findIndex((oldDownloadObject: DownloadProgress) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, and this also applies to my suggested code in an earlier comment. If everything here works as I assume it should work, we should be able to check something like if (newVersions[downloadObject.assignId].assignId !== downloadObject.assignId). AFAICT the assignId and objects position in the array should always be in sync, and a sanity check like this might actually be the only reason why we need to store the assignId in the object at all.

That being said, please test this change thoroughly.

return oldDownloadObject.assignId === downloadObject.assignId;
});
if (index === -1) {
throw new R2Error(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Did you test this? Is the error message shown to user in the error modal like it's written here, or does it get overwritten somewhere along the way? If this error is shown to the user, I think the middle line might be too technical while offering the user no actionable information, nor provides anything for us to debug the issue. Something like "DownloadProgress with id ${oldDownloadObject.assignId} was not found" would at least help in debugging if the value turns out to be undefined or something?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants