database dedup implemented.

This commit is contained in:
vrtmrz committed 2021-10-15 17:58:42 +09:00
1 parent 531cf0d8a4
commit f3f0639d95
5 files changed
+433 -132

No files matched your search

+215 -65
View File
@@ -32,7 +32,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
}); });
} }
var e={105:e=>{e.exports=function(e){return function(){var t=arguments.length;if(t){for(var n=[],r=-1;++r<t;)n[r]=arguments[r];return e.call(this,n)}return e.call(this,[])}};},187:e=>{var t,n="object"==typeof Reflect?Reflect:null,r=n&&"function"==typeof n.apply?n.apply:function(e,t,n){return Function.prototype.apply.call(e,t,n)};t=n&&"function"==typeof n.ownKeys?n.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};var o=Number.isNaN||function(e){return e!=e};function i(){i.init.call(this);}e.exports=i,e.exports.once=function(e,t){return new Promise((function(n,r){function o(n){e.removeListener(t,i),r(n);}function i(){"function"==typeof e.removeListener&&e.removeListener("error",o),n([].slice.call(arguments));}v(e,t,i,{once:!0}),"error"!==t&&function(e,t,n){"function"==typeof e.on&&v(e,"error",t,{once:!0});}(e,o);}))},i.EventEmitter=i,i.prototype._events=void 0,i.prototype._eventsCount=0,i.prototype._maxListeners=void 0;var s=10;function a(e){if("function"!=typeof e)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}function u(e){return void 0===e._maxListeners?i.defaultMaxListeners:e._maxListeners}function c(e,t,n,r){var o,i,s,c;if(a(n),void 0===(i=e._events)?(i=e._events=Object.create(null),e._eventsCount=0):(void 0!==i.newListener&&(e.emit("newListener",t,n.listener?n.listener:n),i=e._events),s=i[t]),void 0===s)s=i[t]=n,++e._eventsCount;else if("function"==typeof s?s=i[t]=r?[n,s]:[s,n]:r?s.unshift(n):s.push(n),(o=u(e))>0&&s.length>o&&!s.warned){s.warned=!0;var f=new Error("Possible EventEmitter memory leak detected. "+s.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");f.name="MaxListenersExceededWarning",f.emitter=e,f.type=t,f.count=s.length,c=f,console&&console.warn&&console.warn(c);}return e}function f(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function l(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},o=f.bind(r);return o.listener=n,r.wrapFn=o,o}function d(e,t,n){var r=e._events;if(void 0===r)return [];var o=r[t];return void 0===o?[]:"function"==typeof o?n?[o.listener||o]:[o]:n?function(e){for(var t=new Array(e.length),n=0;n<t.length;++n)t[n]=e[n].listener||e[n];return t}(o):p(o,o.length)}function h(e){var t=this._events;if(void 0!==t){var n=t[e];if("function"==typeof n)return 1;if(void 0!==n)return n.length}return 0}function p(e,t){for(var n=new Array(t),r=0;r<t;++r)n[r]=e[r];return n}function v(e,t,n,r){if("function"==typeof e.on)r.once?e.once(t,n):e.on(t,n);else {if("function"!=typeof e.addEventListener)throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type '+typeof e);e.addEventListener(t,(function o(i){r.once&&e.removeEventListener(t,o),n(i);}));}}Object.defineProperty(i,"defaultMaxListeners",{enumerable:!0,get:function(){return s},set:function(e){if("number"!=typeof e||e<0||o(e))throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received '+e+".");s=e;}}),i.init=function(){void 0!==this._events&&this._events!==Object.getPrototypeOf(this)._events||(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0;},i.prototype.setMaxListeners=function(e){if("number"!=typeof e||e<0||o(e))throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received '+e+".");return this._maxListeners=e,this},i.prototype.getMaxListeners=function(){return u(this)},i.prototype.emit=function(e){for(var t=[],n=1;n<arguments.length;n++)t.push(arguments[n]);var o="error"===e,i=this._events;if(void 0!==i)o=o&&void 0===i.error;else if(!o)return !1;if(o){var s;if(t.length>0&&(s=t[0]),s instanceof Error)throw s;var a=new Error("Unhandled error."+(s?" ("+s.message+")":""));throw a.context=s,a}var u=i[e];if(void 0===u)return !1;if("function"==typeof u)r(u,this,t);else {var c=u.length,f=p(u,c);for(n=0;n<c;++n)r(f[n],this,t);}return !0},i.prototype.addListener=function(e,t){return c(this,e,t,!1)},i.prototype.on=i.prototype.addListener,i.prototype.prependListener=function(e,t){return c(this,e,t,!0)},i.prototype.once=function(e,t){return a(t),this.on(e,l(this,e,t)),this},i.prototype.prependOnceListener=function(e,t){return a(t),this.prependListener(e,l(this,e,t)),this},i.prototype.removeListener=function(e,t){var n,r,o,i,s;if(a(t),void 0===(r=this._events))return this;if(void 0===(n=r[e]))return this;if(n===t||n.listener===t)0==--this._eventsCount?this._events=Object.create(null):(delete r[e],r.removeListener&&this.emit("removeListener",e,n.listener||t));else if("function"!=typeof n){for(o=-1,i=n.length-1;i>=0;i--)if(n[i]===t||n[i].listener===t){s=n[i].listener,o=i;break}if(o<0)return this;0===o?n.shift():functLine truncated var e$1={105:e=>{e.exports=function(e){return function(){var t=arguments.length;if(t){for(var n=[],r=-1;++r<t;)n[r]=arguments[r];return e.call(this,n)}return e.call(this,[])}};},187:e=>{var t,n="object"==typeof Reflect?Reflect:null,r=n&&"function"==typeof n.apply?n.apply:function(e,t,n){return Function.prototype.apply.call(e,t,n)};t=n&&"function"==typeof n.ownKeys?n.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};var o=Number.isNaN||function(e){return e!=e};function i(){i.init.call(this);}e.exports=i,e.exports.once=function(e,t){return new Promise((function(n,r){function o(n){e.removeListener(t,i),r(n);}function i(){"function"==typeof e.removeListener&&e.removeListener("error",o),n([].slice.call(arguments));}v(e,t,i,{once:!0}),"error"!==t&&function(e,t,n){"function"==typeof e.on&&v(e,"error",t,{once:!0});}(e,o);}))},i.EventEmitter=i,i.prototype._events=void 0,i.prototype._eventsCount=0,i.prototype._maxListeners=void 0;var s=10;function a(e){if("function"!=typeof e)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}function u(e){return void 0===e._maxListeners?i.defaultMaxListeners:e._maxListeners}function c(e,t,n,r){var o,i,s,c;if(a(n),void 0===(i=e._events)?(i=e._events=Object.create(null),e._eventsCount=0):(void 0!==i.newListener&&(e.emit("newListener",t,n.listener?n.listener:n),i=e._events),s=i[t]),void 0===s)s=i[t]=n,++e._eventsCount;else if("function"==typeof s?s=i[t]=r?[n,s]:[s,n]:r?s.unshift(n):s.push(n),(o=u(e))>0&&s.length>o&&!s.warned){s.warned=!0;var f=new Error("Possible EventEmitter memory leak detected. "+s.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");f.name="MaxListenersExceededWarning",f.emitter=e,f.type=t,f.count=s.length,c=f,console&&console.warn&&console.warn(c);}return e}function f(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function l(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},o=f.bind(r);return o.listener=n,r.wrapFn=o,o}function d(e,t,n){var r=e._events;if(void 0===r)return [];var o=r[t];return void 0===o?[]:"function"==typeof o?n?[o.listener||o]:[o]:n?function(e){for(var t=new Array(e.length),n=0;n<t.length;++n)t[n]=e[n].listener||e[n];return t}(o):p(o,o.length)}function h(e){var t=this._events;if(void 0!==t){var n=t[e];if("function"==typeof n)return 1;if(void 0!==n)return n.length}return 0}function p(e,t){for(var n=new Array(t),r=0;r<t;++r)n[r]=e[r];return n}function v(e,t,n,r){if("function"==typeof e.on)r.once?e.once(t,n):e.on(t,n);else {if("function"!=typeof e.addEventListener)throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type '+typeof e);e.addEventListener(t,(function o(i){r.once&&e.removeEventListener(t,o),n(i);}));}}Object.defineProperty(i,"defaultMaxListeners",{enumerable:!0,get:function(){return s},set:function(e){if("number"!=typeof e||e<0||o(e))throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received '+e+".");s=e;}}),i.init=function(){void 0!==this._events&&this._events!==Object.getPrototypeOf(this)._events||(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0;},i.prototype.setMaxListeners=function(e){if("number"!=typeof e||e<0||o(e))throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received '+e+".");return this._maxListeners=e,this},i.prototype.getMaxListeners=function(){return u(this)},i.prototype.emit=function(e){for(var t=[],n=1;n<arguments.length;n++)t.push(arguments[n]);var o="error"===e,i=this._events;if(void 0!==i)o=o&&void 0===i.error;else if(!o)return !1;if(o){var s;if(t.length>0&&(s=t[0]),s instanceof Error)throw s;var a=new Error("Unhandled error."+(s?" ("+s.message+")":""));throw a.context=s,a}var u=i[e];if(void 0===u)return !1;if("function"==typeof u)r(u,this,t);else {var c=u.length,f=p(u,c);for(n=0;n<c;++n)r(f[n],this,t);}return !0},i.prototype.addListener=function(e,t){return c(this,e,t,!1)},i.prototype.on=i.prototype.addListener,i.prototype.prependListener=function(e,t){return c(this,e,t,!0)},i.prototype.once=function(e,t){return a(t),this.on(e,l(this,e,t)),this},i.prototype.prependOnceListener=function(e,t){return a(t),this.prependListener(e,l(this,e,t)),this},i.prototype.removeListener=function(e,t){var n,r,o,i,s;if(a(t),void 0===(r=this._events))return this;if(void 0===(n=r[e]))return this;if(n===t||n.listener===t)0==--this._eventsCount?this._events=Object.create(null):(delete r[e],r.removeListener&&this.emit("removeListener",e,n.listener||t));else if("function"!=typeof n){for(o=-1,i=n.length-1;i>=0;i--)if(n[i]===t||n[i].listener===t){s=n[i].listener,o=i;break}if(o<0)return this;0===o?n.shift():funLine truncated
function createCommonjsModule(fn) { function createCommonjsModule(fn) {
var module = { exports: {} }; var module = { exports: {} };
@@ -2258,10 +2258,13 @@ module.exports['DIFF_INSERT'] = DIFF_INSERT;
module.exports['DIFF_EQUAL'] = DIFF_EQUAL; module.exports['DIFF_EQUAL'] = DIFF_EQUAL;
}); });
const t=new Uint8Array([0,97,115,109,1,0,0,0,1,13,2,96,2,127,127,0,96,3,127,127,127,1,127,3,3,2,1,0,5,3,1,0,1,7,23,3,3,109,101,109,2,0,5,120,120,104,51,50,0,0,5,120,120,104,54,52,0,1,10,152,9,2,242,2,1,4,127,32,0,32,1,106,33,3,32,1,32,1,65,16,79,4,127,32,3,65,16,107,33,6,32,2,65,168,136,141,161,2,106,33,1,32,2,65,137,235,208,208,7,107,33,4,32,2,65,207,140,162,142,6,106,33,5,3,64,32,1,32,0,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,33,1,32,4,32,0,65,4,106,34,0,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,33,4,32,2,32,0,65,4,106,34,0,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,33,2,32,5,32,0,65,4,106,34,0,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,33,5,32,6,32,0,65,4,106,34,0,79,13,0,11,32,2,65,12,119,32,5,65,18,119,106,32,4,65,7,119,106,32,1,65,1,119,106,5,32,2,65,177,207,217,178,1,106,11,106,33,2,3,64,32,3,32,0,65,4,106,79,4,64,32,2,32,0,40,2,0,65,189,220,202,149,124,108,106,65,17,119,65,175,214,211,190,2,108,33,2,32,0,65,4,106,33,0,12,1,11,11,3,64,32,0,32,3,73,4,64,32,2,32,0,45,0,0,65,177,207,217,178,1,108,106,65,11,119,65,177,243,221,241,121,108,33,2,32,0,65,1,106,33,0,12,1,11,11,32,2,32,2,65,15,118,115,65,247,148,175,175,120,108,34,0,65,13,118,32,0,115,65,189,220,202,149,124,108,34,0,65,16,118,32,0,115,11,161,6,2,4,126,3,127,32,0,65,4,106,53,2,0,32,0,53,2,0,66,32,134,132,33,2,32,1,32,0,65,8,106,34,6,106,33,7,32,1,65,32,79,4,126,32,7,65,32,107,33,8,32,2,66,214,235,130,238,234,253,137,245,224,0,124,33,3,32,2,66,177,169,172,193,173,184,212,166,61,125,33,4,32,2,66,249,234,208,208,231,201,161,228,225,0,124,33,5,3,64,32,3,32,6,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,33,3,32,4,32,6,65,8,106,34,6,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,33,4,32,2,32,6,65,8,106,34,6,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,33,2,32,5,32,6,65,8,106,34,6,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,33,5,32,8,32,6,65,8,106,34,6,79,13,0,11,32,2,66,12,137,32,5,66,18,137,124,32,4,66,7,137,124,32,3,66,1,137,124,32,3,66,207,214,211,190,210,199,171,217,66,126,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,133,66,135,149,175,175,152,182,222,155,158,127,126,66,157,163,181,234,131,177,141,138,250,0,125,32,4,66,207,214,211,190,210,199,171,217,66,126,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,133,66,135,149,175,175,152,182,222,155,158,127,126,66,157,163,181,234,131,177,141,138,250,0,125,32,2,66,207,214,211,190,210,199,171,217,66,126,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,133,66,135,149,175,175,152,182,222,155,158,127,126,66,157,163,181,234,131,177,141,138,250,0,125,32,5,66,207,214,211,190,210,199,171,217,66,126,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,133,66,135,149,175,175,152,182,222,155,158,127,126,66,157,163,181,234,131,177,141,138,250,0,125,5,32,2,66,197,207,217,178,241,229,186,234,39,124,11,32,1,173,124,33,2,3,64,32,7,32,6,65,8,106,79,4,64,32,2,32,6,41,3,0,66,207,214,211,190,210,199,171,217,66,126,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,133,66,27,137,66,135,149,175,175,152,182,222,155,158,127,126,66,157,163,181,234,131,177,141,138,250,0,125,33,2,32,6,65,8,106,33,6,12,1,11,11,32,6,65,4,106,32,7,77,4,64,32,2,32,6,53,2,0,66,135,149,175,175,152,182,222,155,158,127,126,133,66,23,137,66,207,214,211,190,210,199,171,217,66,126,66,249,243,221,241,153,246,153,171,22,124,33,2,32,6,65,4,106,33,6,11,3,64,32,6,32,7,73,4,64,32,2,32,6,49,0,0,66,197,207,217,178,241,229,186,234,39,126,133,66,11,137,66,135,149,175,175,152,182,222,155,158,127,126,33,2,32,6,65,1,106,33,6,12,1,11,11,32,0,32,2,32,2,66,33,136,133,66,207,214,211,190,210,199,171,217,66,126,34,2,66,29,136,32,2,133,66,249,243,221,241,153,246,153,171,22,126,34,2,66,32,136,32,2,133,34,2,66,32,136,62,2,0,32,0,65,4,106,32,2,62,2,0,11]);let e;function n(t,e,n){if(e.buffer.byteLength<t.byteLength+n){const i=Math.ceil((t.byteLength+n-e.buffer.byteLength)/65536);e.grow(i);}new Uint8Array(e.buffer,n).set(t);}async function xxhash(){const{instance:{exports:{mem:i,xxh32:o,xxh64:r}}}=await WebAssembly.instantiate(t);function h(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return n(t,i,0),o(0,t.byteLength,e)>>>0}function c(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;n(t,i,8);const h=new DataView(i.buffer);return h.setUint32(0,e,!0),h.setUint32(4,o,!0),r(0,t.byteLength),h}return {h32:function(t){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;e||(e=new TextEncoder);const i=e.encode(t);return h(i,n).toString(16)},h32Raw:h,h64:function(t){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,i=arguments.length>2&&void 0!==argumLine truncated
// docs should be encoded as base64, so 1 char -> 1 bytes // docs should be encoded as base64, so 1 char -> 1 bytes
// and cloudant limitation is 1MB , we use 900kb; // and cloudant limitation is 1MB , we use 900kb;
// const MAX_DOC_SIZE = 921600; // const MAX_DOC_SIZE = 921600;
const MAX_DOC_SIZE = 921600; const MAX_DOC_SIZE = 200; // for .md file
const MAX_DOC_SIZE_BIN = 102400; // 100kb
const DEFAULT_SETTINGS = { const DEFAULT_SETTINGS = {
couchDB_URI: "", couchDB_URI: "",
couchDB_USER: "", couchDB_USER: "",
@@ -2271,6 +2274,7 @@ const DEFAULT_SETTINGS = {
syncOnStart: false, syncOnStart: false,
savingDelay: 200, savingDelay: 200,
lessInformationInLog: false, lessInformationInLog: false,
gcDelay: 30,
}; };
//-->Functions. //-->Functions.
function arrayBufferToBase64(buffer) { function arrayBufferToBase64(buffer) {
@@ -2370,13 +2374,25 @@ class LocalPouchDB {
return "disabled"; return "disabled";
} }
initializeDatabase() { initializeDatabase() {
if (this.localDatabase != null) return __awaiter(this, void 0, void 0, function* () {
this.localDatabase.close(); if (this.localDatabase != null)
this.localDatabase = null; this.localDatabase.close();
this.localDatabase = new o(this.dbname + "-livesync", { this.localDatabase = null;
auto_compaction: true, this.localDatabase = new o(this.dbname + "-livesync", {
revs_limit: 100, auto_compaction: true,
deterministic_revs: true, revs_limit: 100,
deterministic_revs: true,
});
yield this.prepareHashArg();
});
}
prepareHashArg() {
return __awaiter(this, void 0, void 0, function* () {
if (this.h32 != null)
return;
const { h32, h64 } = yield xxhash();
this.h32 = h32;
this.h64 = h64;
}); });
} }
getDatabaseDoc(id, opt) { getDatabaseDoc(id, opt) {
@@ -2413,24 +2429,17 @@ class LocalPouchDB {
// search childrens // search childrens
try { try {
let childrens = []; let childrens = [];
// let childPromise = [];
for (var v of obj.children) { for (var v of obj.children) {
// childPromise.push(this.localDatabase.get(v)); // childPromise.push(this.localDatabase.get(v));
let elem = yield this.localDatabase.get(v); let elem = yield this.localDatabase.get(v);
if (elem.type && elem.type == "leaf") { if (elem.type && elem.type == "leaf") {
childrens.push(elem); childrens.push(elem.data);
} }
else { else {
throw new Error("linked document is not leaf"); throw new Error("linked document is not leaf");
} }
} }
// let childrens = await Promise.all(childPromise); let data = childrens.join("");
let data = childrens
// .filter((e) => e.type == "leaf")
// .map((e) => e as NoteLeaf)
.sort((e) => e.seq)
.map((e) => e.data)
.join("");
let doc = { let doc = {
data: data, data: data,
_id: obj._id, _id: obj._id,
@@ -2447,6 +2456,7 @@ class LocalPouchDB {
if (ex.status && ex.status == 404) { if (ex.status && ex.status == 404) {
this.addLog(`Missing document content!, could not read ${obj._id} from database.`, true); this.addLog(`Missing document content!, could not read ${obj._id} from database.`, true);
// this.addLog(ex); // this.addLog(ex);
return false;
} }
this.addLog(`Something went wrong on reading ${obj._id} from database.`, true); this.addLog(`Something went wrong on reading ${obj._id} from database.`, true);
this.addLog(ex); this.addLog(ex);
@@ -2478,24 +2488,12 @@ class LocalPouchDB {
} }
//Check it out and fix docs to regular case //Check it out and fix docs to regular case
if (!obj.type || (obj.type && obj.type == "notes")) { if (!obj.type || (obj.type && obj.type == "notes")) {
// let note = obj as Notes;
// note._deleted=true;
obj._deleted = true; obj._deleted = true;
let r = yield this.localDatabase.put(obj); let r = yield this.localDatabase.put(obj);
return true; return true;
// simple note // simple note
} }
if (obj.type == "newnote") { if (obj.type == "newnote") {
// search childrens
for (var v of obj.children) {
let d = yield this.localDatabase.get(v);
if (d.type != "leaf") {
this.addLog(`structure went wrong:${id}-${v}`);
}
d._deleted = true;
yield this.localDatabase.put(d);
this.addLog(`content removed:${d.seq}`);
}
obj._deleted = true; obj._deleted = true;
yield this.localDatabase.put(obj); yield this.localDatabase.put(obj);
this.addLog(`entry removed:${obj._id}`); this.addLog(`entry removed:${obj._id}`);
@@ -2513,25 +2511,84 @@ class LocalPouchDB {
putDBEntry(note) { putDBEntry(note) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
let leftData = note.data; let leftData = note.data;
let savenNotes = []; // something occured, kill this . let savenNotes = [];
let seq = 0; let processed = 0;
let now = Date.now(); let made = 0;
let skiped = 0;
let pieceSize = MAX_DOC_SIZE;
if (!note._id.endsWith(".md")) {
pieceSize = MAX_DOC_SIZE_BIN;
}
do { do {
let piece = leftData.substring(0, MAX_DOC_SIZE); // To keep low bandwith and database size,
leftData = leftData.substring(MAX_DOC_SIZE); // Dedup pieces on database.
seq++; let piece = leftData.substring(0, pieceSize);
let leafid = note._id + "-" + now + "-" + seq; leftData = leftData.substring(pieceSize);
let d = { processed++;
_id: leafid, // Get has of piece.
parent: note._id, let hashedPiece = this.h32(piece);
data: piece, let leafid = "h:" + hashedPiece;
seq: seq, let hashQ = 0; // if hash collided, **IF**, count it up.
type: "leaf", let tryNextHash = false;
}; let needMake = true;
yield this.localDatabase.put(d); do {
let nleafid = leafid;
try {
nleafid = `${leafid}${hashQ}`;
// console.log(nleafid);
let pieceData = yield this.localDatabase.get(nleafid);
if (pieceData.type == "leaf" && pieceData.data == piece) {
this.addLog("hashe:data exists.");
leafid = nleafid;
needMake = false;
tryNextHash = false;
}
else if (pieceData.type == "leaf") {
this.addLog("hash:collision!!");
hashQ++;
tryNextHash = true;
}
else {
this.addLog("hash:no collision, it's not leaf. what's going on..");
leafid = nleafid;
tryNextHash = false;
}
}
catch (ex) {
if (ex.status && ex.status == 404) {
//not found, we can use it.
this.addLog(`hash:not found.`);
leafid = nleafid;
needMake = true;
}
else {
needMake = false;
throw ex;
}
}
} while (tryNextHash);
if (needMake) {
//have to make
let d = {
_id: leafid,
data: piece,
type: "leaf",
};
let result = yield this.localDatabase.put(d);
if (result.ok) {
this.addLog(`ok:saven`);
made++;
}
else {
this.addLog("save faild");
}
}
else {
skiped++;
}
savenNotes.push(leafid); savenNotes.push(leafid);
} while (leftData != ""); } while (leftData != "");
this.addLog(`note content saven, pieces:${seq}`); this.addLog(`note content saven, pieces:${processed} new:${made}, skip:${skiped}`);
let newDoc = { let newDoc = {
NewNote: true, NewNote: true,
children: savenNotes, children: savenNotes,
@@ -2541,19 +2598,13 @@ class LocalPouchDB {
size: note.size, size: note.size,
type: "newnote", type: "newnote",
}; };
let deldocs = [];
// Here for upsert logic, // Here for upsert logic,
try { try {
let old = yield this.localDatabase.get(newDoc._id); let old = yield this.localDatabase.get(newDoc._id);
if (!old.type || old.type == "notes") { if (!old.type || old.type == "notes" || old.type == "newnote") {
// simple use rev for new doc // simple use rev for new doc
newDoc._rev = old._rev; newDoc._rev = old._rev;
} }
if (old.type == "newnote") {
//when save finished, we have to garbage collect.
deldocs = old.children;
newDoc._rev = old._rev;
}
} }
catch (ex) { catch (ex) {
if (ex.status && ex.status == 404) ; if (ex.status && ex.status == 404) ;
@@ -2563,15 +2614,6 @@ class LocalPouchDB {
} }
yield this.localDatabase.put(newDoc); yield this.localDatabase.put(newDoc);
this.addLog(`note saven:${newDoc._id}`); this.addLog(`note saven:${newDoc._id}`);
let items = 0;
for (var v of deldocs) {
items++;
//TODO: Check for missing link
let d = yield this.localDatabase.get(v);
d._deleted = true;
yield this.localDatabase.put(d);
}
this.addLog(`old content deleted, pieces:${items}`);
}); });
} }
openReplication(setting, keepAlive, showResult, callback) { openReplication(setting, keepAlive, showResult, callback) {
@@ -2704,11 +2746,60 @@ class LocalPouchDB {
this.addLog("Remote Database Created or Connected", true); this.addLog("Remote Database Created or Connected", true);
}); });
} }
garbageCollect() {
return __awaiter(this, void 0, void 0, function* () {
// get all documents of NewEntry2
// we don't use queries , just use allDocs();
let c = 0;
let readCount = 0;
let hashPieces = [];
let usedPieces = [];
do {
let result = yield this.localDatabase.allDocs({ include_docs: true, skip: c, limit: 100 });
readCount = result.rows.length;
if (readCount > 0) {
//there are some result
for (let v of result.rows) {
let doc = v.doc;
if (doc.type == "newnote") {
// used pieces memo.
usedPieces = Array.from(new Set([...usedPieces, ...doc.children]));
}
if (doc.type == "leaf") {
// all pieces.
hashPieces = Array.from(new Set([...hashPieces, doc._id]));
}
// this.addLog(`GC:processed:${v.doc._id}`);
}
}
c += readCount;
} while (readCount != 0);
// items collected.
const garbages = hashPieces.filter((e) => usedPieces.indexOf(e) == -1);
let deleteCount = 0;
for (let v of garbages) {
try {
let item = yield this.localDatabase.get(v);
item._deleted = true;
yield this.localDatabase.put(item);
deleteCount++;
}
catch (ex) {
if (ex.status && ex.status == 404) ;
else {
throw ex;
}
}
}
this.addLog(`GC:deleted ${deleteCount} items.`);
});
}
} }
class ObsidianLiveSyncPlugin extends obsidian.Plugin { class ObsidianLiveSyncPlugin extends obsidian.Plugin {
constructor() { constructor() {
super(...arguments); super(...arguments);
this.logMessage = []; this.logMessage = [];
this.gcTimerHandler = null;
} }
onload() { onload() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
@@ -2767,10 +2858,14 @@ class ObsidianLiveSyncPlugin extends obsidian.Plugin {
}); });
} }
onunload() { onunload() {
if (this.gcTimerHandler != null) {
clearTimeout(this.gcTimerHandler);
this.gcTimerHandler = null;
}
this.localDatabase.closeReplication(); this.localDatabase.closeReplication();
this.localDatabase.close(); this.localDatabase.close();
this.addLog("unloading plugin");
window.removeEventListener("visibilitychange", this.watchWindowVisiblity); window.removeEventListener("visibilitychange", this.watchWindowVisiblity);
this.addLog("unloading plugin");
} }
openDatabase() { openDatabase() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
@@ -2779,7 +2874,12 @@ class ObsidianLiveSyncPlugin extends obsidian.Plugin {
} }
let vaultName = this.app.vault.getName(); let vaultName = this.app.vault.getName();
this.localDatabase = new LocalPouchDB(this.app, this, vaultName); this.localDatabase = new LocalPouchDB(this.app, this, vaultName);
this.localDatabase.initializeDatabase(); yield this.localDatabase.initializeDatabase();
});
}
garbageCollect() {
return __awaiter(this, void 0, void 0, function* () {
yield this.localDatabase.garbageCollect();
}); });
} }
loadSettings() { loadSettings() {
@@ -2792,6 +2892,19 @@ class ObsidianLiveSyncPlugin extends obsidian.Plugin {
yield this.saveData(this.settings); yield this.saveData(this.settings);
}); });
} }
gcHook() {
if (this.settings.gcDelay == 0)
return;
const GC_DELAY = this.settings.gcDelay * 1000; // if leaving opening window, try GC,
if (this.gcTimerHandler != null) {
clearTimeout(this.gcTimerHandler);
this.gcTimerHandler = null;
}
this.gcTimerHandler = setTimeout(() => {
this.gcTimerHandler = null;
this.garbageCollect();
}, GC_DELAY);
}
registerWatchEvents() { registerWatchEvents() {
this.registerEvent(this.app.vault.on("modify", this.watchVaultChange)); this.registerEvent(this.app.vault.on("modify", this.watchVaultChange));
this.registerEvent(this.app.vault.on("delete", this.watchVaultDelete)); this.registerEvent(this.app.vault.on("delete", this.watchVaultDelete));
@@ -2814,14 +2927,17 @@ class ObsidianLiveSyncPlugin extends obsidian.Plugin {
this.localDatabase.openReplication(this.settings, false, false, this.parseReplicationResult); this.localDatabase.openReplication(this.settings, false, false, this.parseReplicationResult);
} }
} }
this.gcHook();
} }
watchWorkspaceOpen(file) { watchWorkspaceOpen(file) {
if (file == null) if (file == null)
return; return;
this.showIfConflicted(file); this.showIfConflicted(file);
this.gcHook();
} }
watchVaultChange(file, ...args) { watchVaultChange(file, ...args) {
this.updateIntoDB(file); this.updateIntoDB(file);
this.gcHook();
} }
watchVaultDelete(file) { watchVaultDelete(file) {
if (file.children) { if (file.children) {
@@ -2832,6 +2948,7 @@ class ObsidianLiveSyncPlugin extends obsidian.Plugin {
else { else {
this.deleteFromDB(file); this.deleteFromDB(file);
} }
this.gcHook();
} }
watchVaultRename(file, oldFile) { watchVaultRename(file, oldFile) {
if (file.children) { if (file.children) {
@@ -2842,6 +2959,7 @@ class ObsidianLiveSyncPlugin extends obsidian.Plugin {
this.updateIntoDB(file); this.updateIntoDB(file);
this.deleteFromDBbyPath(oldFile); this.deleteFromDBbyPath(oldFile);
} }
this.gcHook();
} }
//--> Basic document Functions //--> Basic document Functions
addLog(message, isNotify) { addLog(message, isNotify) {
@@ -3455,6 +3573,23 @@ class ObsidianLiveSyncSettingTab extends obsidian.PluginSettingTab {
})); }));
text.inputEl.setAttribute("type", "number"); text.inputEl.setAttribute("type", "number");
}); });
new obsidian.Setting(containerEl)
.setName("Auto GC delay")
.setDesc("(seconds), if you set zero, you have to run manually.")
.addText((text) => {
text.setPlaceholder("")
.setValue(this.plugin.settings.gcDelay + "")
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
let v = Number(value);
if (isNaN(v) || v < 200 || v > 5000) {
return 30;
//text.inputEl.va;
}
this.plugin.settings.gcDelay = v;
yield this.plugin.saveSettings();
}));
text.inputEl.setAttribute("type", "number");
});
new obsidian.Setting(containerEl) new obsidian.Setting(containerEl)
.setName("Log") .setName("Log")
.setDesc("Reduce log infomations") .setDesc("Reduce log infomations")
@@ -3499,6 +3634,21 @@ class ObsidianLiveSyncSettingTab extends obsidian.PluginSettingTab {
.onClick(() => __awaiter(this, void 0, void 0, function* () { .onClick(() => __awaiter(this, void 0, void 0, function* () {
//await this.test(); //await this.test();
}))); })));
new obsidian.Setting(containerEl)
.setName("Garbage Collect")
.addButton((button) => button
.setButtonText("Garbage Collection")
.setDisabled(false)
.onClick(() => __awaiter(this, void 0, void 0, function* () {
yield this.plugin.garbageCollect();
//await this.test();
})))
.addButton((button) => button
.setButtonText("Reset local files")
.setDisabled(false)
.onClick(() => __awaiter(this, void 0, void 0, function* () {
//await this.test();
})));
new obsidian.Setting(containerEl).setName("Remote Database Operations").addButton((button) => button new obsidian.Setting(containerEl).setName("Remote Database Operations").addButton((button) => button
.setButtonText("Reset remote database") .setButtonText("Reset remote database")
.setDisabled(false) .setDisabled(false)
@@ -3517,4 +3667,4 @@ class ObsidianLiveSyncSettingTab extends obsidian.PluginSettingTab {
} }
module.exports = ObsidianLiveSyncPlugin; module.exports = ObsidianLiveSyncPlugin;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZXMiOlsibm9kZV9tb2R1bGVzL3RzbGliL3RzbGliLmVzNi5qcyIsInBvdWNoZGItYnJvd3Nlci13ZWJwYWNrL2Rpc3QvcG91Y2hkYi1icm93c2VyLmpzIiwibm9kZV9tb2R1bGVzL2RpZmYtbWF0Y2gtcGF0Y2gvaW5kZXguanMiLCJtYWluLnRzIl0sInNvdXJjZXNDb250ZW50IjpudWxsLCJuYW1lcyI6WyJQb3VjaERCIiwiUGx1Z2luIiwiYWRkSWNvbiIsImRlYm91bmNlIiwiTm90aWNlIiwiZGlmZl9tYXRjaF9wYXRjaCIsIk1vZGFsIiwiRElGRl9ERUxFVEUiLCJESUZGX0VRVUFMIiwiRElGRl9JTlNFUlQiLCJQbHVnaW5TZXR0aW5nVGFiIiwiU2V0dGluZyJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQXVEQTtBQUNPLFNBQVMsU0FBUyxDQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsQ0FBQyxFQUFFLFNBQVMsRUFBRTtBQUM3RCxJQUFJLFNBQVMsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLE9BQU8sS0FBSyxZQUFZLENBQUMsR0FBRyxLQUFLLEdBQUcsSUFBSSxDQUFDLENBQUMsVUFBVSxPQUFPLEVBQUUsRUFBRSxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRTtBQUNoSCxJQUFJLE9BQU8sS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLE9BQU8sQ0FBQyxFQUFFLFVBQVUsT0FBTyxFQUFFLE1BQU0sRUFBRTtBQUMvRCxRQUFRLFNBQVMsU0FBUyxDQUFDLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7QUFDbkcsUUFBUSxTQUFTLFFBQVEsQ0FBQyxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7QUFDdEcsUUFBUSxTQUFTLElBQUksQ0FBQyxNQUFNLEVBQUUsRUFBRSxNQUFNLENBQUMsSUFBSSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFFBQVEsQ0FBQyxDQUFDLEVBQUU7QUFDdEgsUUFBUSxJQUFJLENBQUMsQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsVUFBVSxJQUFJLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7QUFDOUUsS0FBSyxDQUFDLENBQUM7QUFDUDs7QUM3RUEsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLE9BQU8sVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sUUFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMscUJBQXFCLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxPQUFPLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLE9BQU8sTUFBTSxDQUFDLG1CQUFtQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLE9BQU8sRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQUMsY0FBYyxFQUFFLENBQUMsQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxHQUFHLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQUMsTUFBTSxJQUFJLFNBQVMsQ0FBQyxrRUFBa0UsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUF Line truncated //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZXMiOlsibm9kZV9tb2R1bGVzL3RzbGliL3RzbGliLmVzNi5qcyIsInBvdWNoZGItYnJvd3Nlci13ZWJwYWNrL2Rpc3QvcG91Y2hkYi1icm93c2VyLmpzIiwibm9kZV9tb2R1bGVzL2RpZmYtbWF0Y2gtcGF0Y2gvaW5kZXguanMiLCJub2RlX21vZHVsZXMveHhoYXNoLXdhc20vZXNtL3h4aGFzaC13YXNtLmpzIiwibWFpbi50cyJdLCJzb3VyY2VzQ29udGVudCI6bnVsbCwibmFtZXMiOlsiZSIsInQiLCJuIiwiUG91Y2hEQiIsIlBsdWdpbiIsImFkZEljb24iLCJkZWJvdW5jZSIsIk5vdGljZSIsImRpZmZfbWF0Y2hfcGF0Y2giLCJNb2RhbCIsIkRJRkZfREVMRVRFIiwiRElGRl9FUVVBTCIsIkRJRkZfSU5TRVJUIiwiUGx1Z2luU2V0dGluZ1RhYiIsIlNldHRpbmciXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUF1REE7QUFDTyxTQUFTLFNBQVMsQ0FBQyxPQUFPLEVBQUUsVUFBVSxFQUFFLENBQUMsRUFBRSxTQUFTLEVBQUU7QUFDN0QsSUFBSSxTQUFTLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxPQUFPLEtBQUssWUFBWSxDQUFDLEdBQUcsS0FBSyxHQUFHLElBQUksQ0FBQyxDQUFDLFVBQVUsT0FBTyxFQUFFLEVBQUUsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUU7QUFDaEgsSUFBSSxPQUFPLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxPQUFPLENBQUMsRUFBRSxVQUFVLE9BQU8sRUFBRSxNQUFNLEVBQUU7QUFDL0QsUUFBUSxTQUFTLFNBQVMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO0FBQ25HLFFBQVEsU0FBUyxRQUFRLENBQUMsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO0FBQ3RHLFFBQVEsU0FBUyxJQUFJLENBQUMsTUFBTSxFQUFFLEVBQUUsTUFBTSxDQUFDLElBQUksR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsQ0FBQyxFQUFFO0FBQ3RILFFBQVEsSUFBSSxDQUFDLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLFVBQVUsSUFBSSxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0FBQzlFLEtBQUssQ0FBQyxDQUFDO0FBQ1A7O0FDN0VBLElBQUlBLEdBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsT0FBTyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUUsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxRQUFRLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLE9BQU8sTUFBTSxDQUFDLG1CQUFtQixDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMscUJBQXFCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsT0FBTyxNQUFNLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLElBQUksT0FBTyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUcsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQyxNQUFNLElBQUksU0FBUyxDQUFDLGtFQUFrRSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLFNBQVM Line truncated
+200 -61
View File
@@ -1,11 +1,13 @@
import { App, debounce, Modal, Notice, Plugin, PluginSettingTab, Setting, TFile, addIcon, TFolder } from "obsidian"; import { App, debounce, Modal, Notice, Plugin, PluginSettingTab, Setting, TFile, addIcon, TFolder } from "obsidian";
import { PouchDB } from "./pouchdb-browser-webpack/dist/pouchdb-browser"; import { PouchDB } from "./pouchdb-browser-webpack/dist/pouchdb-browser";
import { DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "diff-match-patch"; import { DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "diff-match-patch";
import xxhash from "xxhash-wasm";
// docs should be encoded as base64, so 1 char -> 1 bytes // docs should be encoded as base64, so 1 char -> 1 bytes
// and cloudant limitation is 1MB , we use 900kb; // and cloudant limitation is 1MB , we use 900kb;
// const MAX_DOC_SIZE = 921600; // const MAX_DOC_SIZE = 921600;
const MAX_DOC_SIZE = 921600; const MAX_DOC_SIZE = 200; // for .md file
const MAX_DOC_SIZE_BIN = 102400; // 100kb
interface ObsidianLiveSyncSettings { interface ObsidianLiveSyncSettings {
couchDB_URI: string; couchDB_URI: string;
@@ -16,6 +18,7 @@ interface ObsidianLiveSyncSettings {
syncOnStart: boolean; syncOnStart: boolean;
savingDelay: number; savingDelay: number;
lessInformationInLog: boolean; lessInformationInLog: boolean;
gcDelay: number;
} }
const DEFAULT_SETTINGS: ObsidianLiveSyncSettings = { const DEFAULT_SETTINGS: ObsidianLiveSyncSettings = {
@@ -27,6 +30,7 @@ const DEFAULT_SETTINGS: ObsidianLiveSyncSettings = {
syncOnStart: false, syncOnStart: false,
savingDelay: 200, savingDelay: 200,
lessInformationInLog: false, lessInformationInLog: false,
gcDelay: 30,
}; };
interface Entry { interface Entry {
@@ -56,13 +60,11 @@ type LoadedEntry = Entry & {
interface EntryLeaf { interface EntryLeaf {
_id: string; _id: string;
parent: string;
seq: number;
data: string; data: string;
_rev?: string;
_deleted?: boolean; _deleted?: boolean;
type: "leaf"; type: "leaf";
} }
type EntryDoc = Entry | NewEntry | LoadedEntry | EntryLeaf; type EntryDoc = Entry | NewEntry | LoadedEntry | EntryLeaf;
type diff_result_leaf = { type diff_result_leaf = {
rev: string; rev: string;
@@ -164,6 +166,8 @@ class LocalPouchDB {
addLog: (message: any, isNotify?: boolean) => Promise<void>; addLog: (message: any, isNotify?: boolean) => Promise<void>;
localDatabase: PouchDB.Database<EntryDoc>; localDatabase: PouchDB.Database<EntryDoc>;
h32: (input: string, seed?: number) => string;
h64: (input: string, seedHigh?: number, seedLow?: number) => string;
constructor(app: App, plugin: ObsidianLiveSyncPlugin, dbname: string) { constructor(app: App, plugin: ObsidianLiveSyncPlugin, dbname: string) {
this.plugin = plugin; this.plugin = plugin;
this.app = app; this.app = app;
@@ -185,7 +189,7 @@ class LocalPouchDB {
} }
return "disabled"; return "disabled";
} }
initializeDatabase() { async initializeDatabase() {
if (this.localDatabase != null) this.localDatabase.close(); if (this.localDatabase != null) this.localDatabase.close();
this.localDatabase = null; this.localDatabase = null;
this.localDatabase = new PouchDB<EntryDoc>(this.dbname + "-livesync", { this.localDatabase = new PouchDB<EntryDoc>(this.dbname + "-livesync", {
@@ -193,8 +197,14 @@ class LocalPouchDB {
revs_limit: 100, revs_limit: 100,
deterministic_revs: true, deterministic_revs: true,
}); });
await this.prepareHashArg();
}
async prepareHashArg() {
if (this.h32 != null) return;
const { h32, h64 } = await xxhash();
this.h32 = h32;
this.h64 = h64;
} }
async getDatabaseDoc(id: string, opt?: any): Promise<false | LoadedEntry> { async getDatabaseDoc(id: string, opt?: any): Promise<false | LoadedEntry> {
try { try {
let obj: EntryDoc & PouchDB.Core.IdMeta & PouchDB.Core.GetMeta = null; let obj: EntryDoc & PouchDB.Core.IdMeta & PouchDB.Core.GetMeta = null;
@@ -229,23 +239,16 @@ class LocalPouchDB {
// search childrens // search childrens
try { try {
let childrens = []; let childrens = [];
// let childPromise = [];
for (var v of obj.children) { for (var v of obj.children) {
// childPromise.push(this.localDatabase.get(v)); // childPromise.push(this.localDatabase.get(v));
let elem = await this.localDatabase.get(v); let elem = await this.localDatabase.get(v);
if (elem.type && elem.type == "leaf") { if (elem.type && elem.type == "leaf") {
childrens.push(elem); childrens.push(elem.data);
} else { } else {
throw new Error("linked document is not leaf"); throw new Error("linked document is not leaf");
} }
} }
// let childrens = await Promise.all(childPromise); let data = childrens.join("");
let data = childrens
// .filter((e) => e.type == "leaf")
// .map((e) => e as NoteLeaf)
.sort((e) => e.seq)
.map((e) => e.data)
.join("");
let doc: LoadedEntry = { let doc: LoadedEntry = {
data: data, data: data,
_id: obj._id, _id: obj._id,
@@ -261,6 +264,7 @@ class LocalPouchDB {
if (ex.status && ex.status == 404) { if (ex.status && ex.status == 404) {
this.addLog(`Missing document content!, could not read ${obj._id} from database.`, true); this.addLog(`Missing document content!, could not read ${obj._id} from database.`, true);
// this.addLog(ex); // this.addLog(ex);
return false;
} }
this.addLog(`Something went wrong on reading ${obj._id} from database.`, true); this.addLog(`Something went wrong on reading ${obj._id} from database.`, true);
this.addLog(ex); this.addLog(ex);
@@ -289,24 +293,12 @@ class LocalPouchDB {
} }
//Check it out and fix docs to regular case //Check it out and fix docs to regular case
if (!obj.type || (obj.type && obj.type == "notes")) { if (!obj.type || (obj.type && obj.type == "notes")) {
// let note = obj as Notes;
// note._deleted=true;
obj._deleted = true; obj._deleted = true;
let r = await this.localDatabase.put(obj); let r = await this.localDatabase.put(obj);
return true; return true;
// simple note // simple note
} }
if (obj.type == "newnote") { if (obj.type == "newnote") {
// search childrens
for (var v of obj.children) {
let d = await this.localDatabase.get(v);
if (d.type != "leaf") {
this.addLog(`structure went wrong:${id}-${v}`);
}
d._deleted = true;
await this.localDatabase.put(d);
this.addLog(`content removed:${(d as EntryLeaf).seq}`);
}
obj._deleted = true; obj._deleted = true;
await this.localDatabase.put(obj); await this.localDatabase.put(obj);
this.addLog(`entry removed:${obj._id}`); this.addLog(`entry removed:${obj._id}`);
@@ -322,25 +314,79 @@ class LocalPouchDB {
async putDBEntry(note: LoadedEntry) { async putDBEntry(note: LoadedEntry) {
let leftData = note.data; let leftData = note.data;
let savenNotes = []; // something occured, kill this . let savenNotes = [];
let seq = 0; let processed = 0;
let now = Date.now(); let made = 0;
let skiped = 0;
let pieceSize = MAX_DOC_SIZE;
if (!note._id.endsWith(".md")) {
pieceSize = MAX_DOC_SIZE_BIN;
}
do { do {
let piece = leftData.substring(0, MAX_DOC_SIZE); // To keep low bandwith and database size,
leftData = leftData.substring(MAX_DOC_SIZE); // Dedup pieces on database.
seq++; let piece = leftData.substring(0, pieceSize);
let leafid = note._id + "-" + now + "-" + seq; leftData = leftData.substring(pieceSize);
let d: EntryLeaf = { processed++;
_id: leafid, // Get has of piece.
parent: note._id, let hashedPiece = this.h32(piece);
data: piece, let leafid = "h:" + hashedPiece;
seq: seq, let hashQ: number = 0; // if hash collided, **IF**, count it up.
type: "leaf", let tryNextHash = false;
}; let needMake = true;
let result = await this.localDatabase.put(d);
do {
let nleafid = leafid;
try {
nleafid = `${leafid}${hashQ}`;
// console.log(nleafid);
let pieceData = await this.localDatabase.get<EntryLeaf>(nleafid);
if (pieceData.type == "leaf" && pieceData.data == piece) {
this.addLog("hashe:data exists.");
leafid = nleafid;
needMake = false;
tryNextHash = false;
} else if (pieceData.type == "leaf") {
this.addLog("hash:collision!!");
hashQ++;
tryNextHash = true;
} else {
this.addLog("hash:no collision, it's not leaf. what's going on..");
leafid = nleafid;
tryNextHash = false;
}
} catch (ex) {
if (ex.status && ex.status == 404) {
//not found, we can use it.
this.addLog(`hash:not found.`);
leafid = nleafid;
needMake = true;
} else {
needMake = false;
throw ex;
}
}
} while (tryNextHash);
if (needMake) {
//have to make
let d: EntryLeaf = {
_id: leafid,
data: piece,
type: "leaf",
};
let result = await this.localDatabase.put(d);
if (result.ok) {
this.addLog(`ok:saven`);
made++;
} else {
this.addLog("save faild");
}
} else {
skiped++;
}
savenNotes.push(leafid); savenNotes.push(leafid);
} while (leftData != ""); } while (leftData != "");
this.addLog(`note content saven, pieces:${seq}`); this.addLog(`note content saven, pieces:${processed} new:${made}, skip:${skiped}`);
let newDoc: NewEntry = { let newDoc: NewEntry = {
NewNote: true, NewNote: true,
children: savenNotes, children: savenNotes,
@@ -355,15 +401,10 @@ class LocalPouchDB {
// Here for upsert logic, // Here for upsert logic,
try { try {
let old = await this.localDatabase.get(newDoc._id); let old = await this.localDatabase.get(newDoc._id);
if (!old.type || old.type == "notes") { if (!old.type || old.type == "notes" || old.type == "newnote") {
// simple use rev for new doc // simple use rev for new doc
newDoc._rev = old._rev; newDoc._rev = old._rev;
} }
if (old.type == "newnote") {
//when save finished, we have to garbage collect.
deldocs = old.children;
newDoc._rev = old._rev;
}
} catch (ex) { } catch (ex) {
if (ex.status && ex.status == 404) { if (ex.status && ex.status == 404) {
// NO OP/ // NO OP/
@@ -373,15 +414,6 @@ class LocalPouchDB {
} }
await this.localDatabase.put(newDoc); await this.localDatabase.put(newDoc);
this.addLog(`note saven:${newDoc._id}`); this.addLog(`note saven:${newDoc._id}`);
let items = 0;
for (var v of deldocs) {
items++;
//TODO: Check for missing link
let d = await this.localDatabase.get(v);
d._deleted = true;
await this.localDatabase.put(d);
}
this.addLog(`old content deleted, pieces:${items}`);
} }
syncHandler: PouchDB.Replication.Sync<{}> = null; syncHandler: PouchDB.Replication.Sync<{}> = null;
@@ -506,6 +538,53 @@ class LocalPouchDB {
if (con2 === false) return; if (con2 === false) return;
this.addLog("Remote Database Created or Connected", true); this.addLog("Remote Database Created or Connected", true);
} }
async garbageCollect() {
// get all documents of NewEntry2
// we don't use queries , just use allDocs();
let c = 0;
let readCount = 0;
let hashPieces: string[] = [];
let usedPieces: string[] = [];
do {
let result = await this.localDatabase.allDocs({ include_docs: true, skip: c, limit: 100 });
readCount = result.rows.length;
if (readCount > 0) {
//there are some result
for (let v of result.rows) {
let doc = v.doc;
if (doc.type == "newnote") {
// used pieces memo.
usedPieces = Array.from(new Set([...usedPieces, ...doc.children]));
}
if (doc.type == "leaf") {
// all pieces.
hashPieces = Array.from(new Set([...hashPieces, doc._id]));
}
// this.addLog(`GC:processed:${v.doc._id}`);
}
}
c += readCount;
} while (readCount != 0);
// items collected.
const garbages = hashPieces.filter((e) => usedPieces.indexOf(e) == -1);
let deleteCount = 0;
for (let v of garbages) {
try {
let item = await this.localDatabase.get(v);
item._deleted = true;
await this.localDatabase.put(item);
deleteCount++;
} catch (ex) {
if (ex.status && ex.status == 404) {
// NO OP. It should be timing problem.
} else {
throw ex;
}
}
}
this.addLog(`GC:deleted ${deleteCount} items.`);
}
} }
export default class ObsidianLiveSyncPlugin extends Plugin { export default class ObsidianLiveSyncPlugin extends Plugin {
@@ -585,10 +664,14 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
} }
onunload() { onunload() {
if (this.gcTimerHandler != null) {
clearTimeout(this.gcTimerHandler);
this.gcTimerHandler = null;
}
this.localDatabase.closeReplication(); this.localDatabase.closeReplication();
this.localDatabase.close(); this.localDatabase.close();
this.addLog("unloading plugin");
window.removeEventListener("visibilitychange", this.watchWindowVisiblity); window.removeEventListener("visibilitychange", this.watchWindowVisiblity);
this.addLog("unloading plugin");
} }
async openDatabase() { async openDatabase() {
@@ -597,7 +680,10 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
} }
let vaultName = this.app.vault.getName(); let vaultName = this.app.vault.getName();
this.localDatabase = new LocalPouchDB(this.app, this, vaultName); this.localDatabase = new LocalPouchDB(this.app, this, vaultName);
this.localDatabase.initializeDatabase(); await this.localDatabase.initializeDatabase();
}
async garbageCollect() {
await this.localDatabase.garbageCollect();
} }
async loadSettings() { async loadSettings() {
@@ -607,7 +693,19 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
async saveSettings() { async saveSettings() {
await this.saveData(this.settings); await this.saveData(this.settings);
} }
gcTimerHandler: any = null;
gcHook() {
if (this.settings.gcDelay == 0) return;
const GC_DELAY = this.settings.gcDelay * 1000; // if leaving opening window, try GC,
if (this.gcTimerHandler != null) {
clearTimeout(this.gcTimerHandler);
this.gcTimerHandler = null;
}
this.gcTimerHandler = setTimeout(() => {
this.gcTimerHandler = null;
this.garbageCollect();
}, GC_DELAY);
}
registerWatchEvents() { registerWatchEvents() {
this.registerEvent(this.app.vault.on("modify", this.watchVaultChange)); this.registerEvent(this.app.vault.on("modify", this.watchVaultChange));
this.registerEvent(this.app.vault.on("delete", this.watchVaultDelete)); this.registerEvent(this.app.vault.on("delete", this.watchVaultDelete));
@@ -630,14 +728,17 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
this.localDatabase.openReplication(this.settings, false, false, this.parseReplicationResult); this.localDatabase.openReplication(this.settings, false, false, this.parseReplicationResult);
} }
} }
this.gcHook();
} }
watchWorkspaceOpen(file: TFile) { watchWorkspaceOpen(file: TFile) {
if (file == null) return; if (file == null) return;
this.showIfConflicted(file); this.showIfConflicted(file);
this.gcHook();
} }
watchVaultChange(file: TFile, ...args: any[]) { watchVaultChange(file: TFile, ...args: any[]) {
this.updateIntoDB(file); this.updateIntoDB(file);
this.gcHook();
} }
watchVaultDelete(file: TFile & TFolder) { watchVaultDelete(file: TFile & TFolder) {
if (file.children) { if (file.children) {
@@ -647,6 +748,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
} else { } else {
this.deleteFromDB(file); this.deleteFromDB(file);
} }
this.gcHook();
} }
watchVaultRename(file: TFile & TFolder, oldFile: any) { watchVaultRename(file: TFile & TFolder, oldFile: any) {
if (file.children) { if (file.children) {
@@ -656,6 +758,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
this.updateIntoDB(file); this.updateIntoDB(file);
this.deleteFromDBbyPath(oldFile); this.deleteFromDBbyPath(oldFile);
} }
this.gcHook();
} }
//--> Basic document Functions //--> Basic document Functions
@@ -1242,6 +1345,23 @@ class ObsidianLiveSyncSettingTab extends PluginSettingTab {
}); });
text.inputEl.setAttribute("type", "number"); text.inputEl.setAttribute("type", "number");
}); });
new Setting(containerEl)
.setName("Auto GC delay")
.setDesc("(seconds), if you set zero, you have to run manually.")
.addText((text) => {
text.setPlaceholder("")
.setValue(this.plugin.settings.gcDelay + "")
.onChange(async (value) => {
let v = Number(value);
if (isNaN(v) || v < 200 || v > 5000) {
return 30;
//text.inputEl.va;
}
this.plugin.settings.gcDelay = v;
await this.plugin.saveSettings();
});
text.inputEl.setAttribute("type", "number");
});
new Setting(containerEl) new Setting(containerEl)
.setName("Log") .setName("Log")
.setDesc("Reduce log infomations") .setDesc("Reduce log infomations")
@@ -1298,6 +1418,25 @@ class ObsidianLiveSyncSettingTab extends PluginSettingTab {
//await this.test(); //await this.test();
}) })
); );
new Setting(containerEl)
.setName("Garbage Collect")
.addButton((button) =>
button
.setButtonText("Garbage Collection")
.setDisabled(false)
.onClick(async () => {
await this.plugin.garbageCollect();
//await this.test();
})
)
.addButton((button) =>
button
.setButtonText("Reset local files")
.setDisabled(false)
.onClick(async () => {
//await this.test();
})
);
new Setting(containerEl).setName("Remote Database Operations").addButton((button) => new Setting(containerEl).setName("Remote Database Operations").addButton((button) =>
button button
.setButtonText("Reset remote database") .setButtonText("Reset remote database")
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"id": "obsidian-livesync", "id": "obsidian-livesync",
"name": "Obsidian Live sync", "name": "Obsidian Live sync",
"version": "0.0.7", "version": "0.0.8",
"minAppVersion": "0.9.12", "minAppVersion": "0.9.12",
"description": "obsidian Live synchronization plugin.", "description": "obsidian Live synchronization plugin.",
"author": "vorotamoroz", "author": "vorotamoroz",
+14 -3
View File
@@ -1,15 +1,16 @@
{ {
"name": "obsidian-livesync", "name": "obsidian-livesync",
"version": "0.0.6", "version": "0.0.8",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "obsidian-livesync", "name": "obsidian-livesync",
"version": "0.0.6", "version": "0.0.8",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"diff-match-patch": "^1.0.5" "diff-match-patch": "^1.0.5",
"xxhash-wasm": "^0.4.2"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-commonjs": "^18.0.0", "@rollup/plugin-commonjs": "^18.0.0",
@@ -539,6 +540,11 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true "dev": true
},
"node_modules/xxhash-wasm": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz",
"integrity": "sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA=="
} }
}, },
"dependencies": { "dependencies": {
@@ -975,6 +981,11 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true "dev": true
},
"xxhash-wasm": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz",
"integrity": "sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA=="
} }
} }
} }
+3 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "obsidian-livesync", "name": "obsidian-livesync",
"version": "0.0.7", "version": "0.0.8",
"description": "obsidian Live synchronization plugin.", "description": "obsidian Live synchronization plugin.",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
@@ -22,6 +22,7 @@
"typescript": "^4.2.4" "typescript": "^4.2.4"
}, },
"dependencies": { "dependencies": {
"diff-match-patch": "^1.0.5" "diff-match-patch": "^1.0.5",
"xxhash-wasm": "^0.4.2"
} }
} }