mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2025-12-06 02:30:47 -08:00
chore: upgrade watch-fs plugin
This commit is contained in:
parent
5d9f8ead1d
commit
ac41266982
6 changed files with 88 additions and 19 deletions
|
|
@ -8,7 +8,7 @@
|
||||||
This file is modified based on $:/plugins/OokTech/Bob/FileSystemMonitor.js
|
This file is modified based on $:/plugins/OokTech/Bob/FileSystemMonitor.js
|
||||||
\ */
|
\ */
|
||||||
|
|
||||||
const isNonTiddlerFiles = filePath => filePath.endsWith('.DS_Store');
|
const isNotNonTiddlerFiles = (filePath) => !filePath.endsWith('.DS_Store') && !filePath.includes('.git');
|
||||||
|
|
||||||
function FileSystemMonitor() {
|
function FileSystemMonitor() {
|
||||||
const isDebug = false;
|
const isDebug = false;
|
||||||
|
|
@ -21,6 +21,8 @@ function FileSystemMonitor() {
|
||||||
|
|
||||||
// this allow us to test this module in nodejs directly without "ReferenceError: $tw is not defined"
|
// this allow us to test this module in nodejs directly without "ReferenceError: $tw is not defined"
|
||||||
const $tw = this.$tw || { node: true };
|
const $tw = this.$tw || { node: true };
|
||||||
|
// init our namespace for communication
|
||||||
|
$tw.wiki.watchFs = {};
|
||||||
// folder to watch
|
// folder to watch
|
||||||
// non-tiddler files that needs to be ignored
|
// non-tiddler files that needs to be ignored
|
||||||
|
|
||||||
|
|
@ -29,7 +31,9 @@ function FileSystemMonitor() {
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const watchPathBase = path.resolve($tw.boot.wikiInfo?.config?.watchFolder || $tw.boot.wikiTiddlersPath || './tiddlers');
|
const watchPathBase = path.resolve(
|
||||||
|
$tw.boot.wikiInfo?.config?.watchFolder || $tw.boot.wikiTiddlersPath || './tiddlers'
|
||||||
|
);
|
||||||
debugLog(`watchPathBase`, JSON.stringify(watchPathBase, undefined, ' '));
|
debugLog(`watchPathBase`, JSON.stringify(watchPathBase, undefined, ' '));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -55,6 +59,7 @@ function FileSystemMonitor() {
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
const inverseFilesIndex = {};
|
const inverseFilesIndex = {};
|
||||||
|
$tw.wiki.watchFs.inverseFilesIndex = inverseFilesIndex;
|
||||||
// initialize the inverse index
|
// initialize the inverse index
|
||||||
for (const tiddlerTitle in initialLoadedFiles) {
|
for (const tiddlerTitle in initialLoadedFiles) {
|
||||||
if ({}.hasOwnProperty.call(initialLoadedFiles, tiddlerTitle)) {
|
if ({}.hasOwnProperty.call(initialLoadedFiles, tiddlerTitle)) {
|
||||||
|
|
@ -72,8 +77,8 @@ function FileSystemMonitor() {
|
||||||
delete inverseFilesIndex[filePath];
|
delete inverseFilesIndex[filePath];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const filePathExistsInIndex = filePath => !!inverseFilesIndex[filePath];
|
const filePathExistsInIndex = (filePath) => !!inverseFilesIndex[filePath];
|
||||||
const getTitleByPath = filePath => {
|
const getTitleByPath = (filePath) => {
|
||||||
try {
|
try {
|
||||||
return inverseFilesIndex[filePath].tiddlerTitle;
|
return inverseFilesIndex[filePath].tiddlerTitle;
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -87,7 +92,7 @@ function FileSystemMonitor() {
|
||||||
* we need to get old tiddler path by its name
|
* we need to get old tiddler path by its name
|
||||||
* @param {string} title
|
* @param {string} title
|
||||||
*/
|
*/
|
||||||
const getPathByTitle = title => {
|
const getPathByTitle = (title) => {
|
||||||
try {
|
try {
|
||||||
for (const filePath in inverseFilesIndex) {
|
for (const filePath in inverseFilesIndex) {
|
||||||
if (inverseFilesIndex[filePath].title === title || inverseFilesIndex[filePath].title === `${title}.tid`) {
|
if (inverseFilesIndex[filePath].title === title || inverseFilesIndex[filePath].title === `${title}.tid`) {
|
||||||
|
|
@ -109,6 +114,20 @@ function FileSystemMonitor() {
|
||||||
*/
|
*/
|
||||||
const lockedFiles = new Set();
|
const lockedFiles = new Set();
|
||||||
|
|
||||||
|
// every time a file changed, refresh the count down timer, so only when disk get stable after a while, will we sync to the browser
|
||||||
|
$tw.wiki.watchFs.canSync = false;
|
||||||
|
const debounceInterval = 4 * 1000;
|
||||||
|
let syncTimeoutHandler = undefined;
|
||||||
|
const refreshCanSyncState = () => {
|
||||||
|
$tw.wiki.watchFs.canSync = false;
|
||||||
|
debugLog(`canSync is now ${$tw.wiki.watchFs.canSync}`);
|
||||||
|
clearTimeout(syncTimeoutHandler);
|
||||||
|
syncTimeoutHandler = setTimeout(() => {
|
||||||
|
$tw.wiki.watchFs.canSync = true;
|
||||||
|
debugLog(`canSync is now ${$tw.wiki.watchFs.canSync}`);
|
||||||
|
}, debounceInterval);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This watches for changes to a folder and updates the wiki when anything changes in the folder.
|
* This watches for changes to a folder and updates the wiki when anything changes in the folder.
|
||||||
*
|
*
|
||||||
|
|
@ -127,11 +146,6 @@ function FileSystemMonitor() {
|
||||||
const fileRelativePath = path.relative(watchPathBase, filePath);
|
const fileRelativePath = path.relative(watchPathBase, filePath);
|
||||||
const fileAbsolutePath = path.join(watchPathBase, fileRelativePath);
|
const fileAbsolutePath = path.join(watchPathBase, fileRelativePath);
|
||||||
debugLog(`${fileRelativePath} ${changeType}`);
|
debugLog(`${fileRelativePath} ${changeType}`);
|
||||||
// ignore some cases
|
|
||||||
if (isNonTiddlerFiles(fileRelativePath)) {
|
|
||||||
debugLog(`${fileRelativePath} ignored due to isNonTiddlerFiles`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (lockedFiles.has(fileRelativePath)) {
|
if (lockedFiles.has(fileRelativePath)) {
|
||||||
debugLog(`${fileRelativePath} ignored due to mutex lock`);
|
debugLog(`${fileRelativePath} ignored due to mutex lock`);
|
||||||
// release lock as we have already finished our job
|
// release lock as we have already finished our job
|
||||||
|
|
@ -155,15 +169,15 @@ function FileSystemMonitor() {
|
||||||
* "hasMetaFile": false
|
* "hasMetaFile": false
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
const [tiddlersDescriptor] = $tw.loadTiddlersFromPath(fileAbsolutePath);
|
const tiddlersDescriptor = $tw.loadTiddlersFromFile(fileAbsolutePath, { title: fileAbsolutePath });
|
||||||
debugLog(`tiddlersDescriptor`, JSON.stringify(tiddlersDescriptor, undefined, ' '));
|
debugLog(`tiddlersDescriptor`, JSON.stringify(tiddlersDescriptor, undefined, ' '));
|
||||||
const { tiddlers, ...fileDescriptor } = tiddlersDescriptor;
|
const { tiddlers, ...fileDescriptor } = tiddlersDescriptor;
|
||||||
// if user is using git or VSCode to create new file in the disk, that is not yet exist in the wiki
|
// if user is using git or VSCode to create new file in the disk, that is not yet exist in the wiki
|
||||||
// but maybe our index is not updated, or maybe user is modify a system tiddler, we need to check each case
|
// but maybe our index is not updated, or maybe user is modify a system tiddler, we need to check each case
|
||||||
if (!filePathExistsInIndex(fileRelativePath) || !fileDescriptor.tiddlerTitle) {
|
if (!filePathExistsInIndex(fileRelativePath)) {
|
||||||
tiddlers.forEach(tiddler => {
|
tiddlers.forEach((tiddler) => {
|
||||||
// check whether we are rename an existed tiddler
|
// check whether we are rename an existed tiddler
|
||||||
debugLog('getting tiddler.title', tiddler.title);
|
debugLog('getting new tiddler.title', tiddler.title);
|
||||||
const existedWikiRecord = $tw.wiki.getTiddler(tiddler.title);
|
const existedWikiRecord = $tw.wiki.getTiddler(tiddler.title);
|
||||||
if (existedWikiRecord && deepEqual(tiddler, existedWikiRecord.fields)) {
|
if (existedWikiRecord && deepEqual(tiddler, existedWikiRecord.fields)) {
|
||||||
// because disk file and wiki tiddler is identical, so this file creation is triggered by wiki.
|
// because disk file and wiki tiddler is identical, so this file creation is triggered by wiki.
|
||||||
|
|
@ -192,13 +206,18 @@ function FileSystemMonitor() {
|
||||||
// if it already existed in the wiki, this change might 1. due to our last call to `$tw.syncadaptor.wiki.addTiddler`; 2. due to user change in git or VSCode
|
// if it already existed in the wiki, this change might 1. due to our last call to `$tw.syncadaptor.wiki.addTiddler`; 2. due to user change in git or VSCode
|
||||||
// so we have to check whether tiddler in the disk is identical to the one in the wiki, if so, we ignore it in the case 1.
|
// so we have to check whether tiddler in the disk is identical to the one in the wiki, if so, we ignore it in the case 1.
|
||||||
tiddlers
|
tiddlers
|
||||||
.filter(tiddler => {
|
.filter((tiddler) => {
|
||||||
debugLog('updating existed tiddler', tiddler.title);
|
debugLog('updating existed tiddler', tiddler.title);
|
||||||
const { fields: tiddlerInWiki } = $tw.wiki.getTiddler(tiddler.title);
|
const { fields: tiddlerInWiki } = $tw.wiki.getTiddler(tiddler.title);
|
||||||
return !deepEqual(tiddler, tiddlerInWiki);
|
if (deepEqual(tiddler, tiddlerInWiki)) {
|
||||||
|
debugLog('Ignore update due to change from the Browser', tiddler.title);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
debugLog('Saving updated', tiddler.title);
|
||||||
|
return true;
|
||||||
})
|
})
|
||||||
// then we update wiki with each newly created tiddler
|
// then we update wiki with each newly created tiddler
|
||||||
.forEach(tiddler => {
|
.forEach((tiddler) => {
|
||||||
$tw.syncadaptor.wiki.addTiddler(tiddler);
|
$tw.syncadaptor.wiki.addTiddler(tiddler);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -243,10 +262,12 @@ function FileSystemMonitor() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refreshCanSyncState();
|
||||||
};
|
};
|
||||||
|
|
||||||
// use node-watch
|
// use node-watch
|
||||||
const watch = require('./watch');
|
const watch = require('./watch');
|
||||||
const watcher = watch(watchPathBase, { recursive: true, delay: 200 }, listener);
|
const watcher = watch(watchPathBase, { recursive: true, delay: 200, filter: isNotNonTiddlerFiles }, listener);
|
||||||
}
|
}
|
||||||
FileSystemMonitor();
|
FileSystemMonitor();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
title: $:/config/SyncPollingInterval
|
title: $:/config/SyncPollingInterval
|
||||||
type: text/vnd.tiddlywiki
|
type: text/vnd.tiddlywiki
|
||||||
|
|
||||||
1000
|
32140800000
|
||||||
21
template/wiki/plugins/linonetwo/watch-fs/get-can-sync.js
Normal file
21
template/wiki/plugins/linonetwo/watch-fs/get-can-sync.js
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*\
|
||||||
|
title: $:/plugins/linonetwo/watch-fs/get-can-sync.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: route
|
||||||
|
GET /watch-fs-can-sync
|
||||||
|
\*/
|
||||||
|
(function () {
|
||||||
|
exports.method = 'GET';
|
||||||
|
exports.aaa = 'bbb';
|
||||||
|
|
||||||
|
// route should start with something https://github.com/Jermolene/TiddlyWiki5/issues/4807
|
||||||
|
exports.path = /^\/linonetwo\/watch-fs-can-sync$/;
|
||||||
|
|
||||||
|
exports.handler = function handler(request, response, state) {
|
||||||
|
response.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
|
const { canSync } = state.wiki.watchFs;
|
||||||
|
// DEBUG: console
|
||||||
|
console.log(`canSync`, canSync);
|
||||||
|
response.end(JSON.stringify(canSync), 'utf8');
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
creator: LinOnetwo
|
||||||
|
title: $:/plugins/linonetwo/watch-fs/get-can-sync.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: route
|
||||||
17
template/wiki/plugins/linonetwo/watch-fs/trigger-sync.html
Normal file
17
template/wiki/plugins/linonetwo/watch-fs/trigger-sync.html
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<script type="application/javascript">
|
||||||
|
const checkCanSyncInterval = 1000; // ms
|
||||||
|
// after we sync, set this to false
|
||||||
|
let deSync = false;
|
||||||
|
setInterval(async function checkCanSync() {
|
||||||
|
// debounced sync indicator, will be true if there is no change in the disc for several seconds
|
||||||
|
const canSync = (await fetch('/linonetwo/watch-fs-can-sync').then((response) => response.text())) === 'true';
|
||||||
|
if (!deSync && !canSync) {
|
||||||
|
// we have previously synced, and server have changes that is not debounced yet
|
||||||
|
deSync = true;
|
||||||
|
}
|
||||||
|
if (canSync && deSync) {
|
||||||
|
$tw.syncer.syncFromServer();
|
||||||
|
deSync = false;
|
||||||
|
}
|
||||||
|
}, checkCanSyncInterval);
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
created: 20200411065413157
|
||||||
|
modified: 20200414150804034
|
||||||
|
creator: LinOnetwo
|
||||||
|
tags: $:/tags/RawMarkup
|
||||||
|
title: $:/plugins/linonetwo/copy-on-select/copy-on-select.html
|
||||||
|
type: text/html
|
||||||
Loading…
Add table
Add a link
Reference in a new issue