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