diff --git a/package.json b/package.json index 1e6584cd..68c7ec40 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "server:web": "lerna exec --scope uhk-web npm start", "server:electron": "lerna exec --scope uhk-web npm run server:renderer", "electron": "lerna exec --scope uhk-agent npm start", + "electron:auto-write-config": "lerna exec --scope uhk-agent npm run auto-write-config", "standard-version": "standard-version", "pack": "node ./scripts/release.js", "sprites": "node ./scripts/generate-svg-sprites", diff --git a/packages/uhk-agent/package.json b/packages/uhk-agent/package.json index d66ee79a..e05fe150 100644 --- a/packages/uhk-agent/package.json +++ b/packages/uhk-agent/package.json @@ -36,6 +36,7 @@ }, "scripts": { "start": "electron ./dist/electron-main.js", + "auto-write-config": "electron ./dist/electron-main.js --auto-write-config", "build": "webpack && npm run install:build-deps && npm run build:usb && npm run download-firmware && npm run copy-blhost", "build:usb": "electron-rebuild -w node-hid -p -m ./dist", "install:build-deps": "cd ./dist && npm i", diff --git a/packages/uhk-agent/src/electron-main.ts b/packages/uhk-agent/src/electron-main.ts index 41b9c426..347e4f72 100644 --- a/packages/uhk-agent/src/electron-main.ts +++ b/packages/uhk-agent/src/electron-main.ts @@ -10,7 +10,7 @@ import * as url from 'url'; import * as commandLineArgs from 'command-line-args'; import { UhkHidDevice, UhkOperations } from 'uhk-usb'; // import { ElectronDataStorageRepositoryService } from './services/electron-datastorage-repository.service'; -import { CommandLineArgs, LogRegExps } from 'uhk-common'; +import { LogRegExps } from 'uhk-common'; import { DeviceService } from './services/device.service'; import { logger } from './services/logger.service'; import { AppUpdateService } from './services/app-update.service'; @@ -18,12 +18,14 @@ import { AppService } from './services/app.service'; import { SudoService } from './services/sudo.service'; import { UhkBlhost } from '../../uhk-usb/src'; import * as isDev from 'electron-is-dev'; +import { CommandLineInputs } from './models/command-line-inputs'; const optionDefinitions = [ - {name: 'addons', type: Boolean, defaultOption: false} + {name: 'addons', type: Boolean}, + {name: 'auto-write-config', type: Boolean} ]; -const options: CommandLineArgs = commandLineArgs(optionDefinitions); +const options: CommandLineInputs = commandLineArgs(optionDefinitions); // import './dev-extension'; // require('electron-debug')({ showDevTools: true, enabled: true }); diff --git a/packages/uhk-agent/src/models/command-line-inputs.ts b/packages/uhk-agent/src/models/command-line-inputs.ts new file mode 100644 index 00000000..5443226d --- /dev/null +++ b/packages/uhk-agent/src/models/command-line-inputs.ts @@ -0,0 +1,4 @@ +export interface CommandLineInputs { + addons?: boolean; + 'auto-write-config'?: boolean; +} diff --git a/packages/uhk-agent/src/services/app.service.ts b/packages/uhk-agent/src/services/app.service.ts index 91b824d1..e0b7e986 100644 --- a/packages/uhk-agent/src/services/app.service.ts +++ b/packages/uhk-agent/src/services/app.service.ts @@ -3,19 +3,21 @@ import { UhkHidDevice } from 'uhk-usb'; import { readFile } from 'fs'; import { join } from 'path'; -import { AppStartInfo, CommandLineArgs, IpcEvents, LogService } from 'uhk-common'; +import { AppStartInfo, IpcEvents, LogService } from 'uhk-common'; import { MainServiceBase } from './main-service-base'; import { DeviceService } from './device.service'; +import { CommandLineInputs } from '../models/command-line-inputs'; export class AppService extends MainServiceBase { constructor(protected logService: LogService, protected win: Electron.BrowserWindow, private deviceService: DeviceService, - private options: CommandLineArgs, + private options: CommandLineInputs, private uhkHidDeviceService: UhkHidDevice) { super(logService, win); ipcMain.on(IpcEvents.app.getAppStartInfo, this.handleAppStartInfo.bind(this)); + ipcMain.on(IpcEvents.app.exit, this.exit.bind(this)); logService.info('[AppService] init success'); } @@ -25,7 +27,10 @@ export class AppService extends MainServiceBase { const packageJson = await this.getPackageJson(); const response: AppStartInfo = { - commandLineArgs: this.options, + commandLineArgs: { + addons: this.options.addons || false, + autoWriteConfig: this.options['auto-write-config'] || false + }, deviceConnected: this.deviceService.isConnected, hasPermission: this.uhkHidDeviceService.hasPermission(), agentVersionInfo: { @@ -57,4 +62,9 @@ export class AppService extends MainServiceBase { }); }); } + + private exit() { + this.logService.info('[AppService] exit'); + this.win.close(); + } } diff --git a/packages/uhk-agent/src/services/device.service.ts b/packages/uhk-agent/src/services/device.service.ts index 9c7cbd4e..70f9e4fb 100644 --- a/packages/uhk-agent/src/services/device.service.ts +++ b/packages/uhk-agent/src/services/device.service.ts @@ -89,7 +89,6 @@ export class DeviceService { success: true, ...result }; - event.sender.send(IpcEvents.device.loadConfigurationReply, JSON.stringify(response)); } catch (error) { response = { success: false, diff --git a/packages/uhk-common/src/models/command-line-args.ts b/packages/uhk-common/src/models/command-line-args.ts index 5c91f9ac..ca9df237 100644 --- a/packages/uhk-common/src/models/command-line-args.ts +++ b/packages/uhk-common/src/models/command-line-args.ts @@ -1,3 +1,4 @@ export interface CommandLineArgs { addons: boolean; + autoWriteConfig: boolean; } diff --git a/packages/uhk-common/src/util/ipcEvents.ts b/packages/uhk-common/src/util/ipcEvents.ts index 974aa895..0ce2a7d6 100644 --- a/packages/uhk-common/src/util/ipcEvents.ts +++ b/packages/uhk-common/src/util/ipcEvents.ts @@ -2,6 +2,7 @@ class App { public static readonly appStarted = 'app-started'; public static readonly getAppStartInfo = 'app-get-start-info'; public static readonly getAppStartInfoReply = 'app-get-start-info-reply'; + public static readonly exit = 'app-exit'; } class AutoUpdate { diff --git a/packages/uhk-web/src/app/services/app-renderer.service.ts b/packages/uhk-web/src/app/services/app-renderer.service.ts index 4e3809e4..bcb44b10 100644 --- a/packages/uhk-web/src/app/services/app-renderer.service.ts +++ b/packages/uhk-web/src/app/services/app-renderer.service.ts @@ -21,6 +21,11 @@ export class AppRendererService { this.ipcRenderer.send(IpcEvents.app.getAppStartInfo); } + exit() { + this.logService.info('[AppRendererService] exit'); + this.ipcRenderer.send(IpcEvents.app.exit); + } + private registerEvents() { this.ipcRenderer.on(IpcEvents.app.getAppStartInfoReply, (event: string, arg: AppStartInfo) => { this.dispachStoreAction(new ProcessAppStartInfoAction(arg)); diff --git a/packages/uhk-web/src/app/store/actions/app.ts b/packages/uhk-web/src/app/store/actions/app.ts index 8f090d90..5e79976c 100644 --- a/packages/uhk-web/src/app/store/actions/app.ts +++ b/packages/uhk-web/src/app/store/actions/app.ts @@ -1,6 +1,6 @@ import { Action } from '@ngrx/store'; -import { AppStartInfo, HardwareConfiguration, Notification, type, VersionInformation } from 'uhk-common'; +import { AppStartInfo, CommandLineArgs, HardwareConfiguration, Notification, type, VersionInformation } from 'uhk-common'; import { ElectronLogEntry } from '../../models/xterm-log'; const PREFIX = '[app] '; @@ -10,7 +10,7 @@ export const ActionTypes = { APP_BOOTSRAPPED: type(PREFIX + 'bootstrapped'), APP_STARTED: type(PREFIX + 'started'), APP_SHOW_NOTIFICATION: type(PREFIX + 'show notification'), - APP_TOGGLE_ADDON_MENU: type(PREFIX + 'toggle add-on menu'), + APPLY_COMMAND_LINE_ARGS: type(PREFIX + 'apply command line args'), APP_PROCESS_START_INFO: type(PREFIX + 'process start info'), UNDO_LAST: type(PREFIX + 'undo last action'), UNDO_LAST_SUCCESS: type(PREFIX + 'undo last action success'), @@ -34,10 +34,10 @@ export class ShowNotificationAction implements Action { constructor(public payload: Notification) { } } -export class ToggleAddonMenuAction implements Action { - type = ActionTypes.APP_TOGGLE_ADDON_MENU; +export class ApplyCommandLineArgsAction implements Action { + type = ActionTypes.APPLY_COMMAND_LINE_ARGS; - constructor(public payload: boolean) { } + constructor(public payload: CommandLineArgs) { } } export class ProcessAppStartInfoAction implements Action { @@ -82,7 +82,7 @@ export type Actions = AppStartedAction | AppBootsrappedAction | ShowNotificationAction - | ToggleAddonMenuAction + | ApplyCommandLineArgsAction | ProcessAppStartInfoAction | UndoLastAction | UndoLastSuccessAction diff --git a/packages/uhk-web/src/app/store/effects/app.ts b/packages/uhk-web/src/app/store/effects/app.ts index aa0237f8..1ab1cddd 100644 --- a/packages/uhk-web/src/app/store/effects/app.ts +++ b/packages/uhk-web/src/app/store/effects/app.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { Action } from '@ngrx/store'; +import { Action, Store } from '@ngrx/store'; import { Actions, Effect } from '@ngrx/effects'; import { Observable } from 'rxjs/Observable'; import { NotifierService } from 'angular-notifier'; @@ -13,16 +13,23 @@ import 'rxjs/add/operator/catch'; import { AppStartInfo, LogService, Notification, NotificationType } from 'uhk-common'; import { ActionTypes, + ApplyCommandLineArgsAction, AppStartedAction, DismissUndoNotificationAction, ProcessAppStartInfoAction, ShowNotificationAction, - ToggleAddonMenuAction, - UndoLastAction, UpdateAgentVersionInformationAction + UndoLastAction, + UpdateAgentVersionInformationAction } from '../actions/app'; import { AppRendererService } from '../../services/app-renderer.service'; import { AppUpdateRendererService } from '../../services/app-update-renderer.service'; -import { ConnectionStateChangedAction, PermissionStateChangedAction } from '../actions/device'; +import { + ActionTypes as DeviceActions, + ConnectionStateChangedAction, + PermissionStateChangedAction, + SaveToKeyboardSuccessAction +} from '../actions/device'; +import { AppState, autoWriteUserConfiguration } from '../index'; @Injectable() export class ApplicationEffects { @@ -56,7 +63,7 @@ export class ApplicationEffects { .mergeMap((appInfo: AppStartInfo) => { this.logService.debug('[AppEffect][processStartInfo] payload:', appInfo); return [ - new ToggleAddonMenuAction(appInfo.commandLineArgs.addons), + new ApplyCommandLineArgsAction(appInfo.commandLineArgs), new ConnectionStateChangedAction(appInfo.deviceConnected), new PermissionStateChangedAction(appInfo.hasPermission), new UpdateAgentVersionInformationAction(appInfo.agentVersionInfo) @@ -68,10 +75,20 @@ export class ApplicationEffects { .map(action => action.payload) .mergeMap((action: Action) => [action, new DismissUndoNotificationAction()]); + @Effect({dispatch: false}) saveToKeyboardSuccess$ = this.actions$ + .ofType(DeviceActions.SAVE_TO_KEYBOARD_SUCCESS) + .withLatestFrom(this.store.select(autoWriteUserConfiguration)) + .do(([action, autoWriteUserConfig]) => { + if (autoWriteUserConfig) { + this.appRendererService.exit(); + } + }); + constructor(private actions$: Actions, private notifierService: NotifierService, private appUpdateRendererService: AppUpdateRendererService, private appRendererService: AppRendererService, - private logService: LogService) { + private logService: LogService, + private store: Store) { } } diff --git a/packages/uhk-web/src/app/store/effects/device.ts b/packages/uhk-web/src/app/store/effects/device.ts index cf4f3db3..82f1ef45 100644 --- a/packages/uhk-web/src/app/store/effects/device.ts +++ b/packages/uhk-web/src/app/store/effects/device.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { Action, Store } from '@ngrx/store'; -import { Actions, Effect, toPayload } from '@ngrx/effects'; +import { Actions, Effect } from '@ngrx/effects'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/of'; @@ -20,6 +20,7 @@ import { HideSaveToKeyboardButton, PermissionStateChangedAction, SaveConfigurationAction, + SaveConfigurationReplyAction, SaveToKeyboardSuccessAction, SaveToKeyboardSuccessFailed, SetPrivilegeOnLinuxReplyAction, @@ -113,8 +114,8 @@ export class DeviceEffects { @Effect() saveConfigurationReply$: Observable = this.actions$ - .ofType(ActionTypes.SAVE_CONFIGURATION_REPLY) - .map(toPayload) + .ofType(ActionTypes.SAVE_CONFIGURATION_REPLY) + .map(action => action.payload) .mergeMap((response: IpcResponse) => { if (response.success) { return [ diff --git a/packages/uhk-web/src/app/store/effects/user-config.ts b/packages/uhk-web/src/app/store/effects/user-config.ts index 78c5eef4..f22e0357 100644 --- a/packages/uhk-web/src/app/store/effects/user-config.ts +++ b/packages/uhk-web/src/app/store/effects/user-config.ts @@ -12,35 +12,27 @@ import 'rxjs/add/operator/startWith'; import 'rxjs/add/operator/withLatestFrom'; import 'rxjs/add/operator/mergeMap'; import 'rxjs/add/observable/of'; +import 'rxjs/add/observable/empty'; import { - ConfigurationReply, - HardwareConfiguration, - LogService, - NotificationType, - UhkBuffer, + ConfigurationReply, HardwareConfiguration, LogService, NotificationType, UhkBuffer, UserConfiguration } from 'uhk-common'; import { - ActionTypes, - LoadConfigFromDeviceReplyAction, - LoadUserConfigSuccessAction, - RenameUserConfigurationAction, + ActionTypes, LoadConfigFromDeviceReplyAction, LoadUserConfigSuccessAction, RenameUserConfigurationAction, SaveUserConfigSuccessAction } from '../actions/user-config'; import { DataStorageRepositoryService } from '../../services/datastorage-repository.service'; import { DefaultUserConfigurationService } from '../../services/default-user-configuration.service'; -import { AppState, getPrevUserConfiguration, getUserConfiguration } from '../index'; +import { AppState, autoWriteUserConfiguration, getPrevUserConfiguration, getUserConfiguration } from '../index'; import { KeymapAction, KeymapActions, MacroAction, MacroActions } from '../actions'; import { - DismissUndoNotificationAction, - LoadHardwareConfigurationSuccessAction, - ShowNotificationAction, + DismissUndoNotificationAction, LoadHardwareConfigurationSuccessAction, ShowNotificationAction, UndoLastAction } from '../actions/app'; -import { ShowSaveToKeyboardButtonAction } from '../actions/device'; +import { SaveConfigurationAction, ShowSaveToKeyboardButtonAction } from '../actions/device'; import { DeviceRendererService } from '../../services/device-renderer.service'; import { UndoUserConfigData } from '../../models/undo-user-config-data'; @@ -193,6 +185,19 @@ export class UserConfigEffects { saveAs(blob, 'UserConfiguration.bin'); }); + @Effect() loadUserConfigurationSuccess$ = this.actions$ + .ofType(ActionTypes.LOAD_USER_CONFIG_SUCCESS) + .withLatestFrom(this.store.select(autoWriteUserConfiguration)) + .switchMap(([action, autoWriteUserConfig]) => { + this.logService.debug('[UserConfigEffect] LOAD_USER_CONFIG_SUCCESS', {autoWriteUserConfig}); + if (autoWriteUserConfig) { + return Observable.of(new SaveConfigurationAction()); + } + else { + return Observable.empty(); + } + }); + constructor(private actions$: Actions, private dataStorageRepository: DataStorageRepositoryService, private store: Store, diff --git a/packages/uhk-web/src/app/store/index.ts b/packages/uhk-web/src/app/store/index.ts index 77760338..07500fc1 100644 --- a/packages/uhk-web/src/app/store/index.ts +++ b/packages/uhk-web/src/app/store/index.ts @@ -43,6 +43,7 @@ export const getDeviceName = (state: AppState) => state.userConfiguration.device export const appState = (state: AppState) => state.app; export const showAddonMenu = createSelector(appState, fromApp.showAddonMenu); +export const autoWriteUserConfiguration = createSelector(appState, fromApp.autoWriteUserConfiguration); export const getUndoableNotification = createSelector(appState, fromApp.getUndoableNotification); export const getPrevUserConfiguration = createSelector(appState, fromApp.getPrevUserConfiguration); export const runningInElectron = createSelector(appState, fromApp.runningInElectron); diff --git a/packages/uhk-web/src/app/store/reducers/app.reducer.ts b/packages/uhk-web/src/app/store/reducers/app.reducer.ts index 69c314c9..d7b198d2 100644 --- a/packages/uhk-web/src/app/store/reducers/app.reducer.ts +++ b/packages/uhk-web/src/app/store/reducers/app.reducer.ts @@ -11,6 +11,7 @@ import { KeyboardLayout } from '../../keyboard/keyboard-layout.enum'; export interface State { started: boolean; showAddonMenu: boolean; + autoWriteUserConfiguration: boolean; undoableNotification?: Notification; navigationCountAfterNotification: number; prevUserConfig?: UserConfiguration; @@ -23,6 +24,7 @@ export interface State { export const initialState: State = { started: false, showAddonMenu: false, + autoWriteUserConfiguration: false, navigationCountAfterNotification: 0, runningInElectron: runInElectron(), configLoading: true @@ -37,10 +39,11 @@ export function reducer(state = initialState, action: Action & { payload: any }) }; } - case ActionTypes.APP_TOGGLE_ADDON_MENU: { + case ActionTypes.APPLY_COMMAND_LINE_ARGS: { return { ...state, - showAddonMenu: action.payload + showAddonMenu: action.payload.addons, + autoWriteUserConfiguration: action.payload.autoWriteConfig }; } @@ -124,6 +127,7 @@ export function reducer(state = initialState, action: Action & { payload: any }) } export const showAddonMenu = (state: State) => state.showAddonMenu; +export const autoWriteUserConfiguration = (state: State) => state.autoWriteUserConfiguration; export const getUndoableNotification = (state: State) => state.undoableNotification; export const getPrevUserConfiguration = (state: State) => state.prevUserConfig; export const runningInElectron = (state: State) => state.runningInElectron;