Merge branch 'main' into bundle-ml-demo
This commit is contained in:
commit
0fb8b3700d
23 changed files with 296 additions and 97 deletions
1
.eslintignore
Normal file
1
.eslintignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ui/*
|
13
.github/workflows/build.yml
vendored
13
.github/workflows/build.yml
vendored
|
@ -15,14 +15,14 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out Git repository
|
- name: Check out Git repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: Install Node.js, NPM and Yarn
|
- name: Install Node.js, NPM and Yarn
|
||||||
uses: actions/setup-node@v2.1.5
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 14
|
node-version: 16
|
||||||
|
|
||||||
- name: Prepare for app notarization
|
- name: Prepare for app notarization
|
||||||
if: startsWith(matrix.os, 'macos')
|
if: startsWith(matrix.os, 'macos')
|
||||||
|
@ -35,8 +35,8 @@ jobs:
|
||||||
if: startsWith(matrix.os, 'ubuntu')
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
run: sudo apt-get install libarchive-tools
|
run: sudo apt-get install libarchive-tools
|
||||||
|
|
||||||
- name: Electron Builder Action
|
- name: Ente Electron Builder Action
|
||||||
uses: samuelmeuli/action-electron-builder@v1.6.0
|
uses: ente-io/action-electron-builder@v1.0.0
|
||||||
with:
|
with:
|
||||||
# GitHub token, automatically provided to the action
|
# GitHub token, automatically provided to the action
|
||||||
# (No need to define this secret in the repo settings)
|
# (No need to define this secret in the repo settings)
|
||||||
|
@ -51,8 +51,7 @@ jobs:
|
||||||
env:
|
env:
|
||||||
# macOS notarization API key
|
# macOS notarization API key
|
||||||
API_KEY_ID: ${{ secrets.api_key_id }}
|
API_KEY_ID: ${{ secrets.api_key_id }}
|
||||||
API_KEY_ISSUER_ID: ${{ secrets.api_key_issuer_id }}
|
API_KEY_ISSUER_ID: ${{ secrets.api_key_issuer_id}}
|
||||||
# setry crash reporting token
|
# setry crash reporting token
|
||||||
SENTRY_AUTH_TOKEN: ${{secrets.sentry_auth_token}}
|
SENTRY_AUTH_TOKEN: ${{secrets.sentry_auth_token}}
|
||||||
USE_HARD_LINKS: false
|
USE_HARD_LINKS: false
|
||||||
|
|
||||||
|
|
38
.github/workflows/cla.yaml
vendored
Normal file
38
.github/workflows/cla.yaml
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
name: "CLA Assistant"
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [created]
|
||||||
|
pull_request_target:
|
||||||
|
types: [opened, closed, synchronize]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
CLAAssistant:
|
||||||
|
# This job only runs for pull request comments
|
||||||
|
if: ${{ github.event.issue.pull_request }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: "CLA Assistant"
|
||||||
|
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
|
||||||
|
# Beta Release
|
||||||
|
uses: contributor-assistant/github-action@v2.2.1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
# the below token should have repo scope and must be manually added by you in the repository's secret
|
||||||
|
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||||
|
with:
|
||||||
|
path-to-signatures: "signatures/version1/cla.json"
|
||||||
|
path-to-document: "https://github.com/ente-io/cla/blob/main/CLA.md" # e.g. a CLA or a DCO document
|
||||||
|
# branch should not be protected
|
||||||
|
branch: "main"
|
||||||
|
allowlist: enteio
|
||||||
|
|
||||||
|
# the followings are the optional inputs - If the optional inputs are not given, then default values will be taken
|
||||||
|
#remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository)
|
||||||
|
remote-repository-name: cla
|
||||||
|
#create-file-commit-message: 'For example: Creating file for storing CLA Signatures'
|
||||||
|
#signed-commit-message: 'For example: $contributorName has signed the CLA in #$pullRequestNo'
|
||||||
|
#custom-notsigned-prcomment: 'pull request comment with Introductory message to ask new contributors to sign'
|
||||||
|
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
|
||||||
|
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'
|
||||||
|
#lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)
|
||||||
|
#use-dco-flag: true - If you are using DCO instead of CLA
|
98
CLA.md
Normal file
98
CLA.md
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
## Contributor License Agreement
|
||||||
|
|
||||||
|
Thank you for your contribution to ente projects.
|
||||||
|
|
||||||
|
This contributor license agreement documents the rights granted by contributors
|
||||||
|
to Ente Technologies, Inc ("ente"). This license is for your protection as a
|
||||||
|
Contributor as well as the protection of ente, its users, and its licensees; you
|
||||||
|
may still license your own Contributions under other terms.
|
||||||
|
|
||||||
|
In exchange for the ability to participate in the ente community and for other
|
||||||
|
good consideration, the receipt of which is hereby acknowledged, you accept and
|
||||||
|
agree to the following terms and conditions for Your present and future
|
||||||
|
Contributions submitted to ente. Except for the license granted herein to ente
|
||||||
|
and recipients of software distributed by ente, You reserve all right, title,
|
||||||
|
and interest in and to Your Contributions.
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean the copyright owner or legal entity authorized
|
||||||
|
by the copyright owner that is making this Agreement with ente. For legal
|
||||||
|
entities, the entity making a Contribution and all other entities that
|
||||||
|
control, are controlled by, or are under common control with that entity are
|
||||||
|
considered to be a single Contributor. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the direction or
|
||||||
|
management of such entity, whether by contract or otherwise, or (ii)
|
||||||
|
ownership of fifty percent (50%) or more of the outstanding shares, or (iii)
|
||||||
|
beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"Contribution" shall mean any original work of authorship or invention,
|
||||||
|
including any modifications or additions to an existing work, that is
|
||||||
|
intentionally submitted by You to ente for inclusion in, or documentation of,
|
||||||
|
any of the products owned or managed by ente (the "Work"). For the purposes
|
||||||
|
of this definition, "submitted" means any form of electronic, verbal, or
|
||||||
|
written communication sent to ente or its representatives, including but not
|
||||||
|
limited to communication on electronic mailing lists, source code control
|
||||||
|
systems, and issue tracking systems that are managed by, or on behalf of,
|
||||||
|
ente for the purpose of discussing and improving the Work, but excluding
|
||||||
|
communication that is conspicuously marked or otherwise designated in writing
|
||||||
|
by You as "Not a Contribution."
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of this
|
||||||
|
Agreement, You hereby grant to ente and to recipients of software distributed
|
||||||
|
by ente a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||||
|
irrevocable copyright license to reproduce, prepare derivative works of,
|
||||||
|
publicly display, publicly perform, and distribute Your Contributions and
|
||||||
|
such derivative works.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of this
|
||||||
|
Agreement, You hereby grant to ente and to recipients of software distributed
|
||||||
|
by ente a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||||
|
irrevocable (except as stated in this section) patent license to make, have
|
||||||
|
made, use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable by You that
|
||||||
|
are necessarily infringed by Your Contribution(s) alone or by combination of
|
||||||
|
Your Contribution(s) with the Work to which such Contribution(s) was
|
||||||
|
submitted. If any entity institutes patent litigation against You or any
|
||||||
|
other entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that your Contribution, or the Work to which you have contributed,
|
||||||
|
constitutes direct or contributory patent infringement, then any patent
|
||||||
|
licenses granted to that entity under this Agreement for that Contribution or
|
||||||
|
Work shall terminate as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. You represent that you are legally entitled to grant the above license. If
|
||||||
|
your employer(s) has rights to intellectual property that you create that
|
||||||
|
includes your Contributions, you represent that you have received permission
|
||||||
|
to make Contributions on behalf of that employer, that your employer has
|
||||||
|
waived such rights for your contributions to ente, or that your employer has
|
||||||
|
executed with ente a separate contributor license agreement substantially
|
||||||
|
similar to this Agreement. If You are a current employee or contractor of
|
||||||
|
ente, then the terms of your existing Employment Agreement or Consulting
|
||||||
|
Services Agreement shall supersede this CLA, and remain in full effect.
|
||||||
|
|
||||||
|
5. You represent that each of Your Contributions is Your original creation (see
|
||||||
|
section 7 for submissions on behalf of others). You represent that Your
|
||||||
|
Contribution submissions include complete details of any third-party license
|
||||||
|
or other restriction (including, but not limited to, related patents and
|
||||||
|
trademarks) of which you are personally aware and which are associated with
|
||||||
|
any part of Your Contributions.
|
||||||
|
|
||||||
|
6. You are not expected to provide support for Your Contributions, except to the
|
||||||
|
extent You desire to provide support. You may provide support for free, for
|
||||||
|
a fee, or not at all. Unless required by applicable law or agreed to in
|
||||||
|
writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT
|
||||||
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including,
|
||||||
|
without limitation, any warranties or conditions of title, non-infringement,
|
||||||
|
merchantability, or fitness for a particular purpose.
|
||||||
|
|
||||||
|
7. Should You wish to submit work that is not Your original creation, You may
|
||||||
|
submit it to ente separately from any Contribution, identifying the complete
|
||||||
|
details of its source and of any license or other restriction (including, but
|
||||||
|
not limited to, related patents, trademarks, and license agreements) of which
|
||||||
|
you are personally aware, and conspicuously marking the work as "Not a
|
||||||
|
Contribution". Third-party materials licensed pursuant to: [license name(s)
|
||||||
|
here]" (substituting the bracketed text with the appropriate license
|
||||||
|
name(s)).
|
||||||
|
|
||||||
|
8. You agree to notify ente of any facts or circumstances of which you become
|
||||||
|
aware that would make these representations inaccurate in any respect.
|
|
@ -5,7 +5,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>ente.io | encrypted photo storage - loading failed</title>
|
<title>ente Photos</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body style="background-color: black;">
|
<body style="background-color: black;">
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>ente.io | encrypted photo storage </title>
|
<title>ente Photos</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body style="background-color: black;">
|
<body style="background-color: black;">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "ente",
|
"name": "ente",
|
||||||
"productName": "ente",
|
"productName": "ente",
|
||||||
"version": "1.6.18-alpha.1",
|
"version": "1.6.20",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Desktop client for ente.io",
|
"description": "Desktop client for ente.io",
|
||||||
"main": "app/main.js",
|
"main": "app/main.js",
|
||||||
|
@ -68,7 +68,7 @@
|
||||||
"start": "concurrently \"yarn start-main\" \"yarn start-renderer\"",
|
"start": "concurrently \"yarn start-main\" \"yarn start-renderer\"",
|
||||||
"build-renderer": "cd ui && yarn install && yarn build && cd ..",
|
"build-renderer": "cd ui && yarn install && yarn build && cd ..",
|
||||||
"build": "yarn build-renderer && yarn build-main",
|
"build": "yarn build-renderer && yarn build-main",
|
||||||
"test-release": "yarn build && electron-builder --config.compression=store"
|
"test-release": "cross-env IS_TEST_RELEASE=true yarn build && electron-builder --config.compression=store"
|
||||||
},
|
},
|
||||||
"author": "ente <code@ente.io>",
|
"author": "ente <code@ente.io>",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -83,6 +83,7 @@
|
||||||
"@typescript-eslint/eslint-plugin": "^5.28.0",
|
"@typescript-eslint/eslint-plugin": "^5.28.0",
|
||||||
"@typescript-eslint/parser": "^5.28.0",
|
"@typescript-eslint/parser": "^5.28.0",
|
||||||
"concurrently": "^7.0.0",
|
"concurrently": "^7.0.0",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
"electron": "^21.2.2",
|
"electron": "^21.2.2",
|
||||||
"electron-builder": "^23.0.3",
|
"electron-builder": "^23.0.3",
|
||||||
"electron-builder-notarize": "^1.2.0",
|
"electron-builder-notarize": "^1.2.0",
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
|
import { CustomErrors } from '../constants/errors';
|
||||||
import { ipcRenderer } from 'electron/renderer';
|
import { ipcRenderer } from 'electron/renderer';
|
||||||
import { existsSync } from 'fs';
|
import { existsSync } from 'fs';
|
||||||
import { writeStream } from '../services/fs';
|
import { writeStream } from '../services/fs';
|
||||||
import { logError } from '../services/logging';
|
import { logError } from '../services/logging';
|
||||||
import { ElectronFile } from '../types';
|
import { ElectronFile } from '../types';
|
||||||
|
import { isPlatform } from '../utils/common/platform';
|
||||||
|
|
||||||
export async function convertHEIC(fileData: Uint8Array): Promise<Uint8Array> {
|
export async function convertHEIC(fileData: Uint8Array): Promise<Uint8Array> {
|
||||||
|
if (isPlatform('windows')) {
|
||||||
|
throw Error(CustomErrors.WINDOWS_NATIVE_IMAGE_PROCESSING_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
const convertedFileData = await ipcRenderer.invoke(
|
const convertedFileData = await ipcRenderer.invoke(
|
||||||
'convert-heic',
|
'convert-heic',
|
||||||
fileData
|
fileData
|
||||||
|
@ -20,6 +25,11 @@ export async function generateImageThumbnail(
|
||||||
let inputFilePath = null;
|
let inputFilePath = null;
|
||||||
let createdTempInputFile = null;
|
let createdTempInputFile = null;
|
||||||
try {
|
try {
|
||||||
|
if (isPlatform('windows')) {
|
||||||
|
throw Error(
|
||||||
|
CustomErrors.WINDOWS_NATIVE_IMAGE_PROCESSING_NOT_SUPPORTED
|
||||||
|
);
|
||||||
|
}
|
||||||
if (!existsSync(inputFile.path)) {
|
if (!existsSync(inputFile.path)) {
|
||||||
const tempFilePath = await ipcRenderer.invoke(
|
const tempFilePath = await ipcRenderer.invoke(
|
||||||
'get-temp-file-path',
|
'get-temp-file-path',
|
||||||
|
|
|
@ -4,13 +4,14 @@ import { ipcRenderer } from 'electron';
|
||||||
import { ElectronFile, WatchMapping } from '../types';
|
import { ElectronFile, WatchMapping } from '../types';
|
||||||
import { getElectronFile } from '../services/fs';
|
import { getElectronFile } from '../services/fs';
|
||||||
import { getWatchMappings, setWatchMappings } from '../services/watch';
|
import { getWatchMappings, setWatchMappings } from '../services/watch';
|
||||||
|
import ElectronLog from 'electron-log';
|
||||||
|
|
||||||
export async function addWatchMapping(
|
export async function addWatchMapping(
|
||||||
rootFolderName: string,
|
rootFolderName: string,
|
||||||
folderPath: string,
|
folderPath: string,
|
||||||
uploadStrategy: number
|
uploadStrategy: number
|
||||||
) {
|
) {
|
||||||
folderPath = path.normalize(folderPath);
|
ElectronLog.log(`Adding watch mapping: ${folderPath}`);
|
||||||
const watchMappings = getWatchMappings();
|
const watchMappings = getWatchMappings();
|
||||||
if (isMappingPresent(watchMappings, folderPath)) {
|
if (isMappingPresent(watchMappings, folderPath)) {
|
||||||
throw new Error(`Watch mapping already exists`);
|
throw new Error(`Watch mapping already exists`);
|
||||||
|
@ -93,23 +94,19 @@ export function registerWatcherFunctions(
|
||||||
) {
|
) {
|
||||||
ipcRenderer.removeAllListeners('watch-add');
|
ipcRenderer.removeAllListeners('watch-add');
|
||||||
ipcRenderer.removeAllListeners('watch-change');
|
ipcRenderer.removeAllListeners('watch-change');
|
||||||
ipcRenderer.removeAllListeners('watch-unlink');
|
ipcRenderer.removeAllListeners('watch-unlink-dir');
|
||||||
ipcRenderer.on('watch-add', async (_, filePath: string) => {
|
ipcRenderer.on('watch-add', async (_, filePath: string) => {
|
||||||
filePath = path.normalize(
|
filePath = filePath.split(path.sep).join(path.posix.sep);
|
||||||
filePath.split(path.sep).join(path.posix.sep)
|
|
||||||
);
|
|
||||||
await addFile(await getElectronFile(filePath));
|
await addFile(await getElectronFile(filePath));
|
||||||
});
|
});
|
||||||
ipcRenderer.on('watch-unlink', async (_, filePath: string) => {
|
ipcRenderer.on('watch-unlink', async (_, filePath: string) => {
|
||||||
filePath = path.normalize(
|
filePath = filePath.split(path.sep).join(path.posix.sep);
|
||||||
filePath.split(path.sep).join(path.posix.sep)
|
|
||||||
);
|
|
||||||
await removeFile(filePath);
|
await removeFile(filePath);
|
||||||
});
|
});
|
||||||
ipcRenderer.on('watch-unlink-dir', async (_, folderPath: string) => {
|
ipcRenderer.on('watch-unlink-dir', async (_, folderPath: string) => {
|
||||||
folderPath = path.normalize(
|
folderPath = folderPath.split(path.sep).join(path.posix.sep);
|
||||||
folderPath.split(path.sep).join(path.posix.sep)
|
|
||||||
);
|
|
||||||
await removeFolder(folderPath);
|
await removeFolder(folderPath);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
5
src/constants/errors.ts
Normal file
5
src/constants/errors.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export const CustomErrors = {
|
||||||
|
WINDOWS_NATIVE_IMAGE_PROCESSING_NOT_SUPPORTED:
|
||||||
|
'Windows native image processing is not supported',
|
||||||
|
INVALID_OS: (os: string) => `Invalid OS - ${os}`,
|
||||||
|
};
|
|
@ -51,7 +51,10 @@ import { fixHotReloadNext12 } from './utils/preload';
|
||||||
import { isFolder, getDirFiles } from './api/fs';
|
import { isFolder, getDirFiles } from './api/fs';
|
||||||
import { convertHEIC, generateImageThumbnail } from './api/imageProcessor';
|
import { convertHEIC, generateImageThumbnail } from './api/imageProcessor';
|
||||||
import { setupLogging } from './utils/logging';
|
import { setupLogging } from './utils/logging';
|
||||||
import { setupRendererProcessStatsLogger } from './utils/processStats';
|
import {
|
||||||
|
setupRendererProcessStatsLogger,
|
||||||
|
logRendererProcessMemoryUsage,
|
||||||
|
} from './utils/processStats';
|
||||||
import { runFFmpegCmd } from './api/ffmpeg';
|
import { runFFmpegCmd } from './api/ffmpeg';
|
||||||
|
|
||||||
fixHotReloadNext12();
|
fixHotReloadNext12();
|
||||||
|
@ -107,4 +110,5 @@ windowObject['ElectronAPIs'] = {
|
||||||
runFFmpegCmd,
|
runFFmpegCmd,
|
||||||
muteUpdateNotification,
|
muteUpdateNotification,
|
||||||
generateImageThumbnail,
|
generateImageThumbnail,
|
||||||
|
logRendererProcessMemoryUsage,
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import { logErrorSentry } from './sentry';
|
import { logErrorSentry } from './sentry';
|
||||||
import ElectronLog from 'electron-log';
|
import ElectronLog from 'electron-log';
|
||||||
import { isPlatform } from '../utils/main';
|
import { isPlatform } from '../utils/common/platform';
|
||||||
|
|
||||||
const FIVE_MIN_IN_MICROSECOND = 5 * 60 * 1000;
|
const FIVE_MIN_IN_MICROSECOND = 5 * 60 * 1000;
|
||||||
const ONE_DAY_IN_MICROSECOND = 1 * 24 * 60 * 60 * 1000;
|
const ONE_DAY_IN_MICROSECOND = 1 * 24 * 60 * 60 * 1000;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { isPlatform } from '../utils/main';
|
import { isPlatform } from '../utils/common/platform';
|
||||||
import { AutoLauncherClient } from '../types/autoLauncher';
|
import { AutoLauncherClient } from '../types/autoLauncher';
|
||||||
import linuxAutoLauncher from './autoLauncherClients/linuxAutoLauncher';
|
import linuxAutoLauncher from './autoLauncherClients/linuxAutoLauncher';
|
||||||
import macAndWindowsAutoLauncher from './autoLauncherClients/macAndWindowsAutoLauncher';
|
import macAndWindowsAutoLauncher from './autoLauncherClients/macAndWindowsAutoLauncher';
|
||||||
|
|
|
@ -184,12 +184,22 @@ export const getZipFileStream = async (
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function isFolder(dirPath: string) {
|
export async function isFolder(dirPath: string) {
|
||||||
return await fs
|
try {
|
||||||
.stat(dirPath)
|
const stats = await fs.stat(dirPath);
|
||||||
.then((stats) => {
|
|
||||||
return stats.isDirectory();
|
return stats.isDirectory();
|
||||||
})
|
} catch (e) {
|
||||||
.catch(() => false);
|
let err = e;
|
||||||
|
// if code is defined, it's an error from fs.stat
|
||||||
|
if (typeof e.code !== 'undefined') {
|
||||||
|
// ENOENT means the file does not exist
|
||||||
|
if (e.code === 'ENOENT') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
err = Error(`fs error code: ${e.code}`);
|
||||||
|
}
|
||||||
|
logError(err, 'isFolder failed');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const convertBrowserStreamToNode = (
|
export const convertBrowserStreamToNode = (
|
||||||
|
|
|
@ -5,10 +5,11 @@ import { existsSync, rmSync } from 'fs';
|
||||||
import { readFile, writeFile } from 'promise-fs';
|
import { readFile, writeFile } from 'promise-fs';
|
||||||
import { generateTempFilePath } from '../utils/temp';
|
import { generateTempFilePath } from '../utils/temp';
|
||||||
import { logErrorSentry } from './sentry';
|
import { logErrorSentry } from './sentry';
|
||||||
import { isPlatform } from '../utils/main';
|
import { isPlatform } from '../utils/common/platform';
|
||||||
import { isDev } from '../utils/common';
|
import { isDev } from '../utils/common';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import log from 'electron-log';
|
import log from 'electron-log';
|
||||||
|
import { CustomErrors } from '../constants/errors';
|
||||||
const shellescape = require('any-shell-escape');
|
const shellescape = require('any-shell-escape');
|
||||||
|
|
||||||
const asyncExec = util.promisify(exec);
|
const asyncExec = util.promisify(exec);
|
||||||
|
@ -157,7 +158,7 @@ function constructConvertCommand(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
Error(`${process.platform} native heic convert not supported yet`);
|
throw Error(CustomErrors.INVALID_OS(process.platform));
|
||||||
}
|
}
|
||||||
return convertCmd;
|
return convertCmd;
|
||||||
}
|
}
|
||||||
|
@ -271,9 +272,7 @@ function constructThumbnailGenerationCommand(
|
||||||
return cmdPart;
|
return cmdPart;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Error(
|
throw Error(CustomErrors.INVALID_OS(process.platform));
|
||||||
`${process.platform} native thumbnail generation not supported yet`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return thumbnailGenerationCmd;
|
return thumbnailGenerationCmd;
|
||||||
}
|
}
|
||||||
|
|
11
src/utils/common/platform.ts
Normal file
11
src/utils/common/platform.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
export function isPlatform(platform: 'mac' | 'windows' | 'linux') {
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
return platform === 'mac';
|
||||||
|
} else if (process.platform === 'win32') {
|
||||||
|
return platform === 'windows';
|
||||||
|
} else if (process.platform === 'linux') {
|
||||||
|
return platform === 'linux';
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,9 +3,11 @@ import * as path from 'path';
|
||||||
import { isDev } from './common';
|
import { isDev } from './common';
|
||||||
import { isAppQuitting } from '../main';
|
import { isAppQuitting } from '../main';
|
||||||
import { PROD_HOST_URL } from '../config';
|
import { PROD_HOST_URL } from '../config';
|
||||||
import { isPlatform } from './main';
|
import { isPlatform } from './common/platform';
|
||||||
import { getHideDockIconPreference } from '../services/userPreference';
|
import { getHideDockIconPreference } from '../services/userPreference';
|
||||||
import autoLauncher from '../services/autoLauncher';
|
import autoLauncher from '../services/autoLauncher';
|
||||||
|
import ElectronLog from 'electron-log';
|
||||||
|
import { logErrorSentry } from '../services/sentry';
|
||||||
|
|
||||||
export async function createWindow(): Promise<BrowserWindow> {
|
export async function createWindow(): Promise<BrowserWindow> {
|
||||||
const appImgPath = isDev
|
const appImgPath = isDev
|
||||||
|
@ -64,6 +66,20 @@ export async function createWindow(): Promise<BrowserWindow> {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
mainWindow.webContents.on('render-process-gone', (event, details) => {
|
||||||
|
mainWindow.webContents.reload();
|
||||||
|
logErrorSentry(
|
||||||
|
Error('render-process-gone'),
|
||||||
|
'webContents event render-process-gone',
|
||||||
|
{ details }
|
||||||
|
);
|
||||||
|
ElectronLog.log('webContents event render-process-gone', details);
|
||||||
|
});
|
||||||
|
mainWindow.webContents.on('unresponsive', () => {
|
||||||
|
mainWindow.webContents.forcefullyCrashRenderer();
|
||||||
|
ElectronLog.log('webContents event unresponsive');
|
||||||
|
});
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
try {
|
try {
|
||||||
splash.destroy();
|
splash.destroy();
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { getHideDockIconPreference } from '../services/userPreference';
|
||||||
import { setupAutoUpdater } from '../services/appUpdater';
|
import { setupAutoUpdater } from '../services/appUpdater';
|
||||||
import ElectronLog from 'electron-log';
|
import ElectronLog from 'electron-log';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
|
import { isPlatform } from './common/platform';
|
||||||
|
|
||||||
export function handleUpdates(mainWindow: BrowserWindow) {
|
export function handleUpdates(mainWindow: BrowserWindow) {
|
||||||
if (!isDev) {
|
if (!isDev) {
|
||||||
|
@ -84,18 +85,6 @@ export function setupNextElectronServe() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isPlatform(platform: 'mac' | 'windows' | 'linux') {
|
|
||||||
if (process.platform === 'darwin') {
|
|
||||||
return platform === 'mac';
|
|
||||||
} else if (process.platform === 'win32') {
|
|
||||||
return platform === 'windows';
|
|
||||||
} else if (process.platform === 'linux') {
|
|
||||||
return platform === 'linux';
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function handleDockIconHideOnAutoLaunch() {
|
export async function handleDockIconHideOnAutoLaunch() {
|
||||||
const shouldHideDockIcon = getHideDockIconPreference();
|
const shouldHideDockIcon = getHideDockIconPreference();
|
||||||
const wasAutoLaunched = await autoLauncher.wasAutoLaunched();
|
const wasAutoLaunched = await autoLauncher.wasAutoLaunched();
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
} from '../services/userPreference';
|
} from '../services/userPreference';
|
||||||
import { setIsAppQuitting } from '../main';
|
import { setIsAppQuitting } from '../main';
|
||||||
import autoLauncher from '../services/autoLauncher';
|
import autoLauncher from '../services/autoLauncher';
|
||||||
import { isPlatform } from './main';
|
import { isPlatform } from './common/platform';
|
||||||
import ElectronLog from 'electron-log';
|
import ElectronLog from 'electron-log';
|
||||||
|
|
||||||
export function buildContextMenu(
|
export function buildContextMenu(
|
||||||
|
|
|
@ -5,9 +5,9 @@ const LOGGING_INTERVAL_IN_MICROSECONDS = 30 * 1000; // 30 seconds
|
||||||
|
|
||||||
const SPIKE_DETECTION_INTERVAL_IN_MICROSECONDS = 1 * 1000; // 1 seconds
|
const SPIKE_DETECTION_INTERVAL_IN_MICROSECONDS = 1 * 1000; // 1 seconds
|
||||||
|
|
||||||
const MAIN_MEMORY_USAGE_DIFF_IN_KILOBYTES_CONSIDERED_AS_SPIKE = 10 * 1024; // 10 MB
|
const MAIN_MEMORY_USAGE_DIFF_IN_KILOBYTES_CONSIDERED_AS_SPIKE = 50 * 1024; // 50 MB
|
||||||
|
|
||||||
const HIGH_MAIN_MEMORY_USAGE_THRESHOLD_IN_KILOBYTES = 100 * 1024; // 100 MB
|
const HIGH_MAIN_MEMORY_USAGE_THRESHOLD_IN_KILOBYTES = 200 * 1024; // 200 MB
|
||||||
|
|
||||||
const RENDERER_MEMORY_USAGE_DIFF_IN_KILOBYTES_CONSIDERED_AS_SPIKE = 200 * 1024; // 200 MB
|
const RENDERER_MEMORY_USAGE_DIFF_IN_KILOBYTES_CONSIDERED_AS_SPIKE = 200 * 1024; // 200 MB
|
||||||
|
|
||||||
|
@ -40,15 +40,15 @@ let mainProcessUsingHighMemory = false;
|
||||||
async function logSpikeMainMemoryUsage() {
|
async function logSpikeMainMemoryUsage() {
|
||||||
const processMemoryInfo = await process.getProcessMemoryInfo();
|
const processMemoryInfo = await process.getProcessMemoryInfo();
|
||||||
const currentMemoryUsage = Math.max(
|
const currentMemoryUsage = Math.max(
|
||||||
processMemoryInfo.residentSet,
|
processMemoryInfo.residentSet ?? 0,
|
||||||
processMemoryInfo.private
|
processMemoryInfo.private
|
||||||
);
|
);
|
||||||
const previewMemoryUsage = Math.max(
|
const previousMemoryUsage = Math.max(
|
||||||
previousMainProcessMemoryInfo.private,
|
previousMainProcessMemoryInfo.residentSet ?? 0,
|
||||||
previousMainProcessMemoryInfo.residentSet
|
previousMainProcessMemoryInfo.private
|
||||||
);
|
);
|
||||||
const isSpiking =
|
const isSpiking =
|
||||||
currentMemoryUsage - previewMemoryUsage >=
|
currentMemoryUsage - previousMemoryUsage >=
|
||||||
MAIN_MEMORY_USAGE_DIFF_IN_KILOBYTES_CONSIDERED_AS_SPIKE;
|
MAIN_MEMORY_USAGE_DIFF_IN_KILOBYTES_CONSIDERED_AS_SPIKE;
|
||||||
|
|
||||||
const isHighMemoryUsage =
|
const isHighMemoryUsage =
|
||||||
|
@ -92,15 +92,16 @@ let rendererUsingHighMemory = false;
|
||||||
async function logSpikeRendererMemoryUsage() {
|
async function logSpikeRendererMemoryUsage() {
|
||||||
const processMemoryInfo = await process.getProcessMemoryInfo();
|
const processMemoryInfo = await process.getProcessMemoryInfo();
|
||||||
const currentMemoryUsage = Math.max(
|
const currentMemoryUsage = Math.max(
|
||||||
processMemoryInfo.residentSet,
|
processMemoryInfo.residentSet ?? 0,
|
||||||
processMemoryInfo.private
|
processMemoryInfo.private
|
||||||
);
|
);
|
||||||
const previewMemoryUsage = Math.max(
|
|
||||||
|
const previousMemoryUsage = Math.max(
|
||||||
previousRendererProcessMemoryInfo.private,
|
previousRendererProcessMemoryInfo.private,
|
||||||
previousRendererProcessMemoryInfo.residentSet
|
previousRendererProcessMemoryInfo.residentSet ?? 0
|
||||||
);
|
);
|
||||||
const isSpiking =
|
const isSpiking =
|
||||||
currentMemoryUsage - previewMemoryUsage >=
|
currentMemoryUsage - previousMemoryUsage >=
|
||||||
RENDERER_MEMORY_USAGE_DIFF_IN_KILOBYTES_CONSIDERED_AS_SPIKE;
|
RENDERER_MEMORY_USAGE_DIFF_IN_KILOBYTES_CONSIDERED_AS_SPIKE;
|
||||||
|
|
||||||
const isHighMemoryUsage =
|
const isHighMemoryUsage =
|
||||||
|
@ -168,6 +169,19 @@ export function setupRendererProcessStatsLogger() {
|
||||||
setInterval(logRendererProcessStats, LOGGING_INTERVAL_IN_MICROSECONDS);
|
setInterval(logRendererProcessStats, LOGGING_INTERVAL_IN_MICROSECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function logRendererProcessMemoryUsage(message: string) {
|
||||||
|
const processMemoryInfo = await process.getProcessMemoryInfo();
|
||||||
|
const processMemory = Math.max(
|
||||||
|
processMemoryInfo.private,
|
||||||
|
processMemoryInfo.residentSet ?? 0
|
||||||
|
);
|
||||||
|
ElectronLog.log(
|
||||||
|
'renderer ProcessMemory',
|
||||||
|
message,
|
||||||
|
convertBytesToHumanReadable(processMemory * 1024)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const getNormalizedProcessMemoryInfo = async (
|
const getNormalizedProcessMemoryInfo = async (
|
||||||
processMemoryInfo: Electron.ProcessMemoryInfo
|
processMemoryInfo: Electron.ProcessMemoryInfo
|
||||||
) => {
|
) => {
|
||||||
|
|
2
ui
2
ui
|
@ -1 +1 @@
|
||||||
Subproject commit 0d34202c4121003defea9839355f5c03d238d2c9
|
Subproject commit c56da87161ba582ae21407b2d3a19508b50c8b9b
|
|
@ -1199,6 +1199,13 @@ crc@^3.8.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
buffer "^5.1.0"
|
buffer "^5.1.0"
|
||||||
|
|
||||||
|
cross-env@^7.0.3:
|
||||||
|
version "7.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
|
||||||
|
integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
|
||||||
|
dependencies:
|
||||||
|
cross-spawn "^7.0.1"
|
||||||
|
|
||||||
cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||||
version "7.0.3"
|
version "7.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||||
|
|
Loading…
Add table
Reference in a new issue