From af1a2dad0543480ce0f63a925e752ada53d58c43 Mon Sep 17 00:00:00 2001 From: Dain Nilsson Date: Fri, 21 Jan 2022 11:05:53 +0100 Subject: [PATCH] Replace socket approach with native Windows mutex. --- lib/desktop/single_instance.dart | 68 ------------------- lib/main.dart | 4 -- macos/Flutter/GeneratedPluginRegistrant.swift | 2 - pubspec.lock | 28 -------- pubspec.yaml | 1 - windows/runner/win32_window.cpp | 22 ++++++ 6 files changed, 22 insertions(+), 103 deletions(-) delete mode 100755 lib/desktop/single_instance.dart diff --git a/lib/desktop/single_instance.dart b/lib/desktop/single_instance.dart deleted file mode 100755 index 0ee9383f..00000000 --- a/lib/desktop/single_instance.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'dart:io'; -import 'package:logging/logging.dart'; -import 'package:path/path.dart' as path; - -import 'package:path_provider/path_provider.dart'; -import 'package:window_manager/window_manager.dart'; - -const _lockFileName = 'lockfile'; -const _pingMessage = 'YA-PING'; -const _pongMessage = 'YA-PONG'; - -final log = Logger('single_instance'); - -void _startServer(File lockfile) async { - final socket = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0); - lockfile.writeAsString('${socket.port}'); - - log.info('Lock file and socket created.'); - socket.listen((client) { - client.listen((data) async { - final message = String.fromCharCodes(data); - if (message == _pingMessage) { - log.info('Got incomming connection'); - - if (!await WindowManager.instance.isMinimized()) { - // Causes the window to be brought to the front. - await WindowManager.instance.setAlwaysOnTop(true); - await WindowManager.instance.setAlwaysOnTop(false); - } else { - await WindowManager.instance.restore(); - } - - // This doesn't seem to always work - await WindowManager.instance.focus(); - client.write(_pongMessage); - } - client.close(); - }, cancelOnError: true); - }); -} - -Future ensureSingleInstance() async { - final appSupport = await getApplicationSupportDirectory(); - final lockfile = File(path.join(appSupport.path, _lockFileName)); - log.info('Lock file: $lockfile'); - - if (await lockfile.exists()) { - try { - final port = int.parse(await lockfile.readAsString()); - final client = await Socket.connect(InternetAddress.loopbackIPv4, port); - client.write(_pingMessage); - client.listen((data) async { - final message = String.fromCharCodes(data); - await client.close(); - if (message == _pongMessage) { - log.info('Other application instance already running, exit.'); - exit(0); - } - }, cancelOnError: true); - } on Exception { - // No server listening on the port, or bad data in the file - await lockfile.delete(); - _startServer(lockfile); - } - } else { - _startServer(lockfile); - } -} diff --git a/lib/main.dart b/lib/main.dart index 55d9dcfc..6e5b85a7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,7 +6,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:logging/logging.dart'; import 'package:window_manager/window_manager.dart'; -import 'package:yubico_authenticator/desktop/single_instance.dart'; import 'app/app.dart'; import 'app/views/main_page.dart'; @@ -20,9 +19,6 @@ final log = Logger('main'); void main() async { _initLogging(Level.INFO); WidgetsFlutterBinding.ensureInitialized(); - if (Platform.isWindows) { - await ensureSingleInstance(); - } await windowManager.ensureInitialized(); // Either use the _YKMAN_EXE environment variable, or look relative to executable. diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 1b4cf229..f59e7ec7 100755 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,12 +5,10 @@ import FlutterMacOS import Foundation -import path_provider_macos import shared_preferences_macos import window_manager func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index ab5b8f0f..75599171 100755 --- a/pubspec.lock +++ b/pubspec.lock @@ -352,27 +352,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" - path_provider: - dependency: "direct main" - description: - name: path_provider - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.8" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.11" - path_provider_ios: - dependency: transitive - description: - name: path_provider_ios - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.7" path_provider_linux: dependency: transitive description: @@ -380,13 +359,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.5" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.5" path_provider_platform_interface: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 25dc24e5..85847dea 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,7 +37,6 @@ dependencies: async: ^2.8.2 logging: ^1.0.2 - path_provider: ^2.0.8 shared_preferences: ^2.0.12 flutter_riverpod: ^1.0.0 json_annotation: ^4.4.0 diff --git a/windows/runner/win32_window.cpp b/windows/runner/win32_window.cpp index e77900bd..95ae3d0d 100644 --- a/windows/runner/win32_window.cpp +++ b/windows/runner/win32_window.cpp @@ -107,6 +107,28 @@ bool Win32Window::CreateAndShow(const std::wstring& title, const Size& size) { Destroy(); + // Attempt to create a mutex to enforce single instance. + CreateMutex(NULL, TRUE, L"com.yubico.authenticator.mutex"); + if (GetLastError() == ERROR_ALREADY_EXISTS) { + HWND handle=FindWindowA(NULL, "Yubico Authenticator"); + WINDOWPLACEMENT place = { sizeof(WINDOWPLACEMENT) }; + GetWindowPlacement(handle, &place); + switch(place.showCmd) { + case SW_SHOWMAXIMIZED: + ShowWindow(handle, SW_SHOWMAXIMIZED); + break; + case SW_SHOWMINIMIZED: + ShowWindow(handle, SW_RESTORE); + break; + default: + ShowWindow(handle, SW_NORMAL); + break; + } + SetWindowPos(0, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE); + SetForegroundWindow(handle); + return 0; + } + const wchar_t* window_class = WindowClassRegistrar::GetInstance()->GetWindowClass();