mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-09-01 08:17:07 +00:00
Migrate LiveSync flows to provider-owned resources
This commit is contained in:
@@ -20,6 +20,8 @@
|
||||
import { copyTo, pickBucketSyncSettings } from "@vrtmrz/livesync-commonlib/compat/common/utils";
|
||||
import { TYPE_CANCELLED, type SetupRemoteBucketResultType } from "./setupDialogTypes";
|
||||
import { $msg as translateMessage } from "@/common/translation";
|
||||
import { withOwnedRemoteResource } from "@/common/ownedRemoteResource";
|
||||
import { REMOTE_RESOURCE_KINDS } from "@vrtmrz/livesync-commonlib/replication";
|
||||
|
||||
const default_setting = pickBucketSyncSettings(DEFAULT_SETTINGS);
|
||||
|
||||
@@ -81,13 +83,18 @@
|
||||
try {
|
||||
processing = true;
|
||||
const trialRemoteSetting = generateSetting();
|
||||
const replicator = await context.services.replicator.getNewReplicator(trialRemoteSetting);
|
||||
if (!replicator) {
|
||||
return translateMessage("Failed to create replicator instance.");
|
||||
const probe = await context.services.replicator.createRemoteResource(
|
||||
REMOTE_RESOURCE_KINDS.CONNECTION,
|
||||
trialRemoteSetting
|
||||
);
|
||||
if (!probe) {
|
||||
return translateMessage("Failed to connect to the server. Please check your settings.");
|
||||
}
|
||||
try {
|
||||
const result = await replicator.tryConnectRemote(trialRemoteSetting, false);
|
||||
if (result) {
|
||||
const result = await withOwnedRemoteResource(probe, (ownedProbe) =>
|
||||
ownedProbe.check({ createIfMissing: true, showResult: false })
|
||||
);
|
||||
if (result.ok) {
|
||||
return "";
|
||||
} else {
|
||||
return translateMessage("Failed to connect to the server. Please check your settings.");
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
} from "./setupDialogTypes";
|
||||
import { isValidCouchDBServerURL, probeCouchDBConnection } from "./couchDBConnectionProbe";
|
||||
import { $msg as translateMessage } from "@/common/translation";
|
||||
import { REMOTE_RESOURCE_KINDS } from "@vrtmrz/livesync-commonlib/replication";
|
||||
|
||||
const default_setting = pickCouchDBSyncSettings(DEFAULT_SETTINGS);
|
||||
|
||||
@@ -73,16 +74,15 @@
|
||||
try {
|
||||
processing = true;
|
||||
const trialRemoteSetting = generateSetting();
|
||||
const replicator = await context.services.replicator.getNewReplicator(trialRemoteSetting);
|
||||
if (!replicator) {
|
||||
return translateMessage("Failed to create replicator instance.");
|
||||
const probe = await context.services.replicator.createRemoteResource(
|
||||
REMOTE_RESOURCE_KINDS.CONNECTION,
|
||||
trialRemoteSetting
|
||||
);
|
||||
if (!probe) {
|
||||
return translateMessage("Failed to connect to the server. Please check your settings.");
|
||||
}
|
||||
try {
|
||||
const result = await probeCouchDBConnection(
|
||||
replicator,
|
||||
trialRemoteSetting,
|
||||
setupMode === "create-or-connect"
|
||||
);
|
||||
const result = await probeCouchDBConnection(probe, setupMode === "create-or-connect");
|
||||
if (result.ok) {
|
||||
return "";
|
||||
} else {
|
||||
|
||||
@@ -1,60 +1,14 @@
|
||||
import type {
|
||||
ObsidianLiveSyncSettings,
|
||||
RemoteDBSettings,
|
||||
} from "@vrtmrz/livesync-commonlib/compat/common/models/setting.type";
|
||||
|
||||
export type CouchDBConnectionProbeResult = { ok: true } | { ok: false; reason: string };
|
||||
|
||||
type CouchDBConnectionResult =
|
||||
| string
|
||||
| {
|
||||
db: { close(): Promise<void> };
|
||||
info: unknown;
|
||||
};
|
||||
|
||||
export interface CouchDBConnectionProbe {
|
||||
isMobile(): boolean;
|
||||
connectRemoteCouchDBWithSetting(
|
||||
settings: RemoteDBSettings,
|
||||
isMobile: boolean,
|
||||
performSetup: boolean,
|
||||
skipInfo: boolean
|
||||
): CouchDBConnectionResult | Promise<CouchDBConnectionResult>;
|
||||
}
|
||||
|
||||
export function isCouchDBConnectionProbe(value: unknown): value is CouchDBConnectionProbe {
|
||||
return (
|
||||
typeof value === "object" &&
|
||||
value !== null &&
|
||||
"isMobile" in value &&
|
||||
typeof value.isMobile === "function" &&
|
||||
"connectRemoteCouchDBWithSetting" in value &&
|
||||
typeof value.connectRemoteCouchDBWithSetting === "function"
|
||||
);
|
||||
}
|
||||
import type { RemoteConnectionProbe, RemoteConnectionProbeResult } from "@vrtmrz/livesync-commonlib/replication";
|
||||
import { withOwnedRemoteResource } from "@/common/ownedRemoteResource";
|
||||
|
||||
/** Run the selected CouchDB setup mode within one owned probe lifetime. */
|
||||
export async function probeCouchDBConnection(
|
||||
replicator: unknown,
|
||||
settings: ObsidianLiveSyncSettings,
|
||||
probe: RemoteConnectionProbe,
|
||||
createIfMissing: boolean
|
||||
): Promise<CouchDBConnectionProbeResult> {
|
||||
if (!isCouchDBConnectionProbe(replicator)) {
|
||||
return { ok: false, reason: "The CouchDB connection probe is unavailable." };
|
||||
}
|
||||
const result = await replicator.connectRemoteCouchDBWithSetting(
|
||||
settings,
|
||||
replicator.isMobile(),
|
||||
createIfMissing,
|
||||
false
|
||||
): Promise<RemoteConnectionProbeResult> {
|
||||
return await withOwnedRemoteResource(probe, (ownedProbe) =>
|
||||
ownedProbe.check({ createIfMissing, showResult: false })
|
||||
);
|
||||
if (typeof result === "string") {
|
||||
return { ok: false, reason: result };
|
||||
}
|
||||
try {
|
||||
return { ok: true };
|
||||
} finally {
|
||||
await result.db.close();
|
||||
}
|
||||
}
|
||||
|
||||
export function isValidCouchDBServerURL(value: string): boolean {
|
||||
|
||||
@@ -1,47 +1,34 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { ObsidianLiveSyncSettings } from "@vrtmrz/livesync-commonlib/compat/common/models/setting.type";
|
||||
import { isValidCouchDBServerURL, probeCouchDBConnection } from "./couchDBConnectionProbe";
|
||||
|
||||
const settings = {
|
||||
couchDB_URI: "https://couch.example",
|
||||
couchDB_DBNAME: "notes",
|
||||
} as ObsidianLiveSyncSettings;
|
||||
|
||||
describe("CouchDB setup connection policy", () => {
|
||||
it.each([
|
||||
[false, "connect to an existing database"],
|
||||
[true, "create or connect to a database"],
|
||||
] as const)(
|
||||
"%s can %s without changing the Commonlib connection contract",
|
||||
async (createIfMissing, _description) => {
|
||||
const close = vi.fn(async () => undefined);
|
||||
const connectRemoteCouchDBWithSetting = vi.fn(async () => ({
|
||||
db: { close },
|
||||
info: { db_name: "notes" },
|
||||
}));
|
||||
const replicator = {
|
||||
isMobile: vi.fn(() => false),
|
||||
connectRemoteCouchDBWithSetting,
|
||||
tryConnectRemote: vi.fn(),
|
||||
};
|
||||
] as const)("%s can %s through an owned connection probe", async (createIfMissing, _description) => {
|
||||
const check = vi.fn(async () => ({ ok: true as const }));
|
||||
const dispose = vi.fn(async () => undefined);
|
||||
const probe = { check, getStatus: vi.fn(), dispose };
|
||||
|
||||
await expect(probeCouchDBConnection(replicator, settings, createIfMissing)).resolves.toEqual({ ok: true });
|
||||
expect(connectRemoteCouchDBWithSetting).toHaveBeenCalledWith(settings, false, createIfMissing, false);
|
||||
expect(replicator.tryConnectRemote).not.toHaveBeenCalled();
|
||||
expect(close).toHaveBeenCalledOnce();
|
||||
}
|
||||
);
|
||||
await expect(probeCouchDBConnection(probe, createIfMissing)).resolves.toEqual({ ok: true });
|
||||
|
||||
it("returns the connection error without saving or creating through another path", async () => {
|
||||
const replicator = {
|
||||
isMobile: vi.fn(() => true),
|
||||
connectRemoteCouchDBWithSetting: vi.fn(() => "database does not exist"),
|
||||
expect(check).toHaveBeenCalledWith({ createIfMissing, showResult: false });
|
||||
expect(dispose).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("returns a connection error and still disposes the probe", async () => {
|
||||
const dispose = vi.fn(async () => undefined);
|
||||
const probe = {
|
||||
check: vi.fn(async () => ({ ok: false as const, reason: "database does not exist" })),
|
||||
getStatus: vi.fn(),
|
||||
dispose,
|
||||
};
|
||||
|
||||
await expect(probeCouchDBConnection(replicator, settings, false)).resolves.toEqual({
|
||||
await expect(probeCouchDBConnection(probe, false)).resolves.toEqual({
|
||||
ok: false,
|
||||
reason: "database does not exist",
|
||||
});
|
||||
expect(dispose).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it.each([
|
||||
|
||||
Reference in New Issue
Block a user