/////////////////////////////////////////////////////////////////// //*-------------------------------------------------------------*// //| 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 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 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 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 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 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 int __SetData(const std::string& sData, const bool& bNow, GJ_NETWORK_OUTPUT(gjDataItemPtr)); template int __SetDataBase64(void* pData, const size_t& iSize, const bool& bNow, GJ_NETWORK_OUTPUT(gjDataItemPtr)); template int __GetData(std::string* psOutput, GJ_NETWORK_OUTPUT(std::string)); template int __GetDataBase64(void* pTarget, const size_t& iSize, const bool& bNow, GJ_NETWORK_OUTPUT(gjVoidPtr)); template 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 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 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 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 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 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_ */