/*
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
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace MOBase { class IPluginGame; }
class NexusInterface;
class NXMAccessManager;
/**
* @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(const QString &subModule = "");
/**
* @brief request description for a mod
*
* @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(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(int modID, QVariant userData);
/**
* @brief request info about a single file of a mod
*
* @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(int modID, int fileID, QVariant userData);
/**
* @brief request the download url of a file
*
* @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(int modID, int fileID, QVariant userData);
/**
* @brief requestToggleEndorsement
* @param modID id of the mod caller is interested in
* @param userData user data to be returned with the result
*/
virtual void requestToggleEndorsement(int modID, bool endorse, QVariant userData);
public slots:
void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData, int requestID);
void nxmFilesAvailable(int modID, QVariant userData, QVariant resultData, int requestID);
void nxmFileInfoAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
void nxmDownloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
void nxmEndorsementToggled(int modID, QVariant userData, QVariant resultData, int requestID);
void nxmRequestFailed(int modID, int fileID, QVariant userData, int requestID, 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:
~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 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(int modID, QObject *receiver, QVariant userData, const QString &subModule)
{
return requestDescription(modID, receiver, userData, subModule, m_Game);
}
/**
* @brief request description for a mod
*
* @param modID id of the mod 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 game Game with which the mod is associated
* @return int an id to identify the request
**/
int requestDescription(int modID, QObject *receiver, QVariant userData, const QString &subModule,
MOBase::IPluginGame const *game);
/**
* @brief request nexus descriptions for multiple mods at once
* @param modIDs a list of ids of mods the 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 requestUpdates(const std::vector &modIDs, QObject *receiver, QVariant userData, const QString &subModule)
{
return requestUpdates(modIDs, receiver, userData, subModule, m_Game);
}
/**
* @brief request nexus descriptions for multiple mods at once
* @param modIDs a list of ids of mods 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 game the game with which the mods are associated
* @return int an id to identify the request
*/
int requestUpdates(const std::vector &modIDs, QObject *receiver, QVariant userData, const QString &subModule,
MOBase::IPluginGame const *game);
/**
* @brief request a list of the files belonging to a mod
*
* @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(int modID, QObject *receiver, QVariant userData, const QString &subModule)
{
return requestFiles(modID, receiver, userData, subModule, m_Game);
}
/**
* @brief request a list of the files belonging to a mod
*
* @param modID id of the mod 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
* @param game the game with which the mods are associated
* @return int an id to identify the request
**/
int requestFiles(int modID, QObject *receiver, QVariant userData, const QString &subModule,
MOBase::IPluginGame const *game);
/**
* @brief request info about a single file of a mod
*
* @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(int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule)
{
return requestFileInfo(modID, fileID, receiver, userData, subModule, m_Game);
}
/**
* @brief request info about a single file of a mod
*
* @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
* @param game the game with which the mods are associated
* @return int an id to identify the request
**/
int requestFileInfo(int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule,
MOBase::IPluginGame const *game);
/**
* @brief request the download url of a file
*
* @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(int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule)
{
return requestDownloadURL(modID, fileID, receiver, userData, subModule, m_Game);
}
/**
* @brief request the download url of a file
*
* @param modID id of the mod caller is interested in
* @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
* @param game the game with which the mods are associated
* @return int an id to identify the request
**/
int requestDownloadURL(int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game);
/**
* @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(int modID, bool endorse, QObject *receiver, QVariant userData, const QString &subModule)
{
return requestToggleEndorsement(modID, endorse, receiver, userData, subModule, m_Game);
}
/**
* @brief toggle endorsement state of the mod
* @param modID id of the mod
* @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
* @param game the game with which the mods are associated
* @return int an id to identify the request
*/
int requestToggleEndorsement(int modID, bool endorse, QObject *receiver, QVariant userData, const QString &subModule,
MOBase::IPluginGame const *game);
/**
* @param directory the directory to store cache files
**/
void setCacheDirectory(const QString &directory);
/**
* MO has to send a "Nexus Client Vx.y.z" as part of the user agent to be allowed to use the API
* @param nmmVersion the version of nmm to impersonate
**/
void setNMMVersion(const QString &nmmVersion);
/**
* @brief called when the log-in completes. This was, requests waiting for the log-in can be run
*/
void loginCompleted();
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() const;
/**
* @brief Get the URL for the mod web page
* @param modID
*/
QString getModURL(int modID) 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;
signals:
void requestNXMDownload(const QString &url);
void needLogin();
void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData, int requestID);
void nxmUpdatesAvailable(const std::vector &modIDs, QVariant userData, QVariant resultData, int requestID);
void nxmFilesAvailable(int modID, QVariant userData, QVariant resultData, int requestID);
void nxmFileInfoAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
void nxmDownloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
void nxmEndorsementToggled(int modID, QVariant userData, QVariant resultData, int requestID);
void nxmRequestFailed(int modID, int fileID, QVariant userData, int requestID, const QString &errorString);
public slots:
void managedGameChanged(MOBase::IPluginGame const *game);
private slots:
void requestFinished();
void requestError(QNetworkReply::NetworkError error);
void requestTimeout();
void downloadRequestedNXM(const QString &url);
void fakeFiles();
private:
struct NXMRequestInfo {
int m_ModID;
std::vector m_ModIDList;
int m_FileID;
QNetworkReply *m_Reply;
enum Type {
TYPE_DESCRIPTION,
TYPE_FILES,
TYPE_FILEINFO,
TYPE_DOWNLOADURL,
TYPE_TOGGLEENDORSEMENT,
TYPE_GETUPDATES
} m_Type;
QVariant m_UserData;
QTimer *m_Timeout;
QString m_URL;
QString m_SubModule;
int m_NexusGameID;
bool m_Reroute;
int m_ID;
int m_Endorse;
NXMRequestInfo(int modID, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game);
NXMRequestInfo(std::vector modIDList, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game);
NXMRequestInfo(int modID, int fileID, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game);
private:
static QAtomicInt s_NextID;
};
static const int MAX_ACTIVE_DOWNLOADS = 2;
private:
NexusInterface();
void nextRequest();
void requestFinished(std::list::iterator iter);
bool requiresLogin(const NXMRequestInfo &info);
QString getOldModsURL() const;
private:
QNetworkDiskCache *m_DiskCache;
NXMAccessManager *m_AccessManager;
std::list m_ActiveRequest;
QQueue m_RequestQueue;
MOBase::VersionInfo m_MOVersion;
QString m_NMMVersion;
MOBase::IPluginGame const *m_Game;
};
#endif // NEXUSINTERFACE_H