@velor/remote-mouse 6.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.artifacts/screenshots/remote-mobile-config.png +0 -0
- package/.artifacts/screenshots/remote-mobile-home.png +0 -0
- package/.artifacts/screenshots/remote-mobile-preferences.png +0 -0
- package/.artifacts/screenshots/remote-mobile-server-info.png +0 -0
- package/.artifacts/screenshots/remote-mobile-vlc.png +0 -0
- package/.env.example +93 -0
- package/README.md +370 -0
- package/bin/remote-mouse.js +19 -0
- package/client/core/dom.js +148 -0
- package/client/core/init-socket-io.js +117 -0
- package/client/core/socket-emit.js +6 -0
- package/client/core/window-events.js +23 -0
- package/client/i18n/apply-page-translations.js +18 -0
- package/client/i18n/constants.js +3 -0
- package/client/i18n/core.js +40 -0
- package/client/i18n/locale-registry.js +77 -0
- package/client/i18n/locales/de.js +227 -0
- package/client/i18n/locales/en.js +389 -0
- package/client/i18n/locales/es.js +228 -0
- package/client/i18n/locales/fr.js +389 -0
- package/client/i18n/locales/it.js +227 -0
- package/client/i18n/locales/ja.js +227 -0
- package/client/i18n/locales/pt.js +227 -0
- package/client/i18n/locales/ru.js +240 -0
- package/client/i18n/locales/zh.js +227 -0
- package/client/preferences/constants.js +15 -0
- package/client/preferences/effects.js +24 -0
- package/client/preferences/load.js +19 -0
- package/client/preferences/render.js +26 -0
- package/client/preferences/rows.js +78 -0
- package/client/preferences/state.js +29 -0
- package/client/preview/create-preview-frame-receiver.js +13 -0
- package/client/preview/draw.js +77 -0
- package/client/preview/parse-preview-frame.js +39 -0
- package/client/preview/preview-stream.js +152 -0
- package/client/services/app-state/appStateKeys.js +30 -0
- package/client/services/app-state/createAppStateService.js +216 -0
- package/client/services/app-state/createPersistStoreService.js +122 -0
- package/client/services/app-state/createStateStoreService.js +64 -0
- package/client/services/app-state/localStorageBinding.js +26 -0
- package/client/services/app-state/normalizers.js +74 -0
- package/client/services/app-state/resolveEffectiveStateValue.js +58 -0
- package/client/services/app-state/stateDefinitions.js +107 -0
- package/client/services/backend/createBackendService.js +55 -0
- package/client/services/config/ConfigView.js +45 -0
- package/client/services/config/createClientConfigService.js +122 -0
- package/client/services/config/defaultClientConfig.js +22 -0
- package/client/services/createServicesContainer.js +48 -0
- package/client/services/createServicesRegistry.js +26 -0
- package/client/services/i18n/createI18nService.js +86 -0
- package/client/services/notifications/createNotificationService.js +56 -0
- package/client/services/pubsub/createPubSubService.js +20 -0
- package/client/services/remotes/createRemotesService.js +20 -0
- package/client/services/transport/createSocketIoTransportService.js +50 -0
- package/client/touch/bindTouchPassthrough.js +94 -0
- package/client/touch/createTouchList.js +18 -0
- package/client/touch/dispatchSyntheticTouch.js +20 -0
- package/client/touch/gesture-zone.js +28 -0
- package/client/touch/throttle.js +46 -0
- package/client/touch/touch-handlers.js +193 -0
- package/client/touch/touchpad.js +231 -0
- package/client/ui/config/page.js +840 -0
- package/client/ui/main/applyRemoteVisibilityState.js +60 -0
- package/client/ui/main/bind-client-notifications.js +3 -0
- package/client/ui/main/bindings/bindAccordion.js +121 -0
- package/client/ui/main/bindings/bindActionButtons.js +13 -0
- package/client/ui/main/bindings/bindAdminDrawer.js +137 -0
- package/client/ui/main/bindings/bindAdminRemoteButtons.js +77 -0
- package/client/ui/main/bindings/bindAdminVersion.js +27 -0
- package/client/ui/main/bindings/bindBrowserRemoteButtons.js +119 -0
- package/client/ui/main/bindings/bindRemoteAccordion.js +23 -0
- package/client/ui/main/bindings/bindSamsungRemoteButtons.js +320 -0
- package/client/ui/main/bindings/bindSystemRemoteButtons.js +41 -0
- package/client/ui/main/bindings/bindVlcRemoteButtons.js +64 -0
- package/client/ui/main/canvas-ui.js +33 -0
- package/client/ui/main/connection-overlay.js +57 -0
- package/client/ui/main/init-ui.js +54 -0
- package/client/ui/main/keyboard-panel.js +271 -0
- package/client/ui/main/mouse-buttons.js +94 -0
- package/client/ui/main/page.js +21 -0
- package/client/ui/notifications/show-toast.js +48 -0
- package/client/ui/preferences/bindPreferenceSwitchers.js +49 -0
- package/client/ui/preferences/page.js +61 -0
- package/client/ui/preferences/switchers.js +200 -0
- package/index.js +9 -0
- package/package.json +41 -0
- package/public/admin-config.css +447 -0
- package/public/admin-config.html +63 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/brave-icon.svg +13 -0
- package/public/favicon.svg +30 -0
- package/public/icon-192.png +0 -0
- package/public/icon-512.png +0 -0
- package/public/index.html +246 -0
- package/public/manifest.webmanifest +45 -0
- package/public/preferences.html +55 -0
- package/public/server-info.html +574 -0
- package/public/styles.css +1042 -0
- package/public/sw.js +103 -0
- package/scripts/codex-commit.sh +112 -0
- package/scripts/generate-mobile-screenshots.mjs +244 -0
- package/scripts/install-linux.sh +633 -0
- package/scripts/install-windows.ps1 +369 -0
- package/server/application/createApplicationLifecycle.js +15 -0
- package/server/application/logger.js +216 -0
- package/server/application/shutdown.js +81 -0
- package/server/application/start.js +95 -0
- package/server/application/state.js +19 -0
- package/server/connection/api/admin-actions.router.js +65 -0
- package/server/connection/api/admin-configs.router.js +165 -0
- package/server/connection/api/admin-remotes.router.js +61 -0
- package/server/connection/api/admin-subs.router.js +49 -0
- package/server/connection/api/client.router.js +15 -0
- package/server/connection/api/configs.js +96 -0
- package/server/connection/api/qr-page.handler.js +17 -0
- package/server/connection/api/remotes.router.js +30 -0
- package/server/connection/api/server-info.router.js +149 -0
- package/server/connection/api/session.middleware.js +93 -0
- package/server/connection/api/unauthorized-response.js +73 -0
- package/server/connection/socket/createConnectionRegistrar.js +23 -0
- package/server/connection/socket/createSocketSessionAuthMiddleware.js +49 -0
- package/server/connection/socket/socket-action-responder.js +12 -0
- package/server/connection/socket/socket.timestamp-middleware.js +51 -0
- package/server/index.js +12 -0
- package/server/init/bootstrapApi.js +87 -0
- package/server/init/bootstrapSocket.js +79 -0
- package/server/init/createAdminApiRouter.js +22 -0
- package/server/init/createAdminUiRouter.js +21 -0
- package/server/init/createSocketActionRegistrars.js +52 -0
- package/server/init/observers/startConfigObserver.js +51 -0
- package/server/init/observers/startDisplaySizeObserver.js +55 -0
- package/server/init/observers/startNotificationObserver.js +49 -0
- package/server/init/observers/startQrOverlayHoverObserver.js +89 -0
- package/server/init/observers/startQrOverlayRefreshObserver.js +53 -0
- package/server/os/darwin/app.js +45 -0
- package/server/os/darwin/applescript.js +51 -0
- package/server/os/darwin/cliSocket.js +53 -0
- package/server/os/darwin/url.js +9 -0
- package/server/os/darwin/window.js +10 -0
- package/server/os/linux/app.js +120 -0
- package/server/os/linux/cliSocket.js +53 -0
- package/server/os/linux/process.js +69 -0
- package/server/os/linux/screen.js +58 -0
- package/server/os/linux/systemd.js +139 -0
- package/server/os/linux/url.js +17 -0
- package/server/os/linux/windows.js +144 -0
- package/server/os/win32/app.js +66 -0
- package/server/os/win32/cliSocket.js +15 -0
- package/server/os/win32/powershell.js +70 -0
- package/server/os/win32/process.js +20 -0
- package/server/os/win32/service.js +95 -0
- package/server/os/win32/url.js +9 -0
- package/server/os/win32/window.js +10 -0
- package/server/remotes/admin/createAdminEventGuardMiddleware.js +29 -0
- package/server/remotes/admin/createForceUpdateCheckAction.js +39 -0
- package/server/remotes/admin/createInstallUpdateAction.js +64 -0
- package/server/remotes/admin/createOpenQrBrowserAction.js +63 -0
- package/server/remotes/admin/createOpenServerInfoBrowserAction.js +58 -0
- package/server/remotes/admin/createRestartServiceAction.js +20 -0
- package/server/remotes/admin/createRotateEntryTokenAction.js +43 -0
- package/server/remotes/admin/createToggleQrOverlayAction.js +38 -0
- package/server/remotes/admin/index.js +32 -0
- package/server/remotes/admin/notifyIfRestarted.js +102 -0
- package/server/remotes/admin/registrar.js +94 -0
- package/server/remotes/browser/actions/createFocusOrLaunchBrowserAction.js +22 -0
- package/server/remotes/browser/actions/openUrlOnHost.js +3 -0
- package/server/remotes/browser/browserCatalog.js +70 -0
- package/server/remotes/browser/index.js +15 -0
- package/server/remotes/browser/listBrowsersOnHost.js +23 -0
- package/server/remotes/browser/registrar.js +29 -0
- package/server/remotes/browser/spec.js +18 -0
- package/server/remotes/browser/state.js +5 -0
- package/server/remotes/input/registrar.js +39 -0
- package/server/remotes/preview/bgraToRgbaBuffer.js +20 -0
- package/server/remotes/preview/captureAroundCursor.js +19 -0
- package/server/remotes/preview/createPreviewStreamer.js +85 -0
- package/server/remotes/preview/registrar.js +34 -0
- package/server/remotes/samsung/createSamsungCommandService.js +203 -0
- package/server/remotes/samsung/createSamsungRemote.js +26 -0
- package/server/remotes/samsung/createSamsungRemoteGetter.js +46 -0
- package/server/remotes/samsung/createSamsungTvGetter.js +102 -0
- package/server/remotes/samsung/device-config.js +122 -0
- package/server/remotes/samsung/registrar.js +59 -0
- package/server/remotes/samsung/utils.js +56 -0
- package/server/remotes/vlc/index.js +39 -0
- package/server/remotes/vlc/registrar.js +94 -0
- package/server/remotes/vlc/spec.js +15 -0
- package/server/remotes/vlc/state.js +5 -0
- package/server/remotes/window/index.js +6 -0
- package/server/remotes/window/registrar.js +28 -0
- package/server/services/application/createApplicationDaemonService.js +144 -0
- package/server/services/application/getDaemonServiceAdapter.js +56 -0
- package/server/services/application/utils.js +29 -0
- package/server/services/config/bootstrapConfig.js +38 -0
- package/server/services/config/configPaths.js +42 -0
- package/server/services/config/configSchema.js +297 -0
- package/server/services/config/configService.js +89 -0
- package/server/services/config/defaultConfig.js +137 -0
- package/server/services/config/envConfig.js +49 -0
- package/server/services/config/index.js +9 -0
- package/server/services/config/logConfig.js +54 -0
- package/server/services/config/system-config.js +44 -0
- package/server/services/createServicesContainer.js +94 -0
- package/server/services/createServicesRegistry.js +48 -0
- package/server/services/input/createInputController.js +17 -0
- package/server/services/input/createKeyboardController.js +146 -0
- package/server/services/input/createMouseController.js +182 -0
- package/server/services/notifier/createClientNotifier.js +23 -0
- package/server/services/notifier/createHostNotifier.js +41 -0
- package/server/services/notifier/createNotifier.js +13 -0
- package/server/services/notifier/createNotifierComposite.js +122 -0
- package/server/services/notifier/handleOpenQrBrowserEvent.js +40 -0
- package/server/services/notifier/handleOpenServerInfoBrowserEvent.js +40 -0
- package/server/services/notifier/handleRestartServiceEvent.js +37 -0
- package/server/services/notifier/handleRotateEntryTokenEvent.js +42 -0
- package/server/services/notifier/handleSessionEvent.js +24 -0
- package/server/services/notifier/handleToggleQrOverlayEvent.js +21 -0
- package/server/services/notifier/host-notifier/createLinuxHostNotifier.js +23 -0
- package/server/services/notifier/host-notifier/createNodeNotifierHostNotifier.js +24 -0
- package/server/services/notifier/host-notifier/index.js +11 -0
- package/server/services/notifier/mapper/handleForceUpdateCheckEvent.js +24 -0
- package/server/services/notifier/mapper/handleInstallUpdateEvent.js +53 -0
- package/server/services/notifier/mapper/handleSocketEvent.js +40 -0
- package/server/services/notifier/mapper/handleUpdateManagerEvent.js +24 -0
- package/server/services/notifier/mapper/notify.js +7 -0
- package/server/services/os/index.js +23 -0
- package/server/services/os/platforms/createFallbackAdapter.js +31 -0
- package/server/services/os/platforms/darwin/app.js +6 -0
- package/server/services/os/platforms/darwin/index.js +21 -0
- package/server/services/os/platforms/darwin/scripts.js +4 -0
- package/server/services/os/platforms/darwin/url.js +1 -0
- package/server/services/os/platforms/darwin/window.js +4 -0
- package/server/services/os/platforms/linux/app.js +6 -0
- package/server/services/os/platforms/linux/index.js +33 -0
- package/server/services/os/platforms/linux/url.js +1 -0
- package/server/services/os/platforms/linux/windows.js +11 -0
- package/server/services/os/platforms/win32/app.js +6 -0
- package/server/services/os/platforms/win32/index.js +21 -0
- package/server/services/os/platforms/win32/overlay.js +6 -0
- package/server/services/os/platforms/win32/powershell.js +4 -0
- package/server/services/os/platforms/win32/url.js +1 -0
- package/server/services/os/platforms/win32/window.js +4 -0
- package/server/services/os/shared.js +2 -0
- package/server/services/overlay/createNoopOverlay.js +13 -0
- package/server/services/overlay/createQrOverlay.js +27 -0
- package/server/services/overlay/createQrOverlayWin32.js +158 -0
- package/server/services/overlay/createQrOverlayYad.js +178 -0
- package/server/services/overlay/renderQrPage.js +82 -0
- package/server/services/persistence/createConfigDao.js +106 -0
- package/server/services/persistence/createDatabaseProvider.js +23 -0
- package/server/services/persistence/createEntryTokenDao.js +140 -0
- package/server/services/persistence/createRestartLogDao.js +210 -0
- package/server/services/persistence/index.js +19 -0
- package/server/services/pubsub/createEventStore.js +54 -0
- package/server/services/pubsub/createPubSub.js +89 -0
- package/server/services/pubsub/createServiceEvents.js +29 -0
- package/server/services/pubsub/serviceEventConstants.js +39 -0
- package/server/services/remotes/createRemotes.js +25 -0
- package/server/services/server/createHttpsServer.js +12 -0
- package/server/services/server/createServer.js +66 -0
- package/server/services/sse/createSseService.js +96 -0
- package/server/services/sse/utils.js +7 -0
- package/server/services/system/createSystemService.js +170 -0
- package/server/services/system/getNetworkInfo.js +18 -0
- package/server/services/system/getScreenInfo.js +32 -0
- package/server/services/system/listNetworkInterfaces.js +27 -0
- package/server/services/task-manager/createTaskManager.js +68 -0
- package/server/services/task-runner/createTaskRunner.js +114 -0
- package/server/services/token-manager/createTokenManager.js +244 -0
- package/server/services/token-manager/token-format.js +7 -0
- package/server/services/token-manager/token-store-utils.js +8 -0
- package/server/services/update-manager/CommandUpdateSource.js +70 -0
- package/server/services/update-manager/NpmUpdateSource.js +34 -0
- package/server/services/update-manager/buildNpmGlobalUpdateCommand.js +15 -0
- package/server/services/update-manager/chooseUpdateCheckSource.js +20 -0
- package/server/services/update-manager/chooseUpdateInstallSource.js +5 -0
- package/server/services/update-manager/createUpdateManager.js +109 -0
- package/server/services/update-manager/resolveInstallUpdateCommand.js +42 -0
- package/server/term/cli/executeLocalServiceCommand.js +42 -0
- package/server/term/cli/getCliSocketPath.js +5 -0
- package/server/term/cli/parseCliArgs.js +110 -0
- package/server/term/cli/printCliResult.js +18 -0
- package/server/term/cli/runCliCmd.js +50 -0
- package/server/term/cli/sendCliCommand.js +76 -0
- package/server/term/cliSocket.js +29 -0
- package/server/term/srv/commands/configCommand.js +84 -0
- package/server/term/srv/commands/helpCommand.js +6 -0
- package/server/term/srv/commands/infoCommand.js +7 -0
- package/server/term/srv/commands/openQrCommand.js +7 -0
- package/server/term/srv/commands/samsungDetectCommand.js +52 -0
- package/server/term/srv/commands/serviceCommand.js +25 -0
- package/server/term/srv/commands/systemConfigCommand.js +7 -0
- package/server/term/srv/commands/tasksCommand.js +24 -0
- package/server/term/srv/commands/tokensCommand.js +15 -0
- package/server/term/srv/executeCliCommand.js +44 -0
- package/server/term/srv/executeCliRequest.js +38 -0
- package/server/term/srv/startCliServer.js +140 -0
- package/server/utils/createRandomToken.js +11 -0
- package/server/utils/env.js +155 -0
- package/server/utils/git.js +13 -0
- package/server/utils/http.js +7 -0
- package/server/utils/network.js +45 -0
- package/server/utils/paths.js +10 -0
- package/server/utils/process.js +57 -0
- package/server/utils/robot.js +11 -0
- package/server/utils/semver.js +33 -0
- package/server/utils/truncateText.js +7 -0
- package/utils/createLazy.js +13 -0
- package/utils/functional.js +48 -0
- package/utils/math.js +26 -0
- package/utils/notificationSettings.js +61 -0
- package/utils/object.utils.js +79 -0
- package/utils/predicates.js +17 -0
- package/utils/remoteCommands.js +40 -0
- package/utils/sync.js +3 -0
- package/velor-remote-mouse-6.4.8.tgz +0 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
[CmdletBinding()]
|
|
2
|
+
param(
|
|
3
|
+
[Alias('y')]
|
|
4
|
+
[switch]$Yes,
|
|
5
|
+
|
|
6
|
+
[string]$PackageName = $env:REMOTE_MOUSE_NPM_PACKAGE,
|
|
7
|
+
|
|
8
|
+
[string]$ConfigDir = $env:REMOTE_MOUSE_CONFIG_DIR,
|
|
9
|
+
|
|
10
|
+
[int]$Port = $(if ($env:REMOTE_MOUSE_PORT) { [int]$env:REMOTE_MOUSE_PORT } else { 3000 }),
|
|
11
|
+
|
|
12
|
+
[switch]$Https,
|
|
13
|
+
|
|
14
|
+
[switch]$NoHttps,
|
|
15
|
+
|
|
16
|
+
[switch]$GenerateCert,
|
|
17
|
+
|
|
18
|
+
[switch]$NoGenerateCert,
|
|
19
|
+
|
|
20
|
+
[string]$SslKeyPath = $env:REMOTE_MOUSE_SSL_KEY_PATH,
|
|
21
|
+
|
|
22
|
+
[string]$SslCertPath = $env:REMOTE_MOUSE_SSL_CERT_PATH,
|
|
23
|
+
|
|
24
|
+
[switch]$InstallService,
|
|
25
|
+
|
|
26
|
+
[switch]$NoService
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
$ErrorActionPreference = 'Stop'
|
|
30
|
+
|
|
31
|
+
function Get-DefaultPackageName {
|
|
32
|
+
$fallback = '@velor/remote-mouse'
|
|
33
|
+
if ([string]::IsNullOrWhiteSpace($PSCommandPath)) {
|
|
34
|
+
return $fallback
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
$scriptDir = Split-Path -Parent $PSCommandPath
|
|
38
|
+
$projectRoot = Split-Path -Parent $scriptDir
|
|
39
|
+
$packageJsonPath = Join-Path $projectRoot 'package.json'
|
|
40
|
+
|
|
41
|
+
if (Test-Path -LiteralPath $packageJsonPath) {
|
|
42
|
+
try {
|
|
43
|
+
$packageJson = Get-Content -LiteralPath $packageJsonPath -Raw | ConvertFrom-Json
|
|
44
|
+
if ($packageJson.name) {
|
|
45
|
+
return [string]$packageJson.name
|
|
46
|
+
}
|
|
47
|
+
} catch {
|
|
48
|
+
return $fallback
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return $fallback
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if ([string]::IsNullOrWhiteSpace($PackageName)) {
|
|
56
|
+
$PackageName = Get-DefaultPackageName
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if ([string]::IsNullOrWhiteSpace($ConfigDir)) {
|
|
60
|
+
$ConfigDir = Join-Path $env:APPDATA 'remote-mouse'
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function Write-Step {
|
|
64
|
+
param([string]$Message)
|
|
65
|
+
Write-Host ''
|
|
66
|
+
Write-Host $Message
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function Confirm-Step {
|
|
70
|
+
param([string]$Prompt)
|
|
71
|
+
|
|
72
|
+
if ($Yes) {
|
|
73
|
+
Write-Host "$Prompt [Y/n] y"
|
|
74
|
+
return $true
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
$answer = Read-Host "$Prompt [y/N]"
|
|
78
|
+
return $answer -match '^(y|yes)$'
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function Read-Value {
|
|
82
|
+
param(
|
|
83
|
+
[string]$Prompt,
|
|
84
|
+
[string]$DefaultValue = ''
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if ($Yes) {
|
|
88
|
+
Write-Host "$Prompt [$DefaultValue] $DefaultValue"
|
|
89
|
+
return $DefaultValue
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if ($DefaultValue) {
|
|
93
|
+
$value = Read-Host "$Prompt [$DefaultValue]"
|
|
94
|
+
if ([string]::IsNullOrWhiteSpace($value)) {
|
|
95
|
+
return $DefaultValue
|
|
96
|
+
}
|
|
97
|
+
return $value
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return Read-Host $Prompt
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function Test-Command {
|
|
104
|
+
param([string]$Name)
|
|
105
|
+
return [bool](Get-Command $Name -ErrorAction SilentlyContinue)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function Install-WithWinget {
|
|
109
|
+
param(
|
|
110
|
+
[string]$PackageId,
|
|
111
|
+
[string]$Label
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
if (-not (Test-Command 'winget')) {
|
|
115
|
+
throw "Missing $Label and winget is not available. Install $Label manually, then rerun this script."
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (Confirm-Step "Install $Label with winget?") {
|
|
119
|
+
winget install --id $PackageId --exact --accept-package-agreements --accept-source-agreements
|
|
120
|
+
} else {
|
|
121
|
+
throw "Cannot continue without $Label."
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function Ensure-Node {
|
|
126
|
+
$missingNode = -not (Test-Command 'node')
|
|
127
|
+
$missingNpm = -not (Test-Command 'npm')
|
|
128
|
+
|
|
129
|
+
if (-not $missingNode -and -not $missingNpm) {
|
|
130
|
+
Write-Step "Node: $(node --version)"
|
|
131
|
+
Write-Step "npm: $(npm --version)"
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if ($missingNode) {
|
|
136
|
+
Write-Warning 'node was not found in PATH.'
|
|
137
|
+
}
|
|
138
|
+
if ($missingNpm) {
|
|
139
|
+
Write-Warning 'npm was not found in PATH.'
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
Install-WithWinget -PackageId 'OpenJS.NodeJS.LTS' -Label 'Node.js LTS'
|
|
143
|
+
|
|
144
|
+
if (-not (Test-Command 'node') -or -not (Test-Command 'npm')) {
|
|
145
|
+
throw 'Node.js was installed, but node/npm are still not available in this terminal. Open a new terminal and rerun this script.'
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function Ensure-BuildTools {
|
|
150
|
+
if (Test-Command 'cl') {
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
Write-Warning 'Microsoft C++ build tools were not found in PATH.'
|
|
155
|
+
if (Test-Command 'winget') {
|
|
156
|
+
if (Confirm-Step 'Install Microsoft Visual Studio Build Tools with winget?') {
|
|
157
|
+
winget install --id Microsoft.VisualStudio.2022.BuildTools --exact --accept-package-agreements --accept-source-agreements --override '--quiet --wait --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended'
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
Write-Warning 'Native npm modules may require Microsoft C++ Build Tools. Install them manually if npm install fails.'
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function Ensure-Python {
|
|
166
|
+
if (Test-Command 'python') {
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (Test-Command 'py') {
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
Write-Warning 'Python was not found in PATH.'
|
|
175
|
+
if (Test-Command 'winget') {
|
|
176
|
+
if (Confirm-Step 'Install Python with winget?') {
|
|
177
|
+
winget install --id Python.Python.3.12 --exact --accept-package-agreements --accept-source-agreements
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
Write-Warning 'Native npm modules may require Python. Install it manually if npm install fails.'
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function Ensure-PowerShell {
|
|
186
|
+
if ($PSVersionTable.PSVersion.Major -lt 5) {
|
|
187
|
+
throw 'PowerShell 5 or newer is required.'
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function Install-NpmPackage {
|
|
192
|
+
Write-Step "Installing npm package: $PackageName"
|
|
193
|
+
npm install -g $PackageName
|
|
194
|
+
|
|
195
|
+
if (-not (Test-Command 'remote-mouse')) {
|
|
196
|
+
throw 'remote-mouse CLI was not found in PATH after npm installation. Open a new terminal or check npm global bin path with: npm prefix -g'
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function New-CookieSecret {
|
|
201
|
+
$bytes = New-Object byte[] 32
|
|
202
|
+
$rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()
|
|
203
|
+
try {
|
|
204
|
+
$rng.GetBytes($bytes)
|
|
205
|
+
return -join ($bytes | ForEach-Object { $_.ToString('x2') })
|
|
206
|
+
} finally {
|
|
207
|
+
$rng.Dispose()
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function Configure-Https {
|
|
212
|
+
$config = @{
|
|
213
|
+
Https = 'false'
|
|
214
|
+
KeyPath = ''
|
|
215
|
+
CertPath = ''
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if ($NoHttps) {
|
|
219
|
+
return $config
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (-not $Https -and -not (Confirm-Step 'Serve Remote Mouse over HTTPS?')) {
|
|
223
|
+
return $config
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
$config.Https = 'true'
|
|
227
|
+
$certDir = Join-Path $ConfigDir 'certs'
|
|
228
|
+
|
|
229
|
+
if ($GenerateCert -or (-not $NoGenerateCert -and (Confirm-Step 'Generate a local self-signed certificate?'))) {
|
|
230
|
+
New-Item -ItemType Directory -Force -Path $certDir | Out-Null
|
|
231
|
+
$cert = New-SelfSignedCertificate `
|
|
232
|
+
-DnsName @('localhost', 'remote-mouse.local') `
|
|
233
|
+
-CertStoreLocation 'Cert:\CurrentUser\My' `
|
|
234
|
+
-KeyAlgorithm RSA `
|
|
235
|
+
-KeyLength 2048 `
|
|
236
|
+
-KeyExportPolicy Exportable `
|
|
237
|
+
-NotAfter (Get-Date).AddYears(1)
|
|
238
|
+
|
|
239
|
+
$pfxPath = Join-Path $certDir 'remote-mouse.pfx'
|
|
240
|
+
$password = ConvertTo-SecureString -String (New-CookieSecret) -AsPlainText -Force
|
|
241
|
+
Export-PfxCertificate -Cert $cert -FilePath $pfxPath -Password $password | Out-Null
|
|
242
|
+
|
|
243
|
+
if (-not (Test-Command 'openssl')) {
|
|
244
|
+
Install-WithWinget -PackageId 'ShiningLight.OpenSSL' -Label 'OpenSSL'
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
$keyPath = Join-Path $certDir 'remote-mouse.key'
|
|
248
|
+
$certPath = Join-Path $certDir 'remote-mouse.crt'
|
|
249
|
+
$plainPassword = (New-Object System.Net.NetworkCredential('', $password)).Password
|
|
250
|
+
openssl pkcs12 -in $pfxPath -nocerts -nodes -out $keyPath -passin "pass:$plainPassword"
|
|
251
|
+
openssl pkcs12 -in $pfxPath -clcerts -nokeys -out $certPath -passin "pass:$plainPassword"
|
|
252
|
+
|
|
253
|
+
$config.KeyPath = $keyPath
|
|
254
|
+
$config.CertPath = $certPath
|
|
255
|
+
return $config
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
$keyPathInput = $SslKeyPath
|
|
259
|
+
if ([string]::IsNullOrWhiteSpace($keyPathInput)) {
|
|
260
|
+
$keyPathInput = Read-Value 'Path to the existing PEM private key'
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
$certPathInput = $SslCertPath
|
|
264
|
+
if ([string]::IsNullOrWhiteSpace($certPathInput)) {
|
|
265
|
+
$certPathInput = Read-Value 'Path to the existing PEM certificate'
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (-not (Test-Path -LiteralPath $keyPathInput)) {
|
|
269
|
+
throw "Private key not found: $keyPathInput"
|
|
270
|
+
}
|
|
271
|
+
if (-not (Test-Path -LiteralPath $certPathInput)) {
|
|
272
|
+
throw "Certificate not found: $certPathInput"
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
$config.KeyPath = $keyPathInput
|
|
276
|
+
$config.CertPath = $certPathInput
|
|
277
|
+
return $config
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function Write-EnvFile {
|
|
281
|
+
param([hashtable]$HttpsConfig)
|
|
282
|
+
|
|
283
|
+
New-Item -ItemType Directory -Force -Path $ConfigDir | Out-Null
|
|
284
|
+
$envFile = Join-Path $ConfigDir '.env'
|
|
285
|
+
|
|
286
|
+
if (Test-Path -LiteralPath $envFile) {
|
|
287
|
+
if (-not (Confirm-Step "Overwrite existing $envFile?")) {
|
|
288
|
+
Write-Step "Keeping existing $envFile."
|
|
289
|
+
return
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
$cookieSecret = New-CookieSecret
|
|
294
|
+
$dbPath = Join-Path $ConfigDir 'remote-mouse.sqlite3'
|
|
295
|
+
$content = @"
|
|
296
|
+
PORT=$Port
|
|
297
|
+
SERVER_HOST=
|
|
298
|
+
CONFIG_DIR=$ConfigDir
|
|
299
|
+
PERSISTENCE_DB_PATH=$dbPath
|
|
300
|
+
ENV_FILE_PATH=$envFile
|
|
301
|
+
|
|
302
|
+
HTTPS=$($HttpsConfig.Https)
|
|
303
|
+
SSL_KEY_PATH=$($HttpsConfig.KeyPath)
|
|
304
|
+
SSL_CERT_PATH=$($HttpsConfig.CertPath)
|
|
305
|
+
|
|
306
|
+
ENTRY_PATH_ENABLED=true
|
|
307
|
+
ENTRY_PATH_FIXED=
|
|
308
|
+
ENTRY_PATH_TOKEN_LENGTH=24
|
|
309
|
+
ENTRY_PATH_ROTATE_INTERVAL_MIN=60
|
|
310
|
+
ENTRY_PATH_GRACE_MIN=120
|
|
311
|
+
|
|
312
|
+
SESSION_COOKIE_NAME=remote_mouse_session
|
|
313
|
+
SESSION_COOKIE_SECRET=$cookieSecret
|
|
314
|
+
SESSION_COOKIE_MAX_AGE_DAYS=7
|
|
315
|
+
SOCKET_EVENT_MAX_AGE_MS=1200
|
|
316
|
+
|
|
317
|
+
LOG_LEVEL=info
|
|
318
|
+
LOG_FORMAT=json
|
|
319
|
+
ADMIN_ACTIONS_ENABLED=true
|
|
320
|
+
SERVICE_NAME=remote-mouse
|
|
321
|
+
SERVICE_RESTART_COMMAND=
|
|
322
|
+
"@
|
|
323
|
+
|
|
324
|
+
Set-Content -LiteralPath $envFile -Value $content -Encoding UTF8
|
|
325
|
+
Write-Step "Wrote $envFile"
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function Install-Service {
|
|
329
|
+
if ($NoService) {
|
|
330
|
+
return $false
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (-not $InstallService -and -not (Confirm-Step 'Install the user service?')) {
|
|
334
|
+
return $false
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
remote-mouse service install
|
|
338
|
+
remote-mouse service restart
|
|
339
|
+
return $true
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function Main {
|
|
343
|
+
Write-Step 'Remote Mouse Windows installer'
|
|
344
|
+
Write-Step "Package: $PackageName"
|
|
345
|
+
Write-Step "Config directory: $ConfigDir"
|
|
346
|
+
|
|
347
|
+
Ensure-PowerShell
|
|
348
|
+
Ensure-Node
|
|
349
|
+
Ensure-BuildTools
|
|
350
|
+
Ensure-Python
|
|
351
|
+
Install-NpmPackage
|
|
352
|
+
$httpsConfig = Configure-Https
|
|
353
|
+
Write-EnvFile -HttpsConfig $httpsConfig
|
|
354
|
+
$serviceInstalled = Install-Service
|
|
355
|
+
|
|
356
|
+
Write-Step 'Installation complete.'
|
|
357
|
+
if ($serviceInstalled) {
|
|
358
|
+
Write-Host 'Service installed. Use Task Scheduler or remote-mouse service restart to manage it.'
|
|
359
|
+
} else {
|
|
360
|
+
Write-Host 'Start Remote Mouse with: remote-mouse'
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if ($httpsConfig.Https -eq 'true') {
|
|
364
|
+
Write-Host 'Browsers will warn about the self-signed certificate until it is trusted locally.'
|
|
365
|
+
Write-Host 'Use the browser advanced/details option to continue to the site.'
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
Main
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {createApplicationStart} from './start.js';
|
|
2
|
+
import {createApplicationShutdown} from './shutdown.js';
|
|
3
|
+
import {ensureApplicationLifecycleState} from './state.js';
|
|
4
|
+
|
|
5
|
+
export function createApplicationLifecycle(services) {
|
|
6
|
+
const state = ensureApplicationLifecycleState(services);
|
|
7
|
+
const shutdown = createApplicationShutdown(services);
|
|
8
|
+
state.shutdown = shutdown;
|
|
9
|
+
const start = createApplicationStart(services);
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
start,
|
|
13
|
+
shutdown,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
import {Writable} from 'node:stream';
|
|
3
|
+
import {getSystemConfig} from "../services/config/index.js";
|
|
4
|
+
|
|
5
|
+
const maxStoredLogs = 400;
|
|
6
|
+
const maxStoredMessageLength = 2_000;
|
|
7
|
+
const maxStoredDataLength = 8_000;
|
|
8
|
+
const recentLogs = [];
|
|
9
|
+
const cliLogSubscribers = new Set();
|
|
10
|
+
let rootLogger = null;
|
|
11
|
+
let temporaryLogLevel = '';
|
|
12
|
+
|
|
13
|
+
const levels = {
|
|
14
|
+
trace: 10,
|
|
15
|
+
debug: 20,
|
|
16
|
+
info: 30,
|
|
17
|
+
warn: 40,
|
|
18
|
+
error: 50,
|
|
19
|
+
fatal: 60,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const levelNamesByValue = Object.fromEntries(
|
|
23
|
+
Object.entries(levels).map(([name, value]) => [value, name]),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
function getLevelValue(level) {
|
|
27
|
+
return levels[String(level || '').trim()] ?? levels.info;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function safeClone(value) {
|
|
31
|
+
if (value === undefined) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const serialized = JSON.stringify(value);
|
|
36
|
+
if (typeof serialized !== 'string') {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
if (serialized.length <= maxStoredDataLength) {
|
|
40
|
+
return JSON.parse(serialized);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
truncated: true,
|
|
45
|
+
preview: `${serialized.slice(0, maxStoredDataLength)}...`,
|
|
46
|
+
};
|
|
47
|
+
} catch (_error) {
|
|
48
|
+
const text = String(value);
|
|
49
|
+
return text.length <= maxStoredDataLength
|
|
50
|
+
? text
|
|
51
|
+
: `${text.slice(0, maxStoredDataLength)}...`;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function mapPinoRecord(record) {
|
|
56
|
+
const {time, level, scope, msg, pid: _pid, hostname: _hostname, ...data} = record || {};
|
|
57
|
+
const levelName = levelNamesByValue[level] || String(level || 'info');
|
|
58
|
+
return {
|
|
59
|
+
at: typeof time === 'string' ? time : new Date(time || Date.now()).toISOString(),
|
|
60
|
+
scope: String(scope || 'app'),
|
|
61
|
+
level: levelName,
|
|
62
|
+
message: String(msg || '').slice(0, maxStoredMessageLength),
|
|
63
|
+
data: Object.keys(data).length > 0 ? safeClone(data) : undefined,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function publishCliLog(entry) {
|
|
68
|
+
for (const subscriber of cliLogSubscribers) {
|
|
69
|
+
if (getLevelValue(entry.level) < subscriber.minLevel) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
subscriber.write(entry);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function parseLogLines(buffer, chunk, onRecord) {
|
|
78
|
+
const lines = `${buffer}${String(chunk || '')}`.split('\n');
|
|
79
|
+
const nextBuffer = lines.pop() || '';
|
|
80
|
+
|
|
81
|
+
for (const line of lines) {
|
|
82
|
+
const trimmed = line.trim();
|
|
83
|
+
if (!trimmed) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
onRecord(JSON.parse(trimmed));
|
|
89
|
+
} catch (_error) {
|
|
90
|
+
// Non-JSON transport output is intentionally ignored by structured transports.
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return nextBuffer;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function createRecentLogTransport() {
|
|
98
|
+
let buffer = '';
|
|
99
|
+
|
|
100
|
+
return new Writable({
|
|
101
|
+
write(chunk, _encoding, callback) {
|
|
102
|
+
buffer = parseLogLines(buffer, chunk, (record) => {
|
|
103
|
+
const entry = mapPinoRecord(record);
|
|
104
|
+
recentLogs.push(entry);
|
|
105
|
+
if (recentLogs.length > maxStoredLogs) {
|
|
106
|
+
recentLogs.splice(0, recentLogs.length - maxStoredLogs);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
callback();
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function createCliLogTransport() {
|
|
115
|
+
let buffer = '';
|
|
116
|
+
|
|
117
|
+
return new Writable({
|
|
118
|
+
write(chunk, _encoding, callback) {
|
|
119
|
+
buffer = parseLogLines(buffer, chunk, (record) => {
|
|
120
|
+
publishCliLog(mapPinoRecord(record));
|
|
121
|
+
});
|
|
122
|
+
callback();
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function createDestination(logFormat) {
|
|
128
|
+
if (logFormat === 'flat' || logFormat === 'pretty') {
|
|
129
|
+
return pino.transport({
|
|
130
|
+
target: 'pino-pretty',
|
|
131
|
+
options: {
|
|
132
|
+
colorize: false,
|
|
133
|
+
singleLine: true,
|
|
134
|
+
translateTime: 'SYS:standard',
|
|
135
|
+
ignore: 'pid,hostname',
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function syncLoggerConfig(logger) {
|
|
144
|
+
const nextLevel = temporaryLogLevel || getSystemConfig()?.logging?.level;
|
|
145
|
+
if (nextLevel && logger.level !== nextLevel) {
|
|
146
|
+
logger.level = nextLevel;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function buildRootLogger() {
|
|
151
|
+
const systemConfig = getSystemConfig();
|
|
152
|
+
const systemLogLevel = systemConfig?.logging?.level || 'info';
|
|
153
|
+
const systemLogFormat = systemConfig?.logging?.format || 'json';
|
|
154
|
+
const systemDestination = createDestination(systemLogFormat) || process.stdout;
|
|
155
|
+
const logger = pino({
|
|
156
|
+
level: systemLogLevel,
|
|
157
|
+
timestamp: pino.stdTimeFunctions.isoTime,
|
|
158
|
+
}, pino.multistream([
|
|
159
|
+
{level: systemLogLevel, stream: systemDestination},
|
|
160
|
+
{level: 'trace', stream: createRecentLogTransport()},
|
|
161
|
+
{level: 'trace', stream: createCliLogTransport()},
|
|
162
|
+
]));
|
|
163
|
+
|
|
164
|
+
return logger;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function bootstrapLogger() {
|
|
168
|
+
if (!rootLogger) {
|
|
169
|
+
rootLogger = buildRootLogger();
|
|
170
|
+
} else {
|
|
171
|
+
syncLoggerConfig(rootLogger);
|
|
172
|
+
}
|
|
173
|
+
return rootLogger;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function createLogger(scope) {
|
|
177
|
+
const logger = bootstrapLogger();
|
|
178
|
+
syncLoggerConfig(logger);
|
|
179
|
+
return logger.child({ scope });
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function getRecentLogs(limit = 200) {
|
|
183
|
+
const safeLimit = Math.max(1, Math.min(1000, Math.round(Number(limit) || 200)));
|
|
184
|
+
return recentLogs.slice(-safeLimit);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export async function withTemporaryLoggerLevel(level, callback) {
|
|
188
|
+
const logger = bootstrapLogger();
|
|
189
|
+
const previousTemporaryLogLevel = temporaryLogLevel;
|
|
190
|
+
const previousLevel = logger.level;
|
|
191
|
+
temporaryLogLevel = String(level || '').trim();
|
|
192
|
+
if (temporaryLogLevel) {
|
|
193
|
+
logger.level = temporaryLogLevel;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
return await callback();
|
|
198
|
+
} finally {
|
|
199
|
+
temporaryLogLevel = previousTemporaryLogLevel;
|
|
200
|
+
logger.level = previousTemporaryLogLevel || previousLevel;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export async function withCliLogStream(level, onLog, callback) {
|
|
205
|
+
const subscriber = {
|
|
206
|
+
minLevel: getLevelValue(level),
|
|
207
|
+
write: typeof onLog === 'function' ? onLog : () => {},
|
|
208
|
+
};
|
|
209
|
+
cliLogSubscribers.add(subscriber);
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
return await withTemporaryLoggerLevel(level, callback);
|
|
213
|
+
} finally {
|
|
214
|
+
cliLogSubscribers.delete(subscriber);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {ensureApplicationLifecycleState} from './state.js';
|
|
2
|
+
import {createLogger} from './logger.js';
|
|
3
|
+
|
|
4
|
+
export function createApplicationShutdown(services) {
|
|
5
|
+
const log = createLogger('server');
|
|
6
|
+
|
|
7
|
+
async function runShutdownStep(label, action) {
|
|
8
|
+
try {
|
|
9
|
+
await action();
|
|
10
|
+
} catch (error) {
|
|
11
|
+
log.error({err: error}, label);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return async function shutdown(signal) {
|
|
16
|
+
const state = ensureApplicationLifecycleState(services);
|
|
17
|
+
const serverBundle = services.getServer();
|
|
18
|
+
const httpServer = serverBundle.server;
|
|
19
|
+
const io = serverBundle.io;
|
|
20
|
+
const taskManager = services.getTaskManager();
|
|
21
|
+
const qrOverlay = services.getQrOverlay();
|
|
22
|
+
const sseService = services.getSseService();
|
|
23
|
+
|
|
24
|
+
if (state.shuttingDown) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
state.shuttingDown = true;
|
|
29
|
+
log.info({signal}, 'Arret du serveur');
|
|
30
|
+
services.getPersistence().restartLogDao?.createLifecycleEvent({
|
|
31
|
+
eventAt: Date.now(),
|
|
32
|
+
eventType: 'stop',
|
|
33
|
+
cause: 'user',
|
|
34
|
+
source: signal ? `signal:${signal}` : 'shutdown',
|
|
35
|
+
status: 'completed',
|
|
36
|
+
details: {
|
|
37
|
+
signal: signal || null,
|
|
38
|
+
graceful: true,
|
|
39
|
+
processUptimeSec: Math.floor(process.uptime()),
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
await Promise.allSettled([
|
|
44
|
+
runShutdownStep('Erreur a l arret du task manager', () => taskManager.stop()),
|
|
45
|
+
runShutdownStep('Erreur a l arret de l observateur de configuration', () => state.stopConfigObserver()),
|
|
46
|
+
runShutdownStep('Erreur a l arret de l observateur de notifications', () => state.stopNotificationObserver()),
|
|
47
|
+
runShutdownStep('Erreur a l arret de l observateur de resolution ecran', () => state.stopDisplaySizeObserver()),
|
|
48
|
+
runShutdownStep('Erreur a l arret de l observateur du QR overlay', () => state.stopQrOverlayRefreshObserver()),
|
|
49
|
+
runShutdownStep('Erreur a l arret de l observateur du survol QR overlay', () => state.stopQrOverlayHoverObserver()),
|
|
50
|
+
runShutdownStep('Erreur a la fermeture du socket CLI', () => state.cliServer?.close()),
|
|
51
|
+
runShutdownStep('Erreur a la fermeture du QR overlay', () => qrOverlay.close()),
|
|
52
|
+
runShutdownStep('Erreur a la fermeture des connexions SSE', () => sseService?.closeAll?.()),
|
|
53
|
+
runShutdownStep('Erreur a la fermeture de Socket.IO', () => new Promise((resolve) => {
|
|
54
|
+
io?.close?.(() => resolve());
|
|
55
|
+
})),
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
serverBundle.closeIdleConnections?.();
|
|
60
|
+
} catch (error) {
|
|
61
|
+
log.error({err: error}, 'Erreur a la fermeture des connexions HTTP inactives');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
await new Promise((resolve) => {
|
|
65
|
+
const forceShutdownTimer = setTimeout(() => {
|
|
66
|
+
try {
|
|
67
|
+
serverBundle.destroyConnections?.();
|
|
68
|
+
} catch (error) {
|
|
69
|
+
log.error({err: error}, 'Erreur a la destruction forcee des connexions HTTP');
|
|
70
|
+
}
|
|
71
|
+
}, 1_500);
|
|
72
|
+
|
|
73
|
+
httpServer.close(() => {
|
|
74
|
+
clearTimeout(forceShutdownTimer);
|
|
75
|
+
resolve();
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
process.exit(0);
|
|
80
|
+
};
|
|
81
|
+
}
|