2021-06-18 18:17:25 +02:00
|
|
|
import time from './time';
|
2017-12-18 22:47:25 +02:00
|
|
|
const fs = require('fs-extra');
|
2021-06-18 18:17:25 +02:00
|
|
|
import { basicDelta, MultiPutItem } from './file-api';
|
|
|
|
|
|
|
|
export default class FileApiDriverMemory {
|
|
|
|
|
|
|
|
private items_: any[];
|
|
|
|
private deletedItems_: any[];
|
2017-06-18 01:49:52 +02:00
|
|
|
|
2017-06-27 21:26:29 +02:00
|
|
|
constructor() {
|
2017-06-13 22:12:08 +02:00
|
|
|
this.items_ = [];
|
2017-07-18 22:03:07 +02:00
|
|
|
this.deletedItems_ = [];
|
2017-06-13 22:12:08 +02:00
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
encodeContent_(content: any) {
|
2017-12-18 22:47:25 +02:00
|
|
|
if (content instanceof Buffer) {
|
|
|
|
return content.toString('base64');
|
|
|
|
} else {
|
|
|
|
return Buffer.from(content).toString('base64');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
public get supportsMultiPut() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-06-19 11:34:44 +02:00
|
|
|
public get supportsAccurateTimestamp() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
decodeContent_(content: any) {
|
2018-02-15 19:12:09 +02:00
|
|
|
return Buffer.from(content, 'base64').toString('utf-8');
|
2017-12-18 22:47:25 +02:00
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
itemIndexByPath(path: string) {
|
2017-06-13 22:12:08 +02:00
|
|
|
for (let i = 0; i < this.items_.length; i++) {
|
|
|
|
if (this.items_[i].path == path) return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
itemByPath(path: string) {
|
2020-03-14 01:46:14 +02:00
|
|
|
const index = this.itemIndexByPath(path);
|
2017-06-13 22:12:08 +02:00
|
|
|
return index < 0 ? null : this.items_[index];
|
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
newItem(path: string, isDir = false) {
|
2020-03-14 01:46:14 +02:00
|
|
|
const now = time.unixMs();
|
2017-06-13 22:12:08 +02:00
|
|
|
return {
|
|
|
|
path: path,
|
|
|
|
isDir: isDir,
|
2017-06-19 00:06:10 +02:00
|
|
|
updated_time: now, // In milliseconds!!
|
2018-02-07 22:42:52 +02:00
|
|
|
// created_time: now, // In milliseconds!!
|
2017-06-13 22:12:08 +02:00
|
|
|
content: '',
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
stat(path: string) {
|
2020-03-14 01:46:14 +02:00
|
|
|
const item = this.itemByPath(path);
|
2017-06-18 01:49:52 +02:00
|
|
|
return Promise.resolve(item ? Object.assign({}, item) : null);
|
2017-06-13 22:12:08 +02:00
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
async setTimestamp(path: string, timestampMs: number): Promise<any> {
|
2020-03-14 01:46:14 +02:00
|
|
|
const item = this.itemByPath(path);
|
2019-09-19 23:51:18 +02:00
|
|
|
if (!item) return Promise.reject(new Error(`File not found: ${path}`));
|
2017-06-27 21:48:01 +02:00
|
|
|
item.updated_time = timestampMs;
|
2017-06-13 22:12:08 +02:00
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
async list(path: string) {
|
2020-03-14 01:46:14 +02:00
|
|
|
const output = [];
|
2017-06-13 22:12:08 +02:00
|
|
|
|
|
|
|
for (let i = 0; i < this.items_.length; i++) {
|
2020-03-14 01:46:14 +02:00
|
|
|
const item = this.items_[i];
|
2017-06-13 22:12:08 +02:00
|
|
|
if (item.path == path) continue;
|
2019-09-19 23:51:18 +02:00
|
|
|
if (item.path.indexOf(`${path}/`) === 0) {
|
2020-03-14 01:46:14 +02:00
|
|
|
const s = item.path.substr(path.length + 1);
|
2017-06-13 22:12:08 +02:00
|
|
|
if (s.split('/').length === 1) {
|
2020-03-14 01:46:14 +02:00
|
|
|
const it = Object.assign({}, item);
|
2017-06-23 21:09:49 +02:00
|
|
|
it.path = it.path.substr(path.length + 1);
|
2017-06-13 22:12:08 +02:00
|
|
|
output.push(it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-29 20:03:16 +02:00
|
|
|
return Promise.resolve({
|
|
|
|
items: output,
|
|
|
|
hasMore: false,
|
|
|
|
context: null,
|
|
|
|
});
|
2017-06-13 22:12:08 +02:00
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
async get(path: string, options: any) {
|
2020-03-14 01:46:14 +02:00
|
|
|
const item = this.itemByPath(path);
|
2017-06-18 01:49:52 +02:00
|
|
|
if (!item) return Promise.resolve(null);
|
2019-09-19 23:51:18 +02:00
|
|
|
if (item.isDir) return Promise.reject(new Error(`${path} is a directory, not a file`));
|
2017-12-18 22:47:25 +02:00
|
|
|
|
|
|
|
let output = null;
|
|
|
|
if (options.target === 'file') {
|
|
|
|
await fs.writeFile(options.path, Buffer.from(item.content, 'base64'));
|
|
|
|
} else {
|
|
|
|
const content = this.decodeContent_(item.content);
|
|
|
|
output = Promise.resolve(content);
|
|
|
|
}
|
|
|
|
|
|
|
|
return output;
|
2017-06-13 22:12:08 +02:00
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
async mkdir(path: string) {
|
2020-03-14 01:46:14 +02:00
|
|
|
const index = this.itemIndexByPath(path);
|
2018-02-15 19:12:09 +02:00
|
|
|
if (index >= 0) return;
|
2017-06-13 22:12:08 +02:00
|
|
|
this.items_.push(this.newItem(path, true));
|
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
async put(path: string, content: any, options: any = null) {
|
2017-12-18 22:47:25 +02:00
|
|
|
if (!options) options = {};
|
|
|
|
|
|
|
|
if (options.source === 'file') content = await fs.readFile(options.path);
|
|
|
|
|
2020-03-14 01:46:14 +02:00
|
|
|
const index = this.itemIndexByPath(path);
|
2017-06-13 22:12:08 +02:00
|
|
|
if (index < 0) {
|
2020-03-14 01:46:14 +02:00
|
|
|
const item = this.newItem(path, false);
|
2017-12-18 22:47:25 +02:00
|
|
|
item.content = this.encodeContent_(content);
|
2017-06-13 22:12:08 +02:00
|
|
|
this.items_.push(item);
|
2021-06-18 18:17:25 +02:00
|
|
|
return item;
|
2017-06-13 22:12:08 +02:00
|
|
|
} else {
|
2017-12-18 22:47:25 +02:00
|
|
|
this.items_[index].content = this.encodeContent_(content);
|
2020-08-02 13:28:50 +02:00
|
|
|
this.items_[index].updated_time = time.unixMs();
|
2021-06-18 18:17:25 +02:00
|
|
|
return this.items_[index];
|
2017-06-13 22:12:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
public async multiPut(items: MultiPutItem[], options: any = null) {
|
|
|
|
const output: any = {
|
|
|
|
items: {},
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const item of items) {
|
|
|
|
try {
|
|
|
|
const processedItem = await this.put(`/root/${item.name}`, item.body, options);
|
|
|
|
output.items[item.name] = {
|
|
|
|
item: processedItem,
|
|
|
|
error: null,
|
|
|
|
};
|
|
|
|
} catch (error) {
|
|
|
|
output.items[item.name] = {
|
|
|
|
item: null,
|
|
|
|
error: error,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
|
|
|
async delete(path: string) {
|
2020-03-14 01:46:14 +02:00
|
|
|
const index = this.itemIndexByPath(path);
|
2017-06-13 22:12:08 +02:00
|
|
|
if (index >= 0) {
|
2020-03-14 01:46:14 +02:00
|
|
|
const item = Object.assign({}, this.items_[index]);
|
2017-07-18 22:03:07 +02:00
|
|
|
item.isDeleted = true;
|
|
|
|
item.updated_time = time.unixMs();
|
|
|
|
this.deletedItems_.push(item);
|
2017-06-13 22:12:08 +02:00
|
|
|
this.items_.splice(index, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
async move(oldPath: string, newPath: string): Promise<any> {
|
2020-03-14 01:46:14 +02:00
|
|
|
const sourceItem = this.itemByPath(oldPath);
|
2019-09-19 23:51:18 +02:00
|
|
|
if (!sourceItem) return Promise.reject(new Error(`Path not found: ${oldPath}`));
|
2021-06-18 18:17:25 +02:00
|
|
|
await this.delete(newPath); // Overwrite if newPath already exists
|
2017-06-13 22:12:08 +02:00
|
|
|
sourceItem.path = newPath;
|
|
|
|
}
|
|
|
|
|
2018-02-15 19:12:09 +02:00
|
|
|
async format() {
|
2017-06-13 22:58:17 +02:00
|
|
|
this.items_ = [];
|
|
|
|
}
|
|
|
|
|
2021-06-18 18:17:25 +02:00
|
|
|
async delta(path: string, options: any = null) {
|
|
|
|
const getStatFn = async (path: string) => {
|
2020-03-14 01:46:14 +02:00
|
|
|
const output = this.items_.slice();
|
2018-01-21 21:45:32 +02:00
|
|
|
for (let i = 0; i < output.length; i++) {
|
|
|
|
const item = Object.assign({}, output[i]);
|
2017-07-18 22:03:07 +02:00
|
|
|
item.path = item.path.substr(path.length + 1);
|
2018-01-21 21:45:32 +02:00
|
|
|
output[i] = item;
|
2017-07-18 22:03:07 +02:00
|
|
|
}
|
2018-01-21 21:45:32 +02:00
|
|
|
return output;
|
|
|
|
};
|
2017-07-18 22:03:07 +02:00
|
|
|
|
2018-01-21 21:45:32 +02:00
|
|
|
const output = await basicDelta(path, getStatFn, options);
|
2017-07-18 22:03:07 +02:00
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
2018-02-15 19:12:09 +02:00
|
|
|
async clearRoot() {
|
2018-01-25 23:15:58 +02:00
|
|
|
this.items_ = [];
|
|
|
|
}
|
2017-06-13 22:12:08 +02:00
|
|
|
}
|