mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 13:47:58 +03:00
428 lines
14 KiB
C
428 lines
14 KiB
C
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "sakeMain.h"
|
|
#include "sakeRequest.h"
|
|
#include "../common/gsAvailable.h"
|
|
#include "../common/gsCore.h"
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// General
|
|
|
|
gsi_char gSakeUploadUrlOverride[SAKE_MAX_URL_LENGTH];
|
|
gsi_char gSakeDownloadUrlOverride[SAKE_MAX_URL_LENGTH];
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
SAKEStartupResult SAKE_CALL sakeStartup(SAKE * sakePtr)
|
|
{
|
|
SAKE sake;
|
|
|
|
GS_ASSERT(sakePtr);
|
|
|
|
// check for availability
|
|
if(__GSIACResult != GSIACAvailable)
|
|
return SAKEStartupResult_NOT_AVAILABLE;
|
|
|
|
// check that the core is initialized
|
|
if(gsCoreIsShutdown())
|
|
return SAKEStartupResult_CORE_SHUTDOWN;
|
|
|
|
// allocate the sake object
|
|
sake = (SAKE)gsimalloc(sizeof(SAKEInternal));
|
|
if(sake == NULL)
|
|
return SAKEStartupResult_OUT_OF_MEMORY;
|
|
|
|
// init the sake object
|
|
memset(sake, 0, sizeof(SAKEInternal));
|
|
|
|
// store the object in the user pointer
|
|
*sakePtr = sake;
|
|
|
|
return SAKEStartupResult_SUCCESS;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void SAKE_CALL sakeShutdown(SAKE sake)
|
|
{
|
|
GS_ASSERT(sake);
|
|
|
|
//TODO: ensure that there are no pending operations
|
|
// that might reference this object
|
|
|
|
// free the struct
|
|
gsifree(sake);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Authentication
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void SAKE_CALL sakeSetGame(SAKE sake, const gsi_char * gameName, int gameId, const gsi_char *secretKey)
|
|
{
|
|
GS_ASSERT(sake);
|
|
GS_ASSERT(gameName && (_tcslen(gameName) <= SAKEI_GAME_NAME_LENGTH));
|
|
GS_ASSERT(gameId >= 0);
|
|
GS_ASSERT(secretKey && (_tcslen(secretKey) <= SAKEI_SECRET_KEY_LENGTH));
|
|
|
|
#ifdef GSI_UNICODE
|
|
// convert gamename and secretkey to ascii for executing requests
|
|
UCS2ToAsciiString(gameName, sake->mGameName);
|
|
UCS2ToAsciiString(secretKey, sake->mSecretKey);
|
|
#else
|
|
strcpy(sake->mGameName, gameName);
|
|
strcpy(sake->mSecretKey, secretKey);
|
|
#endif
|
|
|
|
sake->mGameId = gameId;
|
|
sake->mIsGameAuthenticated = gsi_true;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void SAKE_CALL sakeSetProfile(SAKE sake, int profileId, const char *loginTicket)
|
|
{
|
|
GS_ASSERT(sake);
|
|
GS_ASSERT(loginTicket);
|
|
GS_ASSERT(strlen(loginTicket) == SAKEI_LOGIN_TICKET_LENGTH);
|
|
|
|
sake->mProfileId = profileId;
|
|
memcpy(sake->mLoginTicket, loginTicket, SAKEI_LOGIN_TICKET_LENGTH + 1);
|
|
sake->mIsProfileAuthenticated = gsi_true;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Requests
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
SAKEStartRequestResult SAKE_CALL sakeGetStartRequestResult(SAKE sake)
|
|
{
|
|
GS_ASSERT(sake);
|
|
|
|
return sake->mStartRequestResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static SAKERequest SAKE_CALL sakeiRunRequest(SAKE sake, void *input,
|
|
SAKERequestCallback callback, void *userData,
|
|
SAKEIRequestType type,
|
|
SAKEStartRequestResult (*startRequestFunc)(SAKERequest request))
|
|
{
|
|
SAKERequest request;
|
|
|
|
GS_ASSERT(sake);
|
|
|
|
request = sakeiInitRequest(sake, type, input, callback, userData);
|
|
if(!request)
|
|
return NULL;
|
|
|
|
sake->mStartRequestResult = startRequestFunc(request);
|
|
if(sake->mStartRequestResult != SAKEStartRequestResult_SUCCESS)
|
|
{
|
|
sakeiFreeRequest(request);
|
|
return NULL;
|
|
}
|
|
|
|
return request;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
SAKERequest SAKE_CALL sakeCreateRecord(SAKE sake, SAKECreateRecordInput *input, SAKERequestCallback callback, void *userData)
|
|
{
|
|
return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_CREATE_RECORD, sakeiStartCreateRecordRequest);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
SAKERequest SAKE_CALL sakeUpdateRecord(SAKE sake, SAKEUpdateRecordInput *input, SAKERequestCallback callback, void *userData)
|
|
{
|
|
return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_UPDATE_RECORD, sakeiStartUpdateRecordRequest);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
SAKERequest SAKE_CALL sakeDeleteRecord(SAKE sake, SAKEDeleteRecordInput *input, SAKERequestCallback callback, void *userData)
|
|
{
|
|
return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_DELETE_RECORD, sakeiStartDeleteRecordRequest);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
SAKERequest SAKE_CALL sakeSearchForRecords(SAKE sake, SAKESearchForRecordsInput *input, SAKERequestCallback callback, void *userData)
|
|
{
|
|
return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_SEARCH_FOR_RECORDS, sakeiStartSearchForRecordsRequest);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
SAKERequest SAKE_CALL sakeGetMyRecords(SAKE sake, SAKEGetMyRecordsInput *input, SAKERequestCallback callback, void *userData)
|
|
{
|
|
return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_GET_MY_RECORDS, sakeiStartGetMyRecordsRequest);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
SAKERequest SAKE_CALL sakeGetSpecificRecords(SAKE sake, SAKEGetSpecificRecordsInput *input, SAKERequestCallback callback, void *userData)
|
|
{
|
|
return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_GET_SPECIFIC_RECORDS, sakeiStartGetSpecificRecordsRequest);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
SAKERequest SAKE_CALL sakeGetRandomRecord(SAKE sake, SAKEGetRandomRecordInput *input, SAKERequestCallback callback, void *userData)
|
|
{
|
|
return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_GET_RANDOM_RECORD, sakeiStartGetRandomRecordRequest);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
SAKERequest SAKE_CALL sakeRateRecord(SAKE sake, SAKERateRecordInput *input, SAKERequestCallback callback, void *userData)
|
|
{
|
|
return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_RATE_RECORD, sakeiStartRateRecordRequest);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
SAKERequest SAKE_CALL sakeGetRecordLimit(SAKE sake, SAKEGetRecordLimitInput *input, SAKERequestCallback callback, void *userData)
|
|
{
|
|
return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_GET_RECORD_LIMIT, sakeiStartGetRecordLimitRequest);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
SAKERequest SAKE_CALL sakeGetRecordCount(SAKE sake, SAKEGetRecordCountInput *input, SAKERequestCallback callback, void *userData)
|
|
{
|
|
return sakeiRunRequest(sake, input, callback, userData, SAKEIRequestType_GET_RECORD_COUNT, sakeiStartGetRecordCountRequest);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// read request utility
|
|
SAKEField * SAKE_CALL sakeGetFieldByName(const char *name, SAKEField *fields, int numFields)
|
|
{
|
|
int i;
|
|
|
|
GS_ASSERT(name);
|
|
GS_ASSERT(fields);
|
|
GS_ASSERT(numFields >= 0);
|
|
|
|
for(i = 0 ; i < numFields ; i++)
|
|
{
|
|
if(strcmp(fields[i].mName, name) == 0)
|
|
return &fields[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Files
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Set the URL format to be used by sakeGetFileDownloadUrl
|
|
gsi_bool SAKE_CALL sakeSetFileDownloadURL(SAKE sake, gsi_char url[SAKE_MAX_URL_LENGTH])
|
|
{
|
|
GS_ASSERT(sake);
|
|
GS_ASSERT(url);
|
|
|
|
if(!sake || !url)
|
|
return gsi_false;
|
|
|
|
_tcscpy(gSakeDownloadUrlOverride, url);
|
|
return gsi_true;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
gsi_bool SAKE_CALL sakeGetFileDownloadURL(SAKE sake, int fileId, gsi_char url[SAKE_MAX_URL_LENGTH])
|
|
{
|
|
int rcode;
|
|
|
|
GS_ASSERT(sake);
|
|
GS_ASSERT(fileId != 0);
|
|
GS_ASSERT(url);
|
|
GS_ASSERT(sake->mIsGameAuthenticated);
|
|
GS_ASSERT(sake->mIsProfileAuthenticated);
|
|
|
|
if(!sake || !url || !sake->mIsGameAuthenticated || !sake->mIsProfileAuthenticated)
|
|
return gsi_false;
|
|
|
|
if (gSakeDownloadUrlOverride[0] != '\0')
|
|
{
|
|
rcode = _tsnprintf(url, SAKE_MAX_URL_LENGTH, _T("%s?gameid=%d&pid=%d"),
|
|
gSakeDownloadUrlOverride, sake->mGameId, sake->mProfileId);
|
|
}
|
|
else
|
|
{
|
|
#ifdef GSI_UNICODE
|
|
{
|
|
// use capital %S to convert the gamename to a wide string
|
|
rcode = _tsnprintf(url, SAKE_MAX_URL_LENGTH, _T("http://%S.sake.%S/SakeFileServer/download.aspx?fileid=%d&gameid=%d&pid=%d"),
|
|
sake->mGameName, GSI_DOMAIN_NAME, fileId, sake->mGameId, sake->mProfileId);
|
|
}
|
|
#else
|
|
{
|
|
rcode = _tsnprintf(url, SAKE_MAX_URL_LENGTH, _T("http://%s.sake.%s/SakeFileServer/download.aspx?fileid=%d&gameid=%d&pid=%d"),
|
|
sake->mGameName, GSI_DOMAIN_NAME, fileId, sake->mGameId, sake->mProfileId);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if(rcode < 0)
|
|
return gsi_false;
|
|
return gsi_true;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
gsi_bool SAKE_CALL sakeSetFileUploadURL(SAKE sake, gsi_char url[SAKE_MAX_URL_LENGTH])
|
|
{
|
|
GS_ASSERT(sake);
|
|
GS_ASSERT(url);
|
|
|
|
if(!sake || !url)
|
|
return gsi_false;
|
|
|
|
_tcscpy(gSakeUploadUrlOverride, url);
|
|
return gsi_true;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
gsi_bool SAKE_CALL sakeGetFileUploadURL(SAKE sake, gsi_char url[SAKE_MAX_URL_LENGTH])
|
|
{
|
|
int rcode;
|
|
|
|
GS_ASSERT(sake);
|
|
GS_ASSERT(url);
|
|
GS_ASSERT(sake->mIsGameAuthenticated);
|
|
GS_ASSERT(sake->mIsProfileAuthenticated);
|
|
|
|
if(!sake || !url || !sake->mIsGameAuthenticated || !sake->mIsProfileAuthenticated)
|
|
return gsi_false;
|
|
|
|
if (gSakeUploadUrlOverride[0] != '\0')
|
|
{
|
|
rcode = _tsnprintf(url, SAKE_MAX_URL_LENGTH, _T("%s?gameid=%d&pid=%d"),
|
|
gSakeUploadUrlOverride, sake->mGameId, sake->mProfileId);
|
|
}
|
|
else
|
|
{
|
|
#ifdef GSI_UNICODE
|
|
{
|
|
// use capital %S to convert the gamename to a wide string
|
|
rcode = _tsnprintf(url, SAKE_MAX_URL_LENGTH, _T("http://%S.sake.%S/SakeFileServer/upload.aspx?gameid=%d&pid=%d"),
|
|
sake->mGameName, GSI_DOMAIN_NAME, sake->mGameId, sake->mProfileId);
|
|
}
|
|
#else
|
|
{
|
|
rcode = _tsnprintf(url, SAKE_MAX_URL_LENGTH, _T("http://%s.sake.%s/SakeFileServer/upload.aspx?gameid=%d&pid=%d"),
|
|
sake->mGameName, GSI_DOMAIN_NAME, sake->mGameId, sake->mProfileId);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if(rcode < 0)
|
|
return gsi_false;
|
|
return gsi_true;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static SAKEFileResult SAKE_CALL sakeiParseFileResult(int resultCode)
|
|
{
|
|
if(resultCode >= SAKEFileResult_UNKNOWN_ERROR)
|
|
return SAKEFileResult_UNKNOWN_ERROR;
|
|
return (SAKEFileResult)resultCode;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static gsi_bool SAKE_CALL sakeiGetHeaderValueInt(const char *headers, const char *headerName, int *value)
|
|
{
|
|
const char * header;
|
|
int rcode;
|
|
|
|
GS_ASSERT(headers);
|
|
GS_ASSERT(headerName);
|
|
GS_ASSERT(value);
|
|
#ifdef _DEBUG
|
|
// headerName must include the trailing colon
|
|
GS_ASSERT(headerName[strlen(headerName) - 1] == ':');
|
|
#endif
|
|
|
|
// find this header in the list of headers
|
|
header = strstr(headers, headerName);
|
|
if(header)
|
|
{
|
|
// skip the header name
|
|
header += strlen(headerName);
|
|
|
|
// scan in the result
|
|
rcode = sscanf(header, " %d", value);
|
|
if(rcode == 1)
|
|
return gsi_true;
|
|
}
|
|
|
|
return gsi_false;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
gsi_bool SAKE_CALL sakeGetFileResultFromHeaders(const char *headers, SAKEFileResult *result)
|
|
{
|
|
int resultCode;
|
|
gsi_bool foundResultCode;
|
|
|
|
foundResultCode = sakeiGetHeaderValueInt(headers, SAKE_FILE_RESULT_HEADER, &resultCode);
|
|
|
|
if(gsi_is_false(foundResultCode))
|
|
return gsi_false;
|
|
|
|
*result = sakeiParseFileResult(resultCode);
|
|
return gsi_true;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
gsi_bool SAKE_CALL sakeGetFileIdFromHeaders(const char *headers, int *fileId)
|
|
{
|
|
return sakeiGetHeaderValueInt(headers, SAKE_FILE_ID_HEADER, fileId);
|
|
}
|