@mieweb/wikigdrive
Version:
Google Drive to MarkDown synchronization
118 lines (117 loc) • 3.91 kB
JavaScript
import fs from 'node:fs';
import path from 'node:path';
import crypto from 'node:crypto';
export function pathResolve(rootPath, ...args) {
const retVal = path.resolve(path.join(rootPath, ...args));
if (!retVal.startsWith(rootPath)) {
throw new Error('Access denied: ' + retVal + ' outside of ' + rootPath);
}
return retVal;
}
export class FileService {
constructor(rootPath = '/') {
Object.defineProperty(this, "rootPath", {
enumerable: true,
configurable: true,
writable: true,
value: rootPath
});
if (!this.rootPath) {
throw new Error('Empty rootPath');
}
}
async mkdir(dirPath) {
if (!await this.exists(dirPath)) {
fs.mkdirSync(pathResolve(this.rootPath, dirPath), { recursive: true });
}
}
async rmdir(dirPath) {
if (await this.exists(dirPath)) {
fs.rmSync(pathResolve(this.rootPath, dirPath), { recursive: true });
}
}
async remove(filePath) {
if (!await this.exists(filePath)) {
return;
}
const stat = fs.statSync(pathResolve(this.rootPath, filePath));
if (stat.isDirectory()) {
await this.rmdir(filePath);
}
if (stat.isFile()) {
fs.unlinkSync(pathResolve(this.rootPath, filePath));
}
}
async isDirectory(filePath) {
const stat = fs.statSync(pathResolve(this.rootPath, filePath));
return stat.isDirectory();
}
async exists(filePath) {
return fs.existsSync(pathResolve(this.rootPath, filePath));
}
async getSize(filePath) {
const stats = fs.statSync(pathResolve(this.rootPath, filePath));
return stats.size;
}
async getMtime(filePath) {
const stats = fs.statSync(pathResolve(this.rootPath, filePath));
return +stats.mtime;
}
readBuffer(filePath) {
return new Promise((resolve, reject) => {
fs.readFile(pathResolve(this.rootPath, filePath), (err, data) => {
if (err)
return reject(err);
resolve(data);
});
});
}
writeBuffer(filePath, buffer) {
return new Promise((resolve, reject) => {
fs.writeFile(pathResolve(this.rootPath, filePath), buffer, (err) => {
if (err)
return reject(err);
resolve();
});
});
}
createWriteStream(filePath) {
const stream = fs.createWriteStream(pathResolve(this.rootPath, filePath));
return stream;
}
createReadStream(filePath) {
return fs.createReadStream(pathResolve(this.rootPath, filePath));
}
md5File(filePath) {
// TODO migrate to WebAPI when https://github.com/w3c/webcrypto/issues/73 is done
return new Promise((resolve, reject) => {
const hash = crypto.createHash('md5');
hash.setEncoding('hex');
const fullFilePath = pathResolve(this.rootPath, filePath);
if (!fs.existsSync(fullFilePath)) {
return resolve(null);
}
const fd = fs.createReadStream(fullFilePath);
fd
.on('error', function (err) {
reject(err);
})
.on('end', function () {
hash.end();
resolve(hash.read()); // the desired sha1sum
});
fd.pipe(hash);
});
}
async move(path1, path2) {
fs.renameSync(pathResolve(this.rootPath, path1), pathResolve(this.rootPath, path2));
}
async list(dirPath = '') {
const fullPath = pathResolve(this.rootPath, dirPath);
if (!await this.exists(dirPath)) {
return [];
}
const files = fs.readdirSync(fullPath);
return files;
}
}