152 lines
5.0 KiB
C++
152 lines
5.0 KiB
C++
class ModDownloader
|
|
{
|
|
private:
|
|
const char* VERIFICATION_FLAG = "-disablemodverification";
|
|
const char* CUSTOM_MODS_URL_FLAG = "-customverifiedurl=";
|
|
const char* STORE_URL = "https://gcdn.thunderstore.io/live/repository/packages/";
|
|
const char* DEFAULT_MODS_LIST_URL = "https://raw.githubusercontent.com/R2Northstar/VerifiedMods/main/verified-mods.json";
|
|
char* modsListUrl;
|
|
|
|
struct VerifiedModVersion
|
|
{
|
|
std::string checksum;
|
|
};
|
|
struct VerifiedModDetails
|
|
{
|
|
std::string dependencyPrefix;
|
|
std::unordered_map<std::string, VerifiedModVersion> versions = {};
|
|
};
|
|
std::unordered_map<std::string, VerifiedModDetails> verifiedMods = {};
|
|
|
|
/**
|
|
* Mod archive download callback.
|
|
*
|
|
* This function is called by curl as it's downloading the mod archive; this
|
|
* will retrieve the current `ModDownloader` instance and update its `modState`
|
|
* member accordingly.
|
|
*/
|
|
static int ModFetchingProgressCallback(
|
|
void* ptr, curl_off_t totalDownloadSize, curl_off_t finishedDownloadSize, curl_off_t totalToUpload, curl_off_t nowUploaded);
|
|
|
|
/**
|
|
* Downloads a mod archive from distant store.
|
|
*
|
|
* This rebuilds the URI of the mod archive using both a predefined store URI
|
|
* and the mod dependency string from the `verifiedMods` variable, or using
|
|
* input mod name as mod dependency string if bypass flag is set up; fetched
|
|
* archive is then stored in a temporary location.
|
|
*
|
|
* If something went wrong during archive download, this will return an empty
|
|
* optional object.
|
|
*
|
|
* @param modName name of the mod to be downloaded
|
|
* @param modVersion version of the mod to be downloaded
|
|
* @returns location of the downloaded archive
|
|
*/
|
|
std::optional<fs::path> FetchModFromDistantStore(std::string_view modName, std::string_view modVersion);
|
|
|
|
/**
|
|
* Tells if a mod archive has not been corrupted.
|
|
*
|
|
* The mod validation procedure includes computing the SHA256 hash of the final
|
|
* archive, which is stored in the verified mods list. This hash is used by this
|
|
* very method to ensure the archive downloaded from the Internet is the exact
|
|
* same that has been manually verified.
|
|
*
|
|
* @param modPath path of the archive to check
|
|
* @param expectedChecksum checksum the archive should have
|
|
* @returns whether archive is legit
|
|
*/
|
|
bool IsModLegit(fs::path modPath, std::string_view expectedChecksum);
|
|
|
|
/**
|
|
* Extracts a mod archive to the game folder.
|
|
*
|
|
* This extracts a downloaded mod archive from its original location to the
|
|
* current game profile, in the remote mods folder.
|
|
*
|
|
* @param modPath location of the downloaded archive
|
|
* @returns nothing
|
|
*/
|
|
void ExtractMod(fs::path modPath);
|
|
|
|
public:
|
|
ModDownloader();
|
|
|
|
/**
|
|
* Retrieves the verified mods list from the central authority.
|
|
*
|
|
* The Northstar auto-downloading feature does NOT allow automatically installing
|
|
* all mods for various (notably security) reasons; mods that are candidate to
|
|
* auto-downloading are rather listed on a GitHub repository
|
|
* (https://raw.githubusercontent.com/R2Northstar/VerifiedMods/main/verified-mods.json),
|
|
* which this method gets via a HTTP call to load into local state.
|
|
*
|
|
* If list fetching fails, local mods list will be initialized as empty, thus
|
|
* preventing any mod from being auto-downloaded.
|
|
*
|
|
* @returns nothing
|
|
*/
|
|
void FetchModsListFromAPI();
|
|
|
|
/**
|
|
* Checks whether a mod is verified.
|
|
*
|
|
* A mod is deemed verified/authorized through a manual validation process that is
|
|
* described here: https://github.com/R2Northstar/VerifiedMods; in practice, a mod
|
|
* is considered authorized if their name AND exact version appear in the
|
|
* `verifiedMods` variable.
|
|
*
|
|
* @param modName name of the mod to be checked
|
|
* @param modVersion version of the mod to be checked, must follow semantic versioning
|
|
* @returns whether the mod is authorized and can be auto-downloaded
|
|
*/
|
|
bool IsModAuthorized(std::string_view modName, std::string_view modVersion);
|
|
|
|
/**
|
|
* Downloads a given mod from Thunderstore API to local game profile.
|
|
*
|
|
* @param modName name of the mod to be downloaded
|
|
* @param modVersion version of the mod to be downloaded
|
|
* @returns nothing
|
|
**/
|
|
void DownloadMod(std::string modName, std::string modVersion);
|
|
|
|
enum ModInstallState
|
|
{
|
|
// Normal installation process
|
|
DOWNLOADING,
|
|
CHECKSUMING,
|
|
EXTRACTING,
|
|
DONE, // Everything went great, mod can be used in-game
|
|
|
|
// Errors
|
|
FAILED, // Generic error message, should be avoided as much as possible
|
|
FAILED_READING_ARCHIVE,
|
|
FAILED_WRITING_TO_DISK,
|
|
MOD_FETCHING_FAILED,
|
|
MOD_CORRUPTED, // Downloaded archive checksum does not match verified hash
|
|
NO_DISK_SPACE_AVAILABLE,
|
|
NOT_FOUND // Mod is not currently being auto-downloaded
|
|
};
|
|
|
|
struct MOD_STATE
|
|
{
|
|
ModInstallState state;
|
|
int progress;
|
|
int total;
|
|
float ratio;
|
|
} modState = {};
|
|
|
|
/**
|
|
* Cancels installation of the mod.
|
|
*
|
|
* Prevents installation of the mod currently being installed, no matter the install
|
|
* progress (downloading, checksuming, extracting), and frees all resources currently
|
|
* being used in this purpose.
|
|
*
|
|
* @returns nothing
|
|
*/
|
|
void CancelDownload();
|
|
};
|