Files
FlClash/lib/core/spill.dart
T
chen08209 bdbf4ab024 feat(dashboard): redesign the dashboard around the current exit
Changelog: A redesigned dashboard around the current exit
2026-10-17 09:54:29 +08:00

113 lines
2.9 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/models/models.dart';
import 'package:flutter/foundation.dart';
import 'package:path/path.dart';
import 'method.dart';
/// Mirrors spilledResponseDirName in core/spill.go.
const coreSpillDirectoryName = 'responses';
Future<bool> _isSpilled(String file) async {
final directory = join(await appPath.homeDirPath, coreSpillDirectoryName);
return equals(dirname(file), directory);
}
/// Parsed where a transport decodes them, off the UI isolate for a large one.
const _resultModels = <CoreMethod, Object? Function(Object?)>{
CoreMethod.getConnections: trackerInfosOf,
};
Map<String, Object?> withResultModel(
CoreMethod? method,
Map<String, Object?> response,
) {
final model = _resultModels[method];
if (model == null || response['error'] != null || response['file'] != null) {
return response;
}
return {...response, 'result': model(response['result'])};
}
Future<CoreMethodResponse> resolveSpilledResponse(
CoreMethodResponse response, {
CoreMethod? method,
}) async {
final file = response.file;
if (file == null) {
return response;
}
if (!await _isSpilled(file)) {
return CoreMethodResponse(
id: response.id,
error: CoreMethodError(
code: 'spill_error',
message: 'Core answered with a file outside its spill directory: $file',
),
);
}
try {
return CoreMethodResponse.fromJson(
await compute(_readSpilledResponse, (file, method)),
);
} catch (error) {
return CoreMethodResponse(
id: response.id,
error: CoreMethodError(code: 'spill_error', message: '$error'),
);
}
}
Map<String, Object?> _readSpilledResponse((String, CoreMethod?) request) {
final (path, method) = request;
final file = File(path);
try {
final decoded = utf8.decoder
.fuse(json.decoder)
.convert(file.readAsBytesSync());
return withResultModel(method, Map<String, Object?>.from(decoded as Map));
} finally {
try {
file.deleteSync();
} on FileSystemException catch (_) {}
}
}
Future<String> readSpilledText(String path) async {
if (!await _isSpilled(path)) {
throw CoreMethodException(
code: 'spill_error',
message: 'Core wrote a file outside its spill directory: $path',
);
}
return compute(_readSpilledText, path);
}
String _readSpilledText(String path) {
final file = File(path);
try {
return file.readAsStringSync();
} finally {
try {
file.deleteSync();
} on FileSystemException catch (_) {}
}
}
Future<void> discardSpilledResponse(CoreMethodResponse response) async {
await discardSpilledFile(response.file);
await discardSpilledFile(response.result);
}
Future<void> discardSpilledFile(Object? file) async {
if (file is! String || !await _isSpilled(file)) {
return;
}
try {
await File(file).delete();
} on FileSystemException catch (_) {}
}