track local history
This commit is contained in:
parent
9ea3bdca7e
commit
c75962aad5
@ -30,6 +30,7 @@
|
|||||||
"@types/mime-types": "^2.1.1",
|
"@types/mime-types": "^2.1.1",
|
||||||
"aws-crt": "^1.10.1",
|
"aws-crt": "^1.10.1",
|
||||||
"codemirror": "^5.63.1",
|
"codemirror": "^5.63.1",
|
||||||
|
"lovefield-ts": "^0.7.0",
|
||||||
"mime-types": "^2.1.33",
|
"mime-types": "^2.1.33",
|
||||||
"obsidian": "^0.12.0",
|
"obsidian": "^0.12.0",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
|
|||||||
53
src/localdb.ts
Normal file
53
src/localdb.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import * as lf from "lovefield-ts/dist/es6/lf.js";
|
||||||
|
|
||||||
|
export type DatabaseConnection = lf.DatabaseConnection;
|
||||||
|
|
||||||
|
export const DEFAULT_DB_NAME = "saveremotedb";
|
||||||
|
export const DEFAULT_TBL_DELETE_HISTORY = "filefolderoperationhistory";
|
||||||
|
|
||||||
|
export interface FileFolderHistoryRecord {
|
||||||
|
key: string;
|
||||||
|
ctime: number;
|
||||||
|
mtime: number;
|
||||||
|
size: number;
|
||||||
|
action_when: number;
|
||||||
|
action_type: "delete" | "rename";
|
||||||
|
key_type: "folder" | "file";
|
||||||
|
rename_to: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function prepareDB() {
|
||||||
|
const schemaBuilder = lf.schema.create(DEFAULT_DB_NAME, 1);
|
||||||
|
schemaBuilder
|
||||||
|
.createTable(DEFAULT_TBL_DELETE_HISTORY)
|
||||||
|
.addColumn("id", lf.Type.INTEGER)
|
||||||
|
.addColumn("key", lf.Type.STRING)
|
||||||
|
.addColumn("ctime", lf.Type.INTEGER)
|
||||||
|
.addColumn("mtime", lf.Type.INTEGER)
|
||||||
|
.addColumn("size", lf.Type.INTEGER)
|
||||||
|
.addColumn("action_when", lf.Type.INTEGER)
|
||||||
|
.addColumn("action_type", lf.Type.STRING)
|
||||||
|
.addColumn("key_type", lf.Type.STRING)
|
||||||
|
.addPrimaryKey(["id"], true)
|
||||||
|
.addIndex("idxKey", ["key"]);
|
||||||
|
const db = await schemaBuilder.connect({
|
||||||
|
storeType: lf.DataStoreType.INDEXED_DB,
|
||||||
|
});
|
||||||
|
console.log("db connected");
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function destroyDB(db: lf.DatabaseConnection) {
|
||||||
|
db.close();
|
||||||
|
const req = indexedDB.deleteDatabase(DEFAULT_DB_NAME);
|
||||||
|
req.onsuccess = (event) => {
|
||||||
|
console.log("db deleted");
|
||||||
|
};
|
||||||
|
req.onblocked = (event) => {
|
||||||
|
console.warn("trying to delete db but it was blocked");
|
||||||
|
};
|
||||||
|
req.onerror = (event) => {
|
||||||
|
console.error("tried to delete db but something bad!");
|
||||||
|
console.error(event);
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -12,12 +12,21 @@ import {
|
|||||||
Setting,
|
Setting,
|
||||||
request,
|
request,
|
||||||
Platform,
|
Platform,
|
||||||
|
TFile,
|
||||||
|
TFolder,
|
||||||
} from "obsidian";
|
} from "obsidian";
|
||||||
import * as CodeMirror from "codemirror";
|
import * as CodeMirror from "codemirror";
|
||||||
|
import type { FileFolderHistoryRecord, DatabaseConnection } from "./localdb";
|
||||||
|
import {
|
||||||
|
prepareDB,
|
||||||
|
destroyDB,
|
||||||
|
DEFAULT_DB_NAME,
|
||||||
|
DEFAULT_TBL_DELETE_HISTORY,
|
||||||
|
} from "./localdb";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
S3Client,
|
S3Client,
|
||||||
ListObjectsCommand,
|
ListObjectsV2Command,
|
||||||
PutObjectCommand,
|
PutObjectCommand,
|
||||||
GetObjectCommand,
|
GetObjectCommand,
|
||||||
} from "@aws-sdk/client-s3";
|
} from "@aws-sdk/client-s3";
|
||||||
@ -103,12 +112,96 @@ const getObjectBodyToArrayBuffer = async (
|
|||||||
export default class SaveRemotePlugin extends Plugin {
|
export default class SaveRemotePlugin extends Plugin {
|
||||||
settings: SaveRemotePluginSettings;
|
settings: SaveRemotePluginSettings;
|
||||||
cm: CodeMirror.Editor;
|
cm: CodeMirror.Editor;
|
||||||
|
db: DatabaseConnection;
|
||||||
|
|
||||||
async onload() {
|
async onload() {
|
||||||
console.log("loading plugin obsidian-save-remote");
|
console.log("loading plugin obsidian-save-remote");
|
||||||
|
|
||||||
await this.loadSettings();
|
await this.loadSettings();
|
||||||
|
|
||||||
|
await this.prepareDB();
|
||||||
|
|
||||||
|
this.registerEvent(
|
||||||
|
this.app.vault.on("delete", async (fileOrFolder) => {
|
||||||
|
const schema = this.db.getSchema().table(DEFAULT_TBL_DELETE_HISTORY);
|
||||||
|
const tbl = this.db.getSchema().table(DEFAULT_TBL_DELETE_HISTORY);
|
||||||
|
// console.log(fileOrFolder);
|
||||||
|
let k: FileFolderHistoryRecord;
|
||||||
|
if (fileOrFolder instanceof TFile) {
|
||||||
|
k = {
|
||||||
|
key: fileOrFolder.path,
|
||||||
|
ctime: fileOrFolder.stat.ctime,
|
||||||
|
mtime: fileOrFolder.stat.mtime,
|
||||||
|
size: fileOrFolder.stat.size,
|
||||||
|
action_when: Date.now(),
|
||||||
|
action_type: "delete",
|
||||||
|
key_type: "file",
|
||||||
|
rename_to: "",
|
||||||
|
};
|
||||||
|
} else if (fileOrFolder instanceof TFolder) {
|
||||||
|
k = {
|
||||||
|
key: fileOrFolder.path,
|
||||||
|
ctime: 0,
|
||||||
|
mtime: 0,
|
||||||
|
size: 0,
|
||||||
|
action_when: Date.now(),
|
||||||
|
action_type: "delete",
|
||||||
|
key_type: "folder",
|
||||||
|
rename_to: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const row = tbl.createRow(k);
|
||||||
|
await this.db.insertOrReplace().into(tbl).values([row]).exec();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
this.registerEvent(
|
||||||
|
this.app.vault.on("rename", async (fileOrFolder, oldPath) => {
|
||||||
|
const schema = this.db.getSchema().table(DEFAULT_TBL_DELETE_HISTORY);
|
||||||
|
const tbl = this.db.getSchema().table(DEFAULT_TBL_DELETE_HISTORY);
|
||||||
|
// console.log(fileOrFolder);
|
||||||
|
let k: FileFolderHistoryRecord;
|
||||||
|
if (fileOrFolder instanceof TFile) {
|
||||||
|
k = {
|
||||||
|
key: oldPath,
|
||||||
|
ctime: fileOrFolder.stat.ctime,
|
||||||
|
mtime: fileOrFolder.stat.mtime,
|
||||||
|
size: fileOrFolder.stat.size,
|
||||||
|
action_when: Date.now(),
|
||||||
|
action_type: "rename",
|
||||||
|
key_type: "file",
|
||||||
|
rename_to: fileOrFolder.path,
|
||||||
|
};
|
||||||
|
} else if (fileOrFolder instanceof TFolder) {
|
||||||
|
k = {
|
||||||
|
key: oldPath,
|
||||||
|
ctime: 0,
|
||||||
|
mtime: 0,
|
||||||
|
size: 0,
|
||||||
|
action_when: Date.now(),
|
||||||
|
action_type: "rename",
|
||||||
|
key_type: "folder",
|
||||||
|
rename_to: fileOrFolder.path,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const row = tbl.createRow(k);
|
||||||
|
await this.db.insertOrReplace().into(tbl).values([row]).exec();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addRibbonIcon("dice", "Misc", async () => {
|
||||||
|
const a = this.app.vault.getAllLoadedFiles();
|
||||||
|
console.log(a);
|
||||||
|
|
||||||
|
const schema = this.db.getSchema().table(DEFAULT_TBL_DELETE_HISTORY);
|
||||||
|
|
||||||
|
const h = await this.db.select().from(schema).exec();
|
||||||
|
|
||||||
|
console.log(h);
|
||||||
|
|
||||||
|
// console.log(b)
|
||||||
|
});
|
||||||
|
|
||||||
this.addRibbonIcon("right-arrow-with-tail", "Upload", async () => {
|
this.addRibbonIcon("right-arrow-with-tail", "Upload", async () => {
|
||||||
// console.log(this.app.vault.getFiles());
|
// console.log(this.app.vault.getFiles());
|
||||||
// console.log(this.app.vault.getAllLoadedFiles());
|
// console.log(this.app.vault.getAllLoadedFiles());
|
||||||
@ -183,10 +276,15 @@ export default class SaveRemotePlugin extends Plugin {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const listObj = await s3Client.send(
|
const listObj = await s3Client.send(
|
||||||
new ListObjectsCommand({ Bucket: this.settings.s3BucketName })
|
new ListObjectsV2Command({ Bucket: this.settings.s3BucketName })
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const singleContent of listObj.Contents) {
|
for (const singleContent of listObj.Contents) {
|
||||||
|
const mtimeSec = Math.round(
|
||||||
|
singleContent.LastModified.valueOf() / 1000.0
|
||||||
|
);
|
||||||
|
console.log(`key ${singleContent.Key} mtime ${mtimeSec}`);
|
||||||
|
|
||||||
const foldersToBuild = getFolderLevels(singleContent.Key);
|
const foldersToBuild = getFolderLevels(singleContent.Key);
|
||||||
for (const folder of foldersToBuild) {
|
for (const folder of foldersToBuild) {
|
||||||
const r = await this.app.vault.adapter.exists(folder);
|
const r = await this.app.vault.adapter.exists(folder);
|
||||||
@ -246,6 +344,7 @@ export default class SaveRemotePlugin extends Plugin {
|
|||||||
|
|
||||||
onunload() {
|
onunload() {
|
||||||
console.log("unloading plugin obsidian-save-remote");
|
console.log("unloading plugin obsidian-save-remote");
|
||||||
|
this.destroyDB();
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadSettings() {
|
async loadSettings() {
|
||||||
@ -255,6 +354,14 @@ export default class SaveRemotePlugin extends Plugin {
|
|||||||
async saveSettings() {
|
async saveSettings() {
|
||||||
await this.saveData(this.settings);
|
await this.saveData(this.settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async prepareDB() {
|
||||||
|
this.db = await prepareDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyDB() {
|
||||||
|
destroyDB(this.db);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SaveRemoteSettingTab extends PluginSettingTab {
|
class SaveRemoteSettingTab extends PluginSettingTab {
|
||||||
@ -2,7 +2,7 @@ const path = require("path");
|
|||||||
const TerserPlugin = require("terser-webpack-plugin");
|
const TerserPlugin = require("terser-webpack-plugin");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: "./main.ts",
|
entry: "./src/main.ts",
|
||||||
target: "web",
|
target: "web",
|
||||||
output: {
|
output: {
|
||||||
filename: "main.js",
|
filename: "main.js",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user