Fixed amb1810 - Clientprefs no longer blocks load.

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%402418
This commit is contained in:
Matt Woodrow 2008-07-15 00:24:08 +00:00
parent 67e28d7475
commit e64e2534eb
11 changed files with 625 additions and 191 deletions

View File

@ -80,7 +80,17 @@ void CookieManager::Unload()
continue;
}
delete current;
g_ClientPrefs.cookieMutex->Lock();
if (current->usedInQuery)
{
current->shouldDelete = true;
g_ClientPrefs.cookieMutex->Unlock();
}
else
{
g_ClientPrefs.cookieMutex->Unlock();
delete current;
}
_iter = cookieList.erase(_iter);
}
@ -98,7 +108,6 @@ Cookie *CookieManager::FindCookie(const char *name)
return *pCookie;
}
Cookie *CookieManager::CreateCookie(const char *name, const char *description, CookieAccess access)
{
Cookie *pCookie = FindCookie(name);
@ -120,25 +129,16 @@ Cookie *CookieManager::CreateCookie(const char *name, const char *description, C
cookieTrie.insert(name, pCookie);
cookieList.push_back(pCookie);
char quotedname[2 * MAX_NAME_LENGTH + 1];
char quoteddesc[2 * MAX_DESC_LENGTH + 1];
g_ClientPrefs.Database->QuoteString(pCookie->name, quotedname, sizeof(quotedname), NULL);
g_ClientPrefs.Database->QuoteString(pCookie->description, quoteddesc, sizeof(quoteddesc), NULL);
/* Attempt to insert cookie into the db and get its ID num */
char query[300];
if (driver == DRIVER_SQLITE)
{
UTIL_Format(query, sizeof(query), "INSERT OR IGNORE INTO sm_cookies(name, description, access) VALUES('%s', '%s', %i)", quotedname, quoteddesc, access);
}
else
{
UTIL_Format(query, sizeof(query), "INSERT IGNORE INTO sm_cookies(name, description, access) VALUES('%s', '%s', %i)", quotedname, quoteddesc, access);
}
TQueryOp *op = new TQueryOp(g_ClientPrefs.Database, query, Query_InsertCookie, pCookie);
dbi->AddToThreadQueue(op, PrioQueue_Normal);
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;
}
@ -198,11 +198,10 @@ void CookieManager::OnClientAuthorized(int client, const char *authstring)
{
connected[client] = true;
char query[300];
/* Assume that the authstring doesn't need to be quoted */
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);
TQueryOp *op = new TQueryOp(g_ClientPrefs.Database, query, Query_SelectData, client);
dbi->AddToThreadQueue(op, PrioQueue_Normal);
TQueryOp *op = new TQueryOp(Query_SelectData, client);
strcpy(op->m_params.steamId, authstring);
g_ClientPrefs.AddQueryToQueue(op);
}
void CookieManager::OnClientDisconnecting(int client)
@ -245,24 +244,18 @@ void CookieManager::OnClientDisconnecting(int client)
return;
}
char quotedvalue[2 * MAX_VALUE_LENGTH + 1];
g_ClientPrefs.Database->QuoteString(current->value, quotedvalue, sizeof(quotedvalue), NULL);
TQueryOp *op = new TQueryOp(Query_InsertData, client);
char query[300];
if (driver == DRIVER_SQLITE)
{
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));
}
else
{
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));
}
TQueryOp *op = new TQueryOp(g_ClientPrefs.Database, query, Query_InsertData, client);
dbi->AddToThreadQueue(op, PrioQueue_Normal);
strcpy(op->m_params.steamId, player->GetAuthString());
op->m_params.cookieId = dbId;
op->m_params.data = current;
g_ClientPrefs.AddQueryToQueue(op);
current->parent->data[client] = NULL;
delete current;
/* We don't delete here, it will be removed when the query is completed */
_iter = clientData[client].erase(_iter);
}
@ -330,14 +323,10 @@ void CookieManager::InsertCookieCallback(Cookie *pCookie, int dbId)
return;
}
char quotedname[2 * MAX_NAME_LENGTH + 1];
g_ClientPrefs.Database->QuoteString(pCookie->name, quotedname, sizeof(quotedname), NULL);
char query[300];
UTIL_Format(query, sizeof(query), "SELECT id FROM sm_cookies WHERE name='%s'", quotedname);
TQueryOp *op = new TQueryOp(g_ClientPrefs.Database, query, Query_SelectId, pCookie);
dbi->AddToThreadQueue(op, PrioQueue_Normal);
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);
g_ClientPrefs.AddQueryToQueue(op);
}
void CookieManager::SelectIdCallback(Cookie *pCookie, IQuery *data)

View File

@ -80,6 +80,9 @@ struct Cookie
{
data[i] = NULL;
}
shouldDelete = false;
usedInQuery = 0;
}
~Cookie()
@ -98,6 +101,10 @@ struct Cookie
int dbid;
CookieData *data[MAXCLIENTS+1];
CookieAccess access;
/* Reference counting stuff */
bool shouldDelete;
int usedInQuery;
};
class CookieManager : public IClientListener, public IPluginsListener
@ -123,14 +130,13 @@ public:
bool AreClientCookiesCached(int client);
IForward *cookieDataLoadedForward;
SourceHook::List<Cookie *> cookieList;
IBaseMenu *clientMenu;
void OnPluginDestroyed(IPlugin *plugin);
public:
IForward *cookieDataLoadedForward;
SourceHook::List<Cookie *> cookieList;
IBaseMenu *clientMenu;
private:
KTrie<Cookie *> cookieTrie;
SourceHook::List<CookieData *> clientData[MAXCLIENTS];

View File

@ -50,8 +50,11 @@ CookieIteratorHandler g_CookieIteratorHandler;
int driver = 0;
bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late)
{
const DatabaseInfo *DBInfo = dbi->FindDatabaseConf("clientprefs");
{
queryMutex = threader->MakeMutex();
cookieMutex = threader->MakeMutex();
DBInfo = dbi->FindDatabaseConf("clientprefs");
if (DBInfo == NULL)
{
@ -62,7 +65,6 @@ bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late)
snprintf(error, maxlength, "Could not find \"clientprefs\" or \"default\" database configs");
return false;
}
}
if (DBInfo->driver[0] != '\0')
@ -80,92 +82,13 @@ bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late)
return false;
}
Database = Driver->Connect(DBInfo, true, error, maxlength);
if (Database == NULL)
{
return false;
}
Database = NULL;
databaseLoading = true;
TQueryOp *op = new TQueryOp(Query_Connect, 0);
dbi->AddToThreadQueue(op, PrioQueue_High);
dbi->AddDependency(myself, Driver);
const char *identifier = Driver->GetIdentifier();
if (strcmp(identifier, "sqlite") == 0)
{
driver = DRIVER_SQLITE;
TQueryOp *op = new TQueryOp(
Database,
"CREATE TABLE IF NOT EXISTS sm_cookies \
( \
id INTEGER PRIMARY KEY AUTOINCREMENT, \
name varchar(30) NOT NULL UNIQUE, \
description varchar(255), \
access INTEGER \
)",
Query_CreateTable,
0);
dbi->AddToThreadQueue(op, PrioQueue_Normal);
op = new TQueryOp(
Database,
"CREATE TABLE IF NOT EXISTS sm_cookie_cache \
( \
player varchar(65) NOT NULL, \
cookie_id int(10) NOT NULL, \
value varchar(100), \
timestamp int, \
PRIMARY KEY (player, cookie_id) \
)",
Query_CreateTable,
0);
dbi->AddToThreadQueue(op, PrioQueue_Normal);
}
else if (strcmp(identifier, "mysql") == 0)
{
driver = DRIVER_MYSQL;
TQueryOp *op = new TQueryOp(
Database,
"CREATE TABLE IF NOT EXISTS sm_cookies \
( \
id INTEGER unsigned NOT NULL auto_increment, \
name varchar(30) NOT NULL UNIQUE, \
description varchar(255), \
access INTEGER, \
PRIMARY KEY (id) \
)",
Query_CreateTable,
0);
dbi->AddToThreadQueue(op, PrioQueue_Normal);
op = new TQueryOp(
Database,
"CREATE TABLE IF NOT EXISTS sm_cookie_cache \
( \
player varchar(65) NOT NULL, \
cookie_id int(10) NOT NULL, \
value varchar(100), \
timestamp int NOT NULL, \
PRIMARY KEY (player, cookie_id) \
)",
Query_CreateTable,
0);
dbi->AddToThreadQueue(op, PrioQueue_Normal);
}
else
{
snprintf(error, maxlength, "Unsupported driver \"%s\"", identifier);
return false;
}
sharesys->AddNatives(myself, g_ClientPrefNatives);
sharesys->RegisterLibrary(myself, "clientprefs");
g_CookieManager.cookieDataLoadedForward = forwards->CreateForward("OnClientCookiesCached", ET_Ignore, 1, NULL, Param_Cell);
@ -218,6 +141,16 @@ void ClientPrefs::NotifyInterfaceDrop(SMInterface *pInterface)
{
if (Database != NULL && (void *)pInterface == (void *)(Database->GetDriver()))
{
InsertCookieQuery->Destroy();
SelectDataQuery->Destroy();
SelectIdQuery->Destroy();
InsertDataQuery->Destroy();
InsertCookieQuery = NULL;
SelectDataQuery = NULL;
SelectIdQuery = NULL;
InsertDataQuery = NULL;
Database->Close();
Database = NULL;
}
@ -243,6 +176,232 @@ void ClientPrefs::SDK_OnUnload()
plsys->RemovePluginsListener(&g_CookieManager);
playerhelpers->RemoveClientListener(&g_CookieManager);
/* Kill all our prepared queries - Queries are guaranteed to be flushed before this is called */
if (InsertCookieQuery != NULL)
{
InsertCookieQuery->Destroy();
}
if (SelectDataQuery != NULL)
{
SelectDataQuery->Destroy();
}
if (SelectIdQuery != NULL)
{
SelectIdQuery->Destroy();
}
if (InsertDataQuery != NULL)
{
InsertDataQuery->Destroy();
}
queryMutex->DestroyThis();
cookieMutex->DestroyThis();
}
void ClientPrefs::DatabaseConnect()
{
char error[256];
int errCode = 0;
Database = Driver->Connect(DBInfo, true, error, sizeof(error));
if (Database == NULL)
{
g_pSM->LogError(myself, error);
databaseLoading = false;
ProcessQueryCache();
return;
}
const char *identifier = Driver->GetIdentifier();
if (strcmp(identifier, "sqlite") == 0)
{
driver = DRIVER_SQLITE;
TQueryOp *op = new TQueryOp(Query_CreateTable, 0);
op->SetDatabase(Database);
op->SetCustomPreparedQuery
(Database->PrepareQuery(
"CREATE TABLE IF NOT EXISTS sm_cookies \
( \
id INTEGER PRIMARY KEY AUTOINCREMENT, \
name varchar(30) NOT NULL UNIQUE, \
description varchar(255), \
access INTEGER \
)",
error, sizeof(error), &errCode));
dbi->AddToThreadQueue(op, PrioQueue_High);
op = new TQueryOp(Query_CreateTable, 0);
op->SetDatabase(Database);
op->SetCustomPreparedQuery
(Database->PrepareQuery(
"CREATE TABLE IF NOT EXISTS sm_cookie_cache \
( \
player varchar(65) NOT NULL, \
cookie_id int(10) NOT NULL, \
value varchar(100), \
timestamp int, \
PRIMARY KEY (player, cookie_id) \
)",
error, sizeof(error), &errCode));
dbi->AddToThreadQueue(op, PrioQueue_High);
}
else if (strcmp(identifier, "mysql") == 0)
{
driver = DRIVER_MYSQL;
TQueryOp *op = new TQueryOp(Query_CreateTable, 0);
op->SetDatabase(Database);
op->SetCustomPreparedQuery
(Database->PrepareQuery(
"CREATE TABLE IF NOT EXISTS sm_cookies \
( \
id INTEGER unsigned NOT NULL auto_increment, \
name varchar(30) NOT NULL UNIQUE, \
description varchar(255), \
access INTEGER, \
PRIMARY KEY (id) \
)",
error, sizeof(error), &errCode));
dbi->AddToThreadQueue(op, PrioQueue_High);
op = new TQueryOp(Query_CreateTable, 0);
op->SetDatabase(Database);
op->SetCustomPreparedQuery
(Database->PrepareQuery(
"CREATE TABLE IF NOT EXISTS sm_cookie_cache \
( \
player varchar(65) NOT NULL, \
cookie_id int(10) NOT NULL, \
value varchar(100), \
timestamp int NOT NULL, \
PRIMARY KEY (player, cookie_id) \
)",
error, sizeof(error), &errCode));
dbi->AddToThreadQueue(op, PrioQueue_High);
}
else
{
g_pSM->LogError(myself, "Unsupported driver \"%s\"", identifier);
Database->Close();
Database = NULL;
databaseLoading = false;
ProcessQueryCache();
return;
}
if (driver == DRIVER_MYSQL)
{
InsertCookieQuery = Database->PrepareQuery(
"INSERT IGNORE INTO sm_cookies(name, description, access) \
VALUES(?, ?, ?)",
error, sizeof(error), &errCode);
InsertDataQuery = Database->PrepareQuery(
"INSERT INTO sm_cookie_cache(player, cookie_id, value, timestamp) \
VALUES(?, ?, ?, ?) \
ON DUPLICATE KEY UPDATE value = ?, timestamp = ?",
error, sizeof(error), &errCode);
}
else
{
InsertCookieQuery = Database->PrepareQuery(
"INSERT OR IGNORE INTO sm_cookies(name, description, access) \
VALUES(?, ?, ?)",
error, sizeof(error), &errCode);
InsertDataQuery = Database->PrepareQuery(
"INSERT OR REPLACE INTO sm_cookie_cache(player, cookie_id, value, timestamp) \
VALUES(?, ?, ?, ?)",
error, sizeof(error), &errCode);
}
SelectDataQuery = Database->PrepareQuery(
"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 = ?",
error, sizeof(error), &errCode);
SelectIdQuery = Database->PrepareQuery(
"SELECT id \
FROM sm_cookies \
WHERE name=?",
error, sizeof(error), &errCode);
databaseLoading = false;
cell_t result = 0;
ProcessQueryCache();
return;
}
bool ClientPrefs::AddQueryToQueue( TQueryOp *query )
{
queryMutex->Lock();
if (Database == NULL && databaseLoading)
{
cachedQueries.push_back(query);
queryMutex->Unlock();
return true;
}
queryMutex->Unlock();
if (Database)
{
query->SetDatabase(Database);
query->SetPreparedQuery();
dbi->AddToThreadQueue(query, PrioQueue_Normal);
return true;
}
/* If Database is NULL and we're not in the loading phase it must have failed - Can't do much */
return false;
}
void ClientPrefs::ProcessQueryCache()
{
SourceHook::List<TQueryOp *>::iterator iter;
queryMutex->Lock();
iter = cachedQueries.begin();
while (iter != cachedQueries.end())
{
TQueryOp *op = (TQueryOp *)*iter;
if (Database != NULL)
{
op->SetDatabase(Database);
op->SetPreparedQuery();
dbi->AddToThreadQueue(op, PrioQueue_Normal);
}
else
{
delete op;
}
iter++;
}
cachedQueries.clear();
queryMutex->Unlock();
}
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)

View File

@ -47,6 +47,8 @@
#define MAX_TRANSLATE_PARAMS 32
class TQueryOp;
/**
* @brief Sample implementation of the SDK Extension.
* Note: Uncomment one of the pre-defined virtual functions in order to use it.
@ -79,6 +81,11 @@ public:
virtual void NotifyInterfaceDrop(SMInterface *pInterface);
void DatabaseConnect();
bool AddQueryToQueue(TQueryOp *query);
void ProcessQueryCache();
/**
* @brief Called when the pause state is changed.
*/
@ -128,7 +135,20 @@ public:
public:
IDBDriver *Driver;
IDatabase *Database;
bool databaseLoading;
IPhraseCollection *phrases;
const DatabaseInfo *DBInfo;
IPreparedQuery *InsertCookieQuery;
IPreparedQuery *SelectDataQuery;
IPreparedQuery *InsertDataQuery;
IPreparedQuery *SelectIdQuery;
IMutex *cookieMutex;
private:
SourceHook::List<TQueryOp *> cachedQueries;
IMutex *queryMutex;
};
class CookieTypeHandler : public IHandleTypeDispatch
@ -136,7 +156,7 @@ class CookieTypeHandler : public IHandleTypeDispatch
public:
void OnHandleDestroy(HandleType_t type, void *object)
{
/* No delete needed since Cookies are persistant */
/* No delete needed since Cookies are persistent */
}
};

View File

@ -35,6 +35,11 @@
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");
}
char *name;
pContext->LocalToString(params[1], &name);
@ -62,6 +67,11 @@ 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");
}
char *name;
pContext->LocalToString(params[1], &name);
@ -81,6 +91,11 @@ cell_t FindClientPrefCookie(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");
}
int client = params[1];
if ((client < 1) || (client > playerhelpers->GetMaxClients()))
@ -111,6 +126,11 @@ 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");
}
int client = params[1];
if ((client < 1) || (client > playerhelpers->GetMaxClients()))
@ -144,6 +164,11 @@ 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");
}
int client = params[1];
if ((client < 1) || (client > playerhelpers->GetMaxClients()))
@ -156,6 +181,11 @@ 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");
}
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError err;
HandleSecurity sec;
@ -176,6 +206,11 @@ 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");
}
SourceHook::List<Cookie *>::iterator *iter = new SourceHook::List<Cookie *>::iterator;
*iter = g_CookieManager.cookieList.begin();
@ -190,6 +225,11 @@ 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");
}
SourceHook::List<Cookie *>::iterator *iter;
Handle_t hndl = static_cast<Handle_t>(params[1]);
@ -226,6 +266,11 @@ 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");
}
char message[256];
Translate(message, sizeof(message), "%T:", 2, NULL, "Client Settings", &params[1]);
@ -237,6 +282,11 @@ 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");
}
char *display;
pContext->LocalToString(params[3], &display);
@ -278,6 +328,11 @@ 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");
}
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError err;
HandleSecurity sec;

View File

@ -36,52 +36,83 @@ void TQueryOp::RunThinkPart()
{
//handler for threaded sql queries
if (m_type == Query_Connect)
{
return;
}
if (m_pQuery)
{
switch (m_type)
{
case Query_InsertCookie:
g_CookieManager.InsertCookieCallback(pCookie, m_insertId);
break;
case Query_SelectData:
g_CookieManager.ClientConnectCallback(m_client, m_pQuery);
break;
case Query_InsertData:
//No specific handling
break;
case Query_SelectId:
g_CookieManager.SelectIdCallback(pCookie, m_pQuery);
break;
default:
break;
}
case Query_InsertCookie:
{
g_CookieManager.InsertCookieCallback(m_pCookie, m_insertId);
break;
}
m_pQuery->Destroy();
}
else
{
g_pSM->LogError(myself,"Failed SQL Query, Error: \"%s\" (Query id %i - client %i)", error, m_type, m_client);
case Query_SelectData:
{
g_CookieManager.ClientConnectCallback(m_client, m_pQuery);
break;
}
case Query_SelectId:
{
g_CookieManager.SelectIdCallback(m_pCookie, m_pQuery);
break;
}
case Query_CreateTable:
{
m_pQuery->Destroy();
delete m_pQuery;
m_pQuery = NULL;
break;
}
default:
{
break;
}
}
}
}
void TQueryOp::RunThreadPart()
{
m_pDatabase->LockForFullAtomicOperation();
m_pQuery = m_pDatabase->DoQuery(m_Query.c_str());
if (!m_pQuery)
if (m_type == Query_Connect)
{
g_pSM->LogError(myself, "Failed SQL Query, Error: \"%s\" (Query id %i - client %i)", m_pDatabase->GetError(), m_type, m_client);
g_ClientPrefs.DatabaseConnect();
}
else
{
if (m_database == NULL)
{
return;
}
m_insertId = g_ClientPrefs.Database->GetInsertID();
m_database->LockForFullAtomicOperation();
m_pDatabase->UnlockFromFullAtomicOperation();
if (!BindParamsAndRun())
{
g_pSM->LogError(myself, "Failed SQL Query, Error: \"%s\" (Query id %i - client %i)", m_database->GetError(), m_type, m_client);
}
m_insertId = m_database->GetInsertID();
m_database->UnlockFromFullAtomicOperation();
}
}
IDBDriver *TQueryOp::GetDriver()
{
return m_pDatabase->GetDriver();
if (m_database == NULL)
{
return NULL;
}
return m_database->GetDriver();
}
IdentityToken_t *TQueryOp::GetOwner()
{
@ -92,24 +123,157 @@ void TQueryOp::Destroy()
delete this;
}
TQueryOp::TQueryOp(IDatabase *db, const char *query, enum querytype type, int client)
TQueryOp::TQueryOp(enum querytype type, int client)
{
m_pDatabase = db;
m_Query = query;
m_type = type;
m_client = client;
m_pQuery = NULL;
m_pDatabase->IncReferenceCount();
m_database = NULL;
}
TQueryOp::TQueryOp(IDatabase *db, const char *query, enum querytype type, Cookie *cookie)
TQueryOp::TQueryOp(enum querytype type, Cookie *cookie)
{
m_pDatabase = db;
m_Query = query;
m_type = type;
pCookie = cookie;
m_pCookie = cookie;
m_pQuery = NULL;
m_pDatabase->IncReferenceCount();
m_database = NULL;
}
void TQueryOp::SetDatabase( IDatabase *db )
{
m_database = db;
m_database->IncReferenceCount();
}
bool TQueryOp::BindParamsAndRun()
{
if (m_pQuery == NULL)
{
return false;
}
switch (m_type)
{
case Query_InsertCookie:
{
m_pQuery->BindParamString(0, m_params.cookie->name, false);
m_pQuery->BindParamString(1, m_params.cookie->description, false);
m_pQuery->BindParamInt(2, m_params.cookie->access);
break;
}
case Query_SelectData:
{
m_pQuery->BindParamString(0, m_params.steamId, false);
break;
}
case Query_InsertData:
{
m_pQuery->BindParamString(0, m_params.steamId, false);
m_pQuery->BindParamInt(1, m_params.cookieId);
m_pQuery->BindParamString(2, m_params.data->value, false);
m_pQuery->BindParamInt(3, (unsigned int)time(NULL), false);
if (driver == DRIVER_MYSQL)
{
m_pQuery->BindParamString(4, m_params.data->value, false);
m_pQuery->BindParamInt(5, (unsigned int)time(NULL), false);
}
break;
}
case Query_SelectId:
{
/* the steamId var was actually used to store the name of the cookie - Save duplicating vars */
m_pQuery->BindParamString(0, m_params.steamId, false);
break;
}
default:
{
break;
}
}
return m_pQuery->Execute();
}
void TQueryOp::SetPreparedQuery()
{
switch (m_type)
{
case Query_InsertCookie:
{
m_pQuery = g_ClientPrefs.InsertCookieQuery;
break;
}
case Query_SelectData:
{
m_pQuery = g_ClientPrefs.SelectDataQuery;
break;
}
case Query_InsertData:
{
m_pQuery = g_ClientPrefs.InsertDataQuery;
break;
}
case Query_SelectId:
{
m_pQuery = g_ClientPrefs.SelectIdQuery;
break;
}
default:
{
break;
}
}
}
void TQueryOp::SetCustomPreparedQuery(IPreparedQuery *query)
{
m_pQuery = query;
}
ParamData::~ParamData()
{
if (cookie)
{
g_ClientPrefs.cookieMutex->Lock();
cookie->usedInQuery--;
if (cookie->shouldDelete && cookie->usedInQuery <= 0)
{
g_ClientPrefs.cookieMutex->Unlock();
delete cookie;
cookie = NULL;
}
g_ClientPrefs.cookieMutex->Unlock();
}
if (data)
{
/* Data is only ever passed in a client disconnect query and always needs to be deleted */
delete data;
data = NULL;
}
}
ParamData::ParamData()
{
cookie = NULL;
data = NULL;
steamId[0] = '\0';
cookieId = 0;
}

View File

@ -43,36 +43,67 @@ enum querytype
Query_InsertData,
Query_SelectId,
Query_CreateTable,
Query_Connect,
};
struct PreparedQueryWrapper;
struct Cookie;
struct CookieData;
#define MAX_NAME_LENGTH 30
/* This stores all the info required for our param binding until the thread is executed */
struct ParamData
{
ParamData();
~ParamData();
/* Contains a name, description and access for InsertCookie queries */
Cookie *cookie;
/* A clients steamid - Used for most queries - Doubles as storage for the cookie name*/
char steamId[MAX_NAME_LENGTH];
int cookieId;
CookieData *data;
};
class TQueryOp : public IDBThreadOperation
{
public:
TQueryOp(IDatabase *db, const char *query, enum querytype type, int client);
TQueryOp(IDatabase *db, const char *query, enum querytype type, Cookie *cookie);
TQueryOp(enum querytype type, int client);
TQueryOp(enum querytype type, Cookie *cookie);
~TQueryOp() {}
IDBDriver *GetDriver();
IdentityToken_t *GetOwner();
void SetDatabase(IDatabase *db);
void SetPreparedQuery();
void SetCustomPreparedQuery(IPreparedQuery *wrapper);
void Destroy();
void RunThreadPart();
/* Thread has been cancelled due to driver unloading. Nothing else to do? */
void CancelThinkPart()
{
}
void CancelThinkPart() {}
void RunThinkPart();
bool BindParamsAndRun();
/* Params to be bound */
ParamData m_params;
private:
IDatabase *m_pDatabase;
IQuery *m_pQuery;
SourceHook::String m_Query;
char error[255];
IPreparedQuery *m_pQuery;
IDatabase *m_database;
/* Query type */
enum querytype m_type;
/* Data to be passed to the callback */
int m_client;
int m_insertId;
Cookie *pCookie;
Cookie *m_pCookie;
};

View File

@ -69,7 +69,7 @@
//#define SMEXT_ENABLE_MEMUTILS
#define SMEXT_ENABLE_GAMEHELPERS
//#define SMEXT_ENABLE_TIMERSYS
//#define SMEXT_ENABLE_THREADER
#define SMEXT_ENABLE_THREADER
//#define SMEXT_ENABLE_LIBSYS
#define SMEXT_ENABLE_MENUS
//#define SMEXT_ENABLE_ADTFACTORY

View File

@ -58,7 +58,7 @@ public Action:Command_Cookie(client, args)
{
if (args == 0)
{
ReplyToCommand(client, "[SM] Usage: sm_cookie <name> [value]");
ReplyToCommand(client, "[SM] Usage: sm_cookies <name> [value]");
ReplyToCommand(client, "[SM] %t", "Printing Cookie List");
/* Show list of cookies */

View File

@ -74,6 +74,14 @@ enum CookieMenuAction
CookieMenuAction_SelectOption = 1,
};
/**
* Note:
*
* A successful return value/result on any client prefs native only guarantees that the local cache has been updated.
* Database connection problems can still prevent the data from being permanently saved. Connection problems will be logged as
* errors by the clientprefs extension.
*/
/**
* Creates a new Client preference cookie.
*

View File

@ -44,6 +44,8 @@ public CookieSelected(client, CookieMenuAction:action, any:info, String:buffer[]
public bool:OnClientConnect(client, String:rejectmsg[], maxlen)
{
LogMessage("Connect Cookie state: %s", AreClientCookiesCached(client) ? "YES" : "NO");
return true;
}
public OnClientCookiesCached(client)