mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-02-16 09:10:38 +00:00
Implemented:
- using Obsidian API to synchronize. - Copy button on history dialog. Documented: - Document improved.
This commit is contained in:
@@ -2,6 +2,8 @@ import { TFile, Modal, App } from "obsidian";
|
||||
import { path2id, escapeStringToHTML } from "./utils";
|
||||
import ObsidianLiveSyncPlugin from "./main";
|
||||
import { DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "diff-match-patch";
|
||||
import { LOG_LEVEL } from "./types";
|
||||
import { Logger } from "./logger";
|
||||
|
||||
export class DocumentHistoryModal extends Modal {
|
||||
plugin: ObsidianLiveSyncPlugin;
|
||||
@@ -14,6 +16,7 @@ export class DocumentHistoryModal extends Modal {
|
||||
file: string;
|
||||
|
||||
revs_info: PouchDB.Core.RevisionInfo[] = [];
|
||||
currentText = "";
|
||||
|
||||
constructor(app: App, plugin: ObsidianLiveSyncPlugin, file: TFile) {
|
||||
super(app);
|
||||
@@ -37,6 +40,7 @@ export class DocumentHistoryModal extends Modal {
|
||||
const index = this.revs_info.length - 1 - (this.range.value as any) / 1;
|
||||
const rev = this.revs_info[index];
|
||||
const w = await db.getDBEntry(path2id(this.file), { rev: rev.rev }, false, false);
|
||||
this.currentText = "";
|
||||
|
||||
if (w === false) {
|
||||
this.info.innerHTML = "";
|
||||
@@ -44,6 +48,7 @@ export class DocumentHistoryModal extends Modal {
|
||||
} else {
|
||||
this.info.innerHTML = `Modified:${new Date(w.mtime).toLocaleString()}`;
|
||||
let result = "";
|
||||
this.currentText = w.data;
|
||||
if (this.showDiff) {
|
||||
const prevRevIdx = this.revs_info.length - 1 - ((this.range.value as any) / 1 - 1);
|
||||
if (prevRevIdx >= 0 && prevRevIdx < this.revs_info.length) {
|
||||
@@ -124,6 +129,14 @@ export class DocumentHistoryModal extends Modal {
|
||||
this.contentView = div;
|
||||
div.addClass("op-scrollable");
|
||||
div.addClass("op-pre");
|
||||
const buttons = contentEl.createDiv("");
|
||||
buttons.createEl("button", { text: "Copy to clipboard" }, (e) => {
|
||||
e.addClass("mod-cta");
|
||||
e.addEventListener("click", async () => {
|
||||
await navigator.clipboard.writeText(this.currentText);
|
||||
Logger(`Old content copied to clipboard`, LOG_LEVEL.NOTICE);
|
||||
});
|
||||
});
|
||||
}
|
||||
onClose() {
|
||||
const { contentEl } = this;
|
||||
|
||||
@@ -743,7 +743,7 @@ export class LocalPouchDB {
|
||||
username: setting.couchDB_USER,
|
||||
password: setting.couchDB_PASSWORD,
|
||||
};
|
||||
const dbret = await connectRemoteCouchDB(uri, auth);
|
||||
const dbret = await connectRemoteCouchDB(uri, auth, setting.disableRequestURI);
|
||||
if (typeof dbret === "string") {
|
||||
Logger(`could not connect to ${uri}:${dbret}`, LOG_LEVEL.NOTICE);
|
||||
if (notice != null) notice.hide();
|
||||
@@ -820,7 +820,7 @@ export class LocalPouchDB {
|
||||
Logger("Another replication running.");
|
||||
return false;
|
||||
}
|
||||
const dbret = await connectRemoteCouchDB(uri, auth);
|
||||
const dbret = await connectRemoteCouchDB(uri, auth, setting.disableRequestURI);
|
||||
if (typeof dbret === "string") {
|
||||
Logger(`could not connect to ${uri}: ${dbret}`, LOG_LEVEL.NOTICE);
|
||||
return false;
|
||||
@@ -1081,7 +1081,7 @@ export class LocalPouchDB {
|
||||
username: setting.couchDB_USER,
|
||||
password: setting.couchDB_PASSWORD,
|
||||
};
|
||||
const con = await connectRemoteCouchDB(uri, auth);
|
||||
const con = await connectRemoteCouchDB(uri, auth, setting.disableRequestURI);
|
||||
if (typeof con == "string") return;
|
||||
try {
|
||||
await con.db.destroy();
|
||||
@@ -1099,7 +1099,7 @@ export class LocalPouchDB {
|
||||
username: setting.couchDB_USER,
|
||||
password: setting.couchDB_PASSWORD,
|
||||
};
|
||||
const con2 = await connectRemoteCouchDB(uri, auth);
|
||||
const con2 = await connectRemoteCouchDB(uri, auth, setting.disableRequestURI);
|
||||
if (typeof con2 === "string") return;
|
||||
Logger("Remote Database Created or Connected", LOG_LEVEL.NOTICE);
|
||||
}
|
||||
@@ -1109,7 +1109,7 @@ export class LocalPouchDB {
|
||||
username: setting.couchDB_USER,
|
||||
password: setting.couchDB_PASSWORD,
|
||||
};
|
||||
const dbret = await connectRemoteCouchDB(uri, auth);
|
||||
const dbret = await connectRemoteCouchDB(uri, auth, setting.disableRequestURI);
|
||||
if (typeof dbret === "string") {
|
||||
Logger(`could not connect to ${uri}:${dbret}`, LOG_LEVEL.NOTICE);
|
||||
return;
|
||||
@@ -1143,7 +1143,7 @@ export class LocalPouchDB {
|
||||
username: setting.couchDB_USER,
|
||||
password: setting.couchDB_PASSWORD,
|
||||
};
|
||||
const dbret = await connectRemoteCouchDB(uri, auth);
|
||||
const dbret = await connectRemoteCouchDB(uri, auth, setting.disableRequestURI);
|
||||
if (typeof dbret === "string") {
|
||||
Logger(`could not connect to ${uri}:${dbret}`, LOG_LEVEL.NOTICE);
|
||||
return;
|
||||
|
||||
@@ -14,10 +14,14 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
async testConnection(): Promise<void> {
|
||||
const db = await connectRemoteCouchDB(this.plugin.settings.couchDB_URI + (this.plugin.settings.couchDB_DBNAME == "" ? "" : "/" + this.plugin.settings.couchDB_DBNAME), {
|
||||
username: this.plugin.settings.couchDB_USER,
|
||||
password: this.plugin.settings.couchDB_PASSWORD,
|
||||
});
|
||||
const db = await connectRemoteCouchDB(
|
||||
this.plugin.settings.couchDB_URI + (this.plugin.settings.couchDB_DBNAME == "" ? "" : "/" + this.plugin.settings.couchDB_DBNAME),
|
||||
{
|
||||
username: this.plugin.settings.couchDB_USER,
|
||||
password: this.plugin.settings.couchDB_PASSWORD,
|
||||
},
|
||||
this.plugin.settings.disableRequestURI
|
||||
);
|
||||
if (typeof db === "string") {
|
||||
this.plugin.addLog(`could not connect to ${this.plugin.settings.couchDB_URI} : ${this.plugin.settings.couchDB_DBNAME} \n(${db})`, LOG_LEVEL.NOTICE);
|
||||
return;
|
||||
@@ -165,6 +169,12 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
this.plugin.settings.couchDB_DBNAME = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
),
|
||||
new Setting(containerRemoteDatabaseEl).setName("Use the old connecting method").addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.disableRequestURI).onChange(async (value) => {
|
||||
this.plugin.settings.disableRequestURI = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
@@ -603,7 +613,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
);
|
||||
|
||||
new Setting(containerMiscellaneousEl)
|
||||
.setName("Use history (beta)")
|
||||
.setName("Use history")
|
||||
.setDesc("Use history dialog (Restart required, auto compaction would be disabled, and more storage will be consumed)")
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.useHistory).onChange(async (value) => {
|
||||
@@ -832,12 +842,6 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
new Setting(containerPluginSettings).setName("Show own plugins and settings").addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.showOwnPlugins).onChange(async (value) => {
|
||||
this.plugin.settings.showOwnPlugins = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerPluginSettings)
|
||||
.setName("Sweep plugins automatically")
|
||||
|
||||
@@ -60,6 +60,7 @@ export interface ObsidianLiveSyncSettings {
|
||||
batch_size: number;
|
||||
batches_limit: number;
|
||||
useHistory: boolean;
|
||||
disableRequestURI: boolean;
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: ObsidianLiveSyncSettings = {
|
||||
@@ -101,6 +102,7 @@ export const DEFAULT_SETTINGS: ObsidianLiveSyncSettings = {
|
||||
batch_size: 250,
|
||||
batches_limit: 40,
|
||||
useHistory: false,
|
||||
disableRequestURI: false,
|
||||
};
|
||||
|
||||
export const PERIODIC_PLUGIN_SWEEP = 60;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Logger } from "./logger";
|
||||
import { LOG_LEVEL, VER, VERSIONINFO_DOCID, EntryVersionInfo, EntryDoc } from "./types";
|
||||
import { resolveWithIgnoreKnownError } from "./utils";
|
||||
import { PouchDB } from "../pouchdb-browser-webpack/dist/pouchdb-browser.js";
|
||||
import { requestUrl, RequestUrlParam } from "obsidian";
|
||||
|
||||
export const isValidRemoteCouchDBURI = (uri: string): boolean => {
|
||||
if (uri.startsWith("https://")) return true;
|
||||
@@ -12,8 +13,17 @@ let last_post_successed = false;
|
||||
export const getLastPostFailedBySize = () => {
|
||||
return !last_post_successed;
|
||||
};
|
||||
export const connectRemoteCouchDB = async (uri: string, auth: { username: string; password: string }): Promise<string | { db: PouchDB.Database<EntryDoc>; info: PouchDB.Core.DatabaseInfo }> => {
|
||||
|
||||
export const connectRemoteCouchDB = async (uri: string, auth: { username: string; password: string }, disableRequestURI: boolean): Promise<string | { db: PouchDB.Database<EntryDoc>; info: PouchDB.Core.DatabaseInfo }> => {
|
||||
if (!isValidRemoteCouchDBURI(uri)) return "Remote URI is not valid";
|
||||
let authHeader = "";
|
||||
if (auth.username && auth.password) {
|
||||
const utf8str = String.fromCharCode.apply(null, new TextEncoder().encode(`${auth.username}:${auth.password}`));
|
||||
const encoded = window.btoa(utf8str);
|
||||
authHeader = "Basic " + encoded;
|
||||
} else {
|
||||
authHeader = "";
|
||||
}
|
||||
const conf: PouchDB.HttpAdapter.HttpAdapterConfiguration = {
|
||||
adapter: "http",
|
||||
auth,
|
||||
@@ -35,6 +45,54 @@ export const connectRemoteCouchDB = async (uri: string, auth: { username: string
|
||||
}
|
||||
size = ` (${opts_length})`;
|
||||
}
|
||||
|
||||
if (!disableRequestURI && typeof url == "string" && typeof (opts.body ?? "") == "string") {
|
||||
const body = opts.body as string;
|
||||
|
||||
const transformedHeaders = { ...(opts.headers as Record<string, string>) };
|
||||
if (authHeader != "") transformedHeaders["authorization"] = authHeader;
|
||||
delete transformedHeaders["host"];
|
||||
delete transformedHeaders["Host"];
|
||||
delete transformedHeaders["content-length"];
|
||||
delete transformedHeaders["Content-Length"];
|
||||
const requestParam: RequestUrlParam = {
|
||||
url: url as string,
|
||||
method: opts.method,
|
||||
body: body,
|
||||
headers: transformedHeaders,
|
||||
contentType: "application/json",
|
||||
// contentType: opts.headers,
|
||||
};
|
||||
|
||||
try {
|
||||
const r = await requestUrl(requestParam);
|
||||
if (method == "POST" || method == "PUT") {
|
||||
last_post_successed = r.status - (r.status % 100) == 200;
|
||||
} else {
|
||||
last_post_successed = true;
|
||||
}
|
||||
if (r.status - (r.status % 100) !== 200) {
|
||||
throw new Error(`Request Error:${r.status}`);
|
||||
}
|
||||
Logger(`HTTP:${method}${size} to:${localURL} -> ${r.status}`, LOG_LEVEL.VERBOSE);
|
||||
|
||||
return new Response(r.arrayBuffer, {
|
||||
headers: r.headers,
|
||||
status: r.status,
|
||||
statusText: `${r.status}`,
|
||||
});
|
||||
} catch (ex) {
|
||||
Logger(`HTTP:${method}${size} to:${localURL} -> failed`, LOG_LEVEL.VERBOSE);
|
||||
if (!size_ok && (method == "POST" || method == "PUT")) {
|
||||
last_post_successed = false;
|
||||
}
|
||||
Logger(ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
// -old implementation
|
||||
|
||||
try {
|
||||
const responce: Response = await fetch(url, opts);
|
||||
if (method == "POST" || method == "PUT") {
|
||||
|
||||
Reference in New Issue
Block a user