mirror of
https://github.com/Auties00/Reboot-Launcher.git
synced 2026-01-13 03:02:22 +01:00
234 lines
6.5 KiB
Dart
234 lines
6.5 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
import 'package:fluent_ui/fluent_ui.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:get_storage/get_storage.dart';
|
|
import 'package:reboot_common/common.dart';
|
|
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
|
import 'package:sync/semaphore.dart';
|
|
|
|
abstract class ServerController extends GetxController {
|
|
late final GetStorage storage;
|
|
late final TextEditingController host;
|
|
late final TextEditingController port;
|
|
late final Rx<ServerType> type;
|
|
late final Semaphore semaphore;
|
|
late RxBool started;
|
|
late RxBool detached;
|
|
StreamSubscription? worker;
|
|
HttpServer? localServer;
|
|
HttpServer? remoteServer;
|
|
|
|
ServerController() {
|
|
storage = GetStorage(storageName);
|
|
started = RxBool(false);
|
|
type = Rx(ServerType.values.elementAt(storage.read("type") ?? 0));
|
|
type.listen((value) {
|
|
host.text = _readHost();
|
|
port.text = _readPort();
|
|
storage.write("type", value.index);
|
|
if (!started.value) {
|
|
return;
|
|
}
|
|
|
|
stop();
|
|
});
|
|
host = TextEditingController(text: _readHost());
|
|
host.addListener(() =>
|
|
storage.write("${type.value.name}_host", host.text));
|
|
port = TextEditingController(text: _readPort());
|
|
port.addListener(() =>
|
|
storage.write("${type.value.name}_port", port.text));
|
|
detached = RxBool(storage.read("detached") ?? false);
|
|
detached.listen((value) => storage.write("detached", value));
|
|
semaphore = Semaphore();
|
|
}
|
|
|
|
String get controllerName;
|
|
|
|
String get storageName;
|
|
|
|
String get defaultHost;
|
|
|
|
int get defaultPort;
|
|
|
|
Future<Uri?> pingServer(String host, int port);
|
|
|
|
Future<bool> get isPortFree;
|
|
|
|
Future<bool> get isPortTaken async => !(await isPortFree);
|
|
|
|
RebootPageType get pageType;
|
|
|
|
Future<bool> freePort();
|
|
|
|
@protected
|
|
Future<Win32Process> startEmbeddedInternal();
|
|
|
|
void reset() async {
|
|
type.value = ServerType.values.elementAt(0);
|
|
for (final type in ServerType.values) {
|
|
storage.write("${type.name}_host", null);
|
|
storage.write("${type.name}_port", null);
|
|
}
|
|
|
|
host.text = type.value != ServerType.remote ? defaultHost : "";
|
|
port.text = defaultPort.toString();
|
|
detached.value = false;
|
|
}
|
|
|
|
String _readHost() {
|
|
String? value = storage.read("${type.value.name}_host");
|
|
return value != null && value.isNotEmpty ? value
|
|
: type.value != ServerType.remote ? defaultHost : "";
|
|
}
|
|
|
|
String _readPort() =>
|
|
storage.read("${type.value.name}_port") ?? defaultPort.toString();
|
|
|
|
Stream<ServerResult> start() async* {
|
|
try {
|
|
if(started.value) {
|
|
return;
|
|
}
|
|
|
|
final hostData = this.host.text.trim();
|
|
final portData = this.port.text.trim();
|
|
if(type() != ServerType.local) {
|
|
started.value = true;
|
|
yield ServerResult(ServerResultType.starting);
|
|
}else {
|
|
started.value = false;
|
|
if(portData != defaultPort) {
|
|
yield ServerResult(ServerResultType.starting);
|
|
}
|
|
}
|
|
|
|
if (hostData.isEmpty) {
|
|
yield ServerResult(ServerResultType.missingHostError);
|
|
started.value = false;
|
|
return;
|
|
}
|
|
|
|
if (portData.isEmpty) {
|
|
yield ServerResult(ServerResultType.missingPortError);
|
|
started.value = false;
|
|
return;
|
|
}
|
|
|
|
final portNumber = int.tryParse(portData);
|
|
if (portNumber == null) {
|
|
yield ServerResult(ServerResultType.illegalPortError);
|
|
started.value = false;
|
|
return;
|
|
}
|
|
|
|
if ((type() != ServerType.local || portData != defaultPort) && await isPortTaken) {
|
|
yield ServerResult(ServerResultType.freeingPort);
|
|
final result = await freePort();
|
|
yield ServerResult(result ? ServerResultType.freePortSuccess : ServerResultType.freePortError);
|
|
if(!result) {
|
|
started.value = false;
|
|
return;
|
|
}
|
|
}
|
|
|
|
switch(type()){
|
|
case ServerType.embedded:
|
|
final process = await startEmbeddedInternal();
|
|
final processPid = process.pid;
|
|
if(processPid == null) {
|
|
yield ServerResult(ServerResultType.startError);
|
|
started.value = false;
|
|
return;
|
|
}
|
|
|
|
watchProcess(processPid).then((value) {
|
|
if(started()) {
|
|
started.value = false;
|
|
}
|
|
});
|
|
break;
|
|
case ServerType.remote:
|
|
yield ServerResult(ServerResultType.pingingRemote);
|
|
final uriResult = await pingServer(hostData, portNumber);
|
|
if(uriResult == null) {
|
|
yield ServerResult(ServerResultType.pingError);
|
|
started.value = false;
|
|
return;
|
|
}
|
|
|
|
remoteServer = await startRemoteAuthenticatorProxy(uriResult);
|
|
break;
|
|
case ServerType.local:
|
|
if(portData != defaultPort) {
|
|
localServer = await startRemoteAuthenticatorProxy(Uri.parse("http://$defaultHost:$port"));
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
yield ServerResult(ServerResultType.pingingLocal);
|
|
final uriResult = await pingServer(defaultHost, defaultPort);
|
|
if(uriResult == null) {
|
|
yield ServerResult(ServerResultType.pingError);
|
|
remoteServer?.close(force: true);
|
|
localServer?.close(force: true);
|
|
started.value = false;
|
|
return;
|
|
}
|
|
|
|
yield ServerResult(ServerResultType.startSuccess);
|
|
}catch(error, stackTrace) {
|
|
yield ServerResult(
|
|
ServerResultType.startError,
|
|
error: error,
|
|
stackTrace: stackTrace
|
|
);
|
|
remoteServer?.close(force: true);
|
|
localServer?.close(force: true);
|
|
started.value = false;
|
|
}
|
|
}
|
|
|
|
Stream<ServerResult> stop() async* {
|
|
if(!started.value) {
|
|
return;
|
|
}
|
|
|
|
yield ServerResult(ServerResultType.stopping);
|
|
started.value = false;
|
|
try{
|
|
switch(type()){
|
|
case ServerType.embedded:
|
|
killProcessByPort(defaultPort);
|
|
break;
|
|
case ServerType.remote:
|
|
await remoteServer?.close(force: true);
|
|
remoteServer = null;
|
|
break;
|
|
case ServerType.local:
|
|
await localServer?.close(force: true);
|
|
localServer = null;
|
|
break;
|
|
}
|
|
yield ServerResult(ServerResultType.stopSuccess);
|
|
}catch(error, stackTrace){
|
|
yield ServerResult(
|
|
ServerResultType.stopError,
|
|
error: error,
|
|
stackTrace: stackTrace
|
|
);
|
|
started.value = true;
|
|
}
|
|
}
|
|
|
|
Stream<ServerResult> toggle() async* {
|
|
if(started()) {
|
|
yield* stop();
|
|
}else {
|
|
yield* start();
|
|
}
|
|
}
|
|
} |