1.1 --- a/extensions/clientprefs/extension.cpp Sun Jul 13 07:01:54 2008 +0000
1.2 +++ b/extensions/clientprefs/extension.cpp Tue Jul 15 00:24:08 2008 +0000
1.3 @@ -50,8 +50,11 @@
1.4 int driver = 0;
1.5
1.6 bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late)
1.7 -{
1.8 - const DatabaseInfo *DBInfo = dbi->FindDatabaseConf("clientprefs");
1.9 +{
1.10 + queryMutex = threader->MakeMutex();
1.11 + cookieMutex = threader->MakeMutex();
1.12 +
1.13 + DBInfo = dbi->FindDatabaseConf("clientprefs");
1.14
1.15 if (DBInfo == NULL)
1.16 {
1.17 @@ -62,7 +65,6 @@
1.18 snprintf(error, maxlength, "Could not find \"clientprefs\" or \"default\" database configs");
1.19 return false;
1.20 }
1.21 -
1.22 }
1.23
1.24 if (DBInfo->driver[0] != '\0')
1.25 @@ -80,92 +82,13 @@
1.26 return false;
1.27 }
1.28
1.29 - Database = Driver->Connect(DBInfo, true, error, maxlength);
1.30 -
1.31 - if (Database == NULL)
1.32 - {
1.33 - return false;
1.34 - }
1.35 + Database = NULL;
1.36 + databaseLoading = true;
1.37 + TQueryOp *op = new TQueryOp(Query_Connect, 0);
1.38 + dbi->AddToThreadQueue(op, PrioQueue_High);
1.39
1.40 dbi->AddDependency(myself, Driver);
1.41
1.42 - const char *identifier = Driver->GetIdentifier();
1.43 -
1.44 - if (strcmp(identifier, "sqlite") == 0)
1.45 - {
1.46 - driver = DRIVER_SQLITE;
1.47 -
1.48 - TQueryOp *op = new TQueryOp(
1.49 - Database,
1.50 - "CREATE TABLE IF NOT EXISTS sm_cookies \
1.51 - ( \
1.52 - id INTEGER PRIMARY KEY AUTOINCREMENT, \
1.53 - name varchar(30) NOT NULL UNIQUE, \
1.54 - description varchar(255), \
1.55 - access INTEGER \
1.56 - )",
1.57 - Query_CreateTable,
1.58 - 0);
1.59 -
1.60 - dbi->AddToThreadQueue(op, PrioQueue_Normal);
1.61 -
1.62 - op = new TQueryOp(
1.63 - Database,
1.64 - "CREATE TABLE IF NOT EXISTS sm_cookie_cache \
1.65 - ( \
1.66 - player varchar(65) NOT NULL, \
1.67 - cookie_id int(10) NOT NULL, \
1.68 - value varchar(100), \
1.69 - timestamp int, \
1.70 - PRIMARY KEY (player, cookie_id) \
1.71 - )",
1.72 - Query_CreateTable,
1.73 - 0);
1.74 -
1.75 - dbi->AddToThreadQueue(op, PrioQueue_Normal);
1.76 - }
1.77 - else if (strcmp(identifier, "mysql") == 0)
1.78 - {
1.79 - driver = DRIVER_MYSQL;
1.80 -
1.81 - TQueryOp *op = new TQueryOp(
1.82 - Database,
1.83 - "CREATE TABLE IF NOT EXISTS sm_cookies \
1.84 - ( \
1.85 - id INTEGER unsigned NOT NULL auto_increment, \
1.86 - name varchar(30) NOT NULL UNIQUE, \
1.87 - description varchar(255), \
1.88 - access INTEGER, \
1.89 - PRIMARY KEY (id) \
1.90 - )",
1.91 - Query_CreateTable,
1.92 - 0);
1.93 -
1.94 - dbi->AddToThreadQueue(op, PrioQueue_Normal);
1.95 -
1.96 - op = new TQueryOp(
1.97 - Database,
1.98 - "CREATE TABLE IF NOT EXISTS sm_cookie_cache \
1.99 - ( \
1.100 - player varchar(65) NOT NULL, \
1.101 - cookie_id int(10) NOT NULL, \
1.102 - value varchar(100), \
1.103 - timestamp int NOT NULL, \
1.104 - PRIMARY KEY (player, cookie_id) \
1.105 - )",
1.106 - Query_CreateTable,
1.107 - 0);
1.108 -
1.109 - dbi->AddToThreadQueue(op, PrioQueue_Normal);
1.110 - }
1.111 - else
1.112 - {
1.113 - snprintf(error, maxlength, "Unsupported driver \"%s\"", identifier);
1.114 - return false;
1.115 - }
1.116 -
1.117 -
1.118 -
1.119 sharesys->AddNatives(myself, g_ClientPrefNatives);
1.120 sharesys->RegisterLibrary(myself, "clientprefs");
1.121 g_CookieManager.cookieDataLoadedForward = forwards->CreateForward("OnClientCookiesCached", ET_Ignore, 1, NULL, Param_Cell);
1.122 @@ -218,6 +141,16 @@
1.123 {
1.124 if (Database != NULL && (void *)pInterface == (void *)(Database->GetDriver()))
1.125 {
1.126 + InsertCookieQuery->Destroy();
1.127 + SelectDataQuery->Destroy();
1.128 + SelectIdQuery->Destroy();
1.129 + InsertDataQuery->Destroy();
1.130 +
1.131 + InsertCookieQuery = NULL;
1.132 + SelectDataQuery = NULL;
1.133 + SelectIdQuery = NULL;
1.134 + InsertDataQuery = NULL;
1.135 +
1.136 Database->Close();
1.137 Database = NULL;
1.138 }
1.139 @@ -243,6 +176,232 @@
1.140
1.141 plsys->RemovePluginsListener(&g_CookieManager);
1.142 playerhelpers->RemoveClientListener(&g_CookieManager);
1.143 +
1.144 + /* Kill all our prepared queries - Queries are guaranteed to be flushed before this is called */
1.145 +
1.146 + if (InsertCookieQuery != NULL)
1.147 + {
1.148 + InsertCookieQuery->Destroy();
1.149 + }
1.150 +
1.151 + if (SelectDataQuery != NULL)
1.152 + {
1.153 + SelectDataQuery->Destroy();
1.154 + }
1.155 +
1.156 + if (SelectIdQuery != NULL)
1.157 + {
1.158 + SelectIdQuery->Destroy();
1.159 + }
1.160 +
1.161 + if (InsertDataQuery != NULL)
1.162 + {
1.163 + InsertDataQuery->Destroy();
1.164 + }
1.165 +
1.166 + queryMutex->DestroyThis();
1.167 + cookieMutex->DestroyThis();
1.168 +}
1.169 +
1.170 +void ClientPrefs::DatabaseConnect()
1.171 +{
1.172 + char error[256];
1.173 + int errCode = 0;
1.174 +
1.175 + Database = Driver->Connect(DBInfo, true, error, sizeof(error));
1.176 +
1.177 + if (Database == NULL)
1.178 + {
1.179 + g_pSM->LogError(myself, error);
1.180 + databaseLoading = false;
1.181 + ProcessQueryCache();
1.182 + return;
1.183 + }
1.184 +
1.185 + const char *identifier = Driver->GetIdentifier();
1.186 +
1.187 + if (strcmp(identifier, "sqlite") == 0)
1.188 + {
1.189 + driver = DRIVER_SQLITE;
1.190 +
1.191 + TQueryOp *op = new TQueryOp(Query_CreateTable, 0);
1.192 +
1.193 + op->SetDatabase(Database);
1.194 + op->SetCustomPreparedQuery
1.195 + (Database->PrepareQuery(
1.196 + "CREATE TABLE IF NOT EXISTS sm_cookies \
1.197 + ( \
1.198 + id INTEGER PRIMARY KEY AUTOINCREMENT, \
1.199 + name varchar(30) NOT NULL UNIQUE, \
1.200 + description varchar(255), \
1.201 + access INTEGER \
1.202 + )",
1.203 + error, sizeof(error), &errCode));
1.204 +
1.205 + dbi->AddToThreadQueue(op, PrioQueue_High);
1.206 +
1.207 + op = new TQueryOp(Query_CreateTable, 0);
1.208 + op->SetDatabase(Database);
1.209 + op->SetCustomPreparedQuery
1.210 + (Database->PrepareQuery(
1.211 + "CREATE TABLE IF NOT EXISTS sm_cookie_cache \
1.212 + ( \
1.213 + player varchar(65) NOT NULL, \
1.214 + cookie_id int(10) NOT NULL, \
1.215 + value varchar(100), \
1.216 + timestamp int, \
1.217 + PRIMARY KEY (player, cookie_id) \
1.218 + )",
1.219 + error, sizeof(error), &errCode));
1.220 +
1.221 + dbi->AddToThreadQueue(op, PrioQueue_High);
1.222 + }
1.223 + else if (strcmp(identifier, "mysql") == 0)
1.224 + {
1.225 + driver = DRIVER_MYSQL;
1.226 +
1.227 + TQueryOp *op = new TQueryOp(Query_CreateTable, 0);
1.228 + op->SetDatabase(Database);
1.229 + op->SetCustomPreparedQuery
1.230 + (Database->PrepareQuery(
1.231 + "CREATE TABLE IF NOT EXISTS sm_cookies \
1.232 + ( \
1.233 + id INTEGER unsigned NOT NULL auto_increment, \
1.234 + name varchar(30) NOT NULL UNIQUE, \
1.235 + description varchar(255), \
1.236 + access INTEGER, \
1.237 + PRIMARY KEY (id) \
1.238 + )",
1.239 + error, sizeof(error), &errCode));
1.240 +
1.241 + dbi->AddToThreadQueue(op, PrioQueue_High);
1.242 +
1.243 + op = new TQueryOp(Query_CreateTable, 0);
1.244 + op->SetDatabase(Database);
1.245 + op->SetCustomPreparedQuery
1.246 + (Database->PrepareQuery(
1.247 + "CREATE TABLE IF NOT EXISTS sm_cookie_cache \
1.248 + ( \
1.249 + player varchar(65) NOT NULL, \
1.250 + cookie_id int(10) NOT NULL, \
1.251 + value varchar(100), \
1.252 + timestamp int NOT NULL, \
1.253 + PRIMARY KEY (player, cookie_id) \
1.254 + )",
1.255 + error, sizeof(error), &errCode));
1.256 +
1.257 + dbi->AddToThreadQueue(op, PrioQueue_High);
1.258 + }
1.259 + else
1.260 + {
1.261 + g_pSM->LogError(myself, "Unsupported driver \"%s\"", identifier);
1.262 + Database->Close();
1.263 + Database = NULL;
1.264 + databaseLoading = false;
1.265 + ProcessQueryCache();
1.266 + return;
1.267 + }
1.268 +
1.269 + if (driver == DRIVER_MYSQL)
1.270 + {
1.271 + InsertCookieQuery = Database->PrepareQuery(
1.272 + "INSERT IGNORE INTO sm_cookies(name, description, access) \
1.273 + VALUES(?, ?, ?)",
1.274 + error, sizeof(error), &errCode);
1.275 + InsertDataQuery = Database->PrepareQuery(
1.276 + "INSERT INTO sm_cookie_cache(player, cookie_id, value, timestamp) \
1.277 + VALUES(?, ?, ?, ?) \
1.278 + ON DUPLICATE KEY UPDATE value = ?, timestamp = ?",
1.279 + error, sizeof(error), &errCode);
1.280 + }
1.281 + else
1.282 + {
1.283 + InsertCookieQuery = Database->PrepareQuery(
1.284 + "INSERT OR IGNORE INTO sm_cookies(name, description, access) \
1.285 + VALUES(?, ?, ?)",
1.286 + error, sizeof(error), &errCode);
1.287 + InsertDataQuery = Database->PrepareQuery(
1.288 + "INSERT OR REPLACE INTO sm_cookie_cache(player, cookie_id, value, timestamp) \
1.289 + VALUES(?, ?, ?, ?)",
1.290 + error, sizeof(error), &errCode);
1.291 + }
1.292 +
1.293 + SelectDataQuery = Database->PrepareQuery(
1.294 + "SELECT sm_cookies.name, sm_cookie_cache.value, sm_cookies.description, sm_cookies.access \
1.295 + FROM sm_cookies \
1.296 + JOIN sm_cookie_cache \
1.297 + ON sm_cookies.id = sm_cookie_cache.cookie_id \
1.298 + WHERE player = ?",
1.299 + error, sizeof(error), &errCode);
1.300 +
1.301 + SelectIdQuery = Database->PrepareQuery(
1.302 + "SELECT id \
1.303 + FROM sm_cookies \
1.304 + WHERE name=?",
1.305 + error, sizeof(error), &errCode);
1.306 +
1.307 + databaseLoading = false;
1.308 + cell_t result = 0;
1.309 +
1.310 + ProcessQueryCache();
1.311 +
1.312 + return;
1.313 +}
1.314 +
1.315 +bool ClientPrefs::AddQueryToQueue( TQueryOp *query )
1.316 +{
1.317 + queryMutex->Lock();
1.318 +
1.319 + if (Database == NULL && databaseLoading)
1.320 + {
1.321 + cachedQueries.push_back(query);
1.322 + queryMutex->Unlock();
1.323 + return true;
1.324 + }
1.325 +
1.326 + queryMutex->Unlock();
1.327 +
1.328 + if (Database)
1.329 + {
1.330 + query->SetDatabase(Database);
1.331 + query->SetPreparedQuery();
1.332 + dbi->AddToThreadQueue(query, PrioQueue_Normal);
1.333 + return true;
1.334 + }
1.335 +
1.336 + /* If Database is NULL and we're not in the loading phase it must have failed - Can't do much */
1.337 + return false;
1.338 +}
1.339 +
1.340 +void ClientPrefs::ProcessQueryCache()
1.341 +{
1.342 + SourceHook::List<TQueryOp *>::iterator iter;
1.343 +
1.344 + queryMutex->Lock();
1.345 +
1.346 + iter = cachedQueries.begin();
1.347 +
1.348 + while (iter != cachedQueries.end())
1.349 + {
1.350 + TQueryOp *op = (TQueryOp *)*iter;
1.351 +
1.352 + if (Database != NULL)
1.353 + {
1.354 + op->SetDatabase(Database);
1.355 + op->SetPreparedQuery();
1.356 + dbi->AddToThreadQueue(op, PrioQueue_Normal);
1.357 + }
1.358 + else
1.359 + {
1.360 + delete op;
1.361 + }
1.362 +
1.363 + iter++;
1.364 + }
1.365 +
1.366 + cachedQueries.clear();
1.367 +
1.368 + queryMutex->Unlock();
1.369 }
1.370
1.371 size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)