4 changed files with 198 additions and 28 deletions
			
			
		| @ -0,0 +1,37 @@ | |||||
|  | -- You should not modify if this have pushed to Github, unless it do serious wrong with the db. | ||||
|  | -- Change Monitor.created_date from "TIMESTAMP" to "DATETIME" | ||||
|  | -- SQL Generated by Intellij Idea | ||||
|  | PRAGMA foreign_keys=off; | ||||
|  | 
 | ||||
|  | BEGIN TRANSACTION; | ||||
|  | 
 | ||||
|  | create table monitor_dg_tmp | ||||
|  | ( | ||||
|  |     id INTEGER not null | ||||
|  |         primary key autoincrement, | ||||
|  |     name VARCHAR(150), | ||||
|  |     active BOOLEAN default 1 not null, | ||||
|  |     user_id INTEGER | ||||
|  |         references user | ||||
|  |                    on update cascade on delete set null, | ||||
|  |     interval INTEGER default 20 not null, | ||||
|  |     url TEXT, | ||||
|  |     type VARCHAR(20), | ||||
|  |     weight INTEGER default 2000, | ||||
|  |     hostname VARCHAR(255), | ||||
|  |     port INTEGER, | ||||
|  |     created_date DATETIME, | ||||
|  |     keyword VARCHAR(255) | ||||
|  | ); | ||||
|  | 
 | ||||
|  | insert into monitor_dg_tmp(id, name, active, user_id, interval, url, type, weight, hostname, port, created_date, keyword) select id, name, active, user_id, interval, url, type, weight, hostname, port, created_date, keyword from monitor; | ||||
|  | 
 | ||||
|  | drop table monitor; | ||||
|  | 
 | ||||
|  | alter table monitor_dg_tmp rename to monitor; | ||||
|  | 
 | ||||
|  | create index user_id on monitor (user_id); | ||||
|  | 
 | ||||
|  | COMMIT; | ||||
|  | 
 | ||||
|  | PRAGMA foreign_keys=on; | ||||
| @ -0,0 +1,119 @@ | |||||
|  | const fs = require("fs"); | ||||
|  | const {sleep} = require("./util"); | ||||
|  | const {R} = require("redbean-node"); | ||||
|  | const {setSetting, setting} = require("./util-server"); | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class Database { | ||||
|  | 
 | ||||
|  |     static templatePath = "./db/kuma.db" | ||||
|  |     static path =  './data/kuma.db'; | ||||
|  |     static latestVersion = 1; | ||||
|  |     static noReject = true; | ||||
|  | 
 | ||||
|  |     static async patch() { | ||||
|  |         let version = parseInt(await setting("database_version")); | ||||
|  | 
 | ||||
|  |         if (! version) { | ||||
|  |             version = 0; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         console.info("Your database version: " + version); | ||||
|  |         console.info("Latest database version: " + this.latestVersion); | ||||
|  | 
 | ||||
|  |         if (version === this.latestVersion) { | ||||
|  |             console.info("Database no need to patch"); | ||||
|  |         } else { | ||||
|  |             console.info("Database patch is needed") | ||||
|  | 
 | ||||
|  |             console.info("Backup the db") | ||||
|  |             const backupPath = "./data/kuma.db.bak" + version; | ||||
|  |             fs.copyFileSync(Database.path, backupPath); | ||||
|  | 
 | ||||
|  |             // Try catch anything here, if gone wrong, restore the backup
 | ||||
|  |             try { | ||||
|  |                 for (let i = version + 1; i <= this.latestVersion; i++) { | ||||
|  |                     const sqlFile = `./db/patch${i}.sql`; | ||||
|  |                     console.info(`Patching ${sqlFile}`); | ||||
|  |                     await Database.importSQLFile(sqlFile); | ||||
|  |                     console.info(`Patched ${sqlFile}`); | ||||
|  |                     await setSetting("database_version", i); | ||||
|  |                 } | ||||
|  |                 console.log("Database Patched Successfully"); | ||||
|  |             } catch (ex) { | ||||
|  |                 await Database.close(); | ||||
|  |                 console.error("Patch db failed!!! Restoring the backup") | ||||
|  |                 fs.copyFileSync(backupPath, Database.path); | ||||
|  |                 console.error(ex) | ||||
|  | 
 | ||||
|  |                 console.error("Start Uptime-Kuma failed due to patch db failed") | ||||
|  |                 console.error("Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues") | ||||
|  |                 process.exit(1); | ||||
|  |             } | ||||
|  |         } | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     /** | ||||
|  |      * Sadly, multi sql statements is not supported by many sqlite libraries, I have to implement it myself | ||||
|  |      * @param filename | ||||
|  |      * @returns {Promise<void>} | ||||
|  |      */ | ||||
|  |     static async importSQLFile(filename) { | ||||
|  | 
 | ||||
|  |         await R.getCell("SELECT 1"); | ||||
|  | 
 | ||||
|  |         let text = fs.readFileSync(filename).toString(); | ||||
|  | 
 | ||||
|  |         // Remove all comments (--)
 | ||||
|  |         let lines = text.split("\n"); | ||||
|  |         lines = lines.filter((line) => { | ||||
|  |             return ! line.startsWith("--") | ||||
|  |         }); | ||||
|  | 
 | ||||
|  |         // Split statements by semicolon
 | ||||
|  |         // Filter out empty line
 | ||||
|  |         text = lines.join("\n") | ||||
|  | 
 | ||||
|  |         let statements = text.split(";") | ||||
|  |             .map((statement) => { | ||||
|  |                 return statement.trim(); | ||||
|  |             }) | ||||
|  |             .filter((statement) => { | ||||
|  |                 return statement !== ""; | ||||
|  |             }) | ||||
|  | 
 | ||||
|  |         for (let statement of statements) { | ||||
|  |             await R.exec(statement); | ||||
|  |         } | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     /** | ||||
|  |      * Special handle, because tarn.js throw a promise reject that cannot be caught | ||||
|  |      * @returns {Promise<void>} | ||||
|  |      */ | ||||
|  |     static async close() { | ||||
|  |         const listener = (reason, p) => { | ||||
|  |             Database.noReject = false; | ||||
|  |         }; | ||||
|  |         process.addListener('unhandledRejection', listener); | ||||
|  | 
 | ||||
|  |         console.log("Closing DB") | ||||
|  | 
 | ||||
|  |         while (true) { | ||||
|  |             Database.noReject = true; | ||||
|  |             await R.close() | ||||
|  |             await sleep(2000) | ||||
|  | 
 | ||||
|  |             if (Database.noReject) { | ||||
|  |                 break; | ||||
|  |             } else { | ||||
|  |                 console.log("Waiting to close the db") | ||||
|  |             } | ||||
|  |         } | ||||
|  |         console.log("SQLite closed") | ||||
|  | 
 | ||||
|  |         process.removeListener('unhandledRejection', listener); | ||||
|  |     } | ||||
|  | } | ||||
|  | 
 | ||||
|  | module.exports = Database; | ||||
					Loading…
					
					
				
		Reference in new issue