Update: please read the posts below this one to note potential dangers of using MySQL in a blocking manner.
If you're like me I found myself frustrated with the existing MySQL plugin examples code that used callbacks for queries, as this made my code flow messed up. So I got to poking around and it appears the Oxide MySQL extension taps into the mysql connector found at MySQL :: Download Connector/Net which means we can use it directly, and without downloading any extra files! it's located at RustDedicated_Data/Managed/MySql.Data.dll
Here's a simply query example that I put together from looking at stackoverflow that doesn't use callbacks
First put this at the top
Code:using MySql.Data; using MySql.Data.MySqlClient;
And inside your plugin somewhere, here's some test code, you can issue the console command sql via rusty. It
uses host = 127.0.01, database = rust, user = root, pass = abc123 and table = farmstats
enjoy! Also this now means you can use prepared statements for the extra speed and security, just google some examples!Code:[ConsoleCommand("sql")] void MySQLTest() { var DB = new MySqlConnection("Server=127.0.0.1; database=rust; UID=root; password=abc123"); DB.Open(); var cmd = new MySqlCommand("SELECT * FROM farmstats", DB); var reader = cmd.ExecuteReader(); while(reader.Read()) { /* this reads from the wood column, but could be anything */ string woodcolumn = reader.GetString(reader.GetOrdinal("wood")); string stonecolumn = reader.GetString(reader.GetOrdinal("stone")); Puts(woodcolumn); } DB.Close(); }
Using MySQL without callbacks
Discussion in 'Rust Development' started by Caffeine, Jul 10, 2016.
-
Please add that if you use this, you have to take extra measures in your plugin to protect against DDoS attacks and that it may have a huge negative impact on server performance (especially with MySQL!).
Not using the Oxide API opens up a bunch of security problems, allowing players to DDoS your server by abusing the fact that the entire server (not just the plugin!) halts until the query is finished, allowing them to cause massive rubberbanding (for instance by spamming commands that send queries or by flooding your likely weaker MySQL db server).
I just want to make sure that plugin devs know this, otherwise they'll always use non concurrent queries instead of concurrent querries for ease of use (an illusory one, I might add, because instead of worrying about simple callbacks you now have to worry about protecting against DDoS attacks, which is a bunch more complicated) and create plugins that allow attackers and angry players to easily make servers unplayable.Last edited by a moderator: Jul 10, 2016 -
-
The Rust server runs on the main thread. The Rust server calls plugins and blocks until plugin calls are done and uses their return value (if it didn't block, it wouldn't be able to use the return value, also this makes a lot of things easier). This means that hook calls also execute on the main thread. If the hook calls are also executed on the main thread, then that means that your blocking query blocks the main thread.
Plugins cannot run concurrently with the main thread, because plugins and the Rust server concurrently read and modify game state, meaning race conditions would otherwise occur. -
-
Put simply, Oxide just injects Interface.CallHook calls into the DLL via IL patching.
Interface.CallHook calls Oxide/PluginManager.cs at eb1ba03bc0a76e08c638b93999c4e32ebbc7935c · OxideMod/Oxide · GitHub indirectly, which calls Oxide/Plugin.cs at develop · OxideMod/Oxide · GitHub and is implemented by Oxide/CSPlugin.cs at 1919a148d3f5374638c327d4de418f281a8bd3e4 · OxideMod/Oxide · GitHub. You can see that it is also run on the main thread, because the main thread executes Interface.CallHook. -
-
In my opinion, for MySQL, a sensible spot would be a spot not directly called by user input (Universal hooks, timers, that kind of stuff) where the SQL query isn't too large and the code is only run rarely (e.g.: every 30s, when the plugin initializes, stuff like that).
Also, in regards to SQLite, I think blocking queries can be used a lot more liberally with SQLite, because the latency to a local database is mostly better than to a remote database. That being said, one should probably still refrain from using them in spots that are called very frequently (e.g. OnTick) or in spots where queries are huge.