Skip to content

Commit

Permalink
feat: check API port is in use (#524)
Browse files Browse the repository at this point in the history
  • Loading branch information
monkeyWie authored May 7, 2024
1 parent 53b3eea commit d2c70b0
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 8 deletions.
10 changes: 7 additions & 3 deletions ui/flutter/lib/app/modules/app/controllers/app_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,9 @@ class AppController extends GetxController with WindowListener, TrayListener {
}

Future<void> _toCreate(Uri uri) async {
final path = (uri.scheme == "magnet" || uri.scheme == "http" || uri.scheme == "https")
final path = (uri.scheme == "magnet" ||
uri.scheme == "http" ||
uri.scheme == "https")
? uri.toString()
: (await toFile(uri.toString())).path;
await Get.rootDelegate.offAndToNamed(Routes.CREATE, arguments: path);
Expand Down Expand Up @@ -305,22 +307,24 @@ class AppController extends GetxController with WindowListener, TrayListener {
return _defaultStartConfig!;
}

Future<void> loadStartConfig() async {
Future<StartConfig> loadStartConfig() async {
final defaultCfg = await _initDefaultStartConfig();
final saveCfg = Database.instance.getStartConfig();
startConfig.value.network = saveCfg?.network ?? defaultCfg.network;
startConfig.value.address = saveCfg?.address ?? defaultCfg.address;
startConfig.value.apiToken = saveCfg?.apiToken ?? defaultCfg.apiToken;
return startConfig.value;
}

Future<void> loadDownloaderConfig() async {
Future<DownloaderConfig> loadDownloaderConfig() async {
try {
downloaderConfig.value = await getConfig();
} catch (e) {
logger.w("load downloader config fail", e);
downloaderConfig.value = DownloaderConfig();
}
await _initDownloaderConfig();
return downloaderConfig.value;
}

Future<void> trackerUpdate() async {
Expand Down
51 changes: 46 additions & 5 deletions ui/flutter/lib/app/modules/setting/views/setting_view.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:io';

import 'package:badges/badges.dart' as badges;
import 'package:flutter/material.dart';
Expand All @@ -8,6 +9,7 @@ import 'package:intl/intl.dart';
import 'package:url_launcher/url_launcher.dart';

import '../../../../api/model/downloader_config.dart';
import '../../../../database/database.dart';
import '../../../../i18n/message.dart';
import '../../../../util/input_formatter.dart';
import '../../../../util/locale_manager.dart';
Expand All @@ -34,13 +36,22 @@ class SettingView extends GetView<SettingController> {
final startCfg = appController.startConfig;

Timer? timer;
debounceSave({bool needRestart = false}) {
var completer = Completer<void>();
Future<bool> debounceSave(
{Future<String> Function()? check, bool needRestart = false}) {
var completer = Completer<bool>();
timer?.cancel();
timer = Timer(const Duration(milliseconds: 1000), () {
timer = Timer(const Duration(milliseconds: 1000), () async {
if (check != null) {
final checkResult = await check();
if (checkResult.isNotEmpty) {
showErrorMessage(checkResult);
completer.complete(false);
return;
}
}
appController
.saveConfig()
.then(completer.complete)
.then((_) => completer.complete(true))
.onError(completer.completeError);
if (needRestart) {
showMessage('tip'.tr, 'effectAfterRestart'.tr);
Expand Down Expand Up @@ -639,11 +650,41 @@ class SettingView extends GetView<SettingController> {
final ipController = TextEditingController(text: ip);
final portController = TextEditingController(text: port);
updateAddress() async {
if (ipController.text.isEmpty || portController.text.isEmpty) {
return;
}
final newAddress = '${ipController.text}:${portController.text}';
if (newAddress != startCfg.value.address) {
startCfg.value.address = newAddress;

await debounceSave(needRestart: true);
final saved = await debounceSave(
check: () async {
// Check if address already in use
final configIp = ipController.text;
final configPort = int.parse(portController.text);
if (configPort == 0) {
return '';
}
try {
final socket = await Socket.connect(configIp, configPort,
timeout: const Duration(seconds: 3));
socket.close();
return 'portInUse'
.trParams({'port': configPort.toString()});
} catch (e) {
return '';
}
},
needRestart: true);

// If save failed, restore the old address
if (!saved) {
final oldAddress =
(await appController.loadStartConfig()).address;
startCfg.update((val) async {
val!.address = oldAddress;
});
}
}
}

Expand Down
1 change: 1 addition & 0 deletions ui/flutter/lib/i18n/langs/en_us.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const enUS = {
'apiToken': 'API Token',
'notSet': 'NS',
'set': 'SET',
'portInUse': 'Port [@port] is in use, please change the port',
'effectAfterRestart': 'Effect after restart',
'startAll': 'Start All',
'pauseAll': 'Pause All',
Expand Down
1 change: 1 addition & 0 deletions ui/flutter/lib/i18n/langs/zh_cn.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const zhCN = {
'apiToken': '接口令牌',
'notSet': '未设置',
'set': '已设置',
'portInUse': '端口[@port]已被占用,请更换端口',
'effectAfterRestart': '此配置项将在重启应用后生效',
'startAll': '全部开始',
'pauseAll': '全部暂停',
Expand Down
1 change: 1 addition & 0 deletions ui/flutter/lib/i18n/langs/zh_tw.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const zhTW = {
'apiToken': 'API令牌',
'notSet': '未設定',
'set': '已設定',
'portInUse': '端口[@port]已被占用,請更換端口',
'effectAfterRestart': '重啟後生效',
'startAll': '全部開始',
'pauseAll': '全部暫停',
Expand Down

0 comments on commit d2c70b0

Please sign in to comment.