You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-27 20:29:45 +02:00
Compare commits
3 Commits
v3.4.5
...
alt_instan
Author | SHA1 | Date | |
---|---|---|---|
|
04666be15f | ||
|
64d0bec2c5 | ||
|
ab28f2a794 |
@@ -4,15 +4,12 @@ import AutoUpdaterService, { defaultUpdateInterval, initialUpdateStartup } from
|
|||||||
import type ShimType from '@joplin/lib/shim';
|
import type ShimType from '@joplin/lib/shim';
|
||||||
const shim: typeof ShimType = require('@joplin/lib/shim').default;
|
const shim: typeof ShimType = require('@joplin/lib/shim').default;
|
||||||
import { isCallbackUrl } from '@joplin/lib/callbackUrlUtils';
|
import { isCallbackUrl } from '@joplin/lib/callbackUrlUtils';
|
||||||
|
import { BrowserWindow, Tray, WebContents, screen, App, Event, dialog, ipcMain } from 'electron';
|
||||||
import { BrowserWindow, Tray, WebContents, screen } from 'electron';
|
|
||||||
import bridge from './bridge';
|
import bridge from './bridge';
|
||||||
const url = require('url');
|
const url = require('url');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { dirname } = require('@joplin/lib/path-utils');
|
const { dirname } = require('@joplin/lib/path-utils');
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
|
|
||||||
import { dialog, ipcMain } from 'electron';
|
|
||||||
import { _ } from '@joplin/lib/locale';
|
import { _ } from '@joplin/lib/locale';
|
||||||
import restartInSafeModeFromMain from './utils/restartInSafeModeFromMain';
|
import restartInSafeModeFromMain from './utils/restartInSafeModeFromMain';
|
||||||
import handleCustomProtocols, { CustomProtocolHandler } from './utils/customProtocols/handleCustomProtocols';
|
import handleCustomProtocols, { CustomProtocolHandler } from './utils/customProtocols/handleCustomProtocols';
|
||||||
@@ -36,8 +33,7 @@ interface SecondaryWindowData {
|
|||||||
|
|
||||||
export default class ElectronAppWrapper {
|
export default class ElectronAppWrapper {
|
||||||
private logger_: Logger = null;
|
private logger_: Logger = null;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
private electronApp_: App;
|
||||||
private electronApp_: any;
|
|
||||||
private env_: string;
|
private env_: string;
|
||||||
private isDebugMode_: boolean;
|
private isDebugMode_: boolean;
|
||||||
private profilePath_: string;
|
private profilePath_: string;
|
||||||
@@ -48,8 +44,7 @@ export default class ElectronAppWrapper {
|
|||||||
private secondaryWindows_: Map<SecondaryWindowId, SecondaryWindowData> = new Map();
|
private secondaryWindows_: Map<SecondaryWindowId, SecondaryWindowData> = new Map();
|
||||||
|
|
||||||
private willQuitApp_ = false;
|
private willQuitApp_ = false;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
private tray_: Tray = null;
|
||||||
private tray_: any = null;
|
|
||||||
private buildDir_: string = null;
|
private buildDir_: string = null;
|
||||||
private rendererProcessQuitReply_: RendererProcessQuitReply = null;
|
private rendererProcessQuitReply_: RendererProcessQuitReply = null;
|
||||||
|
|
||||||
@@ -57,14 +52,15 @@ export default class ElectronAppWrapper {
|
|||||||
private updaterService_: AutoUpdaterService = null;
|
private updaterService_: AutoUpdaterService = null;
|
||||||
private customProtocolHandler_: CustomProtocolHandler = null;
|
private customProtocolHandler_: CustomProtocolHandler = null;
|
||||||
private updatePollInterval_: ReturnType<typeof setTimeout>|null = null;
|
private updatePollInterval_: ReturnType<typeof setTimeout>|null = null;
|
||||||
|
private isAltInstance_: boolean;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
public constructor(electronApp: App, env: string, profilePath: string|null, isDebugMode: boolean, initialCallbackUrl: string, isAltInstance: boolean) {
|
||||||
public constructor(electronApp: any, env: string, profilePath: string|null, isDebugMode: boolean, initialCallbackUrl: string) {
|
|
||||||
this.electronApp_ = electronApp;
|
this.electronApp_ = electronApp;
|
||||||
this.env_ = env;
|
this.env_ = env;
|
||||||
this.isDebugMode_ = isDebugMode;
|
this.isDebugMode_ = isDebugMode;
|
||||||
this.profilePath_ = profilePath;
|
this.profilePath_ = profilePath;
|
||||||
this.initialCallbackUrl_ = initialCallbackUrl;
|
this.initialCallbackUrl_ = initialCallbackUrl;
|
||||||
|
this.isAltInstance_ = isAltInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public electronApp() {
|
public electronApp() {
|
||||||
@@ -87,6 +83,10 @@ export default class ElectronAppWrapper {
|
|||||||
return BrowserWindow.getFocusedWindow() ?? this.win_;
|
return BrowserWindow.getFocusedWindow() ?? this.win_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isAltInstance() {
|
||||||
|
return this.isAltInstance_;
|
||||||
|
}
|
||||||
|
|
||||||
public windowById(joplinId: string) {
|
public windowById(joplinId: string) {
|
||||||
if (joplinId === defaultWindowId) {
|
if (joplinId === defaultWindowId) {
|
||||||
return this.mainWindow();
|
return this.mainWindow();
|
||||||
@@ -538,6 +538,7 @@ export default class ElectronAppWrapper {
|
|||||||
|
|
||||||
public ensureSingleInstance() {
|
public ensureSingleInstance() {
|
||||||
if (this.env_ === 'dev') return false;
|
if (this.env_ === 'dev') return false;
|
||||||
|
if (this.isAltInstance_) return false;
|
||||||
|
|
||||||
const gotTheLock = this.electronApp_.requestSingleInstanceLock();
|
const gotTheLock = this.electronApp_.requestSingleInstanceLock();
|
||||||
|
|
||||||
@@ -548,8 +549,7 @@ export default class ElectronAppWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Someone tried to open a second instance - focus our window instead
|
// Someone tried to open a second instance - focus our window instead
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
this.electronApp_.on('second-instance', (_event: Event, argv: string[], _workingDirectory: string) => {
|
||||||
this.electronApp_.on('second-instance', (_e: any, argv: string[]) => {
|
|
||||||
const win = this.mainWindow();
|
const win = this.mainWindow();
|
||||||
if (!win) return;
|
if (!win) return;
|
||||||
if (win.isMinimized()) win.restore();
|
if (win.isMinimized()) win.restore();
|
||||||
|
@@ -617,10 +617,11 @@ class Application extends BaseApplication {
|
|||||||
clipperLogger.addTarget(TargetType.Console);
|
clipperLogger.addTarget(TargetType.Console);
|
||||||
|
|
||||||
ClipperServer.instance().initialize(actionApi);
|
ClipperServer.instance().initialize(actionApi);
|
||||||
|
ClipperServer.instance().setEnabled(!Setting.value('isAltInstance'));
|
||||||
ClipperServer.instance().setLogger(clipperLogger);
|
ClipperServer.instance().setLogger(clipperLogger);
|
||||||
ClipperServer.instance().setDispatch(this.store().dispatch);
|
ClipperServer.instance().setDispatch(this.store().dispatch);
|
||||||
|
|
||||||
if (Setting.value('clipperServer.autoStart')) {
|
if (ClipperServer.instance().enabled() && Setting.value('clipperServer.autoStart')) {
|
||||||
void ClipperServer.instance().start();
|
void ClipperServer.instance().start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -24,6 +24,7 @@ class ClipperConfigScreenComponent extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private enableClipperServer_click() {
|
private enableClipperServer_click() {
|
||||||
|
if (!ClipperServer.instance().enabled()) return;
|
||||||
Setting.setValue('clipperServer.autoStart', true);
|
Setting.setValue('clipperServer.autoStart', true);
|
||||||
void ClipperServer.instance().start();
|
void ClipperServer.instance().start();
|
||||||
}
|
}
|
||||||
@@ -70,6 +71,8 @@ class ClipperConfigScreenComponent extends React.Component {
|
|||||||
|
|
||||||
const webClipperStatusComps = [];
|
const webClipperStatusComps = [];
|
||||||
|
|
||||||
|
const clipperEnabled = ClipperServer.instance().enabled();
|
||||||
|
|
||||||
if (this.props.clipperServerAutoStart) {
|
if (this.props.clipperServerAutoStart) {
|
||||||
webClipperStatusComps.push(
|
webClipperStatusComps.push(
|
||||||
<p key="text_1" style={theme.textStyle}>
|
<p key="text_1" style={theme.textStyle}>
|
||||||
@@ -95,13 +98,22 @@ class ClipperConfigScreenComponent extends React.Component {
|
|||||||
</button>,
|
</button>,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
if (!clipperEnabled) {
|
||||||
|
webClipperStatusComps.push(
|
||||||
|
<p key="text_4" style={theme.textStyle}>
|
||||||
|
{_('The web clipper service cannot be enabled in this instance of Joplin.')}
|
||||||
|
</p>,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
webClipperStatusComps.push(
|
||||||
|
<p key="text_4" style={theme.textStyle}>
|
||||||
|
{_('The web clipper service is not enabled.')}
|
||||||
|
</p>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
webClipperStatusComps.push(
|
webClipperStatusComps.push(
|
||||||
<p key="text_4" style={theme.textStyle}>
|
<button key="enable_button" style={buttonStyle} onClick={this.enableClipperServer_click} disabled={!clipperEnabled}>
|
||||||
{_('The web clipper service is not enabled.')}
|
|
||||||
</p>,
|
|
||||||
);
|
|
||||||
webClipperStatusComps.push(
|
|
||||||
<button key="enable_button" style={buttonStyle} onClick={this.enableClipperServer_click}>
|
|
||||||
{_('Enable Web Clipper Service')}
|
{_('Enable Web Clipper Service')}
|
||||||
</button>,
|
</button>,
|
||||||
);
|
);
|
||||||
|
@@ -40,6 +40,7 @@ Logger.fsDriver_ = new FsDriverNode();
|
|||||||
const env = envFromArgs(process.argv);
|
const env = envFromArgs(process.argv);
|
||||||
const profileFromArgs = getProfileFromArgs(process.argv);
|
const profileFromArgs = getProfileFromArgs(process.argv);
|
||||||
const isDebugMode = !!process.argv && process.argv.indexOf('--debug') >= 0;
|
const isDebugMode = !!process.argv && process.argv.indexOf('--debug') >= 0;
|
||||||
|
const isAltInstance = !!process.argv && process.argv.indexOf('--is-alt-instance') >= 0;
|
||||||
|
|
||||||
// We initialize all these variables here because they are needed from the main process. They are
|
// We initialize all these variables here because they are needed from the main process. They are
|
||||||
// then passed to the renderer process via the bridge.
|
// then passed to the renderer process via the bridge.
|
||||||
@@ -65,7 +66,7 @@ void registerCustomProtocols();
|
|||||||
|
|
||||||
const initialCallbackUrl = process.argv.find((arg) => isCallbackUrl(arg));
|
const initialCallbackUrl = process.argv.find((arg) => isCallbackUrl(arg));
|
||||||
|
|
||||||
const wrapper = new ElectronAppWrapper(electronApp, env, rootProfileDir, isDebugMode, initialCallbackUrl);
|
const wrapper = new ElectronAppWrapper(electronApp, env, rootProfileDir, isDebugMode, initialCallbackUrl, isAltInstance);
|
||||||
|
|
||||||
initBridge(wrapper, appId, appName, rootProfileDir, autoUploadCrashDumps);
|
initBridge(wrapper, appId, appName, rootProfileDir, autoUploadCrashDumps);
|
||||||
|
|
||||||
|
@@ -21,7 +21,7 @@ const restartInSafeModeFromMain = async () => {
|
|||||||
shimInit({});
|
shimInit({});
|
||||||
|
|
||||||
const startFlags = await processStartFlags(bridge().processArgv());
|
const startFlags = await processStartFlags(bridge().processArgv());
|
||||||
const { rootProfileDir } = determineBaseAppDirs(startFlags.matched.profileDir, appName);
|
const { rootProfileDir } = determineBaseAppDirs(startFlags.matched.profileDir, appName, Setting.value('isAltInstance'));
|
||||||
const { profileDir } = await initProfile(rootProfileDir);
|
const { profileDir } = await initProfile(rootProfileDir);
|
||||||
|
|
||||||
// We can't access the database, so write to a file instead.
|
// We can't access the database, so write to a file instead.
|
||||||
|
@@ -687,7 +687,7 @@ export default class BaseApplication {
|
|||||||
// https://immerjs.github.io/immer/docs/freezing
|
// https://immerjs.github.io/immer/docs/freezing
|
||||||
setAutoFreeze(initArgs.env === 'dev');
|
setAutoFreeze(initArgs.env === 'dev');
|
||||||
|
|
||||||
const { rootProfileDir, homeDir } = determineProfileAndBaseDir(options.rootProfileDir ?? initArgs.profileDir, appName);
|
const { rootProfileDir, homeDir } = determineProfileAndBaseDir(options.rootProfileDir ?? initArgs.profileDir, appName, initArgs.isAltInstance);
|
||||||
const { profileDir, profileConfig, isSubProfile } = await initProfile(rootProfileDir);
|
const { profileDir, profileConfig, isSubProfile } = await initProfile(rootProfileDir);
|
||||||
this.profileConfig_ = profileConfig;
|
this.profileConfig_ = profileConfig;
|
||||||
|
|
||||||
@@ -806,6 +806,8 @@ export default class BaseApplication {
|
|||||||
Setting.setValue('sync.interval', 3600);
|
Setting.setValue('sync.interval', 3600);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Setting.setValue('isAltInstance', initArgs.isAltInstance);
|
||||||
|
|
||||||
Setting.setValue('firstStart', false);
|
Setting.setValue('firstStart', false);
|
||||||
} else {
|
} else {
|
||||||
Setting.applyDefaultMigrations();
|
Setting.applyDefaultMigrations();
|
||||||
|
@@ -23,6 +23,7 @@ export default class ClipperServer {
|
|||||||
private api_: Api = null;
|
private api_: Api = null;
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
||||||
private dispatch_: Function;
|
private dispatch_: Function;
|
||||||
|
private enabled_ = true;
|
||||||
|
|
||||||
private static instance_: ClipperServer = null;
|
private static instance_: ClipperServer = null;
|
||||||
|
|
||||||
@@ -40,6 +41,18 @@ export default class ClipperServer {
|
|||||||
return this.api_;
|
return this.api_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enabled() {
|
||||||
|
return this.enabled_;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setEnabled(v: boolean) {
|
||||||
|
this.enabled_ = v;
|
||||||
|
|
||||||
|
if (!this.enabled_ && this.isRunning()) {
|
||||||
|
void this.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
public initialize(actionApi: any = null) {
|
public initialize(actionApi: any = null) {
|
||||||
this.api_ = new Api(() => {
|
this.api_ = new Api(() => {
|
||||||
@@ -106,6 +119,8 @@ export default class ClipperServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async start() {
|
public async start() {
|
||||||
|
if (!this.enabled()) throw new Error('Cannot start clipper server because it is disabled');
|
||||||
|
|
||||||
this.setPort(null);
|
this.setPort(null);
|
||||||
|
|
||||||
this.setStartState(StartState.Starting);
|
this.setStartState(StartState.Starting);
|
||||||
@@ -251,8 +266,10 @@ export default class ClipperServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async stop() {
|
public async stop() {
|
||||||
this.server_.destroy();
|
if (this.server_) {
|
||||||
this.server_ = null;
|
this.server_.destroy();
|
||||||
|
this.server_ = null;
|
||||||
|
}
|
||||||
this.setStartState(StartState.Idle);
|
this.setStartState(StartState.Idle);
|
||||||
this.setPort(null);
|
this.setPort(null);
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { homedir } from 'os';
|
import { homedir } from 'os';
|
||||||
import { toSystemSlashes } from './path-utils';
|
import { toSystemSlashes } from './path-utils';
|
||||||
|
|
||||||
export default (profileFromArgs: string, appName: string) => {
|
export default (profileFromArgs: string, appName: string, isAltInstance: boolean) => {
|
||||||
let profileDir = '';
|
let profileDir = '';
|
||||||
let homeDir = '';
|
let homeDir = '';
|
||||||
|
|
||||||
@@ -12,7 +12,8 @@ export default (profileFromArgs: string, appName: string) => {
|
|||||||
profileDir = `${process.env.PORTABLE_EXECUTABLE_DIR}/JoplinProfile`;
|
profileDir = `${process.env.PORTABLE_EXECUTABLE_DIR}/JoplinProfile`;
|
||||||
homeDir = process.env.PORTABLE_EXECUTABLE_DIR;
|
homeDir = process.env.PORTABLE_EXECUTABLE_DIR;
|
||||||
} else {
|
} else {
|
||||||
profileDir = `${homedir()}/.config/${appName}`;
|
const suffix = isAltInstance ? '-alt' : '';
|
||||||
|
profileDir = `${homedir()}/.config/${appName}${suffix}`;
|
||||||
homeDir = homedir();
|
homeDir = homedir();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -62,6 +62,16 @@ const builtInMetadata = (Setting: typeof SettingType) => {
|
|||||||
type: SettingItemType.String,
|
type: SettingItemType.String,
|
||||||
public: false,
|
public: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'isAltInstance': {
|
||||||
|
value: false,
|
||||||
|
type: SettingItemType.Bool,
|
||||||
|
public: false,
|
||||||
|
appTypes: [AppType.Desktop],
|
||||||
|
storage: SettingStorage.File,
|
||||||
|
isGlobal: true,
|
||||||
|
},
|
||||||
|
|
||||||
'editor.codeView': {
|
'editor.codeView': {
|
||||||
value: true,
|
value: true,
|
||||||
type: SettingItemType.Bool,
|
type: SettingItemType.Bool,
|
||||||
|
@@ -13,6 +13,7 @@ export interface MatchedStartFlags {
|
|||||||
logLevel?: LogLevel;
|
logLevel?: LogLevel;
|
||||||
allowOverridingDnsResultOrder?: boolean;
|
allowOverridingDnsResultOrder?: boolean;
|
||||||
devPlugins?: string[];
|
devPlugins?: string[];
|
||||||
|
isAltInstance?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles the initial flags passed to main script and
|
// Handles the initial flags passed to main script and
|
||||||
@@ -181,6 +182,12 @@ const processStartFlags = async (argv: string[], setDefaults = true) => {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg === '--is-alt-instance') {
|
||||||
|
matched.isAltInstance = true;
|
||||||
|
argv.splice(0, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (arg.length && arg[0] === '-') {
|
if (arg.length && arg[0] === '-') {
|
||||||
throw new JoplinError(_('Unknown flag: %s', arg), 'flagError');
|
throw new JoplinError(_('Unknown flag: %s', arg), 'flagError');
|
||||||
} else {
|
} else {
|
||||||
|
@@ -89,6 +89,7 @@ export default function versionInfo(packageInfo: PackageInfo, plugins: Plugins)
|
|||||||
_('Sync Version: %s', Setting.value('syncVersion')),
|
_('Sync Version: %s', Setting.value('syncVersion')),
|
||||||
_('Profile Version: %s', reg.db().version()),
|
_('Profile Version: %s', reg.db().version()),
|
||||||
_('Keychain Supported: %s', keychainSupported ? _('Yes') : _('No')),
|
_('Keychain Supported: %s', keychainSupported ? _('Yes') : _('No')),
|
||||||
|
_('Is alternative instance: %s', Setting.value('isAltInstance') ? _('Yes') : _('No')),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (gitInfo) {
|
if (gitInfo) {
|
||||||
|
Reference in New Issue
Block a user