refactored HTTP error handling and streamlined UI components by centralizing shared logic and removing redundant parameters

This commit is contained in:
2026-07-13 22:58:02 +02:00
parent d7536ea5d0
commit 8274dd46cd
28 changed files with 284 additions and 447 deletions
@@ -1,18 +1,13 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'dart:typed_data';
import 'package:http/http.dart' as http;
import '../../../model/account_data.dart';
import '../../../model/endpoint_data.dart';
import '../../errors/auth_exception.dart';
import '../../errors/network_exception.dart';
import '../../errors/not_found_exception.dart';
import '../../errors/parse_exception.dart';
import '../../errors/server_exception.dart';
import '../../http_errors.dart';
import '../nextcloud_ocs.dart';
/// Mix of two Nextcloud surfaces:
@@ -42,30 +37,17 @@ Future<http.Response> _send(
) async {
final headers = NextcloudOcs.headers();
final http.Response response;
try {
response = await perform(uri, headers);
} on SocketException catch (e) {
throw NetworkException(technicalDetails: 'Cloud $uri: ${e.message}');
} on TimeoutException catch (e) {
throw NetworkException.timeout(technicalDetails: 'Cloud $uri: $e');
} on http.ClientException catch (e) {
throw NetworkException(technicalDetails: 'Cloud $uri: ${e.message}');
}
final response = (await sendGuarded(
'Cloud $uri',
() => perform(uri, headers),
))!;
final status = response.statusCode;
if (status >= 200 && status < 300) return response;
final body = response.body.replaceAll(RegExp(r'\s+'), ' ').trim();
final preview = body.length > 500 ? '${body.substring(0, 500)}' : body;
final detail = body.isEmpty
? 'Cloud $uri -> HTTP $status'
: 'Cloud $uri -> HTTP $status body=$preview';
final detail = httpErrorDetail('Cloud $uri', response.body, status);
log(detail);
if (status == 401) throw AuthException.unauthorized(technicalDetails: detail);
if (status == 403) throw AuthException.forbidden(technicalDetails: detail);
if (status == 404) throw NotFoundException(technicalDetails: detail);
throw ServerException(statusCode: status, technicalDetails: detail);
throwForStatus(status, detail);
}
class SetUserAvatar {
@@ -1,10 +1,7 @@
import 'dart:async';
import 'dart:io';
import 'package:http/http.dart' as http;
import '../../../errors/network_exception.dart';
import '../../../errors/server_exception.dart';
import '../../../http_errors.dart';
import '../../nextcloud_ocs.dart';
import 'get_chat_params.dart';
import 'get_chat_response.dart';
@@ -40,18 +37,12 @@ class LongPollChat {
);
final headers = NextcloudOcs.headers();
final http.Response response;
try {
response = await http
final response = (await sendGuarded(
'LongPollChat $uri',
() => http
.get(uri, headers: headers)
.timeout(Duration(seconds: timeoutSeconds + 15));
} on TimeoutException catch (e) {
throw NetworkException.timeout(technicalDetails: 'LongPollChat $uri: $e');
} on SocketException catch (e) {
throw NetworkException(technicalDetails: 'LongPollChat $uri: ${e.message}');
} on http.ClientException catch (e) {
throw NetworkException(technicalDetails: 'LongPollChat $uri: ${e.message}');
}
.timeout(Duration(seconds: timeoutSeconds + 15)),
))!;
final status = response.statusCode;
if (status == 304) return null;
+13 -40
View File
@@ -1,29 +1,20 @@
import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'package:http/http.dart' as http;
import '../../api_params.dart';
import '../../api_request.dart';
import '../../api_response.dart';
import '../../errors/auth_exception.dart';
import '../../errors/network_exception.dart';
import '../../errors/not_found_exception.dart';
import '../../errors/parse_exception.dart';
import '../../errors/server_exception.dart';
import '../../http_errors.dart';
import '../nextcloud_ocs.dart';
enum TalkApiMethod { get, post, put, delete }
abstract class TalkApi<T extends ApiResponse?> extends ApiRequest {
abstract class TalkApi<T extends ApiResponse?> {
String path;
ApiParams? body;
Map<String, String>? headers;
Map<String, dynamic>? getParameters;
http.Response? response;
TalkApi(this.path, this.body, {this.headers, this.getParameters});
Future<http.Response>? request(
@@ -40,22 +31,15 @@ abstract class TalkApi<T extends ApiResponse?> extends ApiRequest {
);
final mergedHeaders = {...NextcloudOcs.headers(), ...?headers};
final http.Response data;
try {
final raw = await request(endpoint, body, mergedHeaders);
if (raw == null) {
throw const NetworkException(
userMessage: 'Keine Antwort vom Talk-Server erhalten.',
technicalDetails: 'Talk request returned null',
);
}
data = raw;
} on SocketException catch (e) {
throw NetworkException(technicalDetails: 'Talk $endpoint: ${e.message}');
} on TimeoutException catch (e) {
throw NetworkException.timeout(technicalDetails: 'Talk $endpoint: $e');
} on http.ClientException catch (e) {
throw NetworkException(technicalDetails: 'Talk $endpoint: ${e.message}');
final data = await sendGuarded(
'Talk $endpoint',
() => request(endpoint, body, mergedHeaders),
);
if (data == null) {
throw const NetworkException(
userMessage: 'Keine Antwort vom Talk-Server erhalten.',
technicalDetails: 'Talk request returned null',
);
}
final status = data.statusCode;
@@ -63,20 +47,9 @@ abstract class TalkApi<T extends ApiResponse?> extends ApiRequest {
// Talk's OCS errors carry the real reason in the body (expired session,
// removed participant, ...); include a trimmed preview so the dialog and
// logs surface the cause instead of just the bare status code.
final body = data.body.replaceAll(RegExp(r'\s+'), ' ').trim();
final preview = body.length > 500 ? '${body.substring(0, 500)}' : body;
final detail = body.isEmpty
? 'Talk $endpoint -> HTTP $status'
: 'Talk $endpoint -> HTTP $status body=$preview';
final detail = httpErrorDetail('Talk $endpoint', data.body, status);
log(detail);
if (status == 401) {
throw AuthException.unauthorized(technicalDetails: detail);
}
if (status == 403) {
throw AuthException.forbidden(technicalDetails: detail);
}
if (status == 404) throw NotFoundException(technicalDetails: detail);
throw ServerException(statusCode: status, technicalDetails: detail);
throwForStatus(status, detail);
}
try {
+1 -2
View File
@@ -2,10 +2,9 @@ import 'package:nextcloud/nextcloud.dart';
import '../../../model/account_data.dart';
import '../../../model/endpoint_data.dart';
import '../../api_request.dart';
import '../../api_response.dart';
abstract class WebdavApi<T> extends ApiRequest {
abstract class WebdavApi<T> {
T genericParams;
WebdavApi(this.genericParams) {