Fixed amb1810 - Clientprefs no longer blocks load.
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%402418
This commit is contained in:
parent
67e28d7475
commit
e64e2534eb
@ -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)
|
||||
|
@ -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];
|
||||
|
@ -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, ...)
|
||||
|
@ -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 */
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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", ¶ms[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;
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user