This commit is contained in:
2026-09-01 17:58:09 +08:00
parent 046ce2f1ab
commit 33d9bb1696
5 changed files with 18 additions and 10 deletions
+1 -1
View File
@@ -147,7 +147,7 @@ class _CameraScreenState extends State<CameraScreen> {
try {
await ModelManager.instance
.refresh()
.timeout(const Duration(seconds: 15));
.timeout(const Duration(seconds: 30));
} catch (_) {}
await _reloadWorker();
await _startCamera();
+6 -3
View File
@@ -164,7 +164,7 @@ class ModelManager extends ChangeNotifier {
await _loadActive();
final res = await _client
.get(Uri.parse('$baseUrl/api/v1/app/update'))
.timeout(const Duration(seconds: 8));
.timeout(const Duration(seconds: 30));
// 服务器 Content-Type 无 charsethttp 包默认按 latin1 解码会乱码 → 显式 utf8
final body =
jsonDecode(utf8.decode(res.bodyBytes)) as Map<String, dynamic>;
@@ -297,15 +297,18 @@ class ModelManager extends ChangeNotifier {
final sink = part.openWrite();
var received = 0;
try {
// 下载无总时长上限(大模型慢网可能数分钟);连接/响应头与数据流
// 分别做 30s 停滞判定,避免断流黑洞永久卡死
final res = await _client
.send(http.Request('GET', Uri.parse('$baseUrl${item.downloadUrl}')))
.timeout(const Duration(minutes: 3));
.timeout(const Duration(seconds: 30));
if (res.statusCode != 200) {
await sink.close();
return false;
}
final total = res.contentLength ?? item.sizeBytes;
await for (final chunk in res.stream) {
await for (final chunk
in res.stream.timeout(const Duration(seconds: 30))) {
if (_cancelRequested.contains(item.datasetId)) break; // 用户取消
sink.add(chunk);
received += chunk.length;
+3 -3
View File
@@ -97,7 +97,7 @@ class OrderApi {
res = await _client.get(
Uri.parse('$baseUrl/api/v1/plans'),
headers: {'Accept': 'application/json', ...await _authHeaders()},
).timeout(const Duration(seconds: 15));
).timeout(const Duration(seconds: 30));
} catch (e) {
if (e is OrderApiException) rethrow;
throw OrderApiException('网络请求失败: $e');
@@ -115,7 +115,7 @@ class OrderApi {
res = await _client.get(
Uri.parse('$baseUrl/api/v1/license'),
headers: {'Accept': 'application/json', ...await _authHeaders()},
).timeout(const Duration(seconds: 15));
).timeout(const Duration(seconds: 30));
} catch (e) {
if (e is OrderApiException) rethrow;
throw OrderApiException('网络请求失败: $e');
@@ -136,7 +136,7 @@ class OrderApi {
},
body: body,
)
.timeout(const Duration(seconds: 15));
.timeout(const Duration(seconds: 30));
} catch (e) {
if (e is OrderApiException) rethrow;
throw OrderApiException('网络请求失败: $e');
+1 -1
View File
@@ -38,7 +38,7 @@ class UpdateChecker {
try {
final res = await _client
.get(Uri.parse('$baseUrl/api/v1/app/update'))
.timeout(const Duration(seconds: 8));
.timeout(const Duration(seconds: 30));
// 服务器 Content-Type 无 charsethttp 包默认按 latin1 解码会乱码 → 显式 utf8
final body =
jsonDecode(utf8.decode(res.bodyBytes)) as Map<String, dynamic>;
+7 -2
View File
@@ -98,14 +98,19 @@ class _UpdateScreenState extends State<UpdateScreen> {
});
try {
if (_apkPart.existsSync()) _apkPart.deleteSync();
final res = await _client.send(http.Request('GET', Uri.parse(widget.url)));
// 下载无总时长上限(APK 几十 MB 慢网可能数分钟);连接/响应头与
// 数据流分别做 30s 停滞判定,避免断流黑洞永久卡死
final res = await _client
.send(http.Request('GET', Uri.parse(widget.url)))
.timeout(const Duration(seconds: 30));
if (res.statusCode != 200) {
throw HttpException('HTTP ${res.statusCode}');
}
final total = res.contentLength ?? -1;
final sink = _apkPart.openWrite();
var received = 0;
await for (final chunk in res.stream) {
await for (final chunk
in res.stream.timeout(const Duration(seconds: 30))) {
sink.add(chunk);
received += chunk.length;
if (mounted && total > 0) {