From b69a01d34e7b8ab039ef06fc018728fcdc938b71 Mon Sep 17 00:00:00 2001 From: Alex Pankratov Date: Tue, 13 Apr 2021 19:05:14 +0200 Subject: [PATCH] first draft of BackupStorage support --- nullboard.html | 189 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 171 insertions(+), 18 deletions(-) diff --git a/nullboard.html b/nullboard.html index 201af88..6568af5 100644 --- a/nullboard.html +++ b/nullboard.html @@ -1455,15 +1455,18 @@ this.listWidth = null; // list-width this.theme = null; // default or 'dark' + this.backups = [ ]; // [ { id: '?', conf: { } } ]; + this.board = null; // active board } function BoardMeta() { this.title = ''; - this.current = 1; // revision - this.ui_spot = 0; // 0 = not set - this.history = [ ]; // revision IDs + this.current = 1; // revision + this.ui_spot = 0; // 0 = not set + this.history = [ ]; // revision IDs + this.backups = [ ]; // backup agents IDs with which this board is stored } class Storage @@ -1474,6 +1477,8 @@ this.conf = new AppConfig(); this.boardIndex = new Map(); + + this.backups = []; // BackupStorage } open() @@ -1494,13 +1499,13 @@ setVerLast(ver) { this.conf.verLast = ver || NB.codeVersion; - return this.setJson('config', this.conf); + return this.saveConfig(); } setVerSeen(ver) { this.conf.verSeen = ver || NB.codeVersion; - return this.setJson('config', this.conf); + return this.saveConfig(); } setActiveBoard(board_id) @@ -1510,42 +1515,56 @@ if (! meta) throw `Invalid board_id in setActiveBoard(... ${board_id})`; + if (this.conf.board == board_id) + return true; + this.conf.board = board_id; - return this.setJson('config', this.conf); + return this.saveConfig(); } setTheme(theme) { if (this.conf.theme == theme) return; this.conf.theme = theme; - return this.setJson('config', this.conf); + return this.saveConfig(); } setFontName(fname) { if (this.conf.fontName == fname) return; this.conf.fontName = fname; - return this.setJson('config', this.conf); + return this.saveConfig(); } setFontSize(fs) { if (this.conf.fontSize == fs) return; this.conf.fontSize = fs; - return this.setJson('config', this.conf); + return this.saveConfig(); } setLineHeight(lh) { if (this.conf.lineHeight == lh) return; this.conf.lineHeight = lh; - return this.setJson('config', this.conf); + return this.saveConfig(); } setListWidth(lw) { if (this.conf.listWidth == lw) return; this.conf.listWidth = lw; + return this.saveConfig(); + } + + saveConfig() + { + var self = this; + + this.backups.forEach(function(store){ + store.saveConfig(self.conf); + }); + return this.setJson('config', this.conf); } @@ -1613,9 +1632,20 @@ meta.history = rebuild; } + meta.backups = []; + + /* + * save meta + */ ok_meta = this.setJson('board.' + board.id + '.meta', meta) && this.setJson('board.' + board.id, meta.current); // for older versions + /* + * run backups + */ + if (ok_meta && ok_data) + this.backupBoard(board) + board.history = meta.history; // restore console.log( `Saved revision ${board.revision} of ${board.id} (${board.title}), ok = ${ok_data} | ${ok_meta}` ); @@ -1675,6 +1705,10 @@ this.delItem('board.' + board_id + '.meta'); this.boardIndex.delete(board_id); + this.backups.forEach(function(store){ + store.nukeBoard(board_id); + }); + console.log( `Deleted board ${board_id} (${title})` ); } @@ -1749,6 +1783,22 @@ return true; } + + backupBoard(board) + { + var self = this; + var meta = this.boardIndex.get(board.id); + var toGo = 0; + + this.backups.forEach(function(store){ + store.saveBoard(board.id, board, meta, function(ok){ +console.log( `Backup of ${board.id} to ${store.id} -> ${ok ? 'ok' : 'failed'}` ); + if (ok) meta.backups.push(store.id); + if (! --toGo) self.setJson('board.' + board.id + '.meta', meta); + }); + toGo++; + }); + } }; class Storage_Local extends Storage @@ -1791,7 +1841,7 @@ if (conf) { - this.conf = conf; + this.conf = Object.assign(new AppConfig(), conf); } else { @@ -1951,6 +2001,89 @@ } } + /* + * + */ + class BackupStorage + { + constructor(conf) + { + this.id = '?'; + this.conf = conf; + } + + checkStatus(cb) { return false; } + saveConfig(conf, cb) { throw 'implement-me'; } + saveBoard (id, data, meta, cb) { throw 'implement-me'; } + nukeBoard (id, cb) { throw 'implement-me'; } + } + + class SimpleBackup extends BackupStorage + { + constructor(conf) + { + super(); + this.id = 'sb'; + this.conf = { base: 'http://127.0.0.1:10001', auth: '' } + this.conf = Object.assign(this.conf, conf); + } + + checkStatus(cb) + { + var self = this; + + $.get(this.conf.base + '/nullboard/status') + .done(function(){ cb.call(self, true); }) + .fail(function(){ cb.call(self, false); }) + } + + saveConfig(conf, cb) + { + var self = this; + + $.ajax({ + url: this.conf.base + '/nullboard/config', + type: 'put', + headers: { 'X-Access-Token': this.conf.auth }, + data: JSON.stringify(conf), + }) + .done(function(){ if (cb) cb.call(self, true); }) + .fail(function(){ if (cb) cb.call(self, false); }) + } + + saveBoard(id, data, meta, cb) + { + var self = this; + + $.ajax({ + url: this.conf.base + '/nullboard/board/' + id, + type: 'put', + headers: { 'X-Access-Token': this.conf.auth }, + data: + { + data: data ? JSON.stringify(data) : null, + meta: meta ? JSON.stringify(meta) : null + }, + dataType: 'json', + }) + .done(function(){ if (cb) cb.call(self, true); }) + .fail(function(){ if (cb) cb.call(self, false); }) + } + + nukeBoard(id, cb) + { + var self = this; + + $.ajax({ + url: this.conf.base + '/nullboard/board/' + id, + type: 'delete', + headers: { 'X-Access-Token': this.conf.auth }, + }) + .done(function(){ if (cb) cb.call(self, true); }) + .fail(function(){ if (cb) cb.call(self, false); }) + } + } +