You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-06-15 23:00:36 +02:00
All: Refactored filesystem sync driver to support mobile
This commit is contained in:
@ -26,66 +26,55 @@ class FileApiDriverLocal {
|
||||
return output;
|
||||
}
|
||||
|
||||
stat(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.stat(path, (error, s) => {
|
||||
if (error) {
|
||||
if (error.code == 'ENOENT') {
|
||||
resolve(null);
|
||||
} else {
|
||||
reject(this.fsErrorToJsError_(error));
|
||||
}
|
||||
return;
|
||||
}
|
||||
resolve(this.metadataFromStats_(path, s));
|
||||
});
|
||||
});
|
||||
fsDriver() {
|
||||
if (!FileApiDriverLocal.fsDriver_) throw new Error('FileApiDriverLocal.fsDriver_ not set!');
|
||||
return FileApiDriverLocal.fsDriver_;
|
||||
}
|
||||
|
||||
statTimeToTimestampMs_(time) {
|
||||
let m = moment(time, 'YYYY-MM-DDTHH:mm:ss.SSSZ');
|
||||
if (!m.isValid()) {
|
||||
throw new Error('Invalid date: ' + time);
|
||||
async stat(path) {
|
||||
try {
|
||||
const s = await this.fsDriver().stat(path);
|
||||
return this.metadataFromStat_(s);
|
||||
} catch (error) {
|
||||
if (error.code == 'ENOENT') return null;
|
||||
throw this.fsErrorToJsError_(error);
|
||||
}
|
||||
return m.toDate().getTime();
|
||||
}
|
||||
|
||||
metadataFromStats_(path, stats) {
|
||||
metadataFromStat_(stat) {
|
||||
return {
|
||||
path: path,
|
||||
created_time: this.statTimeToTimestampMs_(stats.birthtime),
|
||||
updated_time: this.statTimeToTimestampMs_(stats.mtime),
|
||||
created_time_orig: stats.birthtime,
|
||||
updated_time_orig: stats.mtime,
|
||||
isDir: stats.isDirectory(),
|
||||
path: stat.path,
|
||||
created_time: stat.birthtime.getTime(),
|
||||
updated_time: stat.mtime.getTime(),
|
||||
created_time_orig: stat.birthtime,
|
||||
updated_time_orig: stat.mtime,
|
||||
isDir: stat.isDirectory(),
|
||||
};
|
||||
}
|
||||
|
||||
setTimestamp(path, timestampMs) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let t = Math.floor(timestampMs / 1000);
|
||||
fs.utimes(path, t, t, (error) => {
|
||||
if (error) {
|
||||
reject(this.fsErrorToJsError_(error));
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
metadataFromStats_(stats) {
|
||||
let output = [];
|
||||
for (let i = 0; i < stats.length; i++) {
|
||||
const mdStat = this.metadataFromStat_(stats[i]);
|
||||
output.push(mdStat);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
async setTimestamp(path, timestampMs) {
|
||||
try {
|
||||
await this.fsDriver().setTimestamp(path, new Date(timestampMs));
|
||||
} catch (error) {
|
||||
throw this.fsErrorToJsError_(error);
|
||||
}
|
||||
}
|
||||
|
||||
async delta(path, options) {
|
||||
const itemIds = await options.allItemIdsHandler();
|
||||
|
||||
try {
|
||||
let items = await fs.readdir(path);
|
||||
let output = [];
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
let stat = await this.stat(path + '/' + items[i]);
|
||||
if (!stat) continue; // Has been deleted between the readdir() call and now
|
||||
stat.path = items[i];
|
||||
output.push(stat);
|
||||
}
|
||||
const stats = await this.fsDriver().readDirStats(path);
|
||||
let output = this.metadataFromStats_(stats);
|
||||
|
||||
if (!Array.isArray(itemIds)) throw new Error('Delta API not supported - local IDs must be provided');
|
||||
|
||||
@ -123,14 +112,8 @@ class FileApiDriverLocal {
|
||||
|
||||
async list(path, options) {
|
||||
try {
|
||||
let items = await fs.readdir(path);
|
||||
let output = [];
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
let stat = await this.stat(path + '/' + items[i]);
|
||||
if (!stat) continue; // Has been deleted between the readdir() call and now
|
||||
stat.path = items[i];
|
||||
output.push(stat);
|
||||
}
|
||||
const stats = await this.fsDriver().readDirStats(path);
|
||||
const output = this.metadataFromStats_(stats);
|
||||
|
||||
return {
|
||||
items: output,
|
||||
@ -147,9 +130,11 @@ class FileApiDriverLocal {
|
||||
|
||||
try {
|
||||
if (options.target === 'file') {
|
||||
output = await fs.copy(path, options.path, { overwrite: true });
|
||||
//output = await fs.copy(path, options.path, { overwrite: true });
|
||||
output = await this.fsDriver().copy(path, options.path);
|
||||
} else {
|
||||
output = await fs.readFile(path, options.encoding);
|
||||
//output = await fs.readFile(path, options.encoding);
|
||||
output = await this.fsDriver().readFile(path, options.encoding);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.code == 'ENOENT') return null;
|
||||
@ -159,78 +144,107 @@ class FileApiDriverLocal {
|
||||
return output;
|
||||
}
|
||||
|
||||
mkdir(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.exists(path, (exists) => {
|
||||
if (exists) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
async mkdir(path) {
|
||||
if (await this.fsDriver().exists(path)) return;
|
||||
|
||||
try {
|
||||
await this.fsDriver().mkdir(path);
|
||||
} catch (error) {
|
||||
throw this.fsErrorToJsError_(error);
|
||||
}
|
||||
|
||||
// return new Promise((resolve, reject) => {
|
||||
// fs.exists(path, (exists) => {
|
||||
// if (exists) {
|
||||
// resolve();
|
||||
// return;
|
||||
// }
|
||||
|
||||
fs.mkdirp(path, (error) => {
|
||||
if (error) {
|
||||
reject(this.fsErrorToJsError_(error));
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
// fs.mkdirp(path, (error) => {
|
||||
// if (error) {
|
||||
// reject(this.fsErrorToJsError_(error));
|
||||
// } else {
|
||||
// resolve();
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
async put(path, content, options = null) {
|
||||
if (!options) options = {};
|
||||
|
||||
if (options.source === 'file') content = await fs.readFile(options.path);
|
||||
try {
|
||||
if (options.source === 'file') {
|
||||
await this.fsDriver().copy(options.path, path);
|
||||
return;
|
||||
}
|
||||
|
||||
await this.fsDriver().writeFile(path, content, 'utf8');
|
||||
} catch (error) {
|
||||
throw this.fsErrorToJsError_(error);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.writeFile(path, content, function(error) {
|
||||
if (error) {
|
||||
reject(this.fsErrorToJsError_(error));
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
// if (!options) options = {};
|
||||
|
||||
// if (options.source === 'file') content = await fs.readFile(options.path);
|
||||
|
||||
// return new Promise((resolve, reject) => {
|
||||
// fs.writeFile(path, content, function(error) {
|
||||
// if (error) {
|
||||
// reject(this.fsErrorToJsError_(error));
|
||||
// } else {
|
||||
// resolve();
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
delete(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.unlink(path, function(error) {
|
||||
if (error) {
|
||||
if (error && error.code == 'ENOENT') {
|
||||
// File doesn't exist - it's fine
|
||||
resolve();
|
||||
} else {
|
||||
reject(this.fsErrorToJsError_(error));
|
||||
}
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
async delete(path) {
|
||||
try {
|
||||
await this.fsDriver().unlink(path);
|
||||
} catch (error) {
|
||||
throw this.fsErrorToJsError_(error);
|
||||
}
|
||||
|
||||
// return new Promise((resolve, reject) => {
|
||||
// fs.unlink(path, function(error) {
|
||||
// if (error) {
|
||||
// if (error && error.code == 'ENOENT') {
|
||||
// // File doesn't exist - it's fine
|
||||
// resolve();
|
||||
// } else {
|
||||
// reject(this.fsErrorToJsError_(error));
|
||||
// }
|
||||
// } else {
|
||||
// resolve();
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
async move(oldPath, newPath) {
|
||||
let lastError = null;
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
try {
|
||||
let output = await fs.move(oldPath, newPath, { overwrite: true });
|
||||
return output;
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
// Normally cannot happen with the `overwrite` flag but sometime it still does.
|
||||
// In this case, retry.
|
||||
if (error.code == 'EEXIST') {
|
||||
await time.sleep(1);
|
||||
continue;
|
||||
}
|
||||
throw this.fsErrorToJsError_(error);
|
||||
}
|
||||
}
|
||||
return this.fsDriver().move(oldPath, newPath);
|
||||
|
||||
throw lastError;
|
||||
// let lastError = null;
|
||||
|
||||
// for (let i = 0; i < 5; i++) {
|
||||
// try {
|
||||
// let output = await fs.move(oldPath, newPath, { overwrite: true });
|
||||
// return output;
|
||||
// } catch (error) {
|
||||
// lastError = error;
|
||||
// // Normally cannot happen with the `overwrite` flag but sometime it still does.
|
||||
// // In this case, retry.
|
||||
// if (error.code == 'EEXIST') {
|
||||
// await time.sleep(1);
|
||||
// continue;
|
||||
// }
|
||||
// throw this.fsErrorToJsError_(error);
|
||||
// }
|
||||
// }
|
||||
|
||||
// throw lastError;
|
||||
}
|
||||
|
||||
format() {
|
||||
|
Reference in New Issue
Block a user