1112 lines
49 KiB
C++
1112 lines
49 KiB
C++
////////////////////////////////////////////////////////////////////////////////////////////
|
|
//*--------------------------------------------------------------------------------------*//
|
|
//| ______ ______ __ __ ______ __ ______ __ ______ |//
|
|
//| /\ ___\ /\ __ \ /\ "-./ \ /\ ___\ /\ \ /\ __ \ /\ \ /\__ _\ |//
|
|
//| \ \ \__ \ \ \ __ \ \ \ \-./\ \ \ \ __\ _\_\ \ \ \ \/\ \ \ \ \____ \/_/\ \/ |//
|
|
//| \ \_____\ \ \_\ \_\ \ \_\ \ \_\ \ \_____\ /\_____\ \ \_____\ \ \_____\ \ \_\ |//
|
|
//| \/_____/ \/_/\/_/ \/_/ \/_/ \/_____/ \/_____/ \/_____/ \/_____/ \/_/ |//
|
|
//| |//
|
|
//*--------------------------------------------------------------------------------------*//
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
//*--------------------------------------------------------------------------------------*//
|
|
//| Game Jolt API C++ Library v1.0 (http://gamejolt.com) |//
|
|
//*--------------------------------------------------------------------------------------*//
|
|
//| Special Thanks to: |//
|
|
//| |//
|
|
//| David "CROS" DeCarmine, Joona "erakko" Melartin, Ashley Gwinnell, Bruno Assarisse, |//
|
|
//| Jani "JNyknn" Nykänen, Jorge Martínez "Sasurai" Vargas |//
|
|
//*--------------------------------------------------------------------------------------*//
|
|
//| Copyright (c) 2013-2015 Martin Mauersics |//
|
|
//| |//
|
|
//| This software is provided 'as-is', without any express or implied |//
|
|
//| warranty. In no event will the authors be held liable for any damages |//
|
|
//| arising from the use of this software. |//
|
|
//| |//
|
|
//| Permission is granted to anyone to use this software for any purpose, |//
|
|
//| including commercial applications, and to alter it and redistribute it |//
|
|
//| freely, subject to the following restrictions: |//
|
|
//| |//
|
|
//| 1. The origin of this software must not be misrepresented; you must not |//
|
|
//| claim that you wrote the original software. If you use this software |//
|
|
//| in a product, an acknowledgment in the product documentation would be |//
|
|
//| appreciated but is not required. |//
|
|
//| |//
|
|
//| 2. Altered source versions must be plainly marked as such, and must not be |//
|
|
//| misrepresented as being the original software. |//
|
|
//| |//
|
|
//| 3. This notice may not be removed or altered from any source |//
|
|
//| distribution. |//
|
|
//| |//
|
|
//| 4. This software may only be used within the terms of Game Jolt. |//
|
|
//| (http://gamejolt.com/terms/) |//
|
|
//*--------------------------------------------------------------------------------------*//
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
//! \file
|
|
#pragma once
|
|
#ifndef _GJ_GUARD_API_H_
|
|
#define _GJ_GUARD_API_H_
|
|
|
|
|
|
/* --- configuration --- */
|
|
#define GJ_API_URL "http://gamejolt.com/api/game/v1"
|
|
#define GJ_API_AVATAR_DEFAULT "http://gamejolt.com/img/no-avatar-1.png"
|
|
#define GJ_API_AVATAR_FORMAT ".png"
|
|
#define GJ_API_TROPHY_DEFAULT_1 "http://gamejolt.com/img/trophy-bronze-1.jpg"
|
|
#define GJ_API_TROPHY_DEFAULT_2 "http://gamejolt.com/img/trophy-silver-1.jpg"
|
|
#define GJ_API_TROPHY_DEFAULT_3 "http://gamejolt.com/img/trophy-gold-1.jpg"
|
|
#define GJ_API_TROPHY_DEFAULT_4 "http://gamejolt.com/img/trophy-platinum-1.jpg"
|
|
#define GJ_API_TROPHY_SECRET "http://gamejolt.com/img/trophy-secret-1.jpg"
|
|
#define GJ_API_PING_TIME 30
|
|
#define GJ_API_CRED "gjapi-credentials.txt"
|
|
#define GJ_API_TEXT_NOW "now"
|
|
#define GJ_API_TEXT_SECRET "???"
|
|
#define GJ_API_RESERVE_CALL 16
|
|
#define GJ_API_RESERVE_CALL_OUTPUT 4
|
|
#define GJ_API_RESERVE_TROPHY 32
|
|
#define GJ_API_RESERVE_SCORE 64
|
|
#define GJ_API_RESERVE_FILE 32
|
|
#define GJ_API_TIMEOUT_CONNECTION 3
|
|
#define GJ_API_TIMEOUT_REQUEST 10
|
|
#define GJ_API_NET_COMPRESSION "" // empty for all available compressions (identity, deflate, gzip)
|
|
#define GJ_API_NET_KEEPALIVE true
|
|
#define GJ_API_LOGFILE true
|
|
#define GJ_API_LOGFILE_NAME "gjapi_log.txt"
|
|
#define GJ_API_PREFETCH true
|
|
#define GJ_API_OFFCACHE_TROPHY true // does not work on Android
|
|
#define GJ_API_OFFCACHE_NAME "data/gjapi_cache.dat"
|
|
/* --- configuration --- */
|
|
|
|
|
|
// compiler
|
|
#if defined(_MSC_VER)
|
|
#define _GJ_MSVC_ (_MSC_VER)
|
|
#endif
|
|
#if defined(__GNUC__)
|
|
#define _GJ_GCC_ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__*1)
|
|
#endif
|
|
#if defined(__MINGW32__)
|
|
#define _CORE_MINGW_ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__*1)
|
|
#undef _CORE_GCC_
|
|
#endif
|
|
#if defined(__clang__)
|
|
#define _GJ_CLANG_ (__clang_major__*10000 + __clang_minor__*100 + __clang_patchlevel__*1)
|
|
#endif
|
|
|
|
// operating system
|
|
#if defined(_WIN32)
|
|
#define _GJ_WINDOWS_ (1)
|
|
#endif
|
|
#if defined(__linux__)
|
|
#define _GJ_LINUX_ (1)
|
|
#endif
|
|
#if defined(__APPLE__)
|
|
#define _GJ_OSX_ (1)
|
|
#endif
|
|
#if defined(__ANDROID__)
|
|
#define _GJ_ANDROID_ (1)
|
|
#endif
|
|
|
|
// debug mode
|
|
#if defined(_DEBUG) || defined(DEBUG) || (defined(_GJ_GCC_) && !defined(__OPTIMIZE__))
|
|
#define _GJ_DEBUG_ (1)
|
|
#endif
|
|
|
|
// missing functionality
|
|
#if defined(_GJ_MSVC_)
|
|
#if (_GJ_MSVC_) < 1800
|
|
#define delete_func
|
|
#else
|
|
#define delete_func = delete
|
|
#endif
|
|
#if (_GJ_MSVC_) < 1700
|
|
#define final
|
|
#endif
|
|
#define noexcept throw()
|
|
#define constexpr_func inline
|
|
#define constexpr_var const
|
|
#else
|
|
#define delete_func = delete
|
|
#define constexpr_func constexpr
|
|
#define constexpr_var constexpr
|
|
#endif
|
|
#if defined(_GJ_GCC_)
|
|
#if (_GJ_GCC_) < 40700
|
|
#define override
|
|
#define final
|
|
#endif
|
|
#endif
|
|
|
|
// base libraries
|
|
#define _HAS_EXCEPTIONS (0)
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#define _ALLOW_KEYWORD_MACROS
|
|
|
|
#if !defined(_GJ_WINDOWS_)
|
|
#include <sys/stat.h>
|
|
#endif
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <ctime>
|
|
#include <string>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
/*! \param pOutputObj output receiving object of **class T**
|
|
* \param OutputCallback callback function from **class T** with a specific return **type x**
|
|
* \param pOutputData additional data which will be forwarded to the callback function
|
|
*
|
|
* **Code Example**
|
|
* \code{.cpp}
|
|
* void Function(gjAPI& API, myClass& myObj)
|
|
* {
|
|
* // fetch an user with a callback (does not block)
|
|
* API.InterUser()->FetchUserCall("CROS", &myObj, &myClass::ReceiveUser, NULL);
|
|
* }
|
|
* \endcode */
|
|
#define GJ_NETWORK_OUTPUT(x) T* pOutputObj, void (T::*OutputCallback)(const x&, void*), void* pOutputData
|
|
#define GJ_NETWORK_PROCESS P* pProcessObj, int (P::*ProcessCallback)(const std::string&, void*, D*), void* pProcessData
|
|
|
|
#define GJ_NETWORK_OUTPUT_FW pOutputObj, OutputCallback, pOutputData
|
|
#define GJ_NETWORK_PROCESS_FW pProcessObj, ProcessCallback, pProcessData
|
|
|
|
#define GJ_NETWORK_NULL_THIS(d) this, &gjAPI::Null<d>, NULL
|
|
#define GJ_NETWORK_NULL_API(d) m_pAPI, &gjAPI::Null<d>, NULL
|
|
|
|
#define SAFE_DELETE(p) {if(p) {delete (p); (p) = NULL;}}
|
|
#define SAFE_DELETE_ARRAY(p) {if(p) {delete[] (p); (p) = NULL;}}
|
|
#define SAFE_MAP_GET(o,s) ((o).count(s) ? (o).at(s) : std::string(""))
|
|
|
|
#define FOR_EACH(i,c) for(auto i = (c).begin(), i ## __e = (c).end(); i != i ## __e; ++i)
|
|
#define FOR_EACH_REV(i,c) for(auto i = (c).rbegin(), i ## __e = (c).rend(); i != i ## __e; ++i)
|
|
|
|
#if !defined(ARRAY_SIZE)
|
|
template <typename T, std::size_t iSize> char (&__ARRAY_SIZE(T (&)[iSize]))[iSize];
|
|
#define ARRAY_SIZE(a) (sizeof(__ARRAY_SIZE(a)))
|
|
#endif
|
|
|
|
#if !defined(DISABLE_COPY)
|
|
#define DISABLE_COPY(c) \
|
|
c (const c&)delete_func; \
|
|
c& operator = (const c&)delete_func;
|
|
#endif
|
|
|
|
#if !defined(P_TO_I)
|
|
#define P_TO_I(x) ((int)(std::intptr_t)(void*)(x)) //!< pointer to int
|
|
#define I_TO_P(x) ((void*)(std::intptr_t)(int)(x)) //!< int to pointer
|
|
#endif
|
|
|
|
#undef GetUserName
|
|
|
|
#include "MD5.h"
|
|
#include "Base64.h"
|
|
#include "gjLookup.h"
|
|
#include "curl/curl.h"
|
|
|
|
class gjAPI;
|
|
class gjUser;
|
|
class gjTrophy;
|
|
class gjScoreTable;
|
|
class gjScore;
|
|
class gjDataItem;
|
|
|
|
typedef gjLookup<std::string> gjData;
|
|
typedef std::vector<gjData> gjDataList;
|
|
typedef void* gjVoidPtr;
|
|
typedef gjUser* gjUserPtr;
|
|
typedef std::vector<gjTrophy*> gjTrophyList;
|
|
typedef gjTrophy* gjTrophyPtr;
|
|
typedef std::map<int, gjScoreTable*> gjScoreTableMap;
|
|
typedef std::vector<gjScore*> gjScoreList;
|
|
typedef gjScore* gjScorePtr;
|
|
typedef std::map<std::string, gjDataItem*> gjDataItemMap;
|
|
typedef gjDataItem* gjDataItemPtr;
|
|
|
|
enum GJ_ERROR : unsigned char
|
|
{
|
|
GJ_OK = 0x00, //!< everything is fine
|
|
GJ_INVALID_CALL = 0x01, //!< function cannot be called
|
|
GJ_INVALID_INPUT = 0x02, //!< function parameters are invalid
|
|
GJ_REQUEST_FAILED = 0x04, //!< request to the API failed
|
|
GJ_REQUEST_CANCELED = 0x08, //!< request was canceled because of redundancy
|
|
GJ_NOT_CONNECTED = 0x10, //!< no main user connected (login first)
|
|
GJ_NO_DATA_FOUND = 0x20, //!< no data was found
|
|
GJ_NETWORK_ERROR = 0x40, //!< error sending or receiving data, or failed to establish a connection
|
|
GJ_FILE_ERROR = 0x80 //!< error on opening, writing or finding a file
|
|
};
|
|
|
|
enum GJ_SORT_DIRECTION : int
|
|
{
|
|
GJ_SORT_UNDEF = 0, //!< undefined sorting
|
|
GJ_SORT_DESC = 1, //!< descending sorting (3, 2, 1)
|
|
GJ_SORT_ASC = -1 //!< ascending sorting (1, 2, 3)
|
|
};
|
|
|
|
enum GJ_TROPHY_TYPE : int
|
|
{
|
|
GJ_TROPHY_ALL = 0, //!< all trophies
|
|
GJ_TROPHY_ACHIEVED = 1, //!< only achieved trophies
|
|
GJ_TROPHY_NOT_ACHIEVED = -1 //!< only unachieved trophies
|
|
};
|
|
|
|
#include "gjNetwork.h" // other header files are post-included
|
|
|
|
|
|
// ****************************************************************
|
|
/*! Main interface class of the library to connect with the Game Jolt API.\n
|
|
* Manages sessions, users, trophies, scores, data items and downloaded files.\n
|
|
* http://gamejolt.com/api/doc/game/
|
|
* \brief Main Interface */
|
|
class gjAPI final
|
|
{
|
|
private:
|
|
// ****************************************************************
|
|
/*! Sub-Interface class for user operations.\n
|
|
* http://gamejolt.com/api/doc/game/users/
|
|
* \brief User Sub-Interface */
|
|
class gjInterUser final
|
|
{
|
|
private:
|
|
std::map<int, gjUser*> m_apUser; //!< cached user objects
|
|
|
|
gjAPI* m_pAPI; //!< main interface access pointer
|
|
gjNetwork* m_pNetwork; //!< network access pointer
|
|
|
|
|
|
public:
|
|
gjInterUser(gjAPI* pAPI, gjNetwork* pNetwork)noexcept;
|
|
~gjInterUser();
|
|
|
|
/*! \name Direct Access */
|
|
//! @{
|
|
/*! Get direct access to the user objects.\n
|
|
* This function may block to cache the specific user.
|
|
* \pre Login maybe required
|
|
* \param iID Unique ID of an user (0 = current main user, Login required)
|
|
* \param sName Unique name of an user
|
|
* \return Pointer to specific user or empty object (ID == 0) on error */
|
|
gjUser* GetUser(const int& iID);
|
|
gjUser* GetUser(const std::string& sName);
|
|
gjUser* GetMainUser();
|
|
//! @}
|
|
|
|
/*! \name Fetch User Request */
|
|
//! @{
|
|
/*! Fetch and cache a specific user through an API request.
|
|
* \pre Login maybe required
|
|
* \note \b -Now blocks, \b -Call uses non-blocking callbacks
|
|
* \param iID Unique ID of an user (0 = current main user, Login required)
|
|
* \param sName Unique name of an user
|
|
* \return **GJ_OK** on success\n
|
|
* **GJ_REQUEST_FAILED** if request was unsuccessful\n
|
|
* **GJ_INVALID_INPUT** if name string is empty\n
|
|
* (see #GJ_ERROR) */
|
|
inline int FetchUserNow(const int& iID, gjUserPtr* ppOutput) {if(!ppOutput) return GJ_INVALID_INPUT; return this->__FetchUser(iID, ppOutput, GJ_NETWORK_NULL_API(gjUserPtr));}
|
|
inline int FetchUserNow(const std::string& sName, gjUserPtr* ppOutput) {if(!ppOutput) return GJ_INVALID_INPUT; return this->__FetchUser(sName, ppOutput, GJ_NETWORK_NULL_API(gjUserPtr));}
|
|
template <typename T> inline int FetchUserCall(const int& iID, GJ_NETWORK_OUTPUT(gjUserPtr)) {return this->__FetchUser(iID, NULL, GJ_NETWORK_OUTPUT_FW);}
|
|
template <typename T> inline int FetchUserCall(const std::string& sName, GJ_NETWORK_OUTPUT(gjUserPtr)) {return this->__FetchUser(sName, NULL, GJ_NETWORK_OUTPUT_FW);}
|
|
//! @}
|
|
|
|
/*! \name Check Cache */
|
|
//! @{
|
|
/*! Check and retrieve already cached user objects.
|
|
* \pre Login maybe required
|
|
* \param iID Unique ID of an user (0 = current main user, Login required)
|
|
* \param sName Unique name of an user
|
|
* \return **GJ_OK** on success\n
|
|
* **GJ_NO_DATA_FOUND** if user is not cached yet or does not even exist\n
|
|
* (see #GJ_ERROR) */
|
|
inline int CheckCache(const int& iID, gjUserPtr* ppOutput) {return this->__CheckCache(iID, ppOutput);}
|
|
inline int CheckCache(const std::string& sName, gjUserPtr* ppOutput) {return this->__CheckCache(sName, ppOutput);}
|
|
//! @}
|
|
|
|
/*! \name Clear Cache */
|
|
//! @{
|
|
/*! Delete all cached user objects.
|
|
* \warning All external pointers will be invalid */
|
|
void ClearCache();
|
|
//! @}
|
|
|
|
|
|
private:
|
|
/*! \name Superior Request Functions */
|
|
//! @{
|
|
template <typename T> int __FetchUser(const int& iID, gjUserPtr* ppOutput, GJ_NETWORK_OUTPUT(gjUserPtr));
|
|
template <typename T> int __FetchUser(const std::string& sName, gjUserPtr* ppOutput, GJ_NETWORK_OUTPUT(gjUserPtr));
|
|
//! @}
|
|
|
|
/*! \name Management Functions */
|
|
//! @{
|
|
int __CheckCache(const int& iID, gjUserPtr* ppOutput);
|
|
int __CheckCache(const std::string& sName, gjUserPtr* ppOutput);
|
|
int __Process(const std::string& sData, void* pAdd, gjUserPtr* ppOutput);
|
|
//! @}
|
|
};
|
|
|
|
|
|
// ****************************************************************
|
|
/*! Sub-Interface class for trophy operations.\n
|
|
* http://gamejolt.com/api/doc/game/trophies/
|
|
* \brief Trophy Sub-Interface */
|
|
class gjInterTrophy final
|
|
{
|
|
private:
|
|
std::map<int, gjTrophy*> m_apTrophy; //!< cached trophy objects
|
|
int m_iCache; //!< cache status (0 = empty, 1 = offline, 2 = online)
|
|
|
|
std::vector<int> m_aiSort; //!< layout of the returned trophy list
|
|
std::vector<int> m_aiSecret; //!< secret trophies (only fully visible when achieved)
|
|
std::vector<int> m_aiHidden; //!< hidden trophies (should never be visible, removed from memory)
|
|
|
|
gjAPI* m_pAPI; //!< main interface access pointer
|
|
gjNetwork* m_pNetwork; //!< network access pointer
|
|
|
|
|
|
public:
|
|
gjInterTrophy(gjAPI* pAPI, gjNetwork* pNetwork)noexcept;
|
|
~gjInterTrophy();
|
|
|
|
/*! \name Direct Access */
|
|
//! @{
|
|
/*! Get direct access to the trophy objects.\n
|
|
* This function may block to cache all trophies.
|
|
* \pre Login required
|
|
* \param iID Unique ID of a trophy
|
|
* \return Pointer to specific trophy or empty object (ID == 0) on error */
|
|
gjTrophy* GetTrophy(const int& iID);
|
|
//! @}
|
|
|
|
/*! \name Fetch Trophies Request */
|
|
//! @{
|
|
/*! Fetch and cache all trophies through an API request.\n
|
|
* You can sort the returned list with #SetSort.
|
|
* \pre Login required
|
|
* \note \b -Now blocks, \b -Call uses non-blocking callbacks
|
|
* \param iAchieved Status of the requested trophies (see #GJ_TROPHY_TYPE)
|
|
* \return **GJ_OK** on success\n
|
|
* **GJ_REQUEST_FAILED** if request was unsuccessful\n
|
|
* **GJ_NOT_CONNECTED** if connection/login is missing\n
|
|
* **GJ_NO_DATA_FOUND** if no trophies were found\n
|
|
* (see #GJ_ERROR) */
|
|
inline int FetchTrophiesNow(const long& iAchieved, gjTrophyList* papOutput) {if(!papOutput) return GJ_INVALID_INPUT; return this->__FetchTrophies(iAchieved, papOutput, GJ_NETWORK_NULL_API(gjTrophyList));}
|
|
template <typename T> inline int FetchTrophiesCall(const long& iAchieved, GJ_NETWORK_OUTPUT(gjTrophyList)) {return this->__FetchTrophies(iAchieved, NULL, GJ_NETWORK_OUTPUT_FW);}
|
|
//! @}
|
|
|
|
/*! \name Clear Cache */
|
|
//! @{
|
|
/*! Delete all cached trophy objects.
|
|
* \warning All external pointers will be invalid
|
|
* \param bFull Delete also the offline-cache */
|
|
void ClearCache(const bool& bFull);
|
|
//! @}
|
|
|
|
/*! \name Control Trophies */
|
|
//! @{
|
|
/*! Define the way trophies are handled and returned from the interface.
|
|
* \param piIDList Array with trophy IDs
|
|
* \param iNum Number of elements in the array */
|
|
void SetSort(const int* piIDList, const size_t& iNum);
|
|
void SetSecret(const int* piIDList, const size_t& iNum);
|
|
void SetHidden(const int* piIDList, const size_t& iNum);
|
|
//! @}
|
|
|
|
|
|
private:
|
|
/*! \name Superior Request Functions */
|
|
//! @{
|
|
template <typename T> int __FetchTrophies(const long& iAchieved, gjTrophyList* papOutput, GJ_NETWORK_OUTPUT(gjTrophyList));
|
|
//! @}
|
|
|
|
/*! \name Management Functions */
|
|
//! @{
|
|
int __CheckCache(const int& iAchieved, gjTrophyList* papOutput);
|
|
int __Process(const std::string& sData, void* pAdd, gjTrophyList* papOutput);
|
|
//! @}
|
|
|
|
/*! \name Offline Cache Functions */
|
|
//! @{
|
|
void __SaveOffCache(const std::string& sData);
|
|
void __LoadOffCache();
|
|
//! @}
|
|
};
|
|
|
|
|
|
// ****************************************************************
|
|
/*! Sub-Interface class for score operations.\n
|
|
* http://gamejolt.com/api/doc/game/scores/
|
|
* \brief Score Sub-Interface */
|
|
class gjInterScore final
|
|
{
|
|
private:
|
|
std::map<int, gjScoreTable*> m_apScoreTable; //!< cached score table objects with semi-cached score entries
|
|
|
|
gjAPI* m_pAPI; //!< main interface access pointer
|
|
gjNetwork* m_pNetwork; //!< network access pointer
|
|
|
|
|
|
public:
|
|
gjInterScore(gjAPI* pAPI, gjNetwork* pNetwork)noexcept;
|
|
~gjInterScore();
|
|
|
|
/*! \name Direct Access */
|
|
//! @{
|
|
/*! Get direct access to score table objects.\n
|
|
* This function may block to cache all score tables.
|
|
* \param iID Unique ID of a score table (0 = primary score table)
|
|
* \return Pointer to specific score table or empty object (ID == 0) on error */
|
|
gjScoreTable* GetScoreTable(const int& iID);
|
|
inline gjScoreTable* GetPrimaryTable() {return this->GetScoreTable(0);}
|
|
//! @}
|
|
|
|
/*! \name Fetch Score Tables Request */
|
|
//! @{
|
|
/*! Fetch and cache all score tables through an API request.
|
|
* \bug The API returns already deleted score tables
|
|
*
|
|
* \note \b -Now blocks, \b -Call uses non-blocking callbacks
|
|
* \return **GJ_OK** on success\n
|
|
* **GJ_REQUEST_FAILED** if request was unsuccessful\n
|
|
* **GJ_NO_DATA_FOUND** if no score tables were found\n
|
|
* (see #GJ_ERROR) */
|
|
inline int FetchScoreTablesNow(gjScoreTableMap* papOutput) {if(!papOutput) return GJ_INVALID_INPUT; return this->__FetchScoreTables(papOutput, GJ_NETWORK_NULL_API(gjScoreTableMap));}
|
|
template <typename T> inline int FetchScoreTablesCall(GJ_NETWORK_OUTPUT(gjScoreTableMap)) {return this->__FetchScoreTables(NULL, GJ_NETWORK_OUTPUT_FW);}
|
|
//! @}
|
|
|
|
/*! \name Clear Cache */
|
|
//! @{
|
|
/*! Delete all cached score table objects and score entries.
|
|
* \warning All external pointers will be invalid */
|
|
void ClearCache();
|
|
//! @}
|
|
|
|
|
|
private:
|
|
/*! \name Superior Request Functions */
|
|
//! @{
|
|
template <typename T> int __FetchScoreTables(gjScoreTableMap* papOutput, GJ_NETWORK_OUTPUT(gjScoreTableMap));
|
|
//! @}
|
|
|
|
/*! \name Management Functions */
|
|
//! @{
|
|
int __CheckCache(gjScoreTableMap* papOutput);
|
|
int __Process(const std::string& sData, void* pAdd, gjScoreTableMap* papOutput);
|
|
//! @}
|
|
};
|
|
|
|
|
|
// ****************************************************************
|
|
/*! Sub-Interface class for data store operations.\n
|
|
* http://gamejolt.com/api/doc/game/data-store/
|
|
* \brief Data Store Sub-Interface */
|
|
class gjInterDataStore final
|
|
{
|
|
private:
|
|
std::map<std::string, gjDataItem*> m_apDataItem; //!< semi-cached data store items
|
|
|
|
int m_iType; //!< type of this interface (0 = global, 1 = user)
|
|
|
|
gjAPI* m_pAPI; //!< main interface access pointer
|
|
gjNetwork* m_pNetwork; //!< network access pointer
|
|
|
|
|
|
public:
|
|
gjInterDataStore(const int& iType, gjAPI* pAPI, gjNetwork* pNetwork)noexcept;
|
|
~gjInterDataStore();
|
|
|
|
/*! \name Direct Access */
|
|
//! @{
|
|
/*! Get direct access to data store items.\n
|
|
* This function creates a new data store item, if the key does not exist.\n
|
|
* To get all existing items, use \link FetchDataItemsNow FetchDataItems\endlink.
|
|
* \pre Login maybe required
|
|
* \param sKey Unique key of a data store item
|
|
* \return Pointer to specific data store item or NULL on error */
|
|
gjDataItem* GetDataItem(const std::string& sKey);
|
|
//! @}
|
|
|
|
/*! \name Fetch Data Items Request */
|
|
//! @{
|
|
/*! Fetch and semi-cache all data store items through an API request.
|
|
* \note \b -Now blocks, \b -Call uses non-blocking callbacks
|
|
* \return **GJ_OK** on success\n
|
|
* **GJ_REQUEST_FAILED** if request was unsuccessful\n
|
|
* **GJ_NOT_CONNECTED** if connection/login is missing\n
|
|
* **GJ_NO_DATA_FOUND** if no data items were found\n
|
|
* (see #GJ_ERROR) */
|
|
inline int FetchDataItemsNow(gjDataItemMap* papOutput) {if(!papOutput) return GJ_INVALID_INPUT; return this->__FetchDataItems(papOutput, GJ_NETWORK_NULL_API(gjDataItemMap));}
|
|
template <typename T> inline int FetchDataItemsCall(GJ_NETWORK_OUTPUT(gjDataItemMap)) {return this->__FetchDataItems(NULL, GJ_NETWORK_OUTPUT_FW);}
|
|
//! @}
|
|
|
|
/*! \name Clear Cache */
|
|
//! @{
|
|
/*! Delete all cached data store items.
|
|
* \warning All external pointers will be invalid */
|
|
void ClearCache();
|
|
//! @}
|
|
|
|
/*! \name Get Attributes */
|
|
//! @{
|
|
inline const int& GetType()const {return m_iType;} //!< \copybrief m_iType
|
|
/*! */ //! @}
|
|
|
|
|
|
private:
|
|
/*! \name Superior Request Functions */
|
|
//! @{
|
|
template <typename T> int __FetchDataItems(gjDataItemMap* papOutput, GJ_NETWORK_OUTPUT(gjDataItemMap));
|
|
//! @}
|
|
|
|
/*! \name Management Functions */
|
|
//! @{
|
|
int __CheckCache(gjDataItemMap* papOutput);
|
|
int __Process(const std::string& sData, void* pAdd, gjDataItemMap* papOutput);
|
|
//! @}
|
|
|
|
/*! \name Callback Functions */
|
|
//! @{
|
|
int __AddDataItemCallback(const std::string& sData, void* pAdd, gjTrophyPtr* pOutput);
|
|
int __RemoveDataItemCallback(const std::string& sData, void* pAdd, gjTrophyPtr* ppOutput);
|
|
//! @}
|
|
};
|
|
|
|
|
|
// ****************************************************************
|
|
/*! Sub-Interface class for file downloads.\n
|
|
* \brief File Download Sub-Interface */
|
|
class gjInterFile final
|
|
{
|
|
private:
|
|
std::vector<std::string> m_asFile; //!< cached file paths
|
|
|
|
gjAPI* m_pAPI; //!< main interface access pointer
|
|
gjNetwork* m_pNetwork; //!< network access pointer
|
|
|
|
|
|
public:
|
|
gjInterFile(gjAPI* pAPI, gjNetwork* pNetwork)noexcept;
|
|
~gjInterFile();
|
|
|
|
/*! \name Download File */
|
|
/*! Download a file from any URL.\n
|
|
* Retrieve the local path of the file when finished.
|
|
* \note \b -Now blocks, \b -Call uses non-blocking callbacks
|
|
* \warning You need to overwrite the file name if it's not apparent from the URL
|
|
* \param sURL Full path of the remote file
|
|
* \param sToFolder Relative path of the download target folder
|
|
* \param sFileNameOverwrite Custom target file name (mandatory, if file name is not apparent from the URL)
|
|
* \return **GJ_OK** on success\n
|
|
* **GJ_REQUEST_FAILED** if request was unsuccessful\n
|
|
* **GJ_INVALID_INPUT** if URL string or target folder string is empty\n
|
|
* (see #GJ_ERROR) */
|
|
inline int DownloadFileNow(const std::string& sURL, const std::string& sToFolder, const std::string& sFileNameOverwrite, std::string* psOutput) {if(!psOutput) return GJ_INVALID_INPUT; return this->__DownloadFile(sURL, sToFolder, sFileNameOverwrite, psOutput, GJ_NETWORK_NULL_API(std::string));}
|
|
template <typename T> inline int DownloadFileCall(const std::string& sURL, const std::string& sToFolder, const std::string& sFileNameOverwrite, GJ_NETWORK_OUTPUT(std::string)) {return this->__DownloadFile(sURL, sToFolder, sFileNameOverwrite, NULL, GJ_NETWORK_OUTPUT_FW);}
|
|
|
|
/*! \name Clear Cache */
|
|
//! @{
|
|
/*! Delete all cached file paths. */
|
|
void ClearCache();
|
|
//! @}
|
|
|
|
|
|
private:
|
|
/*! \name Superior Request Functions */
|
|
//! @{
|
|
template <typename T> int __DownloadFile(const std::string& sURL, const std::string& sToFolder, const std::string& sFileNameOverwrite, std::string* psOutput, GJ_NETWORK_OUTPUT(std::string));
|
|
//! @}
|
|
|
|
/*! \name Management Functions */
|
|
//! @{
|
|
int __CheckCache(const std::string& sPath);
|
|
int __Process(const std::string& sData, void* pAdd, std::string* psOutput);
|
|
//! @}
|
|
};
|
|
|
|
|
|
private:
|
|
int m_iGameID; //!< ID to identify the game
|
|
std::string m_sGamePrivateKey; //!< private key to generate MD5 signature
|
|
|
|
std::string m_sUserName; //!< name of the main user
|
|
std::string m_sUserToken; //!< token of the main user
|
|
|
|
time_t m_iNextPing; //!< next ping for the user session
|
|
bool m_bActive; //!< current status for the user session
|
|
bool m_bConnected; //!< current connection status
|
|
|
|
gjInterUser* m_pInterUser; //!< user Sub-Interface object
|
|
gjInterTrophy* m_pInterTrophy; //!< trophy Sub-Interface object
|
|
gjInterScore* m_pInterScore; //!< score Sub-Interface object
|
|
gjInterDataStore* m_pInterDataStoreGlobal; //!< global data store Sub-Interface object
|
|
gjInterDataStore* m_pInterDataStoreUser; //!< user data store Sub-Interface object
|
|
gjInterFile* m_pInterFile; //!< file download Sub-Interface object
|
|
|
|
gjNetwork* m_pNetwork; //!< network object
|
|
|
|
std::string m_sProcGameID; //!< already processed/converted game ID
|
|
std::string m_sProcUserName; //!< already processed/escaped user name
|
|
std::string m_sProcUserToken; //!< already processed/escaped user token
|
|
|
|
static std::vector<std::string> s_asLog; //!< error log
|
|
|
|
|
|
public:
|
|
gjAPI(const int iGameID = 0, const std::string sGamePrivateKey = "")noexcept;
|
|
~gjAPI();
|
|
|
|
/*! \name Init */
|
|
//! @{
|
|
/*! Explicitely initialize the object after construction.
|
|
* \note Needs to be called after empty construction, and only once */
|
|
void Init(const int& iGameID, const std::string& sGamePrivateKey);
|
|
//! @}
|
|
|
|
/*! \name Update */
|
|
//! @{
|
|
/*! Main update function of the library.
|
|
* \brief Must be executed in the main loop of the application
|
|
* \note Must be executed in the main loop of the application */
|
|
void Update();
|
|
//! @}
|
|
|
|
/*! \name Login User*/
|
|
//! @{
|
|
/*! Login with a specific user.\n
|
|
* Authenticate user and establish an user session through the API.\n
|
|
* Prefetch the user object, trophies and user related data store items.
|
|
* \note \b -Now blocks, \b -Call uses non-blocking callbacks
|
|
* \param bSession Establish an user session
|
|
* \param sUserName Login name of the user
|
|
* \param sUserToken Token for that user
|
|
* \param sCredPath Relative path to the credentials file of the quick play function
|
|
* \return **GJ_OK** on success\n
|
|
* **GJ_REQUEST_FAILED** if request was unsuccessful\n
|
|
* **GJ_INVALID_CALL** if already connected\n
|
|
* **GJ_INVALID_INPUT** if user name or user token is missing\n
|
|
* **GJ_FILE_ERROR** if credentials file was not found\n
|
|
* **GJ_NETWORK_ERROR** if service is unavailable or request timed out\n
|
|
* (see #GJ_ERROR) */
|
|
inline int LoginNow(const bool& bSession, const std::string& sUserName, const std::string& sUserToken) {return __Login(bSession, sUserName, sUserToken, true, GJ_NETWORK_NULL_THIS(int));}
|
|
inline int LoginNow(const bool& bSession, const std::string& sCredPath) {return __Login(bSession, sCredPath, true, GJ_NETWORK_NULL_THIS(int));}
|
|
inline int LoginNow(const bool& bSession) {return __Login(bSession, GJ_API_CRED, true, GJ_NETWORK_NULL_THIS(int));}
|
|
template <typename T> inline int LoginCall(const bool& bSession, const std::string& sUserName, const std::string& sUserToken, GJ_NETWORK_OUTPUT(int)) {return __Login(bSession, sUserName, sUserToken, false, GJ_NETWORK_OUTPUT_FW);}
|
|
template <typename T> inline int LoginCall(const bool& bSession, const std::string& sCredPath, GJ_NETWORK_OUTPUT(int)) {return __Login(bSession, sCredPath, false, GJ_NETWORK_OUTPUT_FW);}
|
|
template <typename T> inline int LoginCall(const bool& bSession, GJ_NETWORK_OUTPUT(int)) {return __Login(bSession, GJ_API_CRED, false, GJ_NETWORK_OUTPUT_FW);}
|
|
//! @}
|
|
|
|
/*! \name Logout User */
|
|
//! @{
|
|
/*! Logout with the current main user.
|
|
* \warning External pointers to trophies and user data store items will be invalid
|
|
* \return **GJ_OK** on success\n
|
|
* **GJ_NOT_CONNECTED** if connection/login is missing\n
|
|
* (see #GJ_ERROR) */
|
|
int Logout();
|
|
//! @}
|
|
|
|
/*! \name Sub-Interface Access */
|
|
//! @{
|
|
inline gjInterUser* InterUser()const {return m_pInterUser;}
|
|
inline gjInterTrophy* InterTrophy()const {return m_pInterTrophy;}
|
|
inline gjInterScore* InterScore()const {return m_pInterScore;}
|
|
inline gjInterDataStore* InterDataStoreGlobal()const {return m_pInterDataStoreGlobal;}
|
|
inline gjInterDataStore* InterDataStoreUser()const {return m_pInterDataStoreUser;}
|
|
inline gjInterFile* InterFile()const {return m_pInterFile;}
|
|
inline gjNetwork* AccessNetwork()const {return m_pNetwork;}
|
|
//! @}
|
|
|
|
/*! \name Send Custom Request */
|
|
//! @{
|
|
/*! Send a custom request to the API.\n
|
|
* Retrieve a response string when finished.
|
|
* \note \b -Now blocks, \b -Call uses non-blocking callbacks\n
|
|
* Use "&POST<data>" at the end of the URL for a POST request
|
|
* \param sURL Relative API request string
|
|
* \return **GJ_OK** on success\n
|
|
* **GJ_REQUEST_FAILED** if request was unsuccessful\n
|
|
* **GJ_NETWORK_ERROR** if session cannot be established\n
|
|
* (see #GJ_ERROR) */
|
|
inline int SendRequestNow(const std::string& sURL, std::string* psOutput) {return m_pNetwork->SendRequest(sURL, psOutput, this, &gjAPI::Null, NULL, GJ_NETWORK_NULL_THIS(std::string));}
|
|
template <typename T, typename D> inline int SendRequestCall(const std::string& sURL, GJ_NETWORK_OUTPUT(D)) {return m_pNetwork->SendRequest(sURL, NULL, this, &gjAPI::Null, NULL, GJ_NETWORK_OUTPUT_FW);}
|
|
template <typename T, typename P, typename D> inline int SendRequestCall(const std::string& sURL, GJ_NETWORK_PROCESS, GJ_NETWORK_OUTPUT(D)) {return m_pNetwork->SendRequest(sURL, NULL, GJ_NETWORK_PROCESS_FW, GJ_NETWORK_OUTPUT_FW);}
|
|
template <typename T, typename P, typename D> inline int SendRequest(const std::string& sURL, std::string* psOutput, GJ_NETWORK_PROCESS, GJ_NETWORK_OUTPUT(D)) {return m_pNetwork->SendRequest(sURL, psOutput, GJ_NETWORK_PROCESS_FW, GJ_NETWORK_OUTPUT_FW);}
|
|
//! @}
|
|
|
|
/*! \name Parse Request */
|
|
//! @{
|
|
/*! Parse a valid response string from the API.\n
|
|
* Retrieve a list of data objects or a single string.
|
|
* \param sInput Valid response string
|
|
* \return **GJ_OK** on success\n
|
|
* **GJ_REQUEST_FAILED** if the parsed request was unsuccessful\n
|
|
* **GJ_INVALID_INPUT** if the string parsing failed\n
|
|
* (see #GJ_ERROR) */
|
|
int ParseRequestKeypair(const std::string& sInput, gjDataList* paaOutput);
|
|
int ParseRequestDump(const std::string& sInput, std::string* psOutput);
|
|
//! @}
|
|
|
|
/*! \name Clear Cache */
|
|
//! @{
|
|
/*! Delete all cached objects.
|
|
* \warning All external pointers will be invalid\n
|
|
* Try to avoid using this function */
|
|
void ClearCache();
|
|
//! @}
|
|
|
|
/*! \name Utility Functions */
|
|
//! @{
|
|
static std::string UtilEscapeString(const std::string& sString);
|
|
static void UtilTrimString(std::string* psInput);
|
|
static std::string UtilCharToHex(const char& cChar);
|
|
static std::string UtilIntToString(const int& iInt);
|
|
static void UtilCreateFolder(const std::string& sFolder);
|
|
static std::string UtilTimestamp(const time_t iTime = std::time(NULL));
|
|
//! @}
|
|
|
|
/*! \name Error Log */
|
|
//! @{
|
|
static void ErrorLogReset();
|
|
static void ErrorLogAdd(const std::string& sMsg);
|
|
static inline const std::vector<std::string>& ErrorLogGet(){return s_asLog;}
|
|
//! @}
|
|
|
|
/*! \name Set Attributes */
|
|
//! @{
|
|
inline void SetSessionActive(const bool& bActive) {m_bActive = bActive;} //!< \copybrief m_bActive
|
|
/*! */ //! @}
|
|
|
|
/*! \name Get Attributes */
|
|
//! @{
|
|
inline const int& GetGameID()const {return m_iGameID;} //!< \copybrief m_iGameID
|
|
inline const std::string& GetGamePrivateKey()const {return m_sGamePrivateKey;} //!< \copybrief m_sGamePrivateKey
|
|
inline const std::string& GetUserName()const {return m_sUserName;} //!< \copybrief m_sUserName
|
|
inline const std::string& GetUserToken()const {return m_sUserToken;} //!< \copybrief m_sUserToken
|
|
/*! */ //! @}
|
|
|
|
/*! \name Get Processed Attributes */
|
|
//! @{
|
|
inline const std::string& GetProcGameID()const {return m_sProcGameID;} //!< \copybrief m_sProcGameID
|
|
inline const std::string& GetProcUserName()const {return m_sProcUserName;} //!< \copybrief m_sProcUserName
|
|
inline const std::string& GetProcUserToken()const {return m_sProcUserToken;} //!< \copybrief m_sProcUserToken
|
|
/*! */ //! @}
|
|
|
|
/*! \name Check Status */
|
|
//! @{
|
|
inline const bool& IsSessionActive()const {return m_bActive;} //!< \copybrief m_bActive
|
|
inline const bool& IsUserConnected()const {return m_bConnected;} //!< \copybrief m_bConnected
|
|
//! @}
|
|
|
|
#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
|
|
|
|
/*! \name Callback Placeholder */
|
|
//! @{
|
|
inline int Null(const std::string& sData, void* pAdd, std::string* psOutput) {if(psOutput) (*psOutput) = sData; return GJ_OK;}
|
|
template <typename D> inline void Null(const D& pObject, void* pData) {}
|
|
//! @}
|
|
|
|
#endif
|
|
|
|
|
|
private:
|
|
DISABLE_COPY(gjAPI)
|
|
|
|
/*! \name Session Functions */
|
|
//! @{
|
|
int __OpenSession();
|
|
int __PingSession(const bool& bActive);
|
|
int __CloseSession();
|
|
//! @}
|
|
|
|
/*! \name Superior Request Functions */
|
|
//! @{
|
|
template <typename T> int __Login(const bool& bSession, const std::string& sUserName, const std::string& sUserToken, const bool& bNow, GJ_NETWORK_OUTPUT(int));
|
|
template <typename T> int __Login(const bool& bSession, const std::string& sCredPath, const bool& bNow, GJ_NETWORK_OUTPUT(int));
|
|
//! @}
|
|
|
|
/*! \name Callback Functions */
|
|
//! @{
|
|
int __LoginCallback(const std::string& sData, void* pAdd, int* pbOutput);
|
|
//! @}
|
|
};
|
|
|
|
|
|
// ****************************************************************
|
|
/* fetch and cache a specific user with user ID */
|
|
template <typename T> int gjAPI::gjInterUser::__FetchUser(const int& iID, gjUserPtr* ppOutput, GJ_NETWORK_OUTPUT(gjUserPtr))
|
|
{
|
|
const bool bNow = ppOutput ? true : false;
|
|
|
|
// fetch current main user
|
|
if(!iID) return this->__FetchUser(m_pAPI->GetUserName(), ppOutput, GJ_NETWORK_OUTPUT_FW);
|
|
|
|
// check for cached user
|
|
gjUserPtr pCache = NULL;
|
|
if(this->__CheckCache(iID, &pCache) == GJ_OK)
|
|
{
|
|
if(bNow) (*ppOutput) = pCache;
|
|
else (pOutputObj->*OutputCallback)(pCache, pOutputData);
|
|
return GJ_OK;
|
|
}
|
|
|
|
// send get user request
|
|
std::string sResponse;
|
|
if(m_pNetwork->SendRequest("/users/"
|
|
"?game_id=" + m_pAPI->GetProcGameID() +
|
|
"&user_id=" + gjAPI::UtilIntToString(iID),
|
|
bNow ? &sResponse : NULL, this, &gjAPI::gjInterUser::__Process, NULL, GJ_NETWORK_OUTPUT_FW)) return GJ_REQUEST_FAILED;
|
|
|
|
if(bNow) return this->__Process(sResponse, NULL, ppOutput);
|
|
return GJ_OK;
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
/* fetch and cache a specific user with user name */
|
|
template <typename T> int gjAPI::gjInterUser::__FetchUser(const std::string& sName, gjUserPtr* ppOutput, GJ_NETWORK_OUTPUT(gjUserPtr))
|
|
{
|
|
if(sName == "") return GJ_INVALID_INPUT;
|
|
|
|
const bool bNow = ppOutput ? true : false;
|
|
|
|
// check for cached user
|
|
gjUserPtr pCache = NULL;
|
|
if(this->__CheckCache(sName, &pCache) == GJ_OK)
|
|
{
|
|
if(bNow) (*ppOutput) = pCache;
|
|
else (pOutputObj->*OutputCallback)(pCache, pOutputData);
|
|
return GJ_OK;
|
|
}
|
|
|
|
// send get user request
|
|
std::string sResponse;
|
|
if(m_pNetwork->SendRequest("/users/"
|
|
"?game_id=" + m_pAPI->GetProcGameID() +
|
|
"&username=" + gjAPI::UtilEscapeString(sName),
|
|
bNow ? &sResponse : NULL, this, &gjAPI::gjInterUser::__Process, NULL, GJ_NETWORK_OUTPUT_FW)) return GJ_REQUEST_FAILED;
|
|
|
|
if(bNow) return this->__Process(sResponse, NULL, ppOutput);
|
|
return GJ_OK;
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
/* fetch and cache all trophies */
|
|
template <typename T> int gjAPI::gjInterTrophy::__FetchTrophies(const long& iAchieved, gjTrophyList* papOutput, GJ_NETWORK_OUTPUT(gjTrophyList))
|
|
{
|
|
if(!m_pAPI->IsUserConnected() && m_iCache == 0) return GJ_NOT_CONNECTED;
|
|
|
|
const bool bNow = papOutput ? true : false;
|
|
|
|
// handle offline-cached trophies
|
|
if(m_pAPI->IsUserConnected() && m_iCache != 2)
|
|
m_iCache = 0;
|
|
|
|
// wait for prefetching
|
|
if(bNow && GJ_API_PREFETCH)
|
|
{
|
|
if(m_apTrophy.size() <= 1)
|
|
m_pNetwork->Wait(1);
|
|
}
|
|
|
|
if(m_iCache != 0)
|
|
{
|
|
// check for cached trophies
|
|
gjTrophyList apCache;
|
|
if(this->__CheckCache(iAchieved, &apCache) == GJ_OK)
|
|
{
|
|
if(bNow) (*papOutput) = apCache;
|
|
else (pOutputObj->*OutputCallback)(apCache, pOutputData);
|
|
return GJ_OK;
|
|
}
|
|
}
|
|
|
|
// send get trophies request
|
|
std::string sResponse;
|
|
if(m_pNetwork->SendRequest("/trophies/"
|
|
"?game_id=" + m_pAPI->GetProcGameID() +
|
|
"&username=" + m_pAPI->GetProcUserName() +
|
|
"&user_token=" + m_pAPI->GetProcUserToken(),
|
|
bNow ? &sResponse : NULL, this, &gjAPI::gjInterTrophy::__Process, I_TO_P(iAchieved), GJ_NETWORK_OUTPUT_FW)) return GJ_REQUEST_FAILED;
|
|
|
|
if(bNow) return this->__Process(sResponse, I_TO_P(iAchieved), papOutput);
|
|
return GJ_OK;
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
/* fetch and cache all score tables */
|
|
template <typename T> int gjAPI::gjInterScore::__FetchScoreTables(gjScoreTableMap* papOutput, GJ_NETWORK_OUTPUT(gjScoreTableMap))
|
|
{
|
|
const bool bNow = papOutput ? true : false;
|
|
|
|
// wait for prefetching
|
|
if(bNow && GJ_API_PREFETCH)
|
|
{
|
|
if(m_apScoreTable.size() <= 1)
|
|
m_pNetwork->Wait(1);
|
|
}
|
|
|
|
// check for cached score tables
|
|
gjScoreTableMap apCache;
|
|
if(this->__CheckCache(&apCache) == GJ_OK)
|
|
{
|
|
if(bNow) (*papOutput) = apCache;
|
|
else (pOutputObj->*OutputCallback)(apCache, pOutputData);
|
|
return GJ_OK;
|
|
}
|
|
|
|
// send get score tables request
|
|
std::string sResponse;
|
|
if(m_pNetwork->SendRequest("/scores/tables/"
|
|
"?game_id=" + m_pAPI->GetProcGameID(),
|
|
bNow ? &sResponse : NULL, this, &gjAPI::gjInterScore::__Process, NULL, GJ_NETWORK_OUTPUT_FW)) return GJ_REQUEST_FAILED;
|
|
|
|
if(bNow) return this->__Process(sResponse, NULL, papOutput);
|
|
return GJ_OK;
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
/* fetch and semi-cache all data store items */
|
|
template <typename T> int gjAPI::gjInterDataStore::__FetchDataItems(gjDataItemMap* papOutput, GJ_NETWORK_OUTPUT(gjDataItemMap))
|
|
{
|
|
if(!m_pAPI->IsUserConnected() && m_iType) return GJ_NOT_CONNECTED;
|
|
|
|
const bool bNow = papOutput ? true : false;
|
|
|
|
if(m_iType)
|
|
{
|
|
// wait for prefetching
|
|
if(bNow && GJ_API_PREFETCH)
|
|
{
|
|
if(m_apDataItem.empty())
|
|
m_pNetwork->Wait(1);
|
|
}
|
|
|
|
// check for cached data store items
|
|
gjDataItemMap apCache;
|
|
if(this->__CheckCache(&apCache) == GJ_OK)
|
|
{
|
|
if(bNow) (*papOutput) = apCache;
|
|
else (pOutputObj->*OutputCallback)(apCache, pOutputData);
|
|
return GJ_OK;
|
|
}
|
|
}
|
|
|
|
// access user or global data store items
|
|
const std::string sUserData = m_iType ?
|
|
"&username=" + m_pAPI->GetProcUserName() +
|
|
"&user_token=" + m_pAPI->GetProcUserToken() :
|
|
"";
|
|
|
|
// send get data store item keys request
|
|
std::string sResponse;
|
|
if(m_pNetwork->SendRequest("/data-store/get-keys/"
|
|
"?game_id=" + m_pAPI->GetProcGameID() +
|
|
sUserData, bNow ? &sResponse : NULL, this, &gjAPI::gjInterDataStore::__Process, NULL, GJ_NETWORK_OUTPUT_FW)) return GJ_REQUEST_FAILED;
|
|
|
|
if(bNow) return this->__Process(sResponse, NULL, papOutput);
|
|
return GJ_OK;
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
/* download a file from any URL */
|
|
template <typename T> int gjAPI::gjInterFile::__DownloadFile(const std::string& sURL, const std::string& sToFolder, const std::string& sFileNameOverwrite, std::string* psOutput, GJ_NETWORK_OUTPUT(std::string))
|
|
{
|
|
if(sURL == "" || sToFolder == "") return GJ_INVALID_INPUT;
|
|
|
|
const bool bNow = psOutput ? true : false;
|
|
|
|
// create output path
|
|
const std::string sFileName = (sFileNameOverwrite == "") ? sURL.substr(sURL.find_last_of("/\\")+1) : sFileNameOverwrite;
|
|
const std::string sToFile = sToFolder + "/" + sFileName;
|
|
|
|
// check for cached file
|
|
if(this->__CheckCache(sToFile) == GJ_OK)
|
|
{
|
|
if(bNow) (*psOutput) = sToFile;
|
|
else (pOutputObj->*OutputCallback)(sToFile, pOutputData);
|
|
return GJ_OK;
|
|
}
|
|
|
|
// create folder
|
|
gjAPI::UtilCreateFolder(sToFolder);
|
|
|
|
// download file
|
|
if(m_pNetwork->DownloadFile(sURL, sToFile, psOutput, this, &gjAPI::gjInterFile::__Process, NULL, GJ_NETWORK_OUTPUT_FW)) return GJ_REQUEST_FAILED;
|
|
|
|
if(bNow) this->__Process(*psOutput, NULL, NULL);
|
|
return GJ_OK;
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
/* login with specific user */
|
|
template <typename T> int gjAPI::__Login(const bool& bSession, const std::string& sUserName, const std::string& sUserToken, const bool& bNow, GJ_NETWORK_OUTPUT(int))
|
|
{
|
|
if(this->IsUserConnected()) return GJ_INVALID_CALL;
|
|
|
|
// check for missing credentials
|
|
if(sUserName == "" || sUserToken == "")
|
|
{
|
|
if(!bNow) (pOutputObj->*OutputCallback)(GJ_INVALID_INPUT, pOutputData);
|
|
return GJ_INVALID_INPUT;
|
|
}
|
|
|
|
// set main user data
|
|
m_sUserName = sUserName;
|
|
m_sUserToken = sUserToken;
|
|
m_sProcUserName = gjAPI::UtilEscapeString(m_sUserName);
|
|
m_sProcUserToken = gjAPI::UtilEscapeString(m_sUserToken);
|
|
|
|
// convert session parameter
|
|
void* pSession = I_TO_P(bSession ? 1 : 0);
|
|
|
|
// authenticate user
|
|
std::string sResponse;
|
|
if(m_pNetwork->SendRequest("/users/auth/"
|
|
"?game_id=" + m_sProcGameID +
|
|
"&username=" + m_sProcUserName +
|
|
"&user_token=" + m_sProcUserToken,
|
|
bNow ? &sResponse : NULL, this, &gjAPI::__LoginCallback, pSession, GJ_NETWORK_OUTPUT_FW)) return GJ_REQUEST_FAILED;
|
|
|
|
if(bNow) return this->__LoginCallback(sResponse, pSession, NULL);
|
|
return GJ_OK;
|
|
}
|
|
|
|
template <typename T> int gjAPI::__Login(const bool& bSession, const std::string& sCredPath, const bool& bNow, GJ_NETWORK_OUTPUT(int))
|
|
{
|
|
// open credentials file
|
|
std::FILE* pFile = std::fopen(sCredPath.c_str(), "rb");
|
|
if(!pFile) return GJ_FILE_ERROR;
|
|
|
|
char acName[128], acToken[128];
|
|
char* pcEnd;
|
|
|
|
// get user name
|
|
std::fscanf(pFile, "%127[^\n]%*c", acName);
|
|
pcEnd = std::strchr(acName, 13);
|
|
if(pcEnd) *pcEnd = '\0';
|
|
|
|
// get user token
|
|
std::fscanf(pFile, "%127[^\n]%*c", acToken);
|
|
pcEnd = std::strchr(acToken, 13);
|
|
if(pcEnd) *pcEnd = '\0';
|
|
|
|
// close file and login
|
|
std::fclose(pFile);
|
|
return this->__Login(bSession, acName, acToken, bNow, GJ_NETWORK_OUTPUT_FW);
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
/* post-include because of generic dependencies */
|
|
#include "gjNetwork.hpp"
|
|
#include "gjUser.h"
|
|
#include "gjTrophy.h"
|
|
#include "gjScore.h"
|
|
#include "gjDataItem.h"
|
|
|
|
|
|
#endif /* _GJ_GUARD_API_H_ */ |