299 lines
14 KiB
C
299 lines
14 KiB
C
|
///////////////////////////////////////////////////////////////////
|
||
|
//*-------------------------------------------------------------*//
|
||
|
//| Part of the Game Jolt API C++ Library (http://gamejolt.com) |//
|
||
|
//*-------------------------------------------------------------*//
|
||
|
//| Released under the zlib License |//
|
||
|
//| More information available in the readme file |//
|
||
|
//*-------------------------------------------------------------*//
|
||
|
///////////////////////////////////////////////////////////////////
|
||
|
#pragma once
|
||
|
#ifndef _GJ_GUARD_DATAITEM_H_
|
||
|
#define _GJ_GUARD_DATAITEM_H_
|
||
|
|
||
|
|
||
|
// ****************************************************************
|
||
|
/*! Data store item class.\n
|
||
|
* http://gamejolt.com/api/doc/game/data-store/
|
||
|
* \brief Data Store Item Object
|
||
|
* \bug Data store items are not UTF-8 compatible (server-side),\n
|
||
|
* if you have problems with string data, use Base64 instead */
|
||
|
class gjDataItem final
|
||
|
{
|
||
|
private:
|
||
|
std::string m_sKey; //!< unique key of this item
|
||
|
std::string m_sData; //!< semi-cached data
|
||
|
|
||
|
int m_iType; //!< type of this item (0 = global, 1 = user)
|
||
|
|
||
|
std::string m_sVerify; //!< temporary verification data (helper)
|
||
|
void* m_pTarget; //!< last target for binary data (helper)
|
||
|
|
||
|
gjAPI* m_pAPI; //!< main interface access pointer
|
||
|
|
||
|
|
||
|
public:
|
||
|
gjDataItem(const gjData& aDataItemData, const int& iType, gjAPI* pAPI)noexcept;
|
||
|
|
||
|
/*! \name Set Data Request */
|
||
|
//! @{
|
||
|
/*! Set data of this data store item through an API request.\n
|
||
|
* May does nothing, if this is an user item and the same data was already sent.
|
||
|
* \pre Login maybe required
|
||
|
* \note \b -Now blocks, \b -Call uses non-blocking callbacks
|
||
|
* \param sData Data to send
|
||
|
* \return **GJ_OK** on success\n
|
||
|
* **GJ_REQUEST_FAILED** if request was unsuccessful\n
|
||
|
* **GJ_REQUEST_CANCELED** if this is an user item and the same data was already sent\n
|
||
|
* **GJ_NOT_CONNECTED** if connection/login is missing\n
|
||
|
* (see #GJ_ERROR) */
|
||
|
inline int SetDataNow(const std::string& sData) {return this->__SetData(sData, true, GJ_NETWORK_NULL_API(gjDataItemPtr));}
|
||
|
inline int SetDataCall(const std::string& sData) {return this->__SetData(sData, false, GJ_NETWORK_NULL_API(gjDataItemPtr));}
|
||
|
template <typename T> inline int SetDataCall(const std::string& sData, GJ_NETWORK_OUTPUT(gjDataItemPtr)) {return this->__SetData(sData, false, GJ_NETWORK_OUTPUT_FW);}
|
||
|
//! @}
|
||
|
|
||
|
/*! \name Set Data Request Base64 */
|
||
|
//! @{
|
||
|
/*! Like \link SetDataNow SetData\endlink\n
|
||
|
* Allows to send data in binary form.
|
||
|
* \pre Login maybe required
|
||
|
* \note \b -Now blocks, \b -Call uses non-blocking callbacks
|
||
|
* \param pData Data in binary form to send
|
||
|
* \param iSize Size of the data
|
||
|
* \return **GJ_OK** on success\n
|
||
|
* **GJ_REQUEST_FAILED** if request was unsuccessful\n
|
||
|
* **GJ_REQUEST_CANCELED** if this is an user item and the same data was already sent\n
|
||
|
* **GJ_NOT_CONNECTED** if connection/login is missing\n
|
||
|
* (see #GJ_ERROR) */
|
||
|
inline int SetDataBase64Now(void* pData, const size_t& iSize) {return this->__SetDataBase64(pData, iSize, true, GJ_NETWORK_NULL_API(gjDataItemPtr));}
|
||
|
inline int SetDataBase64Call(void* pData, const size_t& iSize) {return this->__SetDataBase64(pData, iSize, false, GJ_NETWORK_NULL_API(gjDataItemPtr));}
|
||
|
template <typename T> inline int SetDataBase64Call(void* pData, const size_t& iSize, GJ_NETWORK_OUTPUT(gjDataItemPtr)) {return this->__SetDataBase64(pData, iSize, false, GJ_NETWORK_OUTPUT_FW);}
|
||
|
//! @}
|
||
|
|
||
|
/*! \name Get Data Request */
|
||
|
//! @{
|
||
|
/*! Get data of this data store item through an API request.
|
||
|
* \pre Login maybe required
|
||
|
* \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
|
||
|
* (see #GJ_ERROR) */
|
||
|
inline int GetDataNow(std::string* psOutput) {if(!psOutput) return GJ_INVALID_INPUT; return this->__GetData(psOutput, GJ_NETWORK_NULL_API(std::string));}
|
||
|
template <typename T> inline int GetDataCall(GJ_NETWORK_OUTPUT(std::string)) {return this->__GetData(NULL, GJ_NETWORK_OUTPUT_FW);}
|
||
|
//! @}
|
||
|
|
||
|
/*! \name Get Data Request Base64 */
|
||
|
//! @{
|
||
|
/*! Like \link GetDataNow GetData\endlink\n
|
||
|
* Allows to get data in binary form.
|
||
|
* \pre Login maybe required
|
||
|
* \note \b -Now blocks, \b -Call uses non-blocking callbacks
|
||
|
* \param pTarget Pointer to the target
|
||
|
* \param iSize Size of the target
|
||
|
* \return **GJ_OK** on success\n
|
||
|
* **GJ_REQUEST_FAILED** if request was unsuccessful\n
|
||
|
* **GJ_NOT_CONNECTED** if connection/login is missing\n
|
||
|
* (see #GJ_ERROR) */
|
||
|
inline int GetDataBase64Now(void* pTarget, const size_t& iSize) {if(!pTarget || iSize <= 0) return GJ_INVALID_INPUT; return this->__GetDataBase64(pTarget, iSize, true, GJ_NETWORK_NULL_API(gjVoidPtr));}
|
||
|
inline int GetDataBase64Call(void* pTarget, const size_t& iSize) {if(!pTarget || iSize <= 0) return GJ_INVALID_INPUT; return this->__GetDataBase64(pTarget, iSize, false, GJ_NETWORK_NULL_API(gjVoidPtr));}
|
||
|
template <typename T> inline int GetDataBase64Call(void* pTarget, const size_t& iSize, GJ_NETWORK_OUTPUT(gjVoidPtr)) {if(!pTarget || iSize <= 0) return GJ_INVALID_INPUT; return this->__GetDataBase64(pTarget, iSize, false, GJ_NETWORK_OUTPUT_FW);}
|
||
|
//! @}
|
||
|
|
||
|
/*! \name Remove Request */
|
||
|
//! @{
|
||
|
/*! Clears/Removes the data store item through an API request.\n
|
||
|
* \pre Login maybe required
|
||
|
* \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
|
||
|
* (see #GJ_ERROR) */
|
||
|
inline int RemoveNow() {return this->__Remove(true, GJ_NETWORK_NULL_API(gjDataItemPtr));}
|
||
|
inline int RemoveCall() {return this->__Remove(false, GJ_NETWORK_NULL_API(gjDataItemPtr));}
|
||
|
template <typename T> inline int RemoveCall(GJ_NETWORK_OUTPUT(gjDataItemPtr)) {return this->__Remove(false, GJ_NETWORK_OUTPUT_FW);}
|
||
|
//! @}
|
||
|
|
||
|
/*! \name Get Attributes */
|
||
|
//! @{
|
||
|
inline const std::string& GetKey()const {return m_sKey;} //!< \copybrief m_sKey
|
||
|
inline const int& GetType()const {return m_iType;} //!< \copybrief m_iType
|
||
|
/*! */ //! @}
|
||
|
|
||
|
|
||
|
private:
|
||
|
DISABLE_COPY(gjDataItem)
|
||
|
|
||
|
/*! \name Superior Request Functions */
|
||
|
//! @{
|
||
|
template <typename T> int __SetData(const std::string& sData, const bool& bNow, GJ_NETWORK_OUTPUT(gjDataItemPtr));
|
||
|
template <typename T> int __SetDataBase64(void* pData, const size_t& iSize, const bool& bNow, GJ_NETWORK_OUTPUT(gjDataItemPtr));
|
||
|
template <typename T> int __GetData(std::string* psOutput, GJ_NETWORK_OUTPUT(std::string));
|
||
|
template <typename T> int __GetDataBase64(void* pTarget, const size_t& iSize, const bool& bNow, GJ_NETWORK_OUTPUT(gjVoidPtr));
|
||
|
template <typename T> int __Remove(const bool& bNow, GJ_NETWORK_OUTPUT(gjDataItemPtr));
|
||
|
//! @}
|
||
|
|
||
|
/*! \name Callback Functions */
|
||
|
//! @{
|
||
|
int __SetDataCallback(const std::string& sData, void* pAdd, gjDataItemPtr* ppOutput);
|
||
|
int __GetDataCallback(const std::string& sData, void* pAdd, std::string* psOutput);
|
||
|
int __GetDataBase64Callback(const std::string& sData, void* pAdd, gjVoidPtr* ppOutput);
|
||
|
int __RemoveCallback(const std::string& sData, void* pAdd, gjDataItemPtr* ppOutput);
|
||
|
//! @}
|
||
|
};
|
||
|
|
||
|
|
||
|
// ****************************************************************
|
||
|
/* set data of this data store item */
|
||
|
template <typename T> int gjDataItem::__SetData(const std::string& sData, const bool& bNow, GJ_NETWORK_OUTPUT(gjDataItemPtr))
|
||
|
{
|
||
|
if(!m_pAPI->IsUserConnected() && m_iType) return GJ_NOT_CONNECTED;
|
||
|
|
||
|
// cancel request if data was already sent
|
||
|
if(sData == m_sData && m_iType) return GJ_REQUEST_CANCELED;
|
||
|
|
||
|
// set verification data
|
||
|
m_sVerify = sData;
|
||
|
|
||
|
// access user or global data store item
|
||
|
const std::string sUserData = m_iType ?
|
||
|
"&username=" + m_pAPI->GetProcUserName() +
|
||
|
"&user_token=" + m_pAPI->GetProcUserToken() :
|
||
|
"";
|
||
|
|
||
|
// send set data store request
|
||
|
std::string sResponse;
|
||
|
if(m_pAPI->SendRequest("/data-store/set/"
|
||
|
"?game_id=" + m_pAPI->GetProcGameID() +
|
||
|
"&key=" + gjAPI::UtilEscapeString(m_sKey) +
|
||
|
sUserData + "&POST" + sData, bNow ? &sResponse : NULL, this, &gjDataItem::__SetDataCallback, &m_sVerify, GJ_NETWORK_OUTPUT_FW)) return GJ_REQUEST_FAILED;
|
||
|
|
||
|
if(bNow) return this->__SetDataCallback(sResponse, &m_sVerify, NULL);
|
||
|
return GJ_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ****************************************************************
|
||
|
/* set Base64 data of this data store item */
|
||
|
template <typename T> int gjDataItem::__SetDataBase64(void* pData, const size_t& iSize, const bool& bNow, GJ_NETWORK_OUTPUT(gjDataItemPtr))
|
||
|
{
|
||
|
if(!m_pAPI->IsUserConnected() && m_iType) return GJ_NOT_CONNECTED;
|
||
|
if(!pData || iSize <= 0) return GJ_INVALID_INPUT;
|
||
|
|
||
|
const size_t iNeed = base64_needed(iSize);
|
||
|
|
||
|
// convert binary data to Base64 string
|
||
|
char* pcBase64 = new char[iNeed];
|
||
|
base64_encode((unsigned char*)pData, iSize, pcBase64, iNeed);
|
||
|
|
||
|
// execute set data function with Base64 string
|
||
|
const int iReturn = this->__SetData(pcBase64, bNow, GJ_NETWORK_OUTPUT_FW);
|
||
|
SAFE_DELETE_ARRAY(pcBase64)
|
||
|
|
||
|
return iReturn;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ****************************************************************
|
||
|
/* get data of this data store item */
|
||
|
template <typename T> int gjDataItem::__GetData(std::string* psOutput, GJ_NETWORK_OUTPUT(std::string))
|
||
|
{
|
||
|
if(!m_pAPI->IsUserConnected() && m_iType) return GJ_NOT_CONNECTED;
|
||
|
|
||
|
const bool bNow = psOutput ? true : false;
|
||
|
|
||
|
// check for cached data
|
||
|
if(m_iType)
|
||
|
{
|
||
|
if(m_sData.length())
|
||
|
{
|
||
|
if(bNow) (*psOutput) = m_sData;
|
||
|
else (pOutputObj->*OutputCallback)(m_sData, pOutputData);
|
||
|
return GJ_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// access user or global data store item
|
||
|
const std::string sUserData = m_iType ?
|
||
|
"&username=" + m_pAPI->GetProcUserName() +
|
||
|
"&user_token=" + m_pAPI->GetProcUserToken() :
|
||
|
"";
|
||
|
|
||
|
// send get data store request
|
||
|
std::string sResponse;
|
||
|
if(m_pAPI->SendRequest("/data-store/"
|
||
|
"?game_id=" + m_pAPI->GetProcGameID() +
|
||
|
"&key=" + gjAPI::UtilEscapeString(m_sKey) +
|
||
|
"&format=" + "dump" +
|
||
|
sUserData, bNow ? &sResponse : NULL, this, &gjDataItem::__GetDataCallback, NULL, GJ_NETWORK_OUTPUT_FW)) return GJ_REQUEST_FAILED;
|
||
|
|
||
|
if(bNow) return this->__GetDataCallback(sResponse, NULL, psOutput);
|
||
|
return GJ_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ****************************************************************
|
||
|
/* get Base64 data of this data store item */
|
||
|
template <typename T> int gjDataItem::__GetDataBase64(void* pTarget, const size_t& iSize, const bool& bNow, GJ_NETWORK_OUTPUT(gjVoidPtr))
|
||
|
{
|
||
|
if(!m_pAPI->IsUserConnected() && m_iType) return GJ_NOT_CONNECTED;
|
||
|
if(!pTarget || iSize <= 0) return GJ_INVALID_INPUT;
|
||
|
|
||
|
// save last target
|
||
|
m_pTarget = pTarget;
|
||
|
|
||
|
// check for cached data
|
||
|
if(m_iType)
|
||
|
{
|
||
|
if(m_sData.length())
|
||
|
{
|
||
|
// convert Base64 string to binary data
|
||
|
base64_decode(m_sData.c_str(), (unsigned char*)m_pTarget, iSize);
|
||
|
if(!bNow) (pOutputObj->*OutputCallback)(m_pTarget, pOutputData);
|
||
|
return GJ_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// access user or global data store item
|
||
|
const std::string sUserData = m_iType ?
|
||
|
"&username=" + m_pAPI->GetProcUserName() +
|
||
|
"&user_token=" + m_pAPI->GetProcUserToken() :
|
||
|
"";
|
||
|
|
||
|
// send get data store request
|
||
|
std::string sResponse;
|
||
|
if(m_pAPI->SendRequest("/data-store/"
|
||
|
"?game_id=" + m_pAPI->GetProcGameID() +
|
||
|
"&key=" + gjAPI::UtilEscapeString(m_sKey) +
|
||
|
"&format=" + "dump" +
|
||
|
sUserData, bNow ? &sResponse : NULL, this, &gjDataItem::__GetDataBase64Callback, I_TO_P(iSize), GJ_NETWORK_OUTPUT_FW)) return GJ_REQUEST_FAILED;
|
||
|
|
||
|
if(bNow) return this->__GetDataBase64Callback(sResponse, I_TO_P(iSize), NULL);
|
||
|
return GJ_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ****************************************************************
|
||
|
/* clear/remove this data store item */
|
||
|
template <typename T> int gjDataItem::__Remove(const bool& bNow, GJ_NETWORK_OUTPUT(gjDataItemPtr))
|
||
|
{
|
||
|
if(!m_pAPI->IsUserConnected() && m_iType) return GJ_NOT_CONNECTED;
|
||
|
|
||
|
// access user or global data store item
|
||
|
const std::string sUserData = m_iType ?
|
||
|
"&username=" + m_pAPI->GetProcUserName() +
|
||
|
"&user_token=" + m_pAPI->GetProcUserToken() :
|
||
|
"";
|
||
|
|
||
|
// send remove data store request
|
||
|
std::string sResponse;
|
||
|
if(m_pAPI->SendRequest("/data-store/remove/"
|
||
|
"?game_id=" + m_pAPI->GetProcGameID() +
|
||
|
"&key=" + gjAPI::UtilEscapeString(m_sKey) +
|
||
|
sUserData, bNow ? &sResponse : NULL, this, &gjDataItem::__RemoveCallback, NULL, GJ_NETWORK_OUTPUT_FW)) return GJ_REQUEST_FAILED;
|
||
|
|
||
|
if(bNow) return this->__RemoveCallback(sResponse, NULL, NULL);
|
||
|
return GJ_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif /* _GJ_GUARD_DATAITEM_H_ */
|