Fixed amb1810 - Clientprefs no longer blocks load.
1.1 --- a/extensions/clientprefs/cookie.cpp Sun Jul 13 07:01:54 2008 +0000
1.2 +++ b/extensions/clientprefs/cookie.cpp Tue Jul 15 00:24:08 2008 +0000
1.3 @@ -80,7 +80,17 @@
1.4 continue;
1.5 }
1.6
1.7 - delete current;
1.8 + g_ClientPrefs.cookieMutex->Lock();
1.9 + if (current->usedInQuery)
1.10 + {
1.11 + current->shouldDelete = true;
1.12 + g_ClientPrefs.cookieMutex->Unlock();
1.13 + }
1.14 + else
1.15 + {
1.16 + g_ClientPrefs.cookieMutex->Unlock();
1.17 + delete current;
1.18 + }
1.19
1.20 _iter = cookieList.erase(_iter);
1.21 }
1.22 @@ -98,7 +108,6 @@
1.23 return *pCookie;
1.24 }
1.25
1.26 -
1.27 Cookie *CookieManager::CreateCookie(const char *name, const char *description, CookieAccess access)
1.28 {
1.29 Cookie *pCookie = FindCookie(name);
1.30 @@ -120,25 +129,16 @@
1.31 cookieTrie.insert(name, pCookie);
1.32 cookieList.push_back(pCookie);
1.33
1.34 - char quotedname[2 * MAX_NAME_LENGTH + 1];
1.35 - char quoteddesc[2 * MAX_DESC_LENGTH + 1];
1.36 + /* Attempt to insert cookie into the db and get its ID num */
1.37 +
1.38 + TQueryOp *op = new TQueryOp(Query_InsertCookie, pCookie);
1.39
1.40 - g_ClientPrefs.Database->QuoteString(pCookie->name, quotedname, sizeof(quotedname), NULL);
1.41 - g_ClientPrefs.Database->QuoteString(pCookie->description, quoteddesc, sizeof(quoteddesc), NULL);
1.42 -
1.43 - /* Attempt to insert cookie into the db and get its ID num */
1.44 - char query[300];
1.45 - if (driver == DRIVER_SQLITE)
1.46 - {
1.47 - UTIL_Format(query, sizeof(query), "INSERT OR IGNORE INTO sm_cookies(name, description, access) VALUES('%s', '%s', %i)", quotedname, quoteddesc, access);
1.48 - }
1.49 - else
1.50 - {
1.51 - UTIL_Format(query, sizeof(query), "INSERT IGNORE INTO sm_cookies(name, description, access) VALUES('%s', '%s', %i)", quotedname, quoteddesc, access);
1.52 - }
1.53 + g_ClientPrefs.cookieMutex->Lock();
1.54 + op->m_params.cookie = pCookie;
1.55 + pCookie->usedInQuery++;
1.56 + g_ClientPrefs.cookieMutex->Unlock();
1.57
1.58 - TQueryOp *op = new TQueryOp(g_ClientPrefs.Database, query, Query_InsertCookie, pCookie);
1.59 - dbi->AddToThreadQueue(op, PrioQueue_Normal);
1.60 + g_ClientPrefs.AddQueryToQueue(op);
1.61
1.62 return pCookie;
1.63 }
1.64 @@ -198,11 +198,10 @@
1.65 {
1.66 connected[client] = true;
1.67
1.68 - char query[300];
1.69 - /* Assume that the authstring doesn't need to be quoted */
1.70 - UTIL_Format(query, sizeof(query), "SELECT sm_cookies.name, sm_cookie_cache.value, sm_cookies.description, sm_cookies.access FROM sm_cookies JOIN sm_cookie_cache ON sm_cookies.id = sm_cookie_cache.cookie_id WHERE player = '%s'", authstring);
1.71 - TQueryOp *op = new TQueryOp(g_ClientPrefs.Database, query, Query_SelectData, client);
1.72 - dbi->AddToThreadQueue(op, PrioQueue_Normal);
1.73 + TQueryOp *op = new TQueryOp(Query_SelectData, client);
1.74 + strcpy(op->m_params.steamId, authstring);
1.75 +
1.76 + g_ClientPrefs.AddQueryToQueue(op);
1.77 }
1.78
1.79 void CookieManager::OnClientDisconnecting(int client)
1.80 @@ -245,24 +244,18 @@
1.81 return;
1.82 }
1.83
1.84 - char quotedvalue[2 * MAX_VALUE_LENGTH + 1];
1.85 - g_ClientPrefs.Database->QuoteString(current->value, quotedvalue, sizeof(quotedvalue), NULL);
1.86 + TQueryOp *op = new TQueryOp(Query_InsertData, client);
1.87
1.88 - char query[300];
1.89 - if (driver == DRIVER_SQLITE)
1.90 - {
1.91 - UTIL_Format(query, sizeof(query), "INSERT OR REPLACE INTO sm_cookie_cache(player,cookie_id, value, timestamp) VALUES('%s', %i, '%s', %i)", player->GetAuthString(), dbId, quotedvalue, time(NULL));
1.92 - }
1.93 - else
1.94 - {
1.95 - UTIL_Format(query, sizeof(query), "INSERT INTO sm_cookie_cache(player,cookie_id, value, timestamp) VALUES('%s', %i, '%s', %i) ON DUPLICATE KEY UPDATE value = '%s', timestamp = %i", player->GetAuthString(), dbId, quotedvalue, time(NULL), quotedvalue, time(NULL));
1.96 - }
1.97 -
1.98 - TQueryOp *op = new TQueryOp(g_ClientPrefs.Database, query, Query_InsertData, client);
1.99 - dbi->AddToThreadQueue(op, PrioQueue_Normal);
1.100 + strcpy(op->m_params.steamId, player->GetAuthString());
1.101 + op->m_params.cookieId = dbId;
1.102 + op->m_params.data = current;
1.103 +
1.104 + g_ClientPrefs.AddQueryToQueue(op);
1.105
1.106 current->parent->data[client] = NULL;
1.107 - delete current;
1.108 +
1.109 +
1.110 + /* We don't delete here, it will be removed when the query is completed */
1.111
1.112 _iter = clientData[client].erase(_iter);
1.113 }
1.114 @@ -330,14 +323,10 @@
1.115 return;
1.116 }
1.117
1.118 - char quotedname[2 * MAX_NAME_LENGTH + 1];
1.119 - g_ClientPrefs.Database->QuoteString(pCookie->name, quotedname, sizeof(quotedname), NULL);
1.120 -
1.121 - char query[300];
1.122 - UTIL_Format(query, sizeof(query), "SELECT id FROM sm_cookies WHERE name='%s'", quotedname);
1.123 -
1.124 - TQueryOp *op = new TQueryOp(g_ClientPrefs.Database, query, Query_SelectId, pCookie);
1.125 - dbi->AddToThreadQueue(op, PrioQueue_Normal);
1.126 + TQueryOp *op = new TQueryOp(Query_SelectId, pCookie);
1.127 + /* Put the cookie name into the steamId field to save space - Make sure we remember that it's there */
1.128 + strcpy(op->m_params.steamId, pCookie->name);
1.129 + g_ClientPrefs.AddQueryToQueue(op);
1.130 }
1.131
1.132 void CookieManager::SelectIdCallback(Cookie *pCookie, IQuery *data)
2.1 --- a/extensions/clientprefs/cookie.h Sun Jul 13 07:01:54 2008 +0000
2.2 +++ b/extensions/clientprefs/cookie.h Tue Jul 15 00:24:08 2008 +0000
2.3 @@ -80,6 +80,9 @@
2.4 {
2.5 data[i] = NULL;
2.6 }
2.7 +
2.8 + shouldDelete = false;
2.9 + usedInQuery = 0;
2.10 }
2.11
2.12 ~Cookie()
2.13 @@ -98,6 +101,10 @@
2.14 int dbid;
2.15 CookieData *data[MAXCLIENTS+1];
2.16 CookieAccess access;
2.17 +
2.18 + /* Reference counting stuff */
2.19 + bool shouldDelete;
2.20 + int usedInQuery;
2.21 };
2.22
2.23 class CookieManager : public IClientListener, public IPluginsListener
2.24 @@ -123,14 +130,13 @@
2.25
2.26 bool AreClientCookiesCached(int client);
2.27
2.28 - IForward *cookieDataLoadedForward;
2.29 -
2.30 - SourceHook::List<Cookie *> cookieList;
2.31 + void OnPluginDestroyed(IPlugin *plugin);
2.32
2.33 +public:
2.34 + IForward *cookieDataLoadedForward;
2.35 + SourceHook::List<Cookie *> cookieList;
2.36 IBaseMenu *clientMenu;
2.37
2.38 - void OnPluginDestroyed(IPlugin *plugin);
2.39 -
2.40 private:
2.41 KTrie<Cookie *> cookieTrie;
2.42 SourceHook::List<CookieData *> clientData[MAXCLIENTS];
3.1 --- a/extensions/clientprefs/extension.cpp Sun Jul 13 07:01:54 2008 +0000
3.2 +++ b/extensions/clientprefs/extension.cpp Tue Jul 15 00:24:08 2008 +0000
3.3 @@ -50,8 +50,11 @@
3.4 int driver = 0;
3.5
3.6 bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late)
3.7 -{
3.8 - const DatabaseInfo *DBInfo = dbi->FindDatabaseConf("clientprefs");
3.9 +{
3.10 + queryMutex = threader->MakeMutex();
3.11 + cookieMutex = threader->MakeMutex();
3.12 +
3.13 + DBInfo = dbi->FindDatabaseConf("clientprefs");
3.14
3.15 if (DBInfo == NULL)
3.16 {
3.17 @@ -62,7 +65,6 @@
3.18 snprintf(error, maxlength, "Could not find \"clientprefs\" or \"default\" database configs");
3.19 return false;
3.20 }
3.21 -
3.22 }
3.23
3.24 if (DBInfo->driver[0] != '\0')
3.25 @@ -80,92 +82,13 @@
3.26 return false;
3.27 }
3.28
3.29 - Database = Driver->Connect(DBInfo, true, error, maxlength);
3.30 -
3.31 - if (Database == NULL)
3.32 - {
3.33 - return false;
3.34 - }
3.35 + Database = NULL;
3.36 + databaseLoading = true;
3.37 + TQueryOp *op = new TQueryOp(Query_Connect, 0);
3.38 + dbi->AddToThreadQueue(op, PrioQueue_High);
3.39
3.40 dbi->AddDependency(myself, Driver);
3.41
3.42 - const char *identifier = Driver->GetIdentifier();
3.43 -
3.44 - if (strcmp(identifier, "sqlite") == 0)
3.45 - {
3.46 - driver = DRIVER_SQLITE;
3.47 -
3.48 - TQueryOp *op = new TQueryOp(
3.49 - Database,
3.50 - "CREATE TABLE IF NOT EXISTS sm_cookies \
3.51 - ( \
3.52 - id INTEGER PRIMARY KEY AUTOINCREMENT, \
3.53 - name varchar(30) NOT NULL UNIQUE, \
3.54 - description varchar(255), \
3.55 - access INTEGER \
3.56 - )",
3.57 - Query_CreateTable,
3.58 - 0);
3.59 -
3.60 - dbi->AddToThreadQueue(op, PrioQueue_Normal);
3.61 -
3.62 - op = new TQueryOp(
3.63 - Database,
3.64 - "CREATE TABLE IF NOT EXISTS sm_cookie_cache \
3.65 - ( \
3.66 - player varchar(65) NOT NULL, \
3.67 - cookie_id int(10) NOT NULL, \
3.68 - value varchar(100), \
3.69 - timestamp int, \
3.70 - PRIMARY KEY (player, cookie_id) \
3.71 - )",
3.72 - Query_CreateTable,
3.73 - 0);
3.74 -
3.75 - dbi->AddToThreadQueue(op, PrioQueue_Normal);
3.76 - }
3.77 - else if (strcmp(identifier, "mysql") == 0)
3.78 - {
3.79 - driver = DRIVER_MYSQL;
3.80 -
3.81 - TQueryOp *op = new TQueryOp(
3.82 - Database,
3.83 - "CREATE TABLE IF NOT EXISTS sm_cookies \
3.84 - ( \
3.85 - id INTEGER unsigned NOT NULL auto_increment, \
3.86 - name varchar(30) NOT NULL UNIQUE, \
3.87 - description varchar(255), \
3.88 - access INTEGER, \
3.89 - PRIMARY KEY (id) \
3.90 - )",
3.91 - Query_CreateTable,
3.92 - 0);
3.93 -
3.94 - dbi->AddToThreadQueue(op, PrioQueue_Normal);
3.95 -
3.96 - op = new TQueryOp(
3.97 - Database,
3.98 - "CREATE TABLE IF NOT EXISTS sm_cookie_cache \
3.99 - ( \
3.100 - player varchar(65) NOT NULL, \
3.101 - cookie_id int(10) NOT NULL, \
3.102 - value varchar(100), \
3.103 - timestamp int NOT NULL, \
3.104 - PRIMARY KEY (player, cookie_id) \
3.105 - )",
3.106 - Query_CreateTable,
3.107 - 0);
3.108 -
3.109 - dbi->AddToThreadQueue(op, PrioQueue_Normal);
3.110 - }
3.111 - else
3.112 - {
3.113 - snprintf(error, maxlength, "Unsupported driver \"%s\"", identifier);
3.114 - return false;
3.115 - }
3.116 -
3.117 -
3.118 -
3.119 sharesys->AddNatives(myself, g_ClientPrefNatives);
3.120 sharesys->RegisterLibrary(myself, "clientprefs");
3.121 g_CookieManager.cookieDataLoadedForward = forwards->CreateForward("OnClientCookiesCached", ET_Ignore, 1, NULL, Param_Cell);
3.122 @@ -218,6 +141,16 @@
3.123 {
3.124 if (Database != NULL && (void *)pInterface == (void *)(Database->GetDriver()))
3.125 {
3.126 + InsertCookieQuery->Destroy();
3.127 + SelectDataQuery->Destroy();
3.128 + SelectIdQuery->Destroy();
3.129 + InsertDataQuery->Destroy();
3.130 +
3.131 + InsertCookieQuery = NULL;
3.132 + SelectDataQuery = NULL;
3.133 + SelectIdQuery = NULL;
3.134 + InsertDataQuery = NULL;
3.135 +
3.136 Database->Close();
3.137 Database = NULL;
3.138 }
3.139 @@ -243,6 +176,232 @@
3.140
3.141 plsys->RemovePluginsListener(&g_CookieManager);
3.142 playerhelpers->RemoveClientListener(&g_CookieManager);
3.143 +
3.144 + /* Kill all our prepared queries - Queries are guaranteed to be flushed before this is called */
3.145 +
3.146 + if (InsertCookieQuery != NULL)
3.147 + {
3.148 + InsertCookieQuery->Destroy();
3.149 + }
3.150 +
3.151 + if (SelectDataQuery != NULL)
3.152 + {
3.153 + SelectDataQuery->Destroy();
3.154 + }
3.155 +
3.156 + if (SelectIdQuery != NULL)
3.157 + {
3.158 + SelectIdQuery->Destroy();
3.159 + }
3.160 +
3.161 + if (InsertDataQuery != NULL)
3.162 + {
3.163 + InsertDataQuery->Destroy();
3.164 + }
3.165 +
3.166 + queryMutex->DestroyThis();
3.167 + cookieMutex->DestroyThis();
3.168 +}
3.169 +
3.170 +void ClientPrefs::DatabaseConnect()
3.171 +{
3.172 + char error[256];
3.173 + int errCode = 0;
3.174 +
3.175 + Database = Driver->Connect(DBInfo, true, error, sizeof(error));
3.176 +
3.177 + if (Database == NULL)
3.178 + {
3.179 + g_pSM->LogError(myself, error);
3.180 + databaseLoading = false;
3.181 + ProcessQueryCache();
3.182 + return;
3.183 + }
3.184 +
3.185 + const char *identifier = Driver->GetIdentifier();
3.186 +
3.187 + if (strcmp(identifier, "sqlite") == 0)
3.188 + {
3.189 + driver = DRIVER_SQLITE;
3.190 +
3.191 + TQueryOp *op = new TQueryOp(Query_CreateTable, 0);
3.192 +
3.193 + op->SetDatabase(Database);
3.194 + op->SetCustomPreparedQuery
3.195 + (Database->PrepareQuery(
3.196 + "CREATE TABLE IF NOT EXISTS sm_cookies \
3.197 + ( \
3.198 + id INTEGER PRIMARY KEY AUTOINCREMENT, \
3.199 + name varchar(30) NOT NULL UNIQUE, \
3.200 + description varchar(255), \
3.201 + access INTEGER \
3.202 + )",
3.203 + error, sizeof(error), &errCode));
3.204 +
3.205 + dbi->AddToThreadQueue(op, PrioQueue_High);
3.206 +
3.207 + op = new TQueryOp(Query_CreateTable, 0);
3.208 + op->SetDatabase(Database);
3.209 + op->SetCustomPreparedQuery
3.210 + (Database->PrepareQuery(
3.211 + "CREATE TABLE IF NOT EXISTS sm_cookie_cache \
3.212 + ( \
3.213 + player varchar(65) NOT NULL, \
3.214 + cookie_id int(10) NOT NULL, \
3.215 + value varchar(100), \
3.216 + timestamp int, \
3.217 + PRIMARY KEY (player, cookie_id) \
3.218 + )",
3.219 + error, sizeof(error), &errCode));
3.220 +
3.221 + dbi->AddToThreadQueue(op, PrioQueue_High);
3.222 + }
3.223 + else if (strcmp(identifier, "mysql") == 0)
3.224 + {
3.225 + driver = DRIVER_MYSQL;
3.226 +
3.227 + TQueryOp *op = new TQueryOp(Query_CreateTable, 0);
3.228 + op->SetDatabase(Database);
3.229 + op->SetCustomPreparedQuery
3.230 + (Database->PrepareQuery(
3.231 + "CREATE TABLE IF NOT EXISTS sm_cookies \
3.232 + ( \
3.233 + id INTEGER unsigned NOT NULL auto_increment, \
3.234 + name varchar(30) NOT NULL UNIQUE, \
3.235 + description varchar(255), \
3.236 + access INTEGER, \
3.237 + PRIMARY KEY (id) \
3.238 + )",
3.239 + error, sizeof(error), &errCode));
3.240 +
3.241 + dbi->AddToThreadQueue(op, PrioQueue_High);
3.242 +
3.243 + op = new TQueryOp(Query_CreateTable, 0);
3.244 + op->SetDatabase(Database);
3.245 + op->SetCustomPreparedQuery
3.246 + (Database->PrepareQuery(
3.247 + "CREATE TABLE IF NOT EXISTS sm_cookie_cache \
3.248 + ( \
3.249 + player varchar(65) NOT NULL, \
3.250 + cookie_id int(10) NOT NULL, \
3.251 + value varchar(100), \
3.252 + timestamp int NOT NULL, \
3.253 + PRIMARY KEY (player, cookie_id) \
3.254 + )",
3.255 + error, sizeof(error), &errCode));
3.256 +
3.257 + dbi->AddToThreadQueue(op, PrioQueue_High);
3.258 + }
3.259 + else
3.260 + {
3.261 + g_pSM->LogError(myself, "Unsupported driver \"%s\"", identifier);
3.262 + Database->Close();
3.263 + Database = NULL;
3.264 + databaseLoading = false;
3.265 + ProcessQueryCache();
3.266 + return;
3.267 + }
3.268 +
3.269 + if (driver == DRIVER_MYSQL)
3.270 + {
3.271 + InsertCookieQuery = Database->PrepareQuery(
3.272 + "INSERT IGNORE INTO sm_cookies(name, description, access) \
3.273 + VALUES(?, ?, ?)",
3.274 + error, sizeof(error), &errCode);
3.275 + InsertDataQuery = Database->PrepareQuery(
3.276 + "INSERT INTO sm_cookie_cache(player, cookie_id, value, timestamp) \
3.277 + VALUES(?, ?, ?, ?) \
3.278 + ON DUPLICATE KEY UPDATE value = ?, timestamp = ?",
3.279 + error, sizeof(error), &errCode);
3.280 + }
3.281 + else
3.282 + {
3.283 + InsertCookieQuery = Database->PrepareQuery(
3.284 + "INSERT OR IGNORE INTO sm_cookies(name, description, access) \
3.285 + VALUES(?, ?, ?)",
3.286 + error, sizeof(error), &errCode);
3.287 + InsertDataQuery = Database->PrepareQuery(
3.288 + "INSERT OR REPLACE INTO sm_cookie_cache(player, cookie_id, value, timestamp) \
3.289 + VALUES(?, ?, ?, ?)",
3.290 + error, sizeof(error), &errCode);
3.291 + }
3.292 +
3.293 + SelectDataQuery = Database->PrepareQuery(
3.294 + "SELECT sm_cookies.name, sm_cookie_cache.value, sm_cookies.description, sm_cookies.access \
3.295 + FROM sm_cookies \
3.296 + JOIN sm_cookie_cache \
3.297 + ON sm_cookies.id = sm_cookie_cache.cookie_id \
3.298 + WHERE player = ?",
3.299 + error, sizeof(error), &errCode);
3.300 +
3.301 + SelectIdQuery = Database->PrepareQuery(
3.302 + "SELECT id \
3.303 + FROM sm_cookies \
3.304 + WHERE name=?",
3.305 + error, sizeof(error), &errCode);
3.306 +
3.307 + databaseLoading = false;
3.308 + cell_t result = 0;
3.309 +
3.310 + ProcessQueryCache();
3.311 +
3.312 + return;
3.313 +}
3.314 +
3.315 +bool ClientPrefs::AddQueryToQueue( TQueryOp *query )
3.316 +{
3.317 + queryMutex->Lock();
3.318 +
3.319 + if (Database == NULL && databaseLoading)
3.320 + {
3.321 + cachedQueries.push_back(query);
3.322 + queryMutex->Unlock();
3.323 + return true;
3.324 + }
3.325 +
3.326 + queryMutex->Unlock();
3.327 +
3.328 + if (Database)
3.329 + {
3.330 + query->SetDatabase(Database);
3.331 + query->SetPreparedQuery();
3.332 + dbi->AddToThreadQueue(query, PrioQueue_Normal);
3.333 + return true;
3.334 + }
3.335 +
3.336 + /* If Database is NULL and we're not in the loading phase it must have failed - Can't do much */
3.337 + return false;
3.338 +}
3.339 +
3.340 +void ClientPrefs::ProcessQueryCache()
3.341 +{
3.342 + SourceHook::List<TQueryOp *>::iterator iter;
3.343 +
3.344 + queryMutex->Lock();
3.345 +
3.346 + iter = cachedQueries.begin();
3.347 +
3.348 + while (iter != cachedQueries.end())
3.349 + {
3.350 + TQueryOp *op = (TQueryOp *)*iter;
3.351 +
3.352 + if (Database != NULL)
3.353 + {
3.354 + op->SetDatabase(Database);
3.355 + op->SetPreparedQuery();
3.356 + dbi->AddToThreadQueue(op, PrioQueue_Normal);
3.357 + }
3.358 + else
3.359 + {
3.360 + delete op;
3.361 + }
3.362 +
3.363 + iter++;
3.364 + }
3.365 +
3.366 + cachedQueries.clear();
3.367 +
3.368 + queryMutex->Unlock();
3.369 }
3.370
3.371 size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
4.1 --- a/extensions/clientprefs/extension.h Sun Jul 13 07:01:54 2008 +0000
4.2 +++ b/extensions/clientprefs/extension.h Tue Jul 15 00:24:08 2008 +0000
4.3 @@ -47,6 +47,8 @@
4.4
4.5 #define MAX_TRANSLATE_PARAMS 32
4.6
4.7 +class TQueryOp;
4.8 +
4.9 /**
4.10 * @brief Sample implementation of the SDK Extension.
4.11 * Note: Uncomment one of the pre-defined virtual functions in order to use it.
4.12 @@ -79,6 +81,11 @@
4.13
4.14 virtual void NotifyInterfaceDrop(SMInterface *pInterface);
4.15
4.16 + void DatabaseConnect();
4.17 +
4.18 + bool AddQueryToQueue(TQueryOp *query);
4.19 + void ProcessQueryCache();
4.20 +
4.21 /**
4.22 * @brief Called when the pause state is changed.
4.23 */
4.24 @@ -128,7 +135,20 @@
4.25 public:
4.26 IDBDriver *Driver;
4.27 IDatabase *Database;
4.28 + bool databaseLoading;
4.29 IPhraseCollection *phrases;
4.30 + const DatabaseInfo *DBInfo;
4.31 +
4.32 + IPreparedQuery *InsertCookieQuery;
4.33 + IPreparedQuery *SelectDataQuery;
4.34 + IPreparedQuery *InsertDataQuery;
4.35 + IPreparedQuery *SelectIdQuery;
4.36 +
4.37 + IMutex *cookieMutex;
4.38 +
4.39 +private:
4.40 + SourceHook::List<TQueryOp *> cachedQueries;
4.41 + IMutex *queryMutex;
4.42 };
4.43
4.44 class CookieTypeHandler : public IHandleTypeDispatch
4.45 @@ -136,7 +156,7 @@
4.46 public:
4.47 void OnHandleDestroy(HandleType_t type, void *object)
4.48 {
4.49 - /* No delete needed since Cookies are persistant */
4.50 + /* No delete needed since Cookies are persistent */
4.51 }
4.52 };
4.53
5.1 --- a/extensions/clientprefs/natives.cpp Sun Jul 13 07:01:54 2008 +0000
5.2 +++ b/extensions/clientprefs/natives.cpp Tue Jul 15 00:24:08 2008 +0000
5.3 @@ -35,6 +35,11 @@
5.4
5.5 cell_t RegClientPrefCookie(IPluginContext *pContext, const cell_t *params)
5.6 {
5.7 + if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
5.8 + {
5.9 + return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
5.10 + }
5.11 +
5.12 char *name;
5.13 pContext->LocalToString(params[1], &name);
5.14
5.15 @@ -62,6 +67,11 @@
5.16
5.17 cell_t FindClientPrefCookie(IPluginContext *pContext, const cell_t *params)
5.18 {
5.19 + if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
5.20 + {
5.21 + return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
5.22 + }
5.23 +
5.24 char *name;
5.25 pContext->LocalToString(params[1], &name);
5.26
5.27 @@ -81,6 +91,11 @@
5.28
5.29 cell_t SetClientPrefCookie(IPluginContext *pContext, const cell_t *params)
5.30 {
5.31 + if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
5.32 + {
5.33 + return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
5.34 + }
5.35 +
5.36 int client = params[1];
5.37
5.38 if ((client < 1) || (client > playerhelpers->GetMaxClients()))
5.39 @@ -111,6 +126,11 @@
5.40
5.41 cell_t GetClientPrefCookie(IPluginContext *pContext, const cell_t *params)
5.42 {
5.43 + if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
5.44 + {
5.45 + return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
5.46 + }
5.47 +
5.48 int client = params[1];
5.49
5.50 if ((client < 1) || (client > playerhelpers->GetMaxClients()))
5.51 @@ -144,6 +164,11 @@
5.52
5.53 cell_t AreClientCookiesCached(IPluginContext *pContext, const cell_t *params)
5.54 {
5.55 + if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
5.56 + {
5.57 + return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
5.58 + }
5.59 +
5.60 int client = params[1];
5.61
5.62 if ((client < 1) || (client > playerhelpers->GetMaxClients()))
5.63 @@ -156,6 +181,11 @@
5.64
5.65 cell_t GetCookieAccess(IPluginContext *pContext, const cell_t *params)
5.66 {
5.67 + if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
5.68 + {
5.69 + return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
5.70 + }
5.71 +
5.72 Handle_t hndl = static_cast<Handle_t>(params[1]);
5.73 HandleError err;
5.74 HandleSecurity sec;
5.75 @@ -176,6 +206,11 @@
5.76
5.77 static cell_t GetCookieIterator(IPluginContext *pContext, const cell_t *params)
5.78 {
5.79 + if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
5.80 + {
5.81 + return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
5.82 + }
5.83 +
5.84 SourceHook::List<Cookie *>::iterator *iter = new SourceHook::List<Cookie *>::iterator;
5.85 *iter = g_CookieManager.cookieList.begin();
5.86
5.87 @@ -190,6 +225,11 @@
5.88
5.89 static cell_t ReadCookieIterator(IPluginContext *pContext, const cell_t *params)
5.90 {
5.91 + if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
5.92 + {
5.93 + return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
5.94 + }
5.95 +
5.96 SourceHook::List<Cookie *>::iterator *iter;
5.97
5.98 Handle_t hndl = static_cast<Handle_t>(params[1]);
5.99 @@ -226,6 +266,11 @@
5.100
5.101 cell_t ShowSettingsMenu(IPluginContext *pContext, const cell_t *params)
5.102 {
5.103 + if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
5.104 + {
5.105 + return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
5.106 + }
5.107 +
5.108 char message[256];
5.109 Translate(message, sizeof(message), "%T:", 2, NULL, "Client Settings", ¶ms[1]);
5.110
5.111 @@ -237,6 +282,11 @@
5.112
5.113 cell_t AddSettingsMenuItem(IPluginContext *pContext, const cell_t *params)
5.114 {
5.115 + if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
5.116 + {
5.117 + return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
5.118 + }
5.119 +
5.120 char *display;
5.121 pContext->LocalToString(params[3], &display);
5.122
5.123 @@ -278,6 +328,11 @@
5.124
5.125 cell_t AddSettingsPrefabMenuItem(IPluginContext *pContext, const cell_t *params)
5.126 {
5.127 + if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
5.128 + {
5.129 + return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
5.130 + }
5.131 +
5.132 Handle_t hndl = static_cast<Handle_t>(params[1]);
5.133 HandleError err;
5.134 HandleSecurity sec;
6.1 --- a/extensions/clientprefs/query.cpp Sun Jul 13 07:01:54 2008 +0000
6.2 +++ b/extensions/clientprefs/query.cpp Tue Jul 15 00:24:08 2008 +0000
6.3 @@ -36,52 +36,83 @@
6.4 {
6.5 //handler for threaded sql queries
6.6
6.7 + if (m_type == Query_Connect)
6.8 + {
6.9 + return;
6.10 + }
6.11 +
6.12 if (m_pQuery)
6.13 {
6.14 switch (m_type)
6.15 {
6.16 - case Query_InsertCookie:
6.17 - g_CookieManager.InsertCookieCallback(pCookie, m_insertId);
6.18 - break;
6.19 - case Query_SelectData:
6.20 - g_CookieManager.ClientConnectCallback(m_client, m_pQuery);
6.21 - break;
6.22 - case Query_InsertData:
6.23 - //No specific handling
6.24 - break;
6.25 - case Query_SelectId:
6.26 - g_CookieManager.SelectIdCallback(pCookie, m_pQuery);
6.27 - break;
6.28 - default:
6.29 - break;
6.30 + case Query_InsertCookie:
6.31 + {
6.32 + g_CookieManager.InsertCookieCallback(m_pCookie, m_insertId);
6.33 + break;
6.34 + }
6.35 +
6.36 + case Query_SelectData:
6.37 + {
6.38 + g_CookieManager.ClientConnectCallback(m_client, m_pQuery);
6.39 + break;
6.40 + }
6.41 +
6.42 + case Query_SelectId:
6.43 + {
6.44 + g_CookieManager.SelectIdCallback(m_pCookie, m_pQuery);
6.45 + break;
6.46 + }
6.47 +
6.48 + case Query_CreateTable:
6.49 + {
6.50 + m_pQuery->Destroy();
6.51 + delete m_pQuery;
6.52 + m_pQuery = NULL;
6.53 + break;
6.54 + }
6.55 +
6.56 + default:
6.57 + {
6.58 + break;
6.59 + }
6.60 }
6.61 -
6.62 - m_pQuery->Destroy();
6.63 - }
6.64 - else
6.65 - {
6.66 - g_pSM->LogError(myself,"Failed SQL Query, Error: \"%s\" (Query id %i - client %i)", error, m_type, m_client);
6.67 }
6.68 }
6.69
6.70 void TQueryOp::RunThreadPart()
6.71 {
6.72 - m_pDatabase->LockForFullAtomicOperation();
6.73 - m_pQuery = m_pDatabase->DoQuery(m_Query.c_str());
6.74 -
6.75 - if (!m_pQuery)
6.76 + if (m_type == Query_Connect)
6.77 + {
6.78 + g_ClientPrefs.DatabaseConnect();
6.79 + }
6.80 + else
6.81 {
6.82 - g_pSM->LogError(myself, "Failed SQL Query, Error: \"%s\" (Query id %i - client %i)", m_pDatabase->GetError(), m_type, m_client);
6.83 - }
6.84 + if (m_database == NULL)
6.85 + {
6.86 + return;
6.87 + }
6.88 +
6.89 + m_database->LockForFullAtomicOperation();
6.90
6.91 - m_insertId = g_ClientPrefs.Database->GetInsertID();
6.92 + if (!BindParamsAndRun())
6.93 + {
6.94 + g_pSM->LogError(myself, "Failed SQL Query, Error: \"%s\" (Query id %i - client %i)", m_database->GetError(), m_type, m_client);
6.95 + }
6.96
6.97 - m_pDatabase->UnlockFromFullAtomicOperation();
6.98 + m_insertId = m_database->GetInsertID();
6.99 +
6.100 + m_database->UnlockFromFullAtomicOperation();
6.101 + }
6.102 }
6.103
6.104 IDBDriver *TQueryOp::GetDriver()
6.105 {
6.106 - return m_pDatabase->GetDriver();
6.107 + if (m_database == NULL)
6.108 + {
6.109 + return NULL;
6.110 + }
6.111 +
6.112 + return m_database->GetDriver();
6.113 }
6.114 IdentityToken_t *TQueryOp::GetOwner()
6.115 {
6.116 @@ -92,24 +123,157 @@
6.117 delete this;
6.118 }
6.119
6.120 -TQueryOp::TQueryOp(IDatabase *db, const char *query, enum querytype type, int client)
6.121 +TQueryOp::TQueryOp(enum querytype type, int client)
6.122 {
6.123 - m_pDatabase = db;
6.124 - m_Query = query;
6.125 m_type = type;
6.126 m_client = client;
6.127 m_pQuery = NULL;
6.128 + m_database = NULL;
6.129 +}
6.130
6.131 - m_pDatabase->IncReferenceCount();
6.132 +TQueryOp::TQueryOp(enum querytype type, Cookie *cookie)
6.133 +{
6.134 + m_type = type;
6.135 + m_pCookie = cookie;
6.136 + m_pQuery = NULL;
6.137 + m_database = NULL;
6.138 +}
6.139 +
6.140 +void TQueryOp::SetDatabase( IDatabase *db )
6.141 +{
6.142 + m_database = db;
6.143 + m_database->IncReferenceCount();
6.144 }
6.145
6.146 -TQueryOp::TQueryOp(IDatabase *db, const char *query, enum querytype type, Cookie *cookie)
6.147 +bool TQueryOp::BindParamsAndRun()
6.148 +{
6.149 + if (m_pQuery == NULL)
6.150 + {
6.151 + return false;
6.152 + }
6.153 +
6.154 + switch (m_type)
6.155 + {
6.156 + case Query_InsertCookie:
6.157 + {
6.158 + m_pQuery->BindParamString(0, m_params.cookie->name, false);
6.159 + m_pQuery->BindParamString(1, m_params.cookie->description, false);
6.160 + m_pQuery->BindParamInt(2, m_params.cookie->access);
6.161 +
6.162 + break;
6.163 + }
6.164 +
6.165 + case Query_SelectData:
6.166 + {
6.167 + m_pQuery->BindParamString(0, m_params.steamId, false);
6.168 +
6.169 + break;
6.170 + }
6.171 +
6.172 + case Query_InsertData:
6.173 + {
6.174 + m_pQuery->BindParamString(0, m_params.steamId, false);
6.175 + m_pQuery->BindParamInt(1, m_params.cookieId);
6.176 + m_pQuery->BindParamString(2, m_params.data->value, false);
6.177 + m_pQuery->BindParamInt(3, (unsigned int)time(NULL), false);
6.178 +
6.179 + if (driver == DRIVER_MYSQL)
6.180 + {
6.181 + m_pQuery->BindParamString(4, m_params.data->value, false);
6.182 + m_pQuery->BindParamInt(5, (unsigned int)time(NULL), false);
6.183 + }
6.184 +
6.185 + break;
6.186 + }
6.187 +
6.188 + case Query_SelectId:
6.189 + {
6.190 + /* the steamId var was actually used to store the name of the cookie - Save duplicating vars */
6.191 + m_pQuery->BindParamString(0, m_params.steamId, false);
6.192 +
6.193 + break;
6.194 + }
6.195 +
6.196 + default:
6.197 + {
6.198 + break;
6.199 + }
6.200 +
6.201 + }
6.202 +
6.203 + return m_pQuery->Execute();
6.204 +}
6.205 +
6.206 +void TQueryOp::SetPreparedQuery()
6.207 {
6.208 - m_pDatabase = db;
6.209 - m_Query = query;
6.210 - m_type = type;
6.211 - pCookie = cookie;
6.212 - m_pQuery = NULL;
6.213 + switch (m_type)
6.214 + {
6.215 + case Query_InsertCookie:
6.216 + {
6.217 + m_pQuery = g_ClientPrefs.InsertCookieQuery;
6.218 + break;
6.219 + }
6.220 +
6.221 + case Query_SelectData:
6.222 + {
6.223 + m_pQuery = g_ClientPrefs.SelectDataQuery;
6.224 + break;
6.225 + }
6.226 +
6.227 + case Query_InsertData:
6.228 + {
6.229 + m_pQuery = g_ClientPrefs.InsertDataQuery;
6.230 + break;
6.231 + }
6.232 +
6.233 + case Query_SelectId:
6.234 + {
6.235 + m_pQuery = g_ClientPrefs.SelectIdQuery;
6.236 + break;
6.237 + }
6.238 +
6.239 + default:
6.240 + {
6.241 + break;
6.242 + }
6.243 +
6.244 + }
6.245 +}
6.246
6.247 - m_pDatabase->IncReferenceCount();
6.248 +void TQueryOp::SetCustomPreparedQuery(IPreparedQuery *query)
6.249 +{
6.250 + m_pQuery = query;
6.251 }
6.252 +
6.253 +ParamData::~ParamData()
6.254 +{
6.255 + if (cookie)
6.256 + {
6.257 + g_ClientPrefs.cookieMutex->Lock();
6.258 + cookie->usedInQuery--;
6.259 +
6.260 + if (cookie->shouldDelete && cookie->usedInQuery <= 0)
6.261 + {
6.262 + g_ClientPrefs.cookieMutex->Unlock();
6.263 + delete cookie;
6.264 + cookie = NULL;
6.265 + }
6.266 +
6.267 + g_ClientPrefs.cookieMutex->Unlock();
6.268 + }
6.269 +
6.270 + if (data)
6.271 + {
6.272 + /* Data is only ever passed in a client disconnect query and always needs to be deleted */
6.273 + delete data;
6.274 + data = NULL;
6.275 + }
6.276 +}
6.277 +
6.278 +ParamData::ParamData()
6.279 +{
6.280 + cookie = NULL;
6.281 + data = NULL;
6.282 + steamId[0] = '\0';
6.283 + cookieId = 0;
6.284 +}
6.285 \ No newline at end of file
7.1 --- a/extensions/clientprefs/query.h Sun Jul 13 07:01:54 2008 +0000
7.2 +++ b/extensions/clientprefs/query.h Tue Jul 15 00:24:08 2008 +0000
7.3 @@ -43,36 +43,67 @@
7.4 Query_InsertData,
7.5 Query_SelectId,
7.6 Query_CreateTable,
7.7 + Query_Connect,
7.8 +};
7.9 +
7.10 +struct PreparedQueryWrapper;
7.11 +struct Cookie;
7.12 +struct CookieData;
7.13 +#define MAX_NAME_LENGTH 30
7.14 +
7.15 +/* This stores all the info required for our param binding until the thread is executed */
7.16 +struct ParamData
7.17 +{
7.18 + ParamData();
7.19 +
7.20 + ~ParamData();
7.21 +
7.22 + /* Contains a name, description and access for InsertCookie queries */
7.23 + Cookie *cookie;
7.24 + /* A clients steamid - Used for most queries - Doubles as storage for the cookie name*/
7.25 + char steamId[MAX_NAME_LENGTH];
7.26 +
7.27 + int cookieId;
7.28 + CookieData *data;
7.29 };
7.30
7.31 class TQueryOp : public IDBThreadOperation
7.32 {
7.33 public:
7.34 - TQueryOp(IDatabase *db, const char *query, enum querytype type, int client);
7.35 - TQueryOp(IDatabase *db, const char *query, enum querytype type, Cookie *cookie);
7.36 + TQueryOp(enum querytype type, int client);
7.37 + TQueryOp(enum querytype type, Cookie *cookie);
7.38 ~TQueryOp() {}
7.39
7.40 IDBDriver *GetDriver();
7.41 IdentityToken_t *GetOwner();
7.42
7.43 + void SetDatabase(IDatabase *db);
7.44 + void SetPreparedQuery();
7.45 + void SetCustomPreparedQuery(IPreparedQuery *wrapper);
7.46 +
7.47 void Destroy();
7.48
7.49 void RunThreadPart();
7.50 /* Thread has been cancelled due to driver unloading. Nothing else to do? */
7.51 - void CancelThinkPart()
7.52 - {
7.53 - }
7.54 + void CancelThinkPart() {}
7.55 void RunThinkPart();
7.56
7.57 + bool BindParamsAndRun();
7.58 +
7.59 + /* Params to be bound */
7.60 + ParamData m_params;
7.61 +
7.62 private:
7.63 - IDatabase *m_pDatabase;
7.64 - IQuery *m_pQuery;
7.65 - SourceHook::String m_Query;
7.66 - char error[255];
7.67 + IPreparedQuery *m_pQuery;
7.68 + IDatabase *m_database;
7.69 +
7.70 + /* Query type */
7.71 enum querytype m_type;
7.72 +
7.73 + /* Data to be passed to the callback */
7.74 int m_client;
7.75 int m_insertId;
7.76 - Cookie *pCookie;
7.77 + Cookie *m_pCookie;
7.78 };
7.79
7.80
8.1 --- a/extensions/clientprefs/sdk/smsdk_config.h Sun Jul 13 07:01:54 2008 +0000
8.2 +++ b/extensions/clientprefs/sdk/smsdk_config.h Tue Jul 15 00:24:08 2008 +0000
8.3 @@ -69,7 +69,7 @@
8.4 //#define SMEXT_ENABLE_MEMUTILS
8.5 #define SMEXT_ENABLE_GAMEHELPERS
8.6 //#define SMEXT_ENABLE_TIMERSYS
8.7 -//#define SMEXT_ENABLE_THREADER
8.8 +#define SMEXT_ENABLE_THREADER
8.9 //#define SMEXT_ENABLE_LIBSYS
8.10 #define SMEXT_ENABLE_MENUS
8.11 //#define SMEXT_ENABLE_ADTFACTORY
9.1 --- a/plugins/clientprefs.sp Sun Jul 13 07:01:54 2008 +0000
9.2 +++ b/plugins/clientprefs.sp Tue Jul 15 00:24:08 2008 +0000
9.3 @@ -58,7 +58,7 @@
9.4 {
9.5 if (args == 0)
9.6 {
9.7 - ReplyToCommand(client, "[SM] Usage: sm_cookie <name> [value]");
9.8 + ReplyToCommand(client, "[SM] Usage: sm_cookies <name> [value]");
9.9 ReplyToCommand(client, "[SM] %t", "Printing Cookie List");
9.10
9.11 /* Show list of cookies */
10.1 --- a/plugins/include/clientprefs.inc Sun Jul 13 07:01:54 2008 +0000
10.2 +++ b/plugins/include/clientprefs.inc Tue Jul 15 00:24:08 2008 +0000
10.3 @@ -75,6 +75,14 @@
10.4 };
10.5
10.6 /**
10.7 + * Note:
10.8 + *
10.9 + * A successful return value/result on any client prefs native only guarantees that the local cache has been updated.
10.10 + * Database connection problems can still prevent the data from being permanently saved. Connection problems will be logged as
10.11 + * errors by the clientprefs extension.
10.12 + */
10.13 +
10.14 +/**
10.15 * Creates a new Client preference cookie.
10.16 *
10.17 * @param name Name of the new preference cookie.
11.1 --- a/plugins/testsuite/clientprefstest.sp Sun Jul 13 07:01:54 2008 +0000
11.2 +++ b/plugins/testsuite/clientprefstest.sp Tue Jul 15 00:24:08 2008 +0000
11.3 @@ -44,6 +44,8 @@
11.4 public bool:OnClientConnect(client, String:rejectmsg[], maxlen)
11.5 {
11.6 LogMessage("Connect Cookie state: %s", AreClientCookiesCached(client) ? "YES" : "NO");
11.7 +
11.8 + return true;
11.9 }
11.10
11.11 public OnClientCookiesCached(client)