Skip to content

Commit

Permalink
dbstickybans: Qdeleting queries, misc fixes, Query select proc for ex…
Browse files Browse the repository at this point in the history
…ecuting mutiple queries at once...
  • Loading branch information
MrStonedOne committed Mar 16, 2019
1 parent de220da commit 186f6c8
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 97 deletions.
15 changes: 9 additions & 6 deletions SQL/database_changelog.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Any time you make a change to the schema files, remember to increment the database schema version. Generally increment the minor number, major should be reserved for significant changes to the schema. Both values go up to 255.

The latest database version is 4.7; The query to update the schema revision table is:
The latest database version is 5.1; The query to update the schema revision table is:

INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 1);
or
Expand All @@ -10,7 +10,7 @@ In any query remember to add a prefix to the table names if you use one.

----------------------------------------------------

Version 5.1, 23 Dec 2018, by MrStonedOne
Version 5.1, 25 Feb 2018, by MrStonedOne
Added four tables to enable storing of stickybans in the database since byond can lose them, and to enable disabling stickybans for a round without depending on a crash free round. Existing stickybans are automagically imported to the tables.

CREATE TABLE `stickyban` (
Expand All @@ -24,22 +24,25 @@ CREATE TABLE `stickyban` (
CREATE TABLE `stickyban_matched_ckey` (
`stickyban` VARCHAR(32) NOT NULL,
`matched_ckey` VARCHAR(32) NOT NULL,
`first_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`exempt` TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`stickyban`, `matched_ckey`)
) ENGINE=InnoDB;

CREATE TABLE `stickyban_matched_ip` (
`stickyban` VARCHAR(32) NOT NULL,
`matched_ip` INT UNSIGNED NOT NULL,
`first_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`stickyban`, `matched_ip`)
) ENGINE=InnoDB;

CREATE TABLE `stickyban_matched_cid` (
`stickyban` VARCHAR(32) NOT NULL,
`matched_cid` INT UNSIGNED NOT NULL,
`first_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`matched_cid` VARCHAR(32) NOT NULL,
`first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`stickyban`, `matched_cid`)
) ENGINE=InnoDB;

Expand Down
27 changes: 15 additions & 12 deletions SQL/tgstation_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -465,10 +465,10 @@ $$
DELIMITER ;

--
-- Table structure for table `SS13_stickyban`
-- Table structure for table `stickyban`
--
DROP TABLE IF EXISTS `SS13_stickyban`;
CREATE TABLE `SS13_stickyban` (
DROP TABLE IF EXISTS `stickyban`;
CREATE TABLE `stickyban` (
`ckey` VARCHAR(32) NOT NULL,
`reason` VARCHAR(2048) NOT NULL,
`banning_admin` VARCHAR(32) NOT NULL,
Expand All @@ -477,13 +477,14 @@ CREATE TABLE `SS13_stickyban` (
) ENGINE=InnoDB;

--
-- Table structure for table `ss13_stickyban_matched_ckey`
-- Table structure for table `stickyban_matched_ckey`
--
DROP TABLE IF EXISTS `ss13_stickyban_matched_ckey`;
DROP TABLE IF EXISTS `stickyban_matched_ckey`;
CREATE TABLE `ss13_stickyban_matched_ckey` (
`stickyban` VARCHAR(32) NOT NULL,
`matched_ckey` VARCHAR(32) NOT NULL,
`first_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`exempt` TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`stickyban`, `matched_ckey`)
) ENGINE=InnoDB;
Expand All @@ -495,18 +496,20 @@ DROP TABLE IF EXISTS `ss13_stickyban_matched_ip`;
CREATE TABLE `ss13_stickyban_matched_ip` (
`stickyban` VARCHAR(32) NOT NULL,
`matched_ip` INT UNSIGNED NOT NULL,
`first_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`stickyban`, `matched_ip`)
) ENGINE=InnoDB;

--
-- Table structure for table `ss13_stickyban_matched_cid`
-- Table structure for table `stickyban_matched_cid`
--
DROP TABLE IF EXISTS `ss13_stickyban_matched_cid`;
CREATE TABLE `ss13_stickyban_matched_cid` (
DROP TABLE IF EXISTS `stickyban_matched_cid`;
CREATE TABLE `stickyban_matched_cid` (
`stickyban` VARCHAR(32) NOT NULL,
`matched_cid` INT UNSIGNED NOT NULL,
`first_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`matched_cid` VARCHAR(32) NOT NULL,
`first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`stickyban`, `matched_cid`)
) ENGINE=InnoDB;

Expand Down
11 changes: 7 additions & 4 deletions SQL/tgstation_schema_prefixed.sql
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,8 @@ DROP TABLE IF EXISTS `ss13_stickyban_matched_ckey`;
CREATE TABLE `ss13_stickyban_matched_ckey` (
`stickyban` VARCHAR(32) NOT NULL,
`matched_ckey` VARCHAR(32) NOT NULL,
`first_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`exempt` TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`stickyban`, `matched_ckey`)
) ENGINE=InnoDB;
Expand All @@ -495,7 +496,8 @@ DROP TABLE IF EXISTS `ss13_stickyban_matched_ip`;
CREATE TABLE `ss13_stickyban_matched_ip` (
`stickyban` VARCHAR(32) NOT NULL,
`matched_ip` INT UNSIGNED NOT NULL,
`first_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`stickyban`, `matched_ip`)
) ENGINE=InnoDB;

Expand All @@ -505,8 +507,9 @@ CREATE TABLE `ss13_stickyban_matched_ip` (
DROP TABLE IF EXISTS `ss13_stickyban_matched_cid`;
CREATE TABLE `ss13_stickyban_matched_cid` (
`stickyban` VARCHAR(32) NOT NULL,
`matched_cid` INT UNSIGNED NOT NULL,
`first_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`matched_cid` VARCHAR(32) NOT NULL,
`first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`stickyban`, `matched_cid`)
) ENGINE=InnoDB;

Expand Down
2 changes: 1 addition & 1 deletion code/__DEFINES/admin.dm
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,4 @@
#define SPAM_TRIGGER_AUTOMUTE 10 //Number of identical messages required before the spam-prevention will automute you

#define STICKYBAN_DB_CACHE_TIME 10 SECONDS
#define STICKYBAN_ROGUE_CHECK_TIME 5 SECONDS
#define STICKYBAN_ROGUE_CHECK_TIME 5
21 changes: 21 additions & 0 deletions code/controllers/subsystem/dbcore.dm
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,27 @@ SUBSYSTEM_DEF(dbcore)
return FALSE
return new /datum/DBQuery(sql_query, connection)

/datum/controller/subsystem/dbcore/proc/QuerySelect(list/querys, warn = FALSE, qdel = FALSE)
if (!islist(querys))
if (!istype(querys, /datum/DBQuery))
CRASH("Invalid query passed to QuerySelect: [querys]")
querys = list(querys)

for (var/thing in querys)
var/datum/DBQuery/query = thing
if (warn)
INVOKE_ASYNC(query, /datum/DBQuery.proc/warn_execute)
else
INVOKE_ASYNC(query, /datum/DBQuery.proc/Execute)

for (var/thing in querys)
var/datum/DBQuery/query = thing
UNTIL(!query.in_progress)
if (qdel)
qdel(query)



/*
Takes a list of rows (each row being an associated list of column => value) and inserts them via a single mass query.
Rows missing columns present in other rows will resolve to SQL NULL
Expand Down
142 changes: 108 additions & 34 deletions code/controllers/subsystem/stickyban.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ SUBSYSTEM_DEF(stickyban)

var/list/ban = params2list(world.GetConfig("ban", oldban))
if (ban && !ban["fromdb"])
if (!import_to_db(ckey, ban))
if (!import_raw_stickyban_to_db(ckey, ban))
log_world("Could not import stickyban on [oldban] into the database. Ignoring")
continue
dbcacheexpire = 0
Expand Down Expand Up @@ -55,11 +55,17 @@ SUBSYSTEM_DEF(stickyban)
var/newdbcache = list() //so if we runtime or the db connection dies we don't kill the existing cache

var/datum/DBQuery/query_stickybans = SSdbcore.NewQuery("SELECT ckey, reason, banning_admin, datetime FROM [format_table_name("stickyban")] ORDER BY ckey")
if (!query_stickybans.warn_execute())
return
var/datum/DBQuery/query_ckey_matches = SSdbcore.NewQuery("SELECT stickyban, matched_ckey, first_matched, last_matched, exempt FROM [format_table_name("stickyban_matched_ckey")] ORDER BY first_matched")
var/datum/DBQuery/query_cid_matches = SSdbcore.NewQuery("SELECT stickyban, matched_cid, first_matched, last_matched FROM [format_table_name("stickyban_matched_cid")] ORDER BY first_matched")
var/datum/DBQuery/query_ip_matches = SSdbcore.NewQuery("SELECT stickyban, INET_NTOA(matched_ip), first_matched, last_matched FROM [format_table_name("stickyban_matched_ip")] ORDER BY first_matched")

SSdbcore.QuerySelect(list(query_stickybans, query_ckey_matches, query_cid_matches, query_ip_matches))

var/datum/DBQuery/query_stickyban_matches = SSdbcore.NewQuery("SELECT stickyban, matched_ckey, first_matched, exempt FROM [format_table_name("stickyban_matched_ckey")] ORDER BY first_matched")
if (!query_stickyban_matches.warn_execute())
if (query_stickybans.last_error)
qdel(query_stickybans)
qdel(query_ckey_matches)
qdel(query_cid_matches)
qdel(query_ip_matches)
return

while (query_stickybans.NextRow())
Expand All @@ -75,59 +81,127 @@ SUBSYSTEM_DEF(stickyban)
newdbcache["[query_stickybans.item[1]]"] = ban


while (query_stickyban_matches.NextRow())
var/list/match = list()
if (!query_ckey_matches.last_error)
while (query_ckey_matches.NextRow())
var/list/match = list()

match["stickyban"] = query_ckey_matches.item[1]
match["matched_ckey"] = query_ckey_matches.item[2]
match["first_matched"] = query_ckey_matches.item[3]
match["last_matched"] = query_ckey_matches.item[4]
match["exempt"] = text2num(query_ckey_matches.item[5])

var/ban = newdbcache[query_ckey_matches.item[1]]
if (!ban)
continue
var/keys = ban[text2num(query_ckey_matches.item[5]) ? "whitelist" : "keys"]
if (!keys)
keys = ban[text2num(query_ckey_matches.item[5]) ? "whitelist" : "keys"] = list()
keys[query_ckey_matches.item[2]] = match

if (!query_cid_matches.last_error)
while (query_cid_matches.NextRow())
var/list/match = list()

match["stickyban"] = query_cid_matches.item[1]
match["matched_cid"] = query_cid_matches.item[2]
match["first_matched"] = query_cid_matches.item[3]
match["last_matched"] = query_cid_matches.item[4]

var/ban = newdbcache[query_cid_matches.item[1]]
if (!ban)
continue
var/computer_ids = ban["computer_id"]
if (!computer_ids)
computer_ids = ban["computer_id"] = list()
computer_ids[query_cid_matches.item[2]] = match


match["stickyban"] = query_stickyban_matches.item[1]
match["matched_ckey"] = query_stickyban_matches.item[2]
match["first_matched"] = query_stickyban_matches.item[3]
match["exempt"] = text2num(query_stickyban_matches.item[4])
if (!query_ip_matches.last_error)
while (query_ip_matches.NextRow())
var/list/match = list()

var/ban = newdbcache[query_stickyban_matches.item[1]]
if (!ban)
continue
var/keys = ban[query_stickyban_matches.item[4] ? "whitelist" : "keys"]
if (!keys)
keys = ban[query_stickyban_matches.item[4] ? "whitelist" : "keys"] = list()
keys[query_stickyban_matches.item[2]] = match
match["stickyban"] = query_ip_matches.item[1]
match["matched_ip"] = query_ip_matches.item[2]
match["first_matched"] = query_ip_matches.item[3]
match["last_matched"] = query_ip_matches.item[4]

var/ban = newdbcache[query_ip_matches.item[1]]
if (!ban)
continue
var/IPs = ban["IP"]
if (!IPs)
IPs = ban["IP"] = list()
IPs[query_ip_matches.item[2]] = match

dbcache = newdbcache
dbcacheexpire = world.time+STICKYBAN_DB_CACHE_TIME

qdel(query_stickybans)
qdel(query_ckey_matches)
qdel(query_cid_matches)
qdel(query_ip_matches)


/datum/controller/subsystem/stickyban/proc/import_to_db(ckey, list/ban)
/datum/controller/subsystem/stickyban/proc/import_raw_stickyban_to_db(ckey, list/ban)
. = FALSE
if (!ban["admin"])
ban["admin"] = "LEGACY"
if (!ban["message"])
ban["message"] = "Evasion"

var/datum/DBQuery/query_create_stickyban = SSdbcore.NewQuery("INSERT INTO [format_table_name("stickyban")] (ckey, reason, banning_admin) VALUES ('[sanitizeSQL(ckey)]', '[sanitizeSQL(ban["message"])]', '[sanitizeSQL(ban["admin"])]')")
var/datum/DBQuery/query_create_stickyban = SSdbcore.NewQuery("INSERT IGNORE INTO [format_table_name("stickyban")] (ckey, reason, banning_admin) VALUES ('[sanitizeSQL(ckey)]', '[sanitizeSQL(ban["message"])]', '[sanitizeSQL(ban["admin"])]')")
if (!query_create_stickyban.warn_execute())
qdel(query_create_stickyban)
return
qdel(query_create_stickyban)

var/list/sqlkeys = list()
var/list/sqlckeys = list()
var/list/sqlcids = list()
var/list/sqlips = list()

if (ban["keys"])
var/list/keys = splittext(ban["keys"], ",")
for (var/key in keys)
var/list/sqlkey = list()
sqlkey["stickyban"] = "'[sanitizeSQL(ckey)]'"
sqlkey["matched_ckey"] = "'[sanitizeSQL(ckey(key))]'"
sqlkey["exempt"] = FALSE
sqlkeys += sqlkey
var/list/sqlckey = list()
sqlckey["stickyban"] = "'[sanitizeSQL(ckey)]'"
sqlckey["matched_ckey"] = "'[sanitizeSQL(ckey(key))]'"
sqlckey["exempt"] = FALSE
sqlckeys[++sqlckeys.len] = sqlckey

if (ban["whitelist"])
var/list/keys = splittext(ban["whitelist"], ",")
for (var/key in keys)
var/list/sqlkey = list()
sqlkey["stickyban"] = "'[sanitizeSQL(ckey)]'"
sqlkey["matched_ckey"] = "'[sanitizeSQL(ckey(key))]'"
sqlkey["exempt"] = TRUE
sqlkeys += sqlkey

if (length(sqlkeys))
SSdbcore.MassInsert(format_table_name("stickyban_matched_ckey"), sqlkeys, FALSE, TRUE)
var/list/sqlckey = list()
sqlckey["stickyban"] = "'[sanitizeSQL(ckey)]'"
sqlckey["matched_ckey"] = "'[sanitizeSQL(ckey(key))]'"
sqlckey["exempt"] = TRUE
sqlckeys[++sqlckeys.len] = sqlckey

if (ban["computer_id"])
var/list/cids = splittext(ban["computer_id"], ",")
for (var/cid in cids)
var/list/sqlcid = list()
sqlcid["stickyban"] = "'[sanitizeSQL(ckey)]'"
sqlcid["matched_cid"] = "'[sanitizeSQL(cid)]'"
sqlcids[++sqlcids.len] = sqlcid

if (ban["IP"])
var/list/ips = splittext(ban["IP"], ",")
for (var/ip in ips)
var/list/sqlip = list()
sqlip["stickyban"] = "'[sanitizeSQL(ckey)]'"
sqlip["matched_ip"] = "'[sanitizeSQL(ip)]'"
sqlips[++sqlips.len] = sqlip

if (length(sqlckeys))
SSdbcore.MassInsert(format_table_name("stickyban_matched_ckey"), sqlckeys, FALSE, TRUE)

if (length(sqlcids))
SSdbcore.MassInsert(format_table_name("stickyban_matched_cid"), sqlcids, FALSE, TRUE)

if (length(sqlips))
SSdbcore.MassInsert(format_table_name("stickyban_matched_ip"), sqlips, FALSE, TRUE)


return TRUE
3 changes: 2 additions & 1 deletion code/game/world.dm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ GLOBAL_VAR(restart_counter)

config.Load(params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER])

load_admins()

//SetupLogs depends on the RoundID, so lets check
//DB schema and set RoundID if we can
SSdbcore.CheckSchemaVersion()
Expand All @@ -30,7 +32,6 @@ GLOBAL_VAR(restart_counter)
world.log = file("[GLOB.log_directory]/dd.log")
#endif

load_admins()
LoadVerbs(/datum/verbs/menu)
if(CONFIG_GET(flag/usewhitelist))
load_whitelist()
Expand Down
Loading

0 comments on commit 186f6c8

Please sign in to comment.