From 5d942265f96d42f581828546f1ef0d4dbac30b72 Mon Sep 17 00:00:00 2001 From: Kyle Sanderson Date: Thu, 28 Feb 2013 21:51:49 +0000 Subject: [PATCH] Overhaul of ClientPrefs extension (bug 5538, r=asherkin). --- extensions/clientprefs/cookie.cpp | 190 +++++++++---------- extensions/clientprefs/cookie.h | 18 +- extensions/clientprefs/extension.cpp | 261 ++++++++++++++++----------- extensions/clientprefs/extension.h | 13 +- extensions/clientprefs/menus.cpp | 46 +---- extensions/clientprefs/menus.h | 5 +- extensions/clientprefs/natives.cpp | 76 ++------ extensions/clientprefs/query.cpp | 71 ++++---- extensions/clientprefs/query.h | 4 + 9 files changed, 325 insertions(+), 359 deletions(-) diff --git a/extensions/clientprefs/cookie.cpp b/extensions/clientprefs/cookie.cpp index 53ff2fdc..55a1b97a 100644 --- a/extensions/clientprefs/cookie.cpp +++ b/extensions/clientprefs/cookie.cpp @@ -41,6 +41,7 @@ CookieManager::CookieManager() { connected[i] = false; statsLoaded[i] = false; + statsPending[i] = false; } cookieDataLoadedForward = NULL; @@ -51,10 +52,7 @@ CookieManager::~CookieManager(){} void CookieManager::Unload() { /* If clients are connected we should try save their data */ - - int maxclients = playerhelpers->GetMaxClients(); - - for (int i=1; i<=maxclients; i++) + for (int i = playerhelpers->GetMaxClients()+1; --i > 0;) { if (connected[i]) { @@ -63,20 +61,14 @@ void CookieManager::Unload() } /* Find all cookies and delete them */ - - SourceHook::List::iterator _iter; - Cookie *current; - _iter = cookieList.begin(); - - while (_iter != cookieList.end()) + for (SourceHook::List::iterator _iter = cookieList.begin(); _iter != cookieList.end(); _iter++) { current = (Cookie *)*_iter; if (current == NULL) { - _iter++; continue; } @@ -91,9 +83,9 @@ void CookieManager::Unload() g_ClientPrefs.cookieMutex->Unlock(); delete current; } - - _iter = cookieList.erase(_iter); } + + cookieList.clear(); } Cookie *CookieManager::FindCookie(const char *name) @@ -116,9 +108,7 @@ Cookie *CookieManager::CreateCookie(const char *name, const char *description, C if (pCookie != NULL) { /* Update data fields to the provided values */ - strncpy(pCookie->description, description, MAX_DESC_LENGTH); - pCookie->description[MAX_DESC_LENGTH-1] = '\0'; - + UTIL_strncpy(pCookie->description, description, MAX_DESC_LENGTH); pCookie->access = access; return pCookie; @@ -126,18 +116,15 @@ Cookie *CookieManager::CreateCookie(const char *name, const char *description, C /* First time cookie - Create from scratch */ pCookie = new Cookie(name, description, access); + pCookie->usedInQuery++; + + /* Attempt to insert cookie into the db and get its ID num */ + TQueryOp *op = new TQueryOp(Query_InsertCookie, pCookie); + op->m_params.cookie = pCookie; + cookieTrie.insert(name, pCookie); cookieList.push_back(pCookie); - /* Attempt to insert cookie into the db and get its ID num */ - - TQueryOp *op = new TQueryOp(Query_InsertCookie, pCookie); - - g_ClientPrefs.cookieMutex->Lock(); - op->m_params.cookie = pCookie; - pCookie->usedInQuery++; - g_ClientPrefs.cookieMutex->Unlock(); - g_ClientPrefs.AddQueryToQueue(op); return pCookie; @@ -145,8 +132,6 @@ Cookie *CookieManager::CreateCookie(const char *name, const char *description, C bool CookieManager::GetCookieValue(Cookie *pCookie, int client, char **value) { - assert(pCookie); - CookieData *data = pCookie->data[client]; /* Check if a value has been set before */ @@ -156,8 +141,8 @@ bool CookieManager::GetCookieValue(Cookie *pCookie, int client, char **value) data->parent = pCookie; clientData[client].push_back(data); pCookie->data[client] = data; - data->changed = true; - data->timestamp = time(NULL); + data->changed = false; + data->timestamp = 0; } *value = &data->value[0]; @@ -167,8 +152,6 @@ bool CookieManager::GetCookieValue(Cookie *pCookie, int client, char **value) bool CookieManager::SetCookieValue(Cookie *pCookie, int client, const char *value) { - assert(pCookie); - CookieData *data = pCookie->data[client]; if (data == NULL) @@ -180,8 +163,7 @@ bool CookieManager::SetCookieValue(Cookie *pCookie, int client, const char *valu } else { - strncpy(data->value, value, MAX_VALUE_LENGTH); - data->value[MAX_VALUE_LENGTH-1] = '\0'; + UTIL_strncpy(data->value, value, MAX_VALUE_LENGTH); } data->changed = true; @@ -200,9 +182,12 @@ void CookieManager::OnClientAuthorized(int client, const char *authstring) } connected[client] = true; + statsPending[client] = true; + g_ClientPrefs.AttemptReconnection(); + TQueryOp *op = new TQueryOp(Query_SelectData, player->GetSerial()); - strcpy(op->m_params.steamId, authstring); + UTIL_strncpy(op->m_params.steamId, authstring, MAX_NAME_LENGTH); g_ClientPrefs.AddQueryToQueue(op); } @@ -211,105 +196,103 @@ void CookieManager::OnClientDisconnecting(int client) { connected[client] = false; statsLoaded[client] = false; - - SourceHook::List::iterator _iter; + statsPending[client] = false; CookieData *current; - _iter = clientData[client].begin(); - - while (_iter != clientData[client].end()) + g_ClientPrefs.AttemptReconnection(); + + /* Save this cookie to the database */ + IGamePlayer *player = playerhelpers->GetGamePlayer(client); + const char *pAuth = NULL; + int dbId; + + if (player) { + pAuth = player->GetAuthString(); + } + + g_ClientPrefs.ClearQueryCache(player->GetSerial()); + + for (SourceHook::List::iterator _iter = clientData[client].begin();\ + _iter != clientData[client].end(); _iter++) + { + if (player == NULL || pAuth == NULL) + { + /* panic! */ + current->parent->data[client] = NULL; + delete current; + continue; + } + current = (CookieData *)*_iter; - - if (!current->changed) + dbId = current->parent->dbid; + + if (!current->changed || dbId == -1) { current->parent->data[client] = NULL; delete current; - _iter = clientData[client].erase(_iter); continue; } - /* Save this cookie to the database */ - IGamePlayer *player = playerhelpers->GetGamePlayer(client); - - if (player == NULL) - { - /* panic! */ - return; - } - - int dbId = current->parent->dbid; - - if (dbId == -1) - { - /* Insert/Find Query must be still running or failed. */ - return; - } - TQueryOp *op = new TQueryOp(Query_InsertData, client); - strcpy(op->m_params.steamId, player->GetAuthString()); + UTIL_strncpy(op->m_params.steamId, pAuth, MAX_NAME_LENGTH); op->m_params.cookieId = dbId; op->m_params.data = current; g_ClientPrefs.AddQueryToQueue(op); current->parent->data[client] = NULL; - - - /* We don't delete here, it will be removed when the query is completed */ - - _iter = clientData[client].erase(_iter); } + + clientData[client].clear(); } void CookieManager::ClientConnectCallback(int serial, IQuery *data) { int client; - IResultSet *results; /* Check validity of client */ if ((client = playerhelpers->GetClientFromSerial(serial)) == 0) { return; } - + statsPending[client] = false; + + IResultSet *results; /* Check validity of results */ if (data == NULL || (results = data->GetResultSet()) == NULL) { return; } + CookieData *pData; IResultRow *row; - do + unsigned int timestamp; + CookieAccess access; + + while (results->MoreRows() && ((row = results->FetchRow()) != NULL)) { - if ((row = results->FetchRow()) == NULL) - { - break; - } - - const char *name; + const char *name = ""; row->GetString(0, &name, NULL); - - const char *value; + + const char *value = ""; row->GetString(1, &value, NULL); - CookieData *pData = new CookieData(value); + pData = new CookieData(value); pData->changed = false; - unsigned int timestamp = 0; - row->GetInt(4, (int *)×tamp); - pData->timestamp = timestamp; + pData->timestamp = (row->GetInt(4, (int *)×tamp) == DBVal_Data) ? timestamp : 0; Cookie *parent = FindCookie(name); if (parent == NULL) { - const char *desc; + const char *desc = ""; row->GetString(2, &desc, NULL); - CookieAccess access = CookieAccess_Public; + access = CookieAccess_Public; row->GetInt(3, (int *)&access); parent = CreateCookie(name, desc, access); @@ -317,10 +300,8 @@ void CookieManager::ClientConnectCallback(int serial, IQuery *data) pData->parent = parent; parent->data[client] = pData; - clientData[client].push_back(pData); - - } while (results->MoreRows()); + } statsLoaded[client] = true; @@ -338,7 +319,7 @@ void CookieManager::InsertCookieCallback(Cookie *pCookie, int dbId) TQueryOp *op = new TQueryOp(Query_SelectId, pCookie); /* Put the cookie name into the steamId field to save space - Make sure we remember that it's there */ - strcpy(op->m_params.steamId, pCookie->name); + UTIL_strncpy(op->m_params.steamId, pCookie->name, MAX_NAME_LENGTH); g_ClientPrefs.AddQueryToQueue(op); } @@ -366,26 +347,31 @@ bool CookieManager::AreClientCookiesCached(int client) return statsLoaded[client]; } +bool CookieManager::AreClientCookiesPening(int client) +{ + return statsPending[client]; +} + void CookieManager::OnPluginDestroyed(IPlugin *plugin) { SourceHook::List *pList; if (plugin->GetProperty("SettingsMenuItems", (void **)&pList, true)) { - SourceHook::List::iterator p_iter = pList->begin(); char *name; - - while (p_iter != pList->end()) + ItemDrawInfo draw; + const char *info; + AutoMenuData * data; + unsigned itemcount; + + for (SourceHook::List::iterator p_iter = pList->begin(); p_iter != pList->end(); p_iter++) { name = (char *)*p_iter; - - p_iter = pList->erase(p_iter); //remove from this plugins list - - ItemDrawInfo draw; - - for (unsigned int i=0; iGetItemCount(); i++) + itemcount = clientMenu->GetItemCount(); + //remove from this plugins list + for (unsigned int i=0; i < itemcount; i++) { - const char *info = clientMenu->GetItemInfo(i, &draw); + info = clientMenu->GetItemInfo(i, &draw); if (info == NULL) { @@ -394,9 +380,7 @@ void CookieManager::OnPluginDestroyed(IPlugin *plugin) if (strcmp(draw.display, name) == 0) { - ItemDrawInfo draw; - const char *info = clientMenu->GetItemInfo(i, &draw); - AutoMenuData *data = (AutoMenuData *)strtoul(info, NULL, 16); + data = (AutoMenuData *)strtoul(info, NULL, 16); if (data->handler->forward != NULL) { @@ -410,15 +394,15 @@ void CookieManager::OnPluginDestroyed(IPlugin *plugin) } } - delete name; - } + delete [] name; + } + + pList->clear(); } } bool CookieManager::GetCookieTime(Cookie *pCookie, int client, time_t *value) { - assert(pCookie); - CookieData *data = pCookie->data[client]; /* Check if a value has been set before */ diff --git a/extensions/clientprefs/cookie.h b/extensions/clientprefs/cookie.h index fbebb38e..8da6ad6b 100644 --- a/extensions/clientprefs/cookie.h +++ b/extensions/clientprefs/cookie.h @@ -54,11 +54,10 @@ struct CookieData { CookieData(const char *value) { - strncpy(this->value, value, MAX_VALUE_LENGTH); - this->value[MAX_VALUE_LENGTH-1] = '\0'; + UTIL_strncpy(this->value, value, MAX_VALUE_LENGTH); } - char value[MAX_VALUE_LENGTH]; + char value[MAX_VALUE_LENGTH+1]; bool changed; time_t timestamp; Cookie *parent; @@ -68,10 +67,8 @@ struct Cookie { Cookie(const char *name, const char *description, CookieAccess access) { - strncpy(this->name, name, MAX_NAME_LENGTH); - this->name[MAX_NAME_LENGTH-1] = '\0'; - strncpy(this->description, description, MAX_DESC_LENGTH); - this->description[MAX_DESC_LENGTH-1] = '\0'; + UTIL_strncpy(this->name, name, MAX_NAME_LENGTH); + UTIL_strncpy(this->description, description, MAX_DESC_LENGTH); this->access = access; @@ -97,8 +94,8 @@ struct Cookie } } - char name[MAX_NAME_LENGTH]; - char description[MAX_DESC_LENGTH]; + char name[MAX_NAME_LENGTH+1]; + char description[MAX_DESC_LENGTH+1]; int dbid; CookieData *data[MAXCLIENTS+1]; CookieAccess access; @@ -133,6 +130,8 @@ public: bool AreClientCookiesCached(int client); void OnPluginDestroyed(IPlugin *plugin); + + bool AreClientCookiesPening(int client); public: IForward *cookieDataLoadedForward; @@ -145,6 +144,7 @@ private: bool connected[MAXCLIENTS+1]; bool statsLoaded[MAXCLIENTS+1]; + bool statsPending[MAXCLIENTS+1]; }; extern CookieManager g_CookieManager; diff --git a/extensions/clientprefs/extension.cpp b/extensions/clientprefs/extension.cpp index a3976fa9..f907ed5c 100644 --- a/extensions/clientprefs/extension.cpp +++ b/extensions/clientprefs/extension.cpp @@ -47,7 +47,6 @@ CookieTypeHandler g_CookieTypeHandler; HandleType_t g_CookieIterator = 0; CookieIteratorHandler g_CookieIteratorHandler; DbDriver g_DriverType; -static const DatabaseInfo *storage_local = NULL; bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late) { @@ -60,28 +59,19 @@ bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late) { DBInfo = dbi->FindDatabaseConf("default"); - if (DBInfo == NULL || - (strcmp(DBInfo->host, "localhost") == 0 && - strcmp(DBInfo->database, "sourcemod") == 0 && - strcmp(DBInfo->user, "root") == 0 && - strcmp(DBInfo->pass, "") == 0 && - strcmp(DBInfo->driver, "") == 0)) - { - storage_local = dbi->FindDatabaseConf("storage-local"); - if (DBInfo == NULL) - { - DBInfo = storage_local; - } - } - if (DBInfo == NULL) { - snprintf(error, maxlength, "Could not find \"clientprefs\" or \"default\" database configs"); - return false; + DBInfo = dbi->FindDatabaseConf("storage-local"); } } + + if (DBInfo == NULL) + { + snprintf(error, maxlength, "Could not find any suitable database configs"); + return false; + } - if (DBInfo->driver[0] != '\0') + if (DBInfo->driver && DBInfo->driver[0] != '\0') { Driver = dbi->FindOrLoadDriver(DBInfo->driver); } @@ -96,7 +86,6 @@ bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late) return false; } - Database = NULL; databaseLoading = true; TQueryOp *op = new TQueryOp(Query_Connect, 0); dbi->AddToThreadQueue(op, PrioQueue_High); @@ -136,19 +125,7 @@ bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late) if (late) { - int maxclients = playerhelpers->GetMaxClients(); - - for (int i = 1; i <= maxclients; i++) - { - IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(i); - - if (!pPlayer || !pPlayer->IsAuthorized()) - { - continue; - } - - g_CookieManager.OnClientAuthorized(i, pPlayer->GetAuthString()); - } + this->CatchLateLoadClients(); } return true; @@ -188,20 +165,37 @@ void ClientPrefs::SDK_OnUnload() if (Database != NULL) { Database->Close(); + Database = NULL; } - forwards->ReleaseForward(g_CookieManager.cookieDataLoadedForward); - - HandleSecurity sec = HandleSecurity(identity, identity); - HandleError err = handlesys->FreeHandle(g_CookieManager.clientMenu->GetHandle(), &sec); - if (HandleError_None != err) + if (g_CookieManager.cookieDataLoadedForward != NULL) { - g_pSM->LogError(myself, "Error %d when attempting to free client menu handle", err); + forwards->ReleaseForward(g_CookieManager.cookieDataLoadedForward); + g_CookieManager.cookieDataLoadedForward = NULL; } - phrases->Destroy(); + if (g_CookieManager.clientMenu != NULL) + { + Handle_t menuHandle = g_CookieManager.clientMenu->GetHandle(); + + if (menuHandle != BAD_HANDLE) + { + HandleSecurity sec = HandleSecurity(identity, identity); + HandleError err = handlesys->FreeHandle(menuHandle, &sec); + if (HandleError_None != err) + { + g_pSM->LogError(myself, "Error %d when attempting to free client menu handle", err); + } + } + + g_CookieManager.clientMenu = NULL; + } - sharesys->DestroyIdentity( identity ); + if (phrases != NULL) + { + phrases->Destroy(); + phrases = NULL; + } plsys->RemovePluginsListener(&g_CookieManager); playerhelpers->RemoveClientListener(&g_CookieManager); @@ -212,15 +206,23 @@ void ClientPrefs::SDK_OnUnload() void ClientPrefs::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax) { - if (Database == NULL && !databaseLoading) + this->AttemptReconnection(); +} + +void ClientPrefs::AttemptReconnection() +{ + if (Database || databaseLoading) { - g_pSM->LogMessage(myself, "Attempting to reconnect to database..."); - - databaseLoading = true; - - TQueryOp *op = new TQueryOp(Query_Connect, 0); - dbi->AddToThreadQueue(op, PrioQueue_High); + return; /* We're already loading, or have loaded. */ } + + g_pSM->LogMessage(myself, "Attempting to reconnect to database..."); + databaseLoading = true; + + TQueryOp *op = new TQueryOp(Query_Connect, 0); + dbi->AddToThreadQueue(op, PrioQueue_High); + + this->CatchLateLoadClients(); /* DB reconnection, we should check if we missed anyone... */ } void ClientPrefs::DatabaseConnect() @@ -230,19 +232,10 @@ void ClientPrefs::DatabaseConnect() Database = Driver->Connect(DBInfo, true, error, sizeof(error)); - if (Database == NULL && - DBInfo != storage_local && - storage_local != NULL) - { - DBInfo = storage_local; - Database = Driver->Connect(DBInfo, true, error, sizeof(error)); - } - if (Database == NULL) { g_pSM->LogError(myself, error); databaseLoading = false; - ProcessQueryCache(); return; } @@ -319,87 +312,76 @@ void ClientPrefs::DatabaseConnect() databaseLoading = false; - ProcessQueryCache(); - + this->ProcessQueryCache(); return; fatal_fail: Database->Close(); Database = NULL; databaseLoading = false; - ProcessQueryCache(); } bool ClientPrefs::AddQueryToQueue( TQueryOp *query ) { queryMutex->Lock(); - - if (Database == NULL && databaseLoading) + if (Database == NULL) { cachedQueries.push_back(query); queryMutex->Unlock(); - return true; + return false; } - - queryMutex->Unlock(); - - if (Database) + + if (!cachedQueries.empty()) { - query->SetDatabase(Database); - dbi->AddToThreadQueue(query, PrioQueue_Normal); - return true; + queryMutex->Unlock(); + this->ProcessQueryCache(); + } + else + { + queryMutex->Unlock(); } - query->Destroy(); - - /* If Database is NULL and we're not in the loading phase it must have failed - Can't do much */ - return false; + query->SetDatabase(Database); + dbi->AddToThreadQueue(query, PrioQueue_Normal); + return true; } void ClientPrefs::ProcessQueryCache() { - SourceHook::List::iterator iter; + if (Database == NULL) + { + return; + } queryMutex->Lock(); - - iter = cachedQueries.begin(); - - while (iter != cachedQueries.end()) + TQueryOp *op; + for (SourceHook::List::iterator iter = cachedQueries.begin(); iter != cachedQueries.end(); iter++) { - TQueryOp *op = *iter; - - if (Database != NULL) - { - op->SetDatabase(Database); - dbi->AddToThreadQueue(op, PrioQueue_Normal); - } - else - { - op->Destroy(); - } - - iter++; + op = *iter; + op->SetDatabase(Database); + dbi->AddToThreadQueue(op, PrioQueue_Normal); } cachedQueries.clear(); - queryMutex->Unlock(); } size_t IsAuthIdConnected(char *authID) { IGamePlayer *player; - int maxPlayers = playerhelpers->GetMaxClients(); - - for (int playerIndex = 1; playerIndex <= maxPlayers; playerIndex++) + const char *authString; + + for (int playerIndex = playerhelpers->GetMaxClients()+1; --playerIndex > 0;) { player = playerhelpers->GetGamePlayer(playerIndex); - if (!player || !player->IsConnected()) + if (player == NULL || !player->IsConnected()) { continue; } - const char *authString = player->GetAuthString(); - if (!authString || authString[0] == '\0') + + authString = player->GetAuthString(); + + if (authString == NULL || authString[0] == '\0') { continue; } @@ -412,22 +394,45 @@ size_t IsAuthIdConnected(char *authID) return 0; } -size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...) +void ClientPrefs::CatchLateLoadClients() { - va_list ap; - va_start(ap, fmt); - size_t len = vsnprintf(buffer, maxlength, fmt, ap); - va_end(ap); + IGamePlayer *pPlayer; + for (int i = playerhelpers->GetMaxClients()+1; --i > 0;) + { + if (g_CookieManager.AreClientCookiesPening(i) || g_CookieManager.AreClientCookiesCached(i)) + { + continue; + } + + pPlayer = playerhelpers->GetGamePlayer(i); - if (len >= maxlength) - { - buffer[maxlength - 1] = '\0'; - return (maxlength - 1); + if (!pPlayer || !pPlayer->IsAuthorized()) + { + continue; + } + + g_CookieManager.OnClientAuthorized(i, pPlayer->GetAuthString()); } - else +} + +void ClientPrefs::ClearQueryCache(int serial) +{ + queryMutex->Lock(); + + for (SourceHook::List::iterator iter = cachedQueries.begin(); iter != cachedQueries.end();) { - return len; - } + TQueryOp *op = *iter; + if (op && op->PullQueryType() == Query_SelectData && op->PullQuerySerial() == serial) + { + op->Destroy(); + iter = cachedQueries.erase(iter); + } + else + { + iter++; + } + } + queryMutex->Unlock(); } bool Translate(char *buffer, @@ -478,6 +483,30 @@ bool Translate(char *buffer, return true; } +char * UTIL_strncpy(char * destination, const char * source, size_t num) +{ + if (source == NULL) + { + destination[0] = '\0'; + return destination; + } + + size_t req = strlen(source); + if (!req) + { + destination[0] = '\0'; + return destination; + } + else if (req >= num) + { + req = num-1; + } + + strncpy(destination, source, req); + destination[req] = '\0'; + return destination; +} + IdentityToken_t *ClientPrefs::GetIdentity() const { return identity; @@ -493,3 +522,15 @@ const char *ClientPrefs::GetExtensionDateString() return SM_BUILD_TIMESTAMP; } +ClientPrefs::ClientPrefs() +{ + Driver = NULL; + Database = NULL; + databaseLoading = false; + phrases = NULL; + DBInfo = NULL; + + cookieMutex = NULL; + queryMutex = NULL; + identity = NULL; +} diff --git a/extensions/clientprefs/extension.h b/extensions/clientprefs/extension.h index 074db23b..1d104926 100644 --- a/extensions/clientprefs/extension.h +++ b/extensions/clientprefs/extension.h @@ -38,6 +38,9 @@ #include #include "smsdk_ext.h" #include "sh_list.h" + +char * UTIL_strncpy(char * destination, const char * source, size_t num); + #include "cookie.h" #include "menus.h" #include "query.h" @@ -58,6 +61,8 @@ class TQueryOp; */ class ClientPrefs : public SDKExtension { +public: + ClientPrefs(); public: /** * @brief This is called after the initial loading sequence has been processed. @@ -93,6 +98,10 @@ public: bool AddQueryToQueue(TQueryOp *query); void ProcessQueryCache(); + + void AttemptReconnection(); + void CatchLateLoadClients(); + void ClearQueryCache(int serial); /** * @brief Called when the pause state is changed. @@ -145,11 +154,11 @@ public: public: IDBDriver *Driver; IDatabase *Database; - bool databaseLoading; IPhraseCollection *phrases; const DatabaseInfo *DBInfo; IMutex *cookieMutex; + bool databaseLoading; private: SourceHook::List cachedQueries; @@ -177,8 +186,6 @@ public: size_t IsAuthIdConnected(char *authID); -size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); - extern sp_nativeinfo_t g_ClientPrefNatives[]; extern ClientPrefs g_ClientPrefs; diff --git a/extensions/clientprefs/menus.cpp b/extensions/clientprefs/menus.cpp index 884d7ee1..57178189 100644 --- a/extensions/clientprefs/menus.cpp +++ b/extensions/clientprefs/menus.cpp @@ -99,7 +99,7 @@ unsigned int ClientMenuHandler::OnMenuDisplayItem(IBaseMenu *menu, if (data->handler->forward != NULL) { char buffer[100]; - UTIL_Format(buffer, sizeof(buffer), "%s", dr.display); + g_pSM->Format(buffer, sizeof(buffer), "%s", dr.display); data->handler->forward->PushCell(client); data->handler->forward->PushCell(CookieMenuAction_DisplayOption); @@ -118,53 +118,15 @@ unsigned int ClientMenuHandler::OnMenuDisplayItem(IBaseMenu *menu, void AutoMenuHandler::OnMenuSelect(SourceMod::IBaseMenu *menu, int client, unsigned int item) { + static const char settings[CookieMenu_Elements][2][4] = { {"yes", "no"}, {"1", "0"}, {"on", "off"}, {"1", "0"} }; ItemDrawInfo draw; const char *info = menu->GetItemInfo(item, &draw); AutoMenuData *data = (AutoMenuData *)strtoul(info, NULL, 16); - switch (data->type) - { - case CookieMenu_YesNo: - { - if (item == 0) - { - g_CookieManager.SetCookieValue(data->pCookie, client, "yes"); - } - else - { - g_CookieManager.SetCookieValue(data->pCookie, client, "no"); - } - break; - } - case CookieMenu_YesNo_Int: - case CookieMenu_OnOff_Int: - { - if (item == 0) - { - g_CookieManager.SetCookieValue(data->pCookie, client, "1"); - } - else - { - g_CookieManager.SetCookieValue(data->pCookie, client, "0"); - } - break; - } - case CookieMenu_OnOff: - { - if (item == 0) - { - g_CookieManager.SetCookieValue(data->pCookie, client, "on"); - } - else - { - g_CookieManager.SetCookieValue(data->pCookie, client, "off"); - } - break; - } - } - + g_CookieManager.SetCookieValue(data->pCookie, client, settings[data->type][item]); + char message[255]; char *value; g_CookieManager.GetCookieValue(data->pCookie, client, &value); diff --git a/extensions/clientprefs/menus.h b/extensions/clientprefs/menus.h index cf404cad..c25682d4 100644 --- a/extensions/clientprefs/menus.h +++ b/extensions/clientprefs/menus.h @@ -59,13 +59,14 @@ enum CookieMenu CookieMenu_YesNo_Int, /**< Yes/No menu with 1/0 saved into the cookie */ CookieMenu_OnOff, /**< On/Off menu with "on"/"off" results saved into the cookie */ CookieMenu_OnOff_Int, /**< On/Off menu with 1/0 saved into the cookie */ + CookieMenu_Elements }; struct ItemHandler { - bool isAutoMenu; IChangeableForward *forward; CookieMenu autoMenuType; + bool isAutoMenu; }; class ClientMenuHandler : public IMenuHandler @@ -96,8 +97,8 @@ struct AutoMenuData { ItemHandler *handler; Cookie *pCookie; - CookieMenu type; cell_t datavalue; + CookieMenu type; }; #endif // _INCLUDE_SOURCEMOD_CLIENTPREFS_MENUS_H_ diff --git a/extensions/clientprefs/natives.cpp b/extensions/clientprefs/natives.cpp index 525cd2f4..29da7197 100644 --- a/extensions/clientprefs/natives.cpp +++ b/extensions/clientprefs/natives.cpp @@ -35,10 +35,7 @@ cell_t RegClientPrefCookie(IPluginContext *pContext, const cell_t *params) { - if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading) - { - return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection"); - } + g_ClientPrefs.AttemptReconnection(); char *name; pContext->LocalToString(params[1], &name); @@ -67,10 +64,7 @@ cell_t RegClientPrefCookie(IPluginContext *pContext, const cell_t *params) cell_t FindClientPrefCookie(IPluginContext *pContext, const cell_t *params) { - if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading) - { - return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection"); - } + g_ClientPrefs.AttemptReconnection(); char *name; pContext->LocalToString(params[1], &name); @@ -91,10 +85,7 @@ cell_t FindClientPrefCookie(IPluginContext *pContext, const cell_t *params) cell_t SetAuthIdCookie(IPluginContext *pContext, const cell_t *params) { - if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading) - { - return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection"); - } + g_ClientPrefs.AttemptReconnection(); char *steamID; pContext->LocalToString(params[1], &steamID); @@ -136,8 +127,7 @@ cell_t SetAuthIdCookie(IPluginContext *pContext, const cell_t *params) // edit database table TQueryOp *op = new TQueryOp(Query_InsertData, pCookie); // limit player auth length which doubles for cookie name length - strncpy(op->m_params.steamId, steamID, MAX_NAME_LENGTH); - op->m_params.steamId[MAX_NAME_LENGTH-1] = '\0'; + UTIL_strncpy(op->m_params.steamId, steamID, MAX_NAME_LENGTH); op->m_params.cookieId = i_dbId; op->m_params.data = payload; @@ -148,10 +138,7 @@ cell_t SetAuthIdCookie(IPluginContext *pContext, const cell_t *params) cell_t SetClientPrefCookie(IPluginContext *pContext, const cell_t *params) { - if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading) - { - return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection"); - } + g_ClientPrefs.AttemptReconnection(); int client = params[1]; @@ -183,10 +170,7 @@ cell_t SetClientPrefCookie(IPluginContext *pContext, const cell_t *params) cell_t GetClientPrefCookie(IPluginContext *pContext, const cell_t *params) { - if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading) - { - return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection"); - } + g_ClientPrefs.AttemptReconnection(); int client = params[1]; @@ -221,10 +205,7 @@ cell_t GetClientPrefCookie(IPluginContext *pContext, const cell_t *params) cell_t AreClientCookiesCached(IPluginContext *pContext, const cell_t *params) { - if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading) - { - return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection"); - } + g_ClientPrefs.AttemptReconnection(); int client = params[1]; @@ -238,10 +219,7 @@ cell_t AreClientCookiesCached(IPluginContext *pContext, const cell_t *params) cell_t GetCookieAccess(IPluginContext *pContext, const cell_t *params) { - if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading) - { - return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection"); - } + g_ClientPrefs.AttemptReconnection(); Handle_t hndl = static_cast(params[1]); HandleError err; @@ -263,10 +241,7 @@ cell_t GetCookieAccess(IPluginContext *pContext, const cell_t *params) static cell_t GetCookieIterator(IPluginContext *pContext, const cell_t *params) { - if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading) - { - return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection"); - } + g_ClientPrefs.AttemptReconnection(); SourceHook::List::iterator *iter = new SourceHook::List::iterator; *iter = g_CookieManager.cookieList.begin(); @@ -282,10 +257,7 @@ static cell_t GetCookieIterator(IPluginContext *pContext, const cell_t *params) static cell_t ReadCookieIterator(IPluginContext *pContext, const cell_t *params) { - if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading) - { - return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection"); - } + g_ClientPrefs.AttemptReconnection(); SourceHook::List::iterator *iter; @@ -323,10 +295,7 @@ static cell_t ReadCookieIterator(IPluginContext *pContext, const cell_t *params) cell_t ShowSettingsMenu(IPluginContext *pContext, const cell_t *params) { - if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading) - { - return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection"); - } + g_ClientPrefs.AttemptReconnection(); char message[256]; Translate(message, sizeof(message), "%T:", 2, NULL, "Client Settings", ¶ms[1]); @@ -339,10 +308,7 @@ cell_t ShowSettingsMenu(IPluginContext *pContext, const cell_t *params) cell_t AddSettingsMenuItem(IPluginContext *pContext, const cell_t *params) { - if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading) - { - return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection"); - } + g_ClientPrefs.AttemptReconnection(); char *display; pContext->LocalToString(params[3], &display); @@ -358,7 +324,7 @@ cell_t AddSettingsMenuItem(IPluginContext *pContext, const cell_t *params) AutoMenuData *data = new AutoMenuData; data->datavalue = params[2]; data->handler = pItem; - UTIL_Format(info, sizeof(info), "%x", data); + g_pSM->Format(info, sizeof(info), "%x", data); ItemDrawInfo draw(display, 0); @@ -376,7 +342,7 @@ cell_t AddSettingsMenuItem(IPluginContext *pContext, const cell_t *params) } char *copyarray = new char[strlen(display)+1]; - UTIL_Format(copyarray, strlen(display)+1, "%s", display); + g_pSM->Format(copyarray, strlen(display)+1, "%s", display); pList->push_back(copyarray); @@ -385,10 +351,7 @@ cell_t AddSettingsMenuItem(IPluginContext *pContext, const cell_t *params) cell_t AddSettingsPrefabMenuItem(IPluginContext *pContext, const cell_t *params) { - if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading) - { - return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection"); - } + g_ClientPrefs.AttemptReconnection(); Handle_t hndl = static_cast(params[1]); HandleError err; @@ -433,7 +396,7 @@ cell_t AddSettingsPrefabMenuItem(IPluginContext *pContext, const cell_t *params) data->pCookie = pCookie; data->type = (CookieMenu)params[2]; data->handler = pItem; - UTIL_Format(info, sizeof(info), "%x", data); + g_pSM->Format(info, sizeof(info), "%x", data); g_CookieManager.clientMenu->AppendItem(info, draw); @@ -449,7 +412,7 @@ cell_t AddSettingsPrefabMenuItem(IPluginContext *pContext, const cell_t *params) } char *copyarray = new char[strlen(display)+1]; - UTIL_Format(copyarray, strlen(display)+1, "%s", display); + g_pSM->Format(copyarray, strlen(display)+1, "%s", display); pList->push_back(copyarray); @@ -458,10 +421,7 @@ cell_t AddSettingsPrefabMenuItem(IPluginContext *pContext, const cell_t *params) cell_t GetClientCookieTime(IPluginContext *pContext, const cell_t *params) { - if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading) - { - return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection"); - } + g_ClientPrefs.AttemptReconnection(); Handle_t hndl = static_cast(params[2]); HandleError err; diff --git a/extensions/clientprefs/query.cpp b/extensions/clientprefs/query.cpp index 61f112fc..db463df7 100644 --- a/extensions/clientprefs/query.cpp +++ b/extensions/clientprefs/query.cpp @@ -35,12 +35,6 @@ void TQueryOp::RunThinkPart() { //handler for threaded sql queries - - if (m_type == Query_Connect) - { - return; - } - switch (m_type) { case Query_InsertCookie: @@ -61,6 +55,11 @@ void TQueryOp::RunThinkPart() break; } + case Query_Connect: + { + return; + } + default: { break; @@ -73,31 +72,26 @@ void TQueryOp::RunThreadPart() if (m_type == Query_Connect) { g_ClientPrefs.DatabaseConnect(); + return; } - else - { - assert(m_database != NULL); - - /* I don't think this is needed anymore... keeping for now. */ - m_database->LockForFullAtomicOperation(); - + + assert(m_database != NULL); + /* I don't think this is needed anymore... keeping for now. */ + m_database->LockForFullAtomicOperation(); if (!BindParamsAndRun()) - { - g_pSM->LogError(myself, - "Failed SQL Query, Error: \"%s\" (Query id %i - serial %i)", - m_database->GetError(), - m_type, - m_serial); - } - - m_database->UnlockFromFullAtomicOperation(); + { + g_pSM->LogError(myself, + "Failed SQL Query, Error: \"%s\" (Query id %i - serial %i)", + m_database->GetError(), + m_type, + m_serial); } + + m_database->UnlockFromFullAtomicOperation(); } IDBDriver *TQueryOp::GetDriver() { - assert(m_database != NULL); - return m_database->GetDriver(); } @@ -131,6 +125,7 @@ TQueryOp::TQueryOp(enum querytype type, Cookie *cookie) m_database = NULL; m_insertId = -1; m_pResult = NULL; + m_serial = 0; } void TQueryOp::SetDatabase(IDatabase *db) @@ -162,7 +157,7 @@ bool TQueryOp::BindParamsAndRun() if (g_DriverType == Driver_MySQL) { - UTIL_Format(query, + g_pSM->Format(query, sizeof(query), "INSERT IGNORE INTO sm_cookies (name, description, access) \ VALUES (\"%s\", \"%s\", %d)", @@ -172,7 +167,7 @@ bool TQueryOp::BindParamsAndRun() } else if (g_DriverType == Driver_SQLite) { - UTIL_Format(query, + g_pSM->Format(query, sizeof(query), "INSERT OR IGNORE INTO sm_cookies (name, description, access) \ VALUES ('%s', '%s', %d)", @@ -197,7 +192,7 @@ bool TQueryOp::BindParamsAndRun() m_database->QuoteString(m_params.steamId, safe_str, sizeof(safe_str), &ignore); - UTIL_Format(query, + g_pSM->Format(query, sizeof(query), "SELECT sm_cookies.name, sm_cookie_cache.value, sm_cookies.description, \ sm_cookies.access, sm_cookie_cache.timestamp \ @@ -228,7 +223,7 @@ bool TQueryOp::BindParamsAndRun() if (g_DriverType == Driver_MySQL) { - UTIL_Format(query, + g_pSM->Format(query, sizeof(query), "INSERT INTO sm_cookie_cache (player, cookie_id, value, timestamp) \ VALUES (\"%s\", %d, \"%s\", %d) \ @@ -243,7 +238,7 @@ bool TQueryOp::BindParamsAndRun() } else if (g_DriverType == Driver_SQLite) { - UTIL_Format(query, + g_pSM->Format(query, sizeof(query), "INSERT OR REPLACE INTO sm_cookie_cache \ (player, cookie_id, value, timestamp) \ @@ -274,7 +269,7 @@ bool TQueryOp::BindParamsAndRun() sizeof(safe_name), &ignore); - UTIL_Format(query, + g_pSM->Format(query, sizeof(query), "SELECT id FROM sm_cookies WHERE name = '%s'", safe_name); @@ -296,6 +291,16 @@ bool TQueryOp::BindParamsAndRun() return false; } +querytype TQueryOp::PullQueryType() +{ + return m_type; +} + +int TQueryOp::PullQuerySerial() +{ + return m_serial; +} + ParamData::~ParamData() { if (cookie) @@ -309,8 +314,10 @@ ParamData::~ParamData() delete cookie; cookie = NULL; } - - g_ClientPrefs.cookieMutex->Unlock(); + else + { + g_ClientPrefs.cookieMutex->Unlock(); + } } if (data) diff --git a/extensions/clientprefs/query.h b/extensions/clientprefs/query.h index e7c6ff39..73febd3b 100644 --- a/extensions/clientprefs/query.h +++ b/extensions/clientprefs/query.h @@ -93,6 +93,10 @@ public: { return m_database; } + +public: + querytype PullQueryType(); + int PullQuerySerial(); private: IDatabase *m_database;