extensions/clientprefs/extension.cpp
changeset 2207 3a97a56ded62
parent 2135 2c56e1550aaa
child 2220 20b404790b3b
     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, ...)