/*
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
This file is part of Mod Organizer.
Mod Organizer is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Mod Organizer is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see .
*/
#ifndef NEXUSINTERFACE_H
#define NEXUSINTERFACE_H
#include "apiuseraccount.h"
#include "plugincontainer.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace MOBase
{
class IPluginGame;
}
class NexusInterface;
class NXMAccessManager;
class Settings;
/**
* @brief convenience class to make nxm requests easier
* usually, all objects that started a nxm request will be signaled if one finished.
* Therefore, the objects need to store the id of the requests they started and then
*filter the result. NexusBridge does this automatically. Users connect to the signals
*of NexusBridge they intend to handle and only receive the signals the caused
**/
class NexusBridge : public MOBase::IModRepositoryBridge
{
Q_OBJECT
public:
NexusBridge(PluginContainer* pluginContainer, const QString& subModule = "");
/**
* @brief request description for a mod
*
* @param gameName the game short name to support multiple game sources
* @param modID id of the mod caller is interested in
* @param userData user data to be returned with the result
* @param url the url to request from
**/
virtual void requestDescription(QString gameName, int modID, QVariant userData);
/**
* @brief request a list of the files belonging to a mod
*
* @param modID id of the mod caller is interested in
* @param userData user data to be returned with the result
**/
virtual void requestFiles(QString gameName, int modID, QVariant userData);
/**
* @brief request info about a single file of a mod
*
* @param gameName the game short name to support multiple game sources
* @param modID id of the mod caller is interested in
* @param fileID id of the file the caller is interested in
* @param userData user data to be returned with the result
**/
virtual void requestFileInfo(QString gameName, int modID, int fileID,
QVariant userData);
/**
* @brief request the download url of a file
*
* @param gameName the game short name to support multiple game sources
* @param modID id of the mod caller is interested in
* @param fileID id of the file the caller is interested in
* @param userData user data to be returned with the result
**/
virtual void requestDownloadURL(QString gameName, int modID, int fileID,
QVariant userData);
/**
* @brief requestToggleEndorsement
*
* @param gameName the game short name to support multiple game sources
* @param modID id of the mod caller is interested in
* @param userData user data to be returned with the result
*/
virtual void requestToggleEndorsement(QString gameName, int modID, QString modVersion,
bool endorse, QVariant userData);
/**
* @brief requestToggleTracking
*
* @param gameName the game short name to support multiple game sources
* @param modID id of the mod caller is interested in
* @param userData user data to be returned with the result
*/
virtual void requestToggleTracking(QString gameName, int modID, bool track,
QVariant userData);
/**
* @brief requestGameInfo
*
* @param gameName the game short name to support multiple game sources
* @param userData user data to be returned with the result
*/
virtual void requestGameInfo(QString gameName, QVariant userData);
public slots:
void nxmDescriptionAvailable(QString gameName, int modID, QVariant userData,
QVariant resultData, int requestID);
void nxmFilesAvailable(QString gameName, int modID, QVariant userData,
QVariant resultData, int requestID);
void nxmFileInfoAvailable(QString gameName, int modID, int fileID, QVariant userData,
QVariant resultData, int requestID);
void nxmDownloadURLsAvailable(QString gameName, int modID, int fileID,
QVariant userData, QVariant resultData, int requestID);
void nxmEndorsementsAvailable(QVariant userData, QVariant resultData, int requestID);
void nxmEndorsementToggled(QString gameName, int modID, QVariant userData,
QVariant resultData, int requestID);
void nxmTrackedModsAvailable(QVariant userData, QVariant resultData, int requestID);
void nxmTrackingToggled(QString gameName, int modID, QVariant userData, bool tracked,
int requestID);
void nxmGameInfoAvailable(QString gameName, QVariant userData, QVariant resultData,
int requestID);
void nxmRequestFailed(QString gameName, int modID, int fileID, QVariant userData,
int requestID, int errorCode, const QString& errorMessage);
private:
NexusInterface* m_Interface;
QString m_SubModule;
std::set m_RequestIDs;
};
/**
* @brief Makes asynchronous requests to the nexus API
*
* This class can be used to make asynchronous requests to the Nexus API.
* Currently, responses are sent to all receivers that have sent a request of the
*relevant type, so the recipient has to filter the response by the id returned when
*making the request
**/
class NexusInterface : public QObject
{
Q_OBJECT
public:
enum UpdatePeriod
{
NONE,
DAY,
WEEK,
MONTH
};
// Nexus file category IDs (MAIN, OLD etc), not to be confused with mod categories
// (Armors, Texture etc).
enum FileStatus
{
MAIN = 1,
UPDATE = 2,
OPTIONAL_FILE = 3, // actual string version is "OPTIONAL", but that is already
// defined as a macro in minwindef.h
OLD_VERSION = 4,
MISCELLANEOUS = 5,
REMOVED = 6,
ARCHIVED = 7,
ARCHIVED_HIDDEN = 1000 // Archived files can be hidden by authors so if they aren't
// listed we can assume they were hidden.
};
/**
* @brief Whether a Nexus file category represents a file that is still
* listed and considered current on the mod page.
*
* Inactive (false) refers to files that have been marked as obsolete or have been
* removed.
*/
static bool isActiveFileStatus(int status)
{
switch (status) {
case FileStatus::MAIN:
case FileStatus::UPDATE:
case FileStatus::OPTIONAL_FILE:
case FileStatus::MISCELLANEOUS:
return true;
case FileStatus::OLD_VERSION:
case FileStatus::REMOVED:
case FileStatus::ARCHIVED:
case FileStatus::ARCHIVED_HIDDEN:
return false;
default:
return false;
}
}
public:
static APILimits defaultAPILimits();
static APILimits parseLimits(const QNetworkReply* reply);
static APILimits parseLimits(const QList& headers);
NexusInterface(Settings* s);
~NexusInterface();
static NexusInterface& instance();
/**
* @return the access manager object used to connect to nexus
**/
NXMAccessManager* getAccessManager();
/**
* @brief cleanup this interface. this is destructive, afterwards it can't be used
* again
*/
void cleanup();
/**
* @brief clear webcache and cookies associated with this access manager
*/
void clearCache();
/**
* @brief request description for a mod
*
* @param gameName the game short name to support multiple game sources
* @param modID id of the mod caller is interested in (assumed to be for the current
*game)
* @param receiver the object to receive the result asynchronously via a signal
*(nxmDescriptionAvailable)
* @param userData user data to be returned with the result
* @return int an id to identify the request
**/
int requestDescription(QString gameName, int modID, QObject* receiver,
QVariant userData, const QString& subModule);
/**
* @brief request description for a mod
*
* @param gameName the game short name to support multiple game sources
* @param modID id of the mod caller is interested in (assumed to be for the current
*game)
* @param receiver the object to receive the result asynchronously via a signal
*(nxmModInfoAvailable)
* @param userData user data to be returned with the result
* @return int an id to identify the request
**/
int requestModInfo(QString gameName, int modID, QObject* receiver, QVariant userData,
const QString& subModule);
int requestUpdateInfo(QString gameNexusName, NexusInterface::UpdatePeriod period,
QObject* receiver, QVariant userData, const QString& subModule);
/**
* @brief request nexus descriptions for multiple mods at once
* @param modID id of the mod the caller is interested in
* @param receiver the object to receive the result asynchronously via a signal
* (nxmDescriptionAvailable)
* @param userData user data to be returned with the result
* @param gameName the game with which the mods are associated
* @return int an id to identify the request
*/
int requestUpdates(const int& modID, QObject* receiver, QVariant userData,
QString gameName, const QString& subModule);
/**
* @brief request a list of the files belonging to a mod
*
* @param gameName the game short name to support multiple game sources
* @param modID id of the mod caller is interested in (assumed to be for the current
*game)
* @param receiver the object to receive the result asynchronously via a signal
*(nxmFilesAvailable)
* @param userData user data to be returned with the result
* @return int an id to identify the request
**/
int requestFiles(QString gameName, int modID, QObject* receiver, QVariant userData,
const QString& subModule);
/**
* @brief request info about a single file of a mod
*
* @param gameName game short name to request the download from
* @param modID id of the mod caller is interested in (assumed to be for the current
*game)
* @param fileID id of the file the caller is interested in
* @param receiver the object to receive the result asynchronously via a signal
*(nxmFilesAvailable)
* @param userData user data to be returned with the result
* @return int an id to identify the request
**/
int requestFileInfo(QString gameName, int modID, int fileID, QObject* receiver,
QVariant userData, const QString& subModule);
/**
* @brief request the download url of a file
*
* @param gameName the game short name to support multiple game sources
* @param modID id of the mod caller is interested in (assumed to be for the current
*game)
* @param fileID id of the file the caller is interested in
* @param receiver the object to receive the result asynchronously via a signal
*(nxmFilesAvailable)
* @param userData user data to be returned with the result
* @return int an id to identify the request
**/
int requestDownloadURL(QString gameName, int modID, int fileID, QObject* receiver,
QVariant userData, const QString& subModule);
int requestEndorsementInfo(QObject* receiver, QVariant userData,
const QString& subModule);
/**
* @param gameName the game short name to support multiple game sources
* @brief toggle endorsement state of the mod
* @param modID id of the mod (assumed to be for the current game)
* @param endorse true if the mod should be endorsed, false for un-endorse
* @param receiver the object to receive the result asynchronously via a signal
* (nxmFilesAvailable)
* @param userData user data to be returned with the result
* @return int an id to identify the request
*/
int requestToggleEndorsement(QString gameName, int modID, QString modVersion,
bool endorse, QObject* receiver, QVariant userData,
const QString& subModule);
int requestTrackingInfo(QObject* receiver, QVariant userData,
const QString& subModule);
/**
* @param gameName the game short name to support multiple game sources
* @brief toggle tracking state of the mod
* @param modID id of the mod
* @param track true if the mod should be tracked, false for not tracked
* @param receiver the object to receive the result asynchronously via a signal
* (nxmFilesAvailable)
* @param userData user data to be returned with the result
* @param game the game with which the mods are associated
* @return int an id to identify the request
*/
int requestToggleTracking(QString gameName, int modID, bool track, QObject* receiver,
QVariant userData, const QString& subModule);
/**
* @param gameName the game short name to support multiple game sources
* @brief toggle tracking state of the mod
* @param modID id of the mod
* @param track true if the mod should be tracked, false for not tracked
* @param receiver the object to receive the result asynchronously via a signal
* (nxmFilesAvailable)
* @param userData user data to be returned with the result
* @param game the game with which the mods are associated
* @return int an id to identify the request
*/
int requestGameInfo(QString gameName, QObject* receiver, QVariant userData,
const QString& subModule);
/**
*
*/
int requestInfoFromMd5(QString gameName, QByteArray& hash, QObject* receiver,
QVariant userData, const QString& subModule);
/**
* @param directory the directory to store cache files
**/
void setCacheDirectory(const QString& directory);
/**
* @brief called when the log-in completes. This was, requests waiting for the log-in
* can be run
*/
void loginCompleted();
std::vector>
getGameChoices(const MOBase::IPluginGame* game);
APIUserAccount getAPIUserAccount() const;
APIStats getAPIStats() const;
public:
/**
* @brief guess the mod id from a filename as delivered by Nexus
* @param fileName name of the file
* @return the guessed mod id
* @note this currently doesn't fit well with the remaining interface but this is the
* best place for the function
*/
static void interpretNexusFileName(const QString& fileName, QString& modName,
int& modID, bool query);
/**
* @brief get the currently managed game
*/
MOBase::IPluginGame const* managedGame() const;
/**
* @brief see if the passed URL is related to the current game
*
* Arguably, this should optionally take a gameplugin pointer
*/
bool isURLGameRelated(QUrl const& url) const;
/**
* @brief Get the nexus page for the current game
*
* Arguably, this should optionally take a gameplugin pointer
*/
QString getGameURL(QString gameName) const;
/**
* @brief Get the URL for the mod web page
* @param modID
*/
QString getModURL(int modID, QString gameName) const;
/**
* @brief Checks if the specified URL might correspond to a nexus mod
* @param modID
* @param url
* @return
*/
bool isModURL(int modID, QString const& url) const;
void setPluginContainer(PluginContainer* pluginContainer);
signals:
void requestNXMDownload(const QString& url);
void needLogin();
void nxmDescriptionAvailable(QString gameName, int modID, QVariant userData,
QVariant resultData, int requestID);
void nxmModInfoAvailable(QString gameName, int modID, QVariant userData,
QVariant resultData, int requestID);
void nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVariant resultData,
int requestID);
void nxmUpdatesAvailable(QString gameName, int modID, QVariant userData,
QVariant resultData, int requestID);
void nxmFilesAvailable(QString gameName, int modID, QVariant userData,
QVariant resultData, int requestID);
void nxmFileInfoAvailable(QString gameName, int modID, int fileID, QVariant userData,
QVariant resultData, int requestID);
void nxmFileInfoFromMd5Available(QString gameName, QVariant userData,
QVariant resultData, int requestID);
void nxmDownloadURLsAvailable(QString gameName, int modID, int fileID,
QVariant userData, QVariant resultData, int requestID);
void nxmEndorsementsAvailable(QVariant userData, QVariant resultData, int requestID);
void nxmEndorsementToggled(QString gameName, int modID, QVariant userData,
QVariant resultData, int requestID);
void nxmTrackedModsAvailable(QVariant userData, QVariant resultData, int requestID);
void nxmTrackingToggled(QString gameName, int modID, QVariant userData, bool tracked,
int requestID);
void nxmGameInfoAvailable(QString gameName, QVariant userData, QVariant resultData,
int requestID);
void nxmRequestFailed(QString gameName, int modID, int fileID, QVariant userData,
int requestID, int errorCode, const QString& errorString);
void requestsChanged(const APIStats& stats, const APIUserAccount& user);
public slots:
void setUserAccount(const APIUserAccount& user);
private slots:
void requestFinished();
void requestError(QNetworkReply::NetworkError error);
void requestTimeout();
void downloadRequestedNXM(const QString& url);
void fakeFiles();
private:
struct NXMRequestInfo
{
int m_ModID;
QString m_ModVersion;
std::vector m_ModIDList;
int m_FileID;
QNetworkReply* m_Reply;
enum Type
{
TYPE_DESCRIPTION,
TYPE_MODINFO,
TYPE_FILES,
TYPE_FILEINFO,
TYPE_DOWNLOADURL,
TYPE_ENDORSEMENTS,
TYPE_TOGGLEENDORSEMENT,
TYPE_GETUPDATES,
TYPE_CHECKUPDATES,
TYPE_TOGGLETRACKING,
TYPE_TRACKEDMODS,
TYPE_FILEINFO_MD5,
TYPE_GAMEINFO,
} m_Type;
UpdatePeriod m_UpdatePeriod;
QVariant m_UserData;
QTimer* m_Timeout;
QString m_URL;
QString m_SubModule;
QString m_GameName;
bool m_Reroute;
int m_ID;
int m_Endorse;
int m_Track;
QByteArray m_Hash;
QMap> m_AllowedErrors;
bool m_IgnoreGenericErrorHandler;
NXMRequestInfo(int modID, Type type, QVariant userData, const QString& subModule,
const QString& gameNexusName);
NXMRequestInfo(int modID, QString modVersion, Type type, QVariant userData,
const QString& subModule, const QString& gameNexusName);
NXMRequestInfo(int modID, int fileID, Type type, QVariant userData,
const QString& subModule, const QString& gameNexusName);
NXMRequestInfo(Type type, QVariant userData, const QString& subModule,
const QString& gameNexusName);
NXMRequestInfo(Type type, QVariant userData, const QString& subModule);
NXMRequestInfo(UpdatePeriod period, Type type, QVariant userData,
const QString& subModule, const QString& gameNexusName);
NXMRequestInfo(QByteArray& hash, Type type, QVariant userData,
const QString& subModule, const QString& gameNexusName);
private:
static QAtomicInt s_NextID;
};
static const int MAX_ACTIVE_DOWNLOADS = 6;
private:
void nextRequest();
void requestFinished(std::list::iterator iter);
MOBase::IPluginGame* getGame(const QString& gameName) const;
QString getGameNexusName(const QString& gameName) const;
QString getOldModsURL(const QString& gameName) const;
private:
QNetworkDiskCache* m_DiskCache;
NXMAccessManager* m_AccessManager;
std::list m_ActiveRequest;
QQueue m_RequestQueue;
PluginContainer* m_PluginContainer;
APIUserAccount m_User;
};
#endif // NEXUSINTERFACE_H