Merge branch 'restructure-codebase' into watch

This commit is contained in:
Abhinav 2022-08-25 16:05:29 +05:30
commit 101a7f6b65
22 changed files with 188 additions and 189 deletions

View file

@ -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);
}

View file

@ -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');
}
};

View file

@ -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 {

View file

@ -1,4 +1,3 @@
import {} from './common';
import {
createDirectory,
doesPathExists,

View file

@ -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) {

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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,

View file

@ -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
View 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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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
View 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,
});

View 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,
});

View 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
View 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,
});

View file

@ -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';

View file

@ -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';

View file

@ -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
View 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)
}
}
})
});`);
};