Merge branch 'restructure-codebase' into watch
This commit is contained in:
commit
101a7f6b65
|
@ -1,11 +1,9 @@
|
|||
import { ipcRenderer } from 'electron/renderer';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import path from 'path';
|
||||
import { readFile, writeFile, existsSync, mkdir, rmSync } from 'promise-fs';
|
||||
import crypto from 'crypto';
|
||||
import DiskLRUService from '../utils/diskLRU';
|
||||
import { existsSync, mkdir, rmSync } from 'promise-fs';
|
||||
import { DiskCache } from '../services/diskCache';
|
||||
|
||||
const CACHE_DIR = 'ente';
|
||||
const MAX_CACHE_SIZE = 1000 * 1000 * 1000; // 1GB
|
||||
|
||||
const getCacheDir = async () => {
|
||||
const systemCacheDir = await ipcRenderer.invoke('get-path', 'cache');
|
||||
|
@ -35,38 +33,3 @@ export async function deleteDiskCache(cacheName: string) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class DiskCache {
|
||||
constructor(private cacheBucketDir: string) {}
|
||||
|
||||
async put(cacheKey: string, response: Response): Promise<void> {
|
||||
const cachePath = getAssetCachePath(this.cacheBucketDir, cacheKey);
|
||||
await writeFile(
|
||||
cachePath,
|
||||
new Uint8Array(await response.arrayBuffer())
|
||||
);
|
||||
DiskLRUService.enforceCacheSizeLimit(
|
||||
this.cacheBucketDir,
|
||||
MAX_CACHE_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
async match(cacheKey: string): Promise<Response> {
|
||||
const cachePath = getAssetCachePath(this.cacheBucketDir, cacheKey);
|
||||
if (existsSync(cachePath)) {
|
||||
DiskLRUService.touch(cachePath);
|
||||
return new Response(await readFile(cachePath));
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getAssetCachePath(cacheDir: string, cacheKey: string) {
|
||||
// hashing the key to prevent illegal filenames
|
||||
const cacheKeyHash = crypto
|
||||
.createHash('sha256')
|
||||
.update(cacheKey)
|
||||
.digest('hex');
|
||||
return path.join(cacheDir, cacheKeyHash);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
import { ipcRenderer } from 'electron/renderer';
|
||||
import { logError } from '../utils/logging';
|
||||
import {
|
||||
keysStore,
|
||||
uploadStatusStore,
|
||||
watchStore,
|
||||
safeStorageStore,
|
||||
} from '../services/store';
|
||||
|
||||
export const selectRootDirectory = async () => {
|
||||
try {
|
||||
|
@ -14,14 +8,3 @@ export const selectRootDirectory = async () => {
|
|||
logError(e, 'error while selecting root directory');
|
||||
}
|
||||
};
|
||||
|
||||
export const clearElectronStore = () => {
|
||||
try {
|
||||
watchStore.clear();
|
||||
uploadStatusStore.clear();
|
||||
keysStore.clear();
|
||||
safeStorageStore.clear();
|
||||
} catch (e) {
|
||||
logError(e, 'error while clearing electron store');
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import {
|
||||
uploadStatusStore,
|
||||
keysStore,
|
||||
safeStorageStore,
|
||||
} from '../services/store';
|
||||
|
||||
import { logError } from './logging';
|
||||
import { keysStore } from '../stores/keys.store';
|
||||
import { safeStorageStore } from '../stores/safeStorage.store';
|
||||
import { uploadStatusStore } from '../stores/upload.store';
|
||||
import { logError } from '../utils/logging';
|
||||
|
||||
export const clearElectronStore = () => {
|
||||
try {
|
|
@ -1,4 +1,3 @@
|
|||
import {} from './common';
|
||||
import {
|
||||
createDirectory,
|
||||
doesPathExists,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { ipcRenderer } from 'electron';
|
||||
import { safeStorageStore } from '../services/store';
|
||||
import { safeStorageStore } from '../stores/safeStorage.store';
|
||||
import { logError } from '../utils/logging';
|
||||
|
||||
export async function setEncryptionKey(encryptionKey: string) {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { getZipFileStream } from './../services/fs';
|
|||
import { getElectronFile, getValidPaths } from './../services/fs';
|
||||
import path from 'path';
|
||||
import StreamZip from 'node-stream-zip';
|
||||
import { uploadStatusStore } from '../services/store';
|
||||
import { uploadStatusStore } from '../stores/upload.store';
|
||||
import { ElectronFile, FILE_PATH_KEYS, FILE_PATH_TYPE } from '../types';
|
||||
import { logError } from '../utils/logging';
|
||||
import { ipcRenderer } from 'electron';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import path from 'path';
|
||||
import { watchStore } from '../services/store';
|
||||
import { watchStore } from '../stores/watch.store';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { ElectronFile, WatchStoreType } from '../types';
|
||||
import { getElectronFile, getFilesFromDir } from '../services/fs';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { app, BrowserWindow } from 'electron';
|
||||
import { createWindow } from './utils/createWindow';
|
||||
import setupIpcComs from './utils/ipcComms';
|
||||
import initSentry from './utils/sentry';
|
||||
import { initSentry } from './services/sentry';
|
||||
import electronReload from 'electron-reload';
|
||||
import { PROD_HOST_URL, RENDERER_OUTPUT_DIR } from './config';
|
||||
import { isDev } from './utils/common';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { fixHotReloadNext12 } from './utils/next-serve';
|
||||
import { reloadWindow, sendNotification, showOnTray } from './api/system';
|
||||
import {
|
||||
showUploadDirsDialog,
|
||||
showUploadFilesDialog,
|
||||
|
@ -16,6 +16,9 @@ import {
|
|||
addWatchMapping,
|
||||
removeWatchMapping,
|
||||
} from './api/watch';
|
||||
import { getEncryptionKey, setEncryptionKey } from './api/safeStorage';
|
||||
import { clearElectronStore } from './api/electronStore';
|
||||
import { openDiskCache, deleteDiskCache } from './api/cache';
|
||||
import {
|
||||
checkExistsAndCreateCollectionDir,
|
||||
checkExistsAndRename,
|
||||
|
@ -29,15 +32,14 @@ import {
|
|||
setExportRecord,
|
||||
exists,
|
||||
} from './api/export';
|
||||
import { selectRootDirectory, clearElectronStore } from './api/common';
|
||||
import { selectRootDirectory } from './api/common';
|
||||
import { getElectronFile, doesFolderExists } from './services/fs';
|
||||
import { getEncryptionKey, setEncryptionKey } from './api/safeStorage';
|
||||
import { openDiskCache, deleteDiskCache } from './api/cache';
|
||||
import { sendNotification, showOnTray, reloadWindow } from './api/system';
|
||||
import { fixHotReloadNext12 } from './utils/preload';
|
||||
|
||||
fixHotReloadNext12();
|
||||
|
||||
const windowObject: any = window;
|
||||
|
||||
windowObject['ElectronAPIs'] = {
|
||||
exists,
|
||||
checkExistsAndCreateCollectionDir,
|
||||
|
|
|
@ -2,7 +2,7 @@ import { BrowserWindow, dialog, Tray } from 'electron';
|
|||
import { autoUpdater } from 'electron-updater';
|
||||
import log from 'electron-log';
|
||||
import { setIsAppQuitting, setIsUpdateAvailable } from '../main';
|
||||
import { buildContextMenu } from './menu';
|
||||
import { buildContextMenu } from '../utils/menu';
|
||||
|
||||
class AppUpdater {
|
||||
constructor() {
|
40
src/services/diskCache.ts
Normal file
40
src/services/diskCache.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import DiskLRUService from '../services/diskLRU';
|
||||
import crypto from 'crypto';
|
||||
import { existsSync, readFile, writeFile } from 'promise-fs';
|
||||
import path from 'path';
|
||||
|
||||
const MAX_CACHE_SIZE = 1000 * 1000 * 1000; // 1GB
|
||||
|
||||
export class DiskCache {
|
||||
constructor(private cacheBucketDir: string) {}
|
||||
|
||||
async put(cacheKey: string, response: Response): Promise<void> {
|
||||
const cachePath = getAssetCachePath(this.cacheBucketDir, cacheKey);
|
||||
await writeFile(
|
||||
cachePath,
|
||||
new Uint8Array(await response.arrayBuffer())
|
||||
);
|
||||
DiskLRUService.enforceCacheSizeLimit(
|
||||
this.cacheBucketDir,
|
||||
MAX_CACHE_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
async match(cacheKey: string): Promise<Response> {
|
||||
const cachePath = getAssetCachePath(this.cacheBucketDir, cacheKey);
|
||||
if (existsSync(cachePath)) {
|
||||
DiskLRUService.touch(cachePath);
|
||||
return new Response(await readFile(cachePath));
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
function getAssetCachePath(cacheDir: string, cacheKey: string) {
|
||||
// hashing the key to prevent illegal filenames
|
||||
const cacheKeyHash = crypto
|
||||
.createHash('sha256')
|
||||
.update(cacheKey)
|
||||
.digest('hex');
|
||||
return path.join(cacheDir, cacheKeyHash);
|
||||
}
|
|
@ -2,7 +2,7 @@ import path from 'path';
|
|||
import { readdir, stat, unlink } from 'promise-fs';
|
||||
import getFolderSize from 'get-folder-size';
|
||||
import { utimes, close, open } from 'promise-fs';
|
||||
import { logError } from './logging';
|
||||
import { logError } from '../utils/logging';
|
||||
|
||||
export interface LeastRecentlyUsedResult {
|
||||
atime: Date;
|
|
@ -1,14 +1,14 @@
|
|||
import * as Sentry from '@sentry/electron/dist/main';
|
||||
import { keysStore } from '../stores/keys.store';
|
||||
|
||||
import { keysStore } from '../services/store';
|
||||
import { isDev } from './common';
|
||||
import { isDev } from '../utils/common';
|
||||
|
||||
const SENTRY_DSN = 'https://e9268b784d1042a7a116f53c58ad2165@sentry.ente.io/5';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const version = require('../../package.json').version;
|
||||
|
||||
function initSentry(): void {
|
||||
export function initSentry(): void {
|
||||
Sentry.init({
|
||||
dsn: SENTRY_DSN,
|
||||
release: version,
|
||||
|
@ -46,6 +46,15 @@ function errorWithContext(originalError: Error, context: string) {
|
|||
return errorWithContext;
|
||||
}
|
||||
|
||||
function getUserAnonymizedID() {
|
||||
let anonymizeUserID = keysStore.get('AnonymizeUserID')?.id;
|
||||
if (!anonymizeUserID) {
|
||||
anonymizeUserID = makeID(6);
|
||||
keysStore.set('AnonymizeUserID', { id: anonymizeUserID });
|
||||
}
|
||||
return anonymizeUserID;
|
||||
}
|
||||
|
||||
function makeID(length: number) {
|
||||
let result = '';
|
||||
const characters =
|
||||
|
@ -58,14 +67,3 @@ function makeID(length: number) {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getUserAnonymizedID() {
|
||||
let anonymizeUserID = keysStore.get('AnonymizeUserID')?.id;
|
||||
if (!anonymizeUserID) {
|
||||
anonymizeUserID = makeID(6);
|
||||
keysStore.set('AnonymizeUserID', { id: anonymizeUserID });
|
||||
}
|
||||
return anonymizeUserID;
|
||||
}
|
||||
|
||||
export default initSentry;
|
|
@ -1,96 +0,0 @@
|
|||
import Store, { Schema } from 'electron-store';
|
||||
import {
|
||||
KeysStoreType,
|
||||
UploadStoreType,
|
||||
SafeStorageStoreType,
|
||||
WatchStoreType,
|
||||
} from '../types';
|
||||
|
||||
export const uploadStoreSchema: Schema<UploadStoreType> = {
|
||||
filePaths: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
zipPaths: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
collectionName: {
|
||||
type: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
export const uploadStatusStore = new Store({
|
||||
name: 'upload-status',
|
||||
schema: uploadStoreSchema,
|
||||
});
|
||||
|
||||
export const keysStoreSchema: Schema<KeysStoreType> = {
|
||||
AnonymizeUserID: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const keysStore = new Store({
|
||||
name: 'keys',
|
||||
schema: keysStoreSchema,
|
||||
});
|
||||
|
||||
export const watchStoreSchema: Schema<WatchStoreType> = {
|
||||
mappings: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
rootFolderName: {
|
||||
type: 'string',
|
||||
},
|
||||
uploadStrategy: {
|
||||
type: 'number',
|
||||
},
|
||||
folderPath: {
|
||||
type: 'string',
|
||||
},
|
||||
files: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
path: {
|
||||
type: 'string',
|
||||
},
|
||||
id: {
|
||||
type: 'number',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const watchStore = new Store({
|
||||
name: 'watch-status',
|
||||
schema: watchStoreSchema,
|
||||
});
|
||||
|
||||
export const safeStorageSchema: Schema<SafeStorageStoreType> = {
|
||||
encryptionKey: {
|
||||
type: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
export const safeStorageStore = new Store({
|
||||
name: 'safeStorage',
|
||||
schema: safeStorageSchema,
|
||||
});
|
18
src/stores/keys.store.ts
Normal file
18
src/stores/keys.store.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import Store, { Schema } from 'electron-store';
|
||||
import { KeysStoreType } from '../types';
|
||||
|
||||
const keysStoreSchema: Schema<KeysStoreType> = {
|
||||
AnonymizeUserID: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const keysStore = new Store({
|
||||
name: 'keys',
|
||||
schema: keysStoreSchema,
|
||||
});
|
13
src/stores/safeStorage.store.ts
Normal file
13
src/stores/safeStorage.store.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import Store, { Schema } from 'electron-store';
|
||||
import { SafeStorageStoreType } from '../types';
|
||||
|
||||
const safeStorageSchema: Schema<SafeStorageStoreType> = {
|
||||
encryptionKey: {
|
||||
type: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
export const safeStorageStore = new Store({
|
||||
name: 'safeStorage',
|
||||
schema: safeStorageSchema,
|
||||
});
|
25
src/stores/upload.store.ts
Normal file
25
src/stores/upload.store.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import Store, { Schema } from 'electron-store';
|
||||
import { UploadStoreType } from '../types';
|
||||
|
||||
const uploadStoreSchema: Schema<UploadStoreType> = {
|
||||
filePaths: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
zipPaths: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
collectionName: {
|
||||
type: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
export const uploadStatusStore = new Store({
|
||||
name: 'upload-status',
|
||||
schema: uploadStoreSchema,
|
||||
});
|
41
src/stores/watch.store.ts
Normal file
41
src/stores/watch.store.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import Store, { Schema } from 'electron-store';
|
||||
import { WatchStoreType } from '../types';
|
||||
|
||||
const watchStoreSchema: Schema<WatchStoreType> = {
|
||||
mappings: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
rootFolderName: {
|
||||
type: 'string',
|
||||
},
|
||||
uploadStrategy: {
|
||||
type: 'number',
|
||||
},
|
||||
folderPath: {
|
||||
type: 'string',
|
||||
},
|
||||
files: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
path: {
|
||||
type: 'string',
|
||||
},
|
||||
id: {
|
||||
type: 'number',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const watchStore = new Store({
|
||||
name: 'watch-status',
|
||||
schema: watchStoreSchema,
|
||||
});
|
|
@ -9,7 +9,7 @@ import {
|
|||
} from 'electron';
|
||||
import { createWindow } from './createWindow';
|
||||
import { buildContextMenu } from './menu';
|
||||
import { logErrorSentry } from './sentry';
|
||||
import { logErrorSentry } from '../services/sentry';
|
||||
import chokidar from 'chokidar';
|
||||
import path from 'path';
|
||||
import { getFilesFromDir } from '../services/fs';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { nativeImage, Tray, app, BrowserWindow, Menu } from 'electron';
|
||||
import path from 'path';
|
||||
import { existsSync } from 'promise-fs';
|
||||
import appUpdater from './appUpdater';
|
||||
import appUpdater from '../services/appUpdater';
|
||||
import { isDev } from './common';
|
||||
import { buildContextMenu, buildMenuBar } from './menu';
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
MenuItemConstructorOptions,
|
||||
} from 'electron';
|
||||
import { isUpdateAvailable, setIsAppQuitting } from '../main';
|
||||
import { showUpdateDialog } from './appUpdater';
|
||||
import { showUpdateDialog } from '../services/appUpdater';
|
||||
|
||||
const isMac = process.platform === 'darwin';
|
||||
|
||||
|
|
16
src/utils/preload.ts
Normal file
16
src/utils/preload.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { webFrame } from 'electron';
|
||||
|
||||
export const fixHotReloadNext12 = () => {
|
||||
webFrame.executeJavaScript(`Object.defineProperty(globalThis, 'WebSocket', {
|
||||
value: new Proxy(WebSocket, {
|
||||
construct: (Target, [url, protocols]) => {
|
||||
if (url.endsWith('/_next/webpack-hmr')) {
|
||||
// Fix the Next.js hmr client url
|
||||
return new Target("ws://localhost:3000/_next/webpack-hmr", protocols)
|
||||
} else {
|
||||
return new Target(url, protocols)
|
||||
}
|
||||
}
|
||||
})
|
||||
});`);
|
||||
};
|
Loading…
Reference in a new issue