правки по лаунчеру
This commit is contained in:
@@ -22,6 +22,13 @@ typedef InstallationScanProgressCallback =
|
||||
int totalFiles,
|
||||
);
|
||||
|
||||
final class GameProcessHandle {
|
||||
final int pid;
|
||||
final Future<int> exitCode;
|
||||
|
||||
const GameProcessHandle({required this.pid, required this.exitCode});
|
||||
}
|
||||
|
||||
@lazySingleton
|
||||
class GameInstallationService {
|
||||
Future<ClientInstallationSnapshot> scanInstallation(
|
||||
@@ -209,7 +216,7 @@ class GameInstallationService {
|
||||
await cacheDirectory.create(recursive: true);
|
||||
}
|
||||
|
||||
Future<void> launchGame(String installationDir) async {
|
||||
Future<GameProcessHandle> launchGame(String installationDir) async {
|
||||
final executablePath = getExecutablePath(installationDir);
|
||||
final executable = File(executablePath);
|
||||
|
||||
@@ -219,12 +226,16 @@ class GameInstallationService {
|
||||
);
|
||||
}
|
||||
|
||||
await Process.start(
|
||||
final process = await Process.start(
|
||||
executablePath,
|
||||
const <String>[],
|
||||
workingDirectory: installationDir,
|
||||
mode: ProcessStartMode.detached,
|
||||
mode: ProcessStartMode.normal,
|
||||
);
|
||||
await process.stdin.close();
|
||||
unawaited(process.stdout.drain<void>());
|
||||
unawaited(process.stderr.drain<void>());
|
||||
return GameProcessHandle(pid: process.pid, exitCode: process.exitCode);
|
||||
}
|
||||
|
||||
Future<bool> hasClientExecutable(String installationDir) async {
|
||||
|
||||
@@ -9,8 +9,10 @@ import 'package:moonwell_launcher/features/downloader/domain/entities/download_e
|
||||
import 'package:moonwell_launcher/features/launcher/data/launcher_log_service.dart';
|
||||
import 'package:moonwell_launcher/features/launcher/domain/entities/client_manifest.dart';
|
||||
import 'package:moonwell_launcher/features/launcher/domain/entities/client_manifest_file.dart';
|
||||
import 'package:moonwell_launcher/features/launcher/domain/entities/launcher_account.dart';
|
||||
import 'package:moonwell_launcher/features/launcher/domain/entities/launcher_exception.dart';
|
||||
import 'package:moonwell_launcher/features/launcher/domain/entities/launcher_news_item.dart';
|
||||
import 'package:moonwell_launcher/features/launcher/domain/entities/launcher_realm.dart';
|
||||
import 'package:moonwell_launcher/features/launcher/domain/entities/launcher_session.dart';
|
||||
|
||||
@lazySingleton
|
||||
@@ -58,6 +60,108 @@ class LauncherApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> register({
|
||||
required String username,
|
||||
required String email,
|
||||
required String password,
|
||||
required String passwordConfirmation,
|
||||
required bool terms,
|
||||
String? inviteCode,
|
||||
}) async {
|
||||
final registerUri = _resolveUri('api/launcher/register');
|
||||
final normalizedInviteCode = inviteCode?.trim();
|
||||
|
||||
try {
|
||||
final response = await _dio.postUri(
|
||||
registerUri,
|
||||
data: <String, Object?>{
|
||||
'username': username,
|
||||
'email': email,
|
||||
'password': password,
|
||||
'password_confirmation': passwordConfirmation,
|
||||
'terms': terms,
|
||||
if (normalizedInviteCode != null && normalizedInviteCode.isNotEmpty)
|
||||
'invite_code': normalizedInviteCode,
|
||||
},
|
||||
);
|
||||
final payload = _coerceMap(response.data);
|
||||
return payload['message'] as String? ?? 'Аккаунт успешно создан.';
|
||||
} on DioException catch (error, stackTrace) {
|
||||
await _launcherLogService.error(
|
||||
'Launcher registration request failed.',
|
||||
details: <String, Object?>{
|
||||
'endpoint': registerUri.toString(),
|
||||
'statusCode': error.response?.statusCode,
|
||||
'dioType': error.type.name,
|
||||
'responseBody': _summarizePayload(error.response?.data),
|
||||
},
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
throw LauncherApiException(_extractErrorMessage(error));
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<LauncherRealm>> fetchRealms() async {
|
||||
final realmsUri = _resolveUri('api/launcher/realms');
|
||||
|
||||
try {
|
||||
final response = await _dio.getUri(realmsUri);
|
||||
final payload = _coerceMap(response.data);
|
||||
final rawItems = payload['data'];
|
||||
if (rawItems is! List) {
|
||||
throw const LauncherApiException('Unexpected launcher realms payload.');
|
||||
}
|
||||
|
||||
return rawItems
|
||||
.whereType<Map>()
|
||||
.map(
|
||||
(item) => LauncherRealm.fromJson(
|
||||
item.map((key, value) => MapEntry(key.toString(), value)),
|
||||
),
|
||||
)
|
||||
.toList(growable: false);
|
||||
} on DioException catch (error, stackTrace) {
|
||||
await _launcherLogService.error(
|
||||
'Launcher realms request failed.',
|
||||
details: <String, Object?>{
|
||||
'endpoint': realmsUri.toString(),
|
||||
'statusCode': error.response?.statusCode,
|
||||
'dioType': error.type.name,
|
||||
'responseBody': _summarizePayload(error.response?.data),
|
||||
},
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
throw LauncherApiException(_extractErrorMessage(error));
|
||||
}
|
||||
}
|
||||
|
||||
Future<LauncherAccount> fetchAccount(String accessToken) async {
|
||||
final accountUri = _resolveUri('api/launcher/account');
|
||||
|
||||
try {
|
||||
final response = await _dio.getUri(
|
||||
accountUri,
|
||||
options: _authorizedOptions(accessToken),
|
||||
);
|
||||
return LauncherAccount.fromJson(_coerceMap(response.data));
|
||||
} on DioException catch (error, stackTrace) {
|
||||
await _launcherLogService.error(
|
||||
'Launcher account request failed.',
|
||||
details: <String, Object?>{
|
||||
'endpoint': accountUri.toString(),
|
||||
'statusCode': error.response?.statusCode,
|
||||
'dioType': error.type.name,
|
||||
'responseBody': _summarizePayload(error.response?.data),
|
||||
},
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
throw LauncherApiException(_extractErrorMessage(error));
|
||||
}
|
||||
}
|
||||
|
||||
Future<ClientManifest> fetchManifest(String accessToken) async {
|
||||
final manifestUri = _resolveUri('api/launcher/manifest');
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
Uri? buildLauncherNewsUri(String rawBaseUrl, int newsId) {
|
||||
final normalizedBaseUrl = rawBaseUrl.trim();
|
||||
final baseUri = Uri.tryParse(
|
||||
normalizedBaseUrl.endsWith('/') ? normalizedBaseUrl : '$normalizedBaseUrl/',
|
||||
);
|
||||
if (baseUri == null ||
|
||||
!baseUri.hasScheme ||
|
||||
baseUri.host.isEmpty ||
|
||||
newsId <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return baseUri.resolve('news/$newsId');
|
||||
}
|
||||
Reference in New Issue
Block a user