From a8eb4032807691dce629aeefed7f24869a53be11 Mon Sep 17 00:00:00 2001 From: Paul Makles <paulmakles@gmail.com> Date: Tue, 11 Aug 2020 21:08:01 +0200 Subject: [PATCH] Logging + database migrations system. --- Cargo.lock | 41 ++++++++++++++++++++--- Cargo.toml | 2 ++ src/database/guild.rs | 1 + src/database/migrations/init.rs | 39 ++++++++++++++++++++++ src/database/migrations/mod.rs | 19 +++++++++++ src/database/migrations/scripts.rs | 53 ++++++++++++++++++++++++++++++ src/database/mod.rs | 9 ++--- src/main.rs | 1 + src/notifications/ws.rs | 4 +-- 9 files changed, 157 insertions(+), 12 deletions(-) create mode 100644 src/database/migrations/init.rs create mode 100644 src/database/migrations/mod.rs create mode 100644 src/database/migrations/scripts.rs diff --git a/Cargo.lock b/Cargo.lock index 6e85b9e..842ac0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -509,6 +509,19 @@ dependencies = [ "syn 1.0.37", ] +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log 0.4.11", + "regex", + "termcolor", +] + [[package]] name = "err-derive" version = "0.2.4" @@ -888,6 +901,15 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + [[package]] name = "hyper" version = "0.10.16" @@ -1891,8 +1913,10 @@ dependencies = [ "bitfield", "chrono", "dotenv", + "env_logger", "hashbrown 0.7.2", "lazy_static", + "log 0.4.11", "lru", "mongodb", "num_enum", @@ -2423,6 +2447,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "termcolor" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.20" @@ -2586,9 +2619,9 @@ checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" [[package]] name = "tracing" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0aae59226cf195d8e74d4b34beae1859257efb4e5fed3f147d2dc2c7d372178" +checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c" dependencies = [ "cfg-if", "log 0.4.11", @@ -2597,9 +2630,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2734b5a028fa697686f16c6d18c2c6a3c7e41513f9a213abb6754c4acb3c8d7" +checksum = "db63662723c316b43ca36d833707cc93dff82a02ba3d7e354f342682cc8b3545" dependencies = [ "lazy_static", ] diff --git a/Cargo.toml b/Cargo.toml index 849b553..0a7a76a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,3 +28,5 @@ rocket_cors = "0.5.2" bitfield = "0.13.2" lru = "0.5.3" lazy_static = "1.4.0" +log = "0.4.11" +env_logger = "0.7.1" diff --git a/src/database/guild.rs b/src/database/guild.rs index 68cc5c5..73a2698 100644 --- a/src/database/guild.rs +++ b/src/database/guild.rs @@ -42,6 +42,7 @@ pub struct Guild { pub description: String, pub owner: String, + // ? FIXME: ADD: pub channels: Vec<Channel>, pub invites: Vec<Invite>, pub bans: Vec<Ban>, diff --git a/src/database/migrations/init.rs b/src/database/migrations/init.rs new file mode 100644 index 0000000..4616760 --- /dev/null +++ b/src/database/migrations/init.rs @@ -0,0 +1,39 @@ +use super::super::get_db; +use super::scripts::LATEST_REVISION; + +use mongodb::options::CreateCollectionOptions; +use mongodb::bson::doc; +use log::info; + +pub fn create_database() { + info!("Creating database."); + let db = get_db(); + + db.create_collection("users", None).expect("Failed to create users collection."); + db.create_collection("channels", None).expect("Failed to create channels collection."); + db.create_collection("guilds", None).expect("Failed to create guilds collection."); + db.create_collection("members", None).expect("Failed to create members collection."); + db.create_collection("messages", None).expect("Failed to create messages collection."); + db.create_collection("migrations", None).expect("Failed to create migrations collection."); + + db.create_collection( + "pubsub", + CreateCollectionOptions::builder() + .capped(true) + .size(1_000_000) + .build() + ) + .expect("Failed to create pubsub collection."); + + db.collection("migrations") + .insert_one( + doc! { + "_id": 0, + "revision": LATEST_REVISION + }, + None + ) + .expect("Failed to save migration info."); + + info!("Created database."); +} diff --git a/src/database/migrations/mod.rs b/src/database/migrations/mod.rs new file mode 100644 index 0000000..6e188b0 --- /dev/null +++ b/src/database/migrations/mod.rs @@ -0,0 +1,19 @@ +use super::get_connection; + +pub mod init; +pub mod scripts; + +pub fn run_migrations() { + let client = get_connection(); + + let list = client.list_database_names( + None, + None + ).expect("Failed to fetch database names."); + + if list.iter().position(|x| x == "revolt").is_none() { + init::create_database(); + } else { + scripts::migrate_database(); + } +} diff --git a/src/database/migrations/scripts.rs b/src/database/migrations/scripts.rs new file mode 100644 index 0000000..72291af --- /dev/null +++ b/src/database/migrations/scripts.rs @@ -0,0 +1,53 @@ +use super::super::get_collection; + +use serde::{Serialize, Deserialize}; +use mongodb::bson::{Bson, from_bson, doc}; +use log::info; + +#[derive(Serialize, Deserialize)] +struct MigrationInfo { + _id: i32, + revision: i32 +} + +pub const LATEST_REVISION: i32 = 1; + +pub fn migrate_database() { + let migrations = get_collection("migrations"); + let data = migrations.find_one(None, None) + .expect("Failed to fetch migration data."); + + if let Some(doc) = data { + let info: MigrationInfo = from_bson(Bson::Document(doc)) + .expect("Failed to read migration information."); + + let revision = run_migrations(info.revision); + + migrations.update_one( + doc! { + "_id": info._id + }, + doc! { + "$set": { + "revision": revision + } + }, + None + ).expect("Failed to commit migration information."); + + info!("Migration complete. Currently at revision {}.", revision); + } else { + panic!("Database was configured incorrectly, possibly because initalization failed.") + } +} + +pub fn run_migrations(revision: i32) -> i32 { + info!("Starting database migration."); + + if revision <= 0 { + info!("Running migration [revision 0]: Test migration system."); + } + + // Reminder to update LATEST_REVISION when adding new migrations. + LATEST_REVISION +} diff --git a/src/database/mod.rs b/src/database/mod.rs index 49d688b..0c5c534 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -10,13 +10,8 @@ pub fn connect() { Client::with_uri_str(&env::var("DB_URI").expect("DB_URI not in environment variables!")) .expect("Failed to init db connection."); - client - .database("revolt") - .collection("migrations") - .find(doc! {}, None) - .expect("Failed to get migration data from database."); - DBCONN.set(client).unwrap(); + migrations::run_migrations(); } pub fn get_connection() -> &'static Client { @@ -31,6 +26,8 @@ pub fn get_collection(collection: &str) -> Collection { get_db().collection(collection) } +pub mod migrations; + pub mod channel; pub mod guild; pub mod message; diff --git a/src/main.rs b/src/main.rs index b220a02..72161bc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,6 +21,7 @@ use std::thread; fn main() { dotenv::dotenv().ok(); + env_logger::init(); database::connect(); notifications::start_worker(); diff --git a/src/notifications/ws.rs b/src/notifications/ws.rs index 0d3f343..55ae2f5 100644 --- a/src/notifications/ws.rs +++ b/src/notifications/ws.rs @@ -38,7 +38,6 @@ impl Handler for Server { StateResult::Success(user_id) => { let user = crate::database::user::fetch_user(&user_id).unwrap().unwrap(); - self.user_id = Some(user_id); self.sender.send( json!({ "type": "authenticate", @@ -47,12 +46,13 @@ impl Handler for Server { .to_string(), )?; + self.user_id = Some(user_id); self.sender.send( json!({ "type": "ready", "data": { // ! FIXME: rewrite - "user": user + "user": user, } }) .to_string(), -- GitLab