Skip to content

Install a mod from the index into an instance #6

Description

@MrJeranimo

current status

There is one downloader, SpaceDockModDownloader, and it is built around SpaceDock's API: it resolves the id through SpaceDockResolver, calls api/mod/{id}, picks a version row, and takes the download path from it.

Every release in the index today points at GitHub, with SpaceDock only as a mirror:

AdvancedFlightComputer 0.7.3   github.com/.../releases/download/v0.7.3/AdvancedFlightComputer.zip
MeasureTools 1.1.8             github.com/.../releases/download/v1.1.8/MeasureTools.zip
StarMap 0.4.6                  github.com/StarMapLoader/StarMap/releases/download/0.4.6/StarMap-0.4.6.zip

So Borea cannot install a single entry from its own index.

One host indepentend downloader should be enough

All the host-specific work already happened at stamp time.
download.url is absolute, download.mirrors lists the alternates, and even SpaceDockModRepository builds an absolute URL out of version.DownloadPath before anybody downloads anything.

What it should be instead

Today Should be
SpaceDockModDownloader is the only implementation, and it re-queries api/mod/{id} for a path the repository already resolved. One host-agnostic downloader that fetches Download.Url. GitHub, SpaceDock and any later host need no code of their own.
DownloadAsync gets an id and a version, so it has to ask a host again for the URL. It gets the release, because ModVersionMetadata.Download already carries the URL, the hash, the size and the content type.
DownloadResult.Checksum is computed and then compared against nothing. The bytes are checked against DownloadInfo.Sha256 through HashMatches before anything is written, and a mismatch fails the install rather than warning.
One URL, so a dead link is a dead end. Download.Mirrors is tried next. Every AdvancedFlightComputer and MeasureTools release in the index already carries its SpaceDock mirror, and RFC 0031 accepts any source whose bytes match the hash.
ResolveContentRoot guesses: one top-level directory and no top-level files wins, otherwise the archive root. InstallInfo.Root decides, and null means the archive root per RFC 0035 rule 9.
The installed folder is named by whatever the caller passed as destinationDirectory. The folder is named by the id, because Mod.MakeUsing assigns the id from the folder name and overwrites whatever the archive declared.
ModTomlReader.ReadModId recovers the identity from the archive after the copy. The id is known before the download starts, from the listing.
Nothing records the install. The DownloadResult doc says a caller builds an InstalledMod from it, and no such caller exists. The install writes an InstalledMod with the version, the checksum and the InstallReason into the Instance, which is the only place a mod version will ever be recorded, since nothing on disk carries one.

Three things the table does not cover

  • Installing is not enabling. A new folder becomes a disabled manifest entry through ModLibrary.AddMods, and the manifest rules are their own issue.
  • Uninstall stays symmetric and removes only what the install wrote. IModUninstaller says itself that it does not check dependencies, so the caller asks ModDependencyResolver.CheckUninstall first.
  • Progress and cancellation already work through DownloadProgress and the token, and I would keep both as they are.

Tests

A GitHub URL and a SpaceDock URL through the same code path, a hash mismatch, a mirror that saves the install, a release with no hash at all, an authored install.root, and a top-level folder that disagrees with the id.

Not in scope: any UI, installing a loader, installing a pack, and the manifest.toml rules.

Depends on

#44, for a repository that can return a release file at all.
#41 is done, so InstallInfo already carries Root, Target and Path since #45 and #46 merged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:coreBorea.Core, the domain modelarea:networkBorea.Network, SpaceDock and other sourcesarea:storageBorea.Storage, persistence and TOML

    Type

    Projects

    • Status
      Todo

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions