Files
obsidian-livesync/src/serviceFeatures/fileRepairPresentation.ts
T

145 lines
4.7 KiB
TypeScript

import {
BASE_IS_NEW,
EVEN,
TARGET_IS_NEW,
} from "@vrtmrz/livesync-commonlib/compat/common/models/shared.const.symbols";
import {
compareMTime,
readAsBlob,
} from "@vrtmrz/livesync-commonlib/compat/common/utils";
import { isPlainText } from "@vrtmrz/livesync-commonlib/compat/string_and_binary/path";
import type {
FileRepairInspection,
FileRepairRevision,
} from "./fileRepair";
export type FileRepairRevisionActions = {
compareWithVault: boolean;
applyRevisionToVault: boolean;
markAsVaultRevision: boolean;
storeVaultOnBranch: boolean;
applyLogicalDeletionToVault: boolean;
retryRevision: boolean;
discardBranch: boolean;
discardRevision: boolean;
};
export type FileRepairTimestampRelation =
| "vault-newer"
| "database-newer"
| "same-window"
| "unavailable";
export type FileRepairRevisionComparison = {
recordedSize: number;
decodedSize: number | null;
recordedToDecodedSizeDifference: number | null;
vaultSize: number | null;
databaseToVaultSizeDifference: number | null;
databaseMtime: number;
vaultMtime: number | null;
timestampDifferenceMs: number | null;
timestampRelation: FileRepairTimestampRelation;
};
export function getFileRepairRevisionActions(
inspection: FileRepairInspection,
revision: FileRepairRevision
): FileRepairRevisionActions {
const storageExists = inspection.information.storage.exists;
const hasRevision = revision.metadata.revision !== null;
const readableFileRevision =
!revision.metadata.deleted &&
revision.contentReadable &&
revision.loadedEntry !== false;
const matchesVault = storageExists && revision.contentMatchesStorage === true;
const hasConflictBranches = inspection.information.database.conflictCount > 0;
return {
compareWithVault:
readableFileRevision &&
storageExists &&
revision.contentMatchesStorage === false &&
isPlainText(inspection.information.path),
applyRevisionToVault:
hasRevision &&
readableFileRevision &&
(!storageExists || revision.contentMatchesStorage !== true),
markAsVaultRevision:
hasRevision &&
readableFileRevision &&
matchesVault,
storeVaultOnBranch:
hasRevision &&
storageExists &&
revision.contentMatchesStorage !== true,
applyLogicalDeletionToVault:
hasRevision &&
revision.metadata.deleted &&
storageExists,
retryRevision:
hasRevision &&
!revision.metadata.deleted &&
!revision.contentReadable,
discardBranch: hasRevision && hasConflictBranches,
discardRevision:
hasRevision &&
!hasConflictBranches &&
!revision.metadata.deleted &&
!revision.contentReadable,
};
}
export function getFileRepairRevisionComparison(
inspection: FileRepairInspection,
revision: FileRepairRevision
): FileRepairRevisionComparison {
const decodedSize =
revision.loadedEntry === false
? null
: readAsBlob(revision.loadedEntry).size;
const vaultSize =
inspection.information.storage.exists
? (inspection.information.storage.size ?? null)
: null;
const databaseMtime = revision.metadata.mtime;
const vaultMtime =
inspection.information.storage.exists
? (inspection.information.storage.mtime ?? null)
: null;
const timestampDifferenceMs =
databaseMtime > 0 && vaultMtime !== null && vaultMtime > 0
? vaultMtime - databaseMtime
: null;
let timestampRelation: FileRepairTimestampRelation = "unavailable";
if (timestampDifferenceMs !== null) {
const comparison = compareMTime(vaultMtime!, databaseMtime);
timestampRelation =
comparison === EVEN
? "same-window"
: comparison === BASE_IS_NEW
? "vault-newer"
: comparison === TARGET_IS_NEW
? "database-newer"
: "unavailable";
}
return {
recordedSize: revision.metadata.recordedSize,
decodedSize,
recordedToDecodedSizeDifference:
decodedSize === null
? null
: decodedSize - revision.metadata.recordedSize,
vaultSize,
databaseToVaultSizeDifference:
decodedSize === null || vaultSize === null
? null
: vaultSize - decodedSize,
databaseMtime,
vaultMtime,
timestampDifferenceMs,
timestampRelation,
};
}