mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-11-22 16:32:01 +03:00
Replace socket approach with native Windows mutex.
This commit is contained in:
parent
71b66f53b0
commit
af1a2dad05
@ -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<void> 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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
import 'package:yubico_authenticator/desktop/single_instance.dart';
|
|
||||||
|
|
||||||
import 'app/app.dart';
|
import 'app/app.dart';
|
||||||
import 'app/views/main_page.dart';
|
import 'app/views/main_page.dart';
|
||||||
@ -20,9 +19,6 @@ final log = Logger('main');
|
|||||||
void main() async {
|
void main() async {
|
||||||
_initLogging(Level.INFO);
|
_initLogging(Level.INFO);
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
if (Platform.isWindows) {
|
|
||||||
await ensureSingleInstance();
|
|
||||||
}
|
|
||||||
await windowManager.ensureInitialized();
|
await windowManager.ensureInitialized();
|
||||||
|
|
||||||
// Either use the _YKMAN_EXE environment variable, or look relative to executable.
|
// Either use the _YKMAN_EXE environment variable, or look relative to executable.
|
||||||
|
@ -5,12 +5,10 @@
|
|||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
import path_provider_macos
|
|
||||||
import shared_preferences_macos
|
import shared_preferences_macos
|
||||||
import window_manager
|
import window_manager
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
|
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
|
||||||
}
|
}
|
||||||
|
28
pubspec.lock
28
pubspec.lock
@ -352,27 +352,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0"
|
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:
|
path_provider_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -380,13 +359,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.5"
|
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:
|
path_provider_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -37,7 +37,6 @@ dependencies:
|
|||||||
|
|
||||||
async: ^2.8.2
|
async: ^2.8.2
|
||||||
logging: ^1.0.2
|
logging: ^1.0.2
|
||||||
path_provider: ^2.0.8
|
|
||||||
shared_preferences: ^2.0.12
|
shared_preferences: ^2.0.12
|
||||||
flutter_riverpod: ^1.0.0
|
flutter_riverpod: ^1.0.0
|
||||||
json_annotation: ^4.4.0
|
json_annotation: ^4.4.0
|
||||||
|
@ -107,6 +107,28 @@ bool Win32Window::CreateAndShow(const std::wstring& title,
|
|||||||
const Size& size) {
|
const Size& size) {
|
||||||
Destroy();
|
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 =
|
const wchar_t* window_class =
|
||||||
WindowClassRegistrar::GetInstance()->GetWindowClass();
|
WindowClassRegistrar::GetInstance()->GetWindowClass();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user