refactor: more logs

This commit is contained in:
cogwheel0
2025-09-25 23:22:48 +05:30
parent 9210b2155a
commit 3124bccfeb
20 changed files with 937 additions and 846 deletions

View File

@@ -1,4 +1,4 @@
import 'package:flutter/foundation.dart' hide debugPrint;
import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
// Types are used through app_providers.dart
import '../providers/app_providers.dart';
@@ -7,11 +7,6 @@ import 'token_validator.dart';
import 'auth_cache_manager.dart';
import '../utils/debug_logger.dart';
void debugPrint(String? message, {int? wrapWidth}) {
if (message == null) return;
DebugLogger.fromLegacy(message, scope: 'auth/state');
}
/// Comprehensive auth state representation
@immutable
class AuthState {
@@ -153,7 +148,7 @@ class AuthStateManager extends Notifier<AuthState> {
);
}
} catch (e) {
debugPrint('ERROR: Auth initialization failed: $e');
DebugLogger.error('auth-init-failed', scope: 'auth/state', error: e);
state = state.copyWith(
status: AuthStatus.error,
error: 'Failed to initialize auth: $e',
@@ -244,7 +239,7 @@ class AuthStateManager extends Notifier<AuthState> {
throw Exception('Invalid API key or insufficient permissions');
}
} catch (e) {
debugPrint('ERROR: API key login failed: $e');
DebugLogger.error('api-key-login-failed', scope: 'auth/state', error: e);
state = state.copyWith(
status: AuthStatus.error,
error: e.toString(),
@@ -325,7 +320,7 @@ class AuthStateManager extends Notifier<AuthState> {
DebugLogger.auth('Login successful');
return true;
} catch (e) {
debugPrint('ERROR: Login failed: $e');
DebugLogger.error('login-failed', scope: 'auth/state', error: e);
state = state.copyWith(
status: AuthStatus.error,
error: e.toString(),
@@ -433,7 +428,7 @@ class AuthStateManager extends Notifier<AuthState> {
return await login(username, password, rememberCredentials: false);
}
} catch (e) {
debugPrint('ERROR: Silent login failed: $e');
DebugLogger.error('silent-login-failed', scope: 'auth/state', error: e);
// Clear invalid credentials on auth errors
if (e.toString().contains('401') ||
@@ -496,7 +491,11 @@ class AuthStateManager extends Notifier<AuthState> {
try {
await api.logout();
} catch (e) {
debugPrint('Warning: Server logout failed: $e');
DebugLogger.warning(
'server-logout-failed',
scope: 'auth/state',
data: {'error': e.toString()},
);
}
}
@@ -516,7 +515,7 @@ class AuthStateManager extends Notifier<AuthState> {
DebugLogger.auth('Logout complete');
} catch (e) {
debugPrint('ERROR: Logout failed: $e');
DebugLogger.error('logout-failed', scope: 'auth/state', error: e);
// Even if logout fails, clear local state
state = state.copyWith(
status: AuthStatus.unauthenticated,
@@ -551,7 +550,11 @@ class AuthStateManager extends Notifier<AuthState> {
// Fall back to server data loading
await _loadServerUserData();
} catch (e) {
debugPrint('Warning: Failed to load user data: $e');
DebugLogger.warning(
'user-data-load-failed',
scope: 'auth/state',
data: {'error': e.toString()},
);
// Don't update state on user data load failure
}
}
@@ -563,9 +566,7 @@ class AuthStateManager extends Notifier<AuthState> {
if (api != null && state.isAuthenticated) {
// Check if we already have user data from token validation
if (state.user != null) {
debugPrint(
'DEBUG: User data already available from token validation',
);
DebugLogger.auth('user-data-present-from-token', scope: 'auth/state');
return;
}
@@ -574,7 +575,11 @@ class AuthStateManager extends Notifier<AuthState> {
DebugLogger.auth('Loaded complete user data from server');
}
} catch (e) {
debugPrint('Warning: Failed to load server user data: $e');
DebugLogger.warning(
'server-user-data-load-failed',
scope: 'auth/state',
data: {'error': e.toString()},
);
// Don't update state on server data load failure - keep JWT data if available
}
}
@@ -605,21 +610,25 @@ class AuthStateManager extends Notifier<AuthState> {
// Fast format validation first
final formatResult = TokenValidator.validateTokenFormat(token);
if (!formatResult.isValid) {
debugPrint('DEBUG: Token format invalid: ${formatResult.message}');
DebugLogger.warning(
'token-format-invalid',
scope: 'auth/state',
data: {'message': formatResult.message},
);
TokenValidationCache.cacheResult(token, formatResult);
return false;
}
// If format is valid but token is expiring soon, try server validation
if (formatResult.isExpiringSoon) {
debugPrint('DEBUG: Token expiring soon, validating with server');
DebugLogger.auth('token-expiring-soon', scope: 'auth/state');
}
// Server validation (async with timeout)
try {
final api = ref.read(apiServiceProvider);
if (api == null) {
debugPrint('DEBUG: No API service available for token validation');
DebugLogger.warning('token-validation-no-api', scope: 'auth/state');
return formatResult.isValid; // Fall back to format validation
}
@@ -650,7 +659,11 @@ class AuthStateManager extends Notifier<AuthState> {
);
return serverResult.isValid;
} catch (e) {
debugPrint('DEBUG: Token server validation failed: $e');
DebugLogger.warning(
'token-validation-failed',
scope: 'auth/state',
data: {'error': e.toString()},
);
// On network error, fall back to format validation if it was valid
return formatResult.isValid;
}

View File

@@ -2,11 +2,6 @@ import 'dart:convert';
import 'package:crypto/crypto.dart';
import '../utils/debug_logger.dart';
void debugPrint(String? message, {int? wrapWidth}) {
if (message == null) return;
DebugLogger.fromLegacy(message, scope: 'auth/token-validator');
}
/// JWT token validation utilities
class TokenValidator {
static const Duration _validationTimeout = Duration(seconds: 5);
@@ -68,8 +63,10 @@ class TokenValidator {
);
} catch (e) {
// If we can't decode JWT, treat as opaque token
debugPrint(
'DEBUG: Could not decode JWT payload, treating as opaque token: $e',
DebugLogger.warning(
'jwt-decode-failed',
scope: 'auth/token-validator',
data: {'error': e.toString()},
);
return TokenValidationResult.valid('Opaque token format valid');
}
@@ -153,7 +150,11 @@ class TokenValidator {
'iat': payload['iat'], // Issued at
};
} catch (e) {
debugPrint('DEBUG: Could not extract user info from token: $e');
DebugLogger.warning(
'token-user-info-failed',
scope: 'auth/token-validator',
data: {'error': e.toString()},
);
return null;
}
}

View File

@@ -1,14 +1,9 @@
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart' hide debugPrint;
import 'package:flutter/foundation.dart';
import 'api_error.dart';
import 'error_parser.dart';
import '../utils/debug_logger.dart';
void debugPrint(String? message, {int? wrapWidth}) {
if (message == null) return;
DebugLogger.fromLegacy(message, scope: 'api/error-handler');
}
/// Comprehensive API error handler with structured error parsing
/// Handles all types of API errors and converts them to standardized format
class ApiErrorHandler {
@@ -39,7 +34,10 @@ class ApiErrorHandler {
}
} catch (e) {
// Fallback error if transformation itself fails
debugPrint('ApiErrorHandler: Error transforming exception: $e');
DebugLogger.log(
'ApiErrorHandler: Error transforming exception: $e',
scope: 'api/error-handler',
);
return ApiError.unknown(
message: 'A system error occurred',
originalError: error,
@@ -318,21 +316,33 @@ class ApiErrorHandler {
String httpMethod,
) {
if (kDebugMode) {
debugPrint('🔴 API Error Details:');
debugPrint(' Method: ${httpMethod.toUpperCase()}');
debugPrint(' Endpoint: $requestPath');
debugPrint(' Type: ${dioError.type}');
debugPrint(' Status: ${dioError.response?.statusCode}');
DebugLogger.log('🔴 API Error Details:', scope: 'api/error-handler');
DebugLogger.log(
' Method: ${httpMethod.toUpperCase()}',
scope: 'api/error-handler',
);
DebugLogger.log(' Endpoint: $requestPath', scope: 'api/error-handler');
DebugLogger.log(' Type: ${dioError.type}', scope: 'api/error-handler');
DebugLogger.log(
' Status: ${dioError.response?.statusCode}',
scope: 'api/error-handler',
);
if (dioError.response?.data != null) {
DebugLogger.error('Response data available (truncated for security)');
}
if (dioError.requestOptions.data != null) {
debugPrint(' Request Data: ${dioError.requestOptions.data}');
DebugLogger.log(
' Request Data: ${dioError.requestOptions.data}',
scope: 'api/error-handler',
);
}
debugPrint(' Error: ${dioError.message}');
DebugLogger.log(
' Error: ${dioError.message}',
scope: 'api/error-handler',
);
}
// In production, you would send this to your error tracking service

View File

@@ -1,14 +1,9 @@
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart' hide debugPrint;
import 'package:flutter/foundation.dart';
import 'api_error_handler.dart';
import 'api_error.dart';
import '../utils/debug_logger.dart';
void debugPrint(String? message, {int? wrapWidth}) {
if (message == null) return;
DebugLogger.fromLegacy(message, scope: 'api/error-interceptor');
}
/// Dio interceptor for automatic error handling and transformation
/// Converts all HTTP errors into standardized ApiError format
class ApiErrorInterceptor extends Interceptor {
@@ -51,7 +46,11 @@ class ApiErrorInterceptor extends Interceptor {
}
} catch (e) {
// Fallback if error transformation fails
debugPrint('ApiErrorInterceptor: Failed to transform error: $e');
DebugLogger.error(
'transform-failed',
scope: 'api/error-interceptor',
error: e,
);
handler.next(err);
}
}
@@ -71,7 +70,16 @@ class ApiErrorInterceptor extends Interceptor {
);
if (logErrors) {
debugPrint('🟡 API Error in successful response: $apiError');
DebugLogger.warning(
'successful-response-error',
scope: 'api/error-interceptor',
data: {
'endpoint': apiError.endpoint,
'method': apiError.method,
'status': apiError.statusCode,
'message': apiError.message,
},
);
}
// Store the error for later handling
@@ -122,74 +130,59 @@ class ApiErrorInterceptor extends Interceptor {
void _logApiError(ApiError apiError, DioException originalError) {
if (!kDebugMode) return;
final typeIcon = _getErrorTypeIcon(apiError.type);
debugPrint('$typeIcon API Error [${apiError.type.name.toUpperCase()}]');
debugPrint(' Method: ${apiError.method?.toUpperCase() ?? 'UNKNOWN'}');
debugPrint(' Endpoint: ${apiError.endpoint ?? 'unknown'}');
debugPrint(' Status: ${apiError.statusCode ?? 'N/A'}');
debugPrint(' Message: ${apiError.message}');
final payload = <String, Object?>{
'type': apiError.type.name,
'endpoint': apiError.endpoint,
'method': apiError.method,
'status': apiError.statusCode,
'message': apiError.message,
if (apiError.technical != null) 'technical': apiError.technical,
if (apiError.retryAfter != null)
'retryAfterSeconds': apiError.retryAfter!.inSeconds,
'originalType': originalError.type.name,
};
if (apiError.hasFieldErrors) {
debugPrint(' Field Errors:');
for (final entry in apiError.fieldErrors.entries) {
final field = entry.key;
final errors = entry.value;
debugPrint(' $field: ${errors.join(', ')}');
}
payload['fieldErrors'] = {
for (final entry in apiError.fieldErrors.entries)
entry.key: entry.value,
};
}
if (apiError.technical != null) {
debugPrint(' Technical: ${apiError.technical}');
}
if (apiError.retryAfter != null) {
debugPrint(' Retry After: ${apiError.retryAfter!.inSeconds}s');
}
// Log original error type for debugging
debugPrint(' Original Type: ${originalError.type}');
// Log request details if available
final requestData = originalError.requestOptions.data;
if (requestData != null && requestData.toString().length < 500) {
debugPrint(' Request: $requestData');
payload['request'] = requestData;
}
// Log response data if available and not too large
final responseData = originalError.response?.data;
if (responseData != null && responseData.toString().length < 1000) {
DebugLogger.error('Response data available (truncated for security)');
payload['response'] = responseData;
}
}
/// Get emoji icon for error type
String _getErrorTypeIcon(ApiErrorType type) {
switch (type) {
case ApiErrorType.network:
return '🌐';
case ApiErrorType.timeout:
return '⏱️';
case ApiErrorType.authentication:
return '🔐';
case ApiErrorType.authorization:
return '🚫';
case ApiErrorType.validation:
return '✏️';
case ApiErrorType.badRequest:
return '';
case ApiErrorType.notFound:
return '🔍';
case ApiErrorType.server:
return '🔥';
case ApiErrorType.rateLimit:
return '🐌';
case ApiErrorType.cancelled:
return '🛑';
case ApiErrorType.security:
return '🔒';
case ApiErrorType.unknown:
return '';
final headers = originalError.requestOptions.headers;
if (headers.isNotEmpty) {
payload['requestHeaders'] = {
for (final entry in headers.entries) entry.key: entry.value.toString(),
};
}
final responseHeaders = originalError.response?.headers;
if (responseHeaders != null && responseHeaders.map.isNotEmpty) {
payload['responseHeaders'] = responseHeaders.map;
}
final requestDuration =
originalError.response?.requestOptions.extra['requestDuration'];
if (requestDuration is Duration) {
payload['requestDurationMs'] = requestDuration.inMilliseconds;
}
DebugLogger.error(
'api-error',
scope: 'api/error-interceptor',
data: payload,
error: apiError,
);
}
/// Extract ApiError from DioException if available

View File

@@ -1,5 +1,5 @@
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart' hide debugPrint;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'api_error.dart';
import 'api_error_handler.dart';
@@ -9,11 +9,6 @@ import '../../shared/theme/theme_extensions.dart';
import 'package:conduit/l10n/app_localizations.dart';
import '../utils/debug_logger.dart';
void debugPrint(String? message, {int? wrapWidth}) {
if (message == null) return;
DebugLogger.fromLegacy(message, scope: 'api/error-service');
}
/// Enhanced error service with comprehensive error handling capabilities
/// Provides unified error management across the application
class EnhancedErrorService {
@@ -306,16 +301,31 @@ class EnhancedErrorService {
}) {
if (kDebugMode) {
final timestamp = DateTime.now().toIso8601String();
debugPrint('🔴 ERROR [$timestamp] ${context ?? 'Unknown Context'}');
debugPrint(' Message: ${getUserMessage(error)}');
debugPrint(' Technical: ${getTechnicalDetails(error)}');
DebugLogger.log(
'🔴 ERROR [$timestamp] ${context ?? 'Unknown Context'}',
scope: 'api/error-service',
);
DebugLogger.log(
' Message: ${getUserMessage(error)}',
scope: 'api/error-service',
);
DebugLogger.log(
' Technical: ${getTechnicalDetails(error)}',
scope: 'api/error-service',
);
if (additionalData != null && additionalData.isNotEmpty) {
debugPrint(' Additional Data: $additionalData');
DebugLogger.log(
' Additional Data: $additionalData',
scope: 'api/error-service',
);
}
if (stackTrace != null) {
debugPrint(' Stack Trace: $stackTrace');
DebugLogger.log(
' Stack Trace: $stackTrace',
scope: 'api/error-service',
);
}
}

View File

@@ -1,11 +1,6 @@
import 'api_error.dart';
import '../utils/debug_logger.dart';
void debugPrint(String? message, {int? wrapWidth}) {
if (message == null) return;
DebugLogger.fromLegacy(message, scope: 'api/error-parser');
}
/// Comprehensive error response parser
/// Handles various API error response formats and extracts structured information
class ErrorParser {
@@ -29,7 +24,10 @@ class ErrorParser {
);
}
} catch (e) {
debugPrint('ErrorParser: Error parsing response: $e');
DebugLogger.log(
'ErrorParser: Error parsing response: $e',
scope: 'api/error-parser',
);
return ParsedErrorResponse(
message: 'Failed to parse error response',
metadata: {

File diff suppressed because it is too large Load Diff

View File

@@ -5,11 +5,6 @@ import 'package:dio/dio.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../utils/debug_logger.dart';
void debugPrint(String? message, {int? wrapWidth}) {
if (message == null) return;
DebugLogger.fromLegacy(message, scope: 'attachments/queue');
}
/// Status of a queued attachment upload
enum QueuedAttachmentStatus { pending, uploading, completed, failed, cancelled }
@@ -144,8 +139,9 @@ class AttachmentUploadQueue {
_prefs ??= await SharedPreferences.getInstance();
await _load();
_startPeriodicProcessing();
debugPrint(
'DEBUG: AttachmentUploadQueue initialized with ${_queue.length} items',
DebugLogger.log(
'AttachmentUploadQueue initialized with ${_queue.length} items',
scope: 'attachments/queue',
);
}
@@ -223,8 +219,9 @@ class AttachmentUploadQueue {
await _save();
_notify();
debugPrint(
'DEBUG: Attachment ${item.id} uploaded successfully (fileId=$fileId)',
DebugLogger.log(
'Attachment ${item.id} uploaded successfully (fileId=$fileId)',
scope: 'attachments/queue',
);
} catch (e) {
final retries = item.retryCount + 1;
@@ -239,8 +236,9 @@ class AttachmentUploadQueue {
);
await _save();
_notify();
debugPrint(
DebugLogger.log(
'WARNING: Attachment ${item.id} failed after $_maxRetries attempts',
scope: 'attachments/queue',
);
return;
}
@@ -257,8 +255,9 @@ class AttachmentUploadQueue {
);
await _save();
_notify();
debugPrint(
'DEBUG: Scheduled retry for attachment ${item.id} in ${delay.inSeconds}s',
DebugLogger.log(
'Scheduled retry for attachment ${item.id} in ${delay.inSeconds}s',
scope: 'attachments/queue',
);
}
}

View File

@@ -6,11 +6,6 @@ import '../models/server_config.dart';
import '../models/conversation.dart';
import '../utils/debug_logger.dart';
void debugPrint(String? message, {int? wrapWidth}) {
if (message == null) return;
DebugLogger.fromLegacy(message, scope: 'storage/optimized');
}
/// Optimized storage service with single secure storage implementation
/// Eliminates dual storage overhead and improves performance
class OptimizedStorageService {
@@ -46,9 +41,15 @@ class OptimizedStorageService {
await _secureCredentialStorage.saveAuthToken(token);
_cache[_authTokenKey] = token;
_cacheTimestamps[_authTokenKey] = DateTime.now();
debugPrint('DEBUG: Auth token saved and cached');
DebugLogger.log(
'Auth token saved and cached',
scope: 'storage/optimized',
);
} catch (e) {
debugPrint('ERROR: Failed to save auth token: $e');
DebugLogger.log(
'Failed to save auth token: $e',
scope: 'storage/optimized',
);
rethrow;
}
}
@@ -58,7 +59,7 @@ class OptimizedStorageService {
if (_isCacheValid(_authTokenKey)) {
final cachedToken = _cache[_authTokenKey] as String?;
if (cachedToken != null) {
debugPrint('DEBUG: Using cached auth token');
DebugLogger.log('Using cached auth token', scope: 'storage/optimized');
return cachedToken;
}
}
@@ -71,7 +72,10 @@ class OptimizedStorageService {
}
return token;
} catch (e) {
debugPrint('ERROR: Failed to retrieve auth token: $e');
DebugLogger.log(
'Failed to retrieve auth token: $e',
scope: 'storage/optimized',
);
return null;
}
}
@@ -81,9 +85,15 @@ class OptimizedStorageService {
await _secureCredentialStorage.deleteAuthToken();
_cache.remove(_authTokenKey);
_cacheTimestamps.remove(_authTokenKey);
debugPrint('DEBUG: Auth token deleted and cache cleared');
DebugLogger.log(
'Auth token deleted and cache cleared',
scope: 'storage/optimized',
);
} catch (e) {
debugPrint('ERROR: Failed to delete auth token: $e');
DebugLogger.log(
'Failed to delete auth token: $e',
scope: 'storage/optimized',
);
}
}
@@ -104,9 +114,15 @@ class OptimizedStorageService {
_cache['has_credentials'] = true;
_cacheTimestamps['has_credentials'] = DateTime.now();
debugPrint('DEBUG: Credentials saved via optimized storage');
DebugLogger.log(
'Credentials saved via optimized storage',
scope: 'storage/optimized',
);
} catch (e) {
debugPrint('ERROR: Failed to save credentials: $e');
DebugLogger.log(
'Failed to save credentials: $e',
scope: 'storage/optimized',
);
rethrow;
}
}
@@ -122,7 +138,10 @@ class OptimizedStorageService {
return credentials;
} catch (e) {
debugPrint('ERROR: Failed to retrieve credentials: $e');
DebugLogger.log(
'Failed to retrieve credentials: $e',
scope: 'storage/optimized',
);
return null;
}
}
@@ -132,9 +151,15 @@ class OptimizedStorageService {
await _secureCredentialStorage.deleteSavedCredentials();
_cache.remove('has_credentials');
_cacheTimestamps.remove('has_credentials');
debugPrint('DEBUG: Credentials deleted via optimized storage');
DebugLogger.log(
'Credentials deleted via optimized storage',
scope: 'storage/optimized',
);
} catch (e) {
debugPrint('ERROR: Failed to delete credentials: $e');
DebugLogger.log(
'Failed to delete credentials: $e',
scope: 'storage/optimized',
);
}
}
@@ -167,9 +192,15 @@ class OptimizedStorageService {
_cache['server_config_count'] = configs.length;
_cacheTimestamps['server_config_count'] = DateTime.now();
debugPrint('DEBUG: Server configs saved (${configs.length} configs)');
DebugLogger.log(
'Server configs saved (${configs.length} configs)',
scope: 'storage/optimized',
);
} catch (e) {
debugPrint('ERROR: Failed to save server configs: $e');
DebugLogger.log(
'Failed to save server configs: $e',
scope: 'storage/optimized',
);
rethrow;
}
}
@@ -194,7 +225,10 @@ class OptimizedStorageService {
return configs;
} catch (e) {
debugPrint('ERROR: Failed to retrieve server configs: $e');
DebugLogger.log(
'Failed to retrieve server configs: $e',
scope: 'storage/optimized',
);
return [];
}
}
@@ -275,7 +309,10 @@ class OptimizedStorageService {
final decoded = jsonDecode(jsonString) as List<dynamic>;
return decoded.map((item) => Conversation.fromJson(item)).toList();
} catch (e) {
debugPrint('ERROR: Failed to retrieve local conversations: $e');
DebugLogger.log(
'Failed to retrieve local conversations: $e',
scope: 'storage/optimized',
);
return [];
}
}
@@ -298,11 +335,15 @@ class OptimizedStorageService {
final jsonString = jsonEncode(lightweightConversations);
await _prefs.setString(_localConversationsKey, jsonString);
debugPrint(
'DEBUG: Saved ${conversations.length} local conversations (lightweight)',
DebugLogger.log(
'Saved ${conversations.length} local conversations (lightweight)',
scope: 'storage/optimized',
);
} catch (e) {
debugPrint('ERROR: Failed to save local conversations: $e');
DebugLogger.log(
'Failed to save local conversations: $e',
scope: 'storage/optimized',
);
}
}
@@ -331,9 +372,15 @@ class OptimizedStorageService {
key.contains('server'),
);
debugPrint('DEBUG: Auth data cleared in batch operation');
DebugLogger.log(
'Auth data cleared in batch operation',
scope: 'storage/optimized',
);
} catch (e) {
debugPrint('ERROR: Failed to clear auth data: $e');
DebugLogger.log(
'Failed to clear auth data: $e',
scope: 'storage/optimized',
);
}
}
@@ -344,9 +391,12 @@ class OptimizedStorageService {
_cache.clear();
_cacheTimestamps.clear();
debugPrint('DEBUG: All storage cleared');
DebugLogger.log('All storage cleared', scope: 'storage/optimized');
} catch (e) {
debugPrint('ERROR: Failed to clear all storage: $e');
DebugLogger.log(
'Failed to clear all storage: $e',
scope: 'storage/optimized',
);
}
}
@@ -366,21 +416,30 @@ class OptimizedStorageService {
void clearCache() {
_cache.clear();
_cacheTimestamps.clear();
debugPrint('DEBUG: Storage cache cleared');
DebugLogger.log('Storage cache cleared', scope: 'storage/optimized');
}
/// Migration from old storage service (one-time operation)
Future<void> migrateFromLegacyStorage() async {
try {
debugPrint('DEBUG: Starting migration from legacy storage');
DebugLogger.log(
'Starting migration from legacy storage',
scope: 'storage/optimized',
);
// This would be called once during app upgrade
// Implementation would depend on the specific migration needs
// For now, the SecureCredentialStorage already handles legacy migration
debugPrint('DEBUG: Legacy storage migration completed');
DebugLogger.log(
'Legacy storage migration completed',
scope: 'storage/optimized',
);
} catch (e) {
debugPrint('ERROR: Legacy storage migration failed: $e');
DebugLogger.log(
'Legacy storage migration failed: $e',
scope: 'storage/optimized',
);
}
}

View File

@@ -1,7 +1,7 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart' hide debugPrint;
import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:share_handler/share_handler.dart' as sh;
@@ -85,7 +85,10 @@ final shareReceiverInitializerProvider = Provider<void>((ref) {
maybeProcessPending();
}
} catch (e) {
debugPrint('ShareReceiver: failed to get initial shared media: $e');
DebugLogger.log(
'ShareReceiver: failed to get initial shared media: $e',
scope: 'share',
);
}
});
@@ -98,7 +101,10 @@ final shareReceiverInitializerProvider = Provider<void>((ref) {
maybeProcessPending();
}
} catch (e) {
debugPrint('ShareReceiver: failed to parse shared media: $e');
DebugLogger.log(
'ShareReceiver: failed to parse shared media: $e',
scope: 'share',
);
}
});
@@ -197,11 +203,9 @@ Future<void> _processPayload(Ref ref, SharedPayload payload) async {
// Do NOT create a server chat here. The chat is created on first send
// (with server syncing + title generation) in chat_providers.dart.
} catch (e) {
debugPrint('ShareReceiver: failed to process payload: $e');
DebugLogger.log(
'ShareReceiver: failed to process payload: $e',
scope: 'share',
);
}
}
void debugPrint(String? message, {int? wrapWidth}) {
if (message == null) return;
DebugLogger.fromLegacy(message, scope: 'share');
}

View File

@@ -2,11 +2,6 @@ import 'package:socket_io_client/socket_io_client.dart' as io;
import '../models/server_config.dart';
import '../utils/debug_logger.dart';
void debugPrint(String? message, {int? wrapWidth}) {
if (message == null) return;
DebugLogger.fromLegacy(message, scope: 'socket');
}
class SocketService {
final ServerConfig serverConfig;
final bool websocketOnly;
@@ -97,7 +92,7 @@ class SocketService {
_socket = io.io(base, builder.build());
_socket!.on('connect', (_) {
debugPrint('Socket connected: ${_socket!.id}');
DebugLogger.log('Socket connected: ${_socket!.id}', scope: 'socket');
if (_authToken != null && _authToken!.isNotEmpty) {
_socket!.emit('user-join', {
'auth': {'token': _authToken},
@@ -106,15 +101,18 @@ class SocketService {
});
_socket!.on('connect_error', (err) {
debugPrint('Socket connect_error: $err');
DebugLogger.log('Socket connect_error: $err', scope: 'socket');
});
_socket!.on('reconnect_attempt', (attempt) {
debugPrint('Socket reconnect_attempt: $attempt');
DebugLogger.log('Socket reconnect_attempt: $attempt', scope: 'socket');
});
_socket!.on('reconnect', (attempt) {
debugPrint('Socket reconnected after $attempt attempts');
DebugLogger.log(
'Socket reconnected after $attempt attempts',
scope: 'socket',
);
if (_authToken != null && _authToken!.isNotEmpty) {
// Best-effort rejoin
_socket!.emit('user-join', {
@@ -124,11 +122,11 @@ class SocketService {
});
_socket!.on('reconnect_failed', (_) {
debugPrint('Socket reconnect_failed');
DebugLogger.log('Socket reconnect_failed', scope: 'socket');
});
_socket!.on('disconnect', (reason) {
debugPrint('Socket disconnected: $reason');
DebugLogger.log('Socket disconnected: $reason', scope: 'socket');
});
}

View File

@@ -6,11 +6,6 @@ import '../models/conversation.dart';
import 'secure_credential_storage.dart';
import '../utils/debug_logger.dart';
void debugPrint(String? message, {int? wrapWidth}) {
if (message == null) return;
DebugLogger.fromLegacy(message, scope: 'storage');
}
class StorageService {
final FlutterSecureStorage _secureStorage;
final SharedPreferences _prefs;
@@ -42,7 +37,10 @@ class StorageService {
try {
await _secureCredentialStorage.saveAuthToken(token);
} catch (e) {
debugPrint('Warning: Enhanced secure storage failed, using fallback: $e');
DebugLogger.log(
'Enhanced secure storage failed, using fallback: $e',
scope: 'storage',
);
await _secureStorage.write(key: _authTokenKey, value: token);
}
}
@@ -53,7 +51,10 @@ class StorageService {
final token = await _secureCredentialStorage.getAuthToken();
if (token != null) return token;
} catch (e) {
debugPrint('Warning: Enhanced secure storage failed, using fallback: $e');
DebugLogger.log(
'Enhanced secure storage failed, using fallback: $e',
scope: 'storage',
);
}
// Fallback to legacy storage
@@ -65,7 +66,10 @@ class StorageService {
try {
await _secureCredentialStorage.deleteAuthToken();
} catch (e) {
debugPrint('Warning: Failed to delete from enhanced storage: $e');
DebugLogger.log(
'Failed to delete from enhanced storage: $e',
scope: 'storage',
);
}
await _secureStorage.delete(key: _authTokenKey);
@@ -83,8 +87,9 @@ class StorageService {
final isSecureAvailable = await _secureCredentialStorage
.isSecureStorageAvailable();
if (!isSecureAvailable) {
debugPrint(
'DEBUG: Enhanced secure storage not available, using legacy storage',
DebugLogger.log(
'Enhanced secure storage not available, using legacy storage',
scope: 'storage',
);
throw Exception('Enhanced secure storage not available');
}
@@ -94,9 +99,15 @@ class StorageService {
username: username,
password: password,
);
debugPrint('DEBUG: Credentials saved using enhanced secure storage');
DebugLogger.log(
'Credentials saved using enhanced secure storage',
scope: 'storage',
);
} catch (e) {
debugPrint('Warning: Enhanced secure storage failed, using fallback: $e');
DebugLogger.log(
'Enhanced secure storage failed, using fallback: $e',
scope: 'storage',
);
// Fallback to legacy storage
try {
@@ -120,10 +131,14 @@ class StorageService {
);
}
debugPrint('DEBUG: Credentials saved using fallback storage');
DebugLogger.log(
'Credentials saved using fallback storage',
scope: 'storage',
);
} catch (fallbackError) {
debugPrint(
'ERROR: Both enhanced and fallback credential storage failed: $fallbackError',
DebugLogger.log(
'Both enhanced and fallback credential storage failed: $fallbackError',
scope: 'storage',
);
rethrow;
}
@@ -138,7 +153,10 @@ class StorageService {
return credentials;
}
} catch (e) {
debugPrint('Warning: Enhanced secure storage failed, using fallback: $e');
DebugLogger.log(
'Enhanced secure storage failed, using fallback: $e',
scope: 'storage',
);
}
// Fallback to legacy storage and migrate if found
@@ -153,7 +171,7 @@ class StorageService {
if (!decoded.containsKey('serverId') ||
!decoded.containsKey('username') ||
!decoded.containsKey('password')) {
debugPrint('Warning: Invalid saved credentials format');
DebugLogger.log('Invalid saved credentials format', scope: 'storage');
await deleteSavedCredentials();
return null;
}
@@ -170,16 +188,17 @@ class StorageService {
await _secureCredentialStorage.migrateFromOldStorage(legacyCredentials);
// If migration successful, clean up legacy storage
await _secureStorage.delete(key: _credentialsKey);
debugPrint(
'DEBUG: Successfully migrated credentials to enhanced storage',
DebugLogger.log(
'Successfully migrated credentials to enhanced storage',
scope: 'storage',
);
} catch (e) {
debugPrint('Warning: Failed to migrate credentials: $e');
DebugLogger.log('Failed to migrate credentials: $e', scope: 'storage');
}
return legacyCredentials;
} catch (e) {
debugPrint('Error loading saved credentials: $e');
DebugLogger.log('Error loading saved credentials: $e', scope: 'storage');
return null;
}
}
@@ -189,7 +208,10 @@ class StorageService {
try {
await _secureCredentialStorage.deleteSavedCredentials();
} catch (e) {
debugPrint('Warning: Failed to delete from enhanced storage: $e');
DebugLogger.log(
'Failed to delete from enhanced storage: $e',
scope: 'storage',
);
}
await _secureStorage.delete(key: _credentialsKey);
@@ -218,7 +240,10 @@ class StorageService {
final decoded = jsonDecode(jsonString);
if (decoded is! List) {
debugPrint('Warning: Server configs data is not a list, resetting');
DebugLogger.log(
'Server configs data is not a list, resetting',
scope: 'storage',
);
return [];
}
@@ -232,20 +257,24 @@ class StorageService {
item.containsKey('url')) {
configs.add(ServerConfig.fromJson(item));
} else {
debugPrint(
'Warning: Skipping invalid server config: missing required fields',
DebugLogger.log(
'Skipping invalid server config: missing required fields',
scope: 'storage',
);
}
}
} catch (e) {
debugPrint('Warning: Failed to parse server config: $e');
DebugLogger.log(
'Failed to parse server config: $e',
scope: 'storage',
);
// Continue with other configs
}
}
return configs;
} catch (e) {
debugPrint('Error loading server configs: $e');
DebugLogger.log('Error loading server configs: $e', scope: 'storage');
return [];
}
}
@@ -279,8 +308,9 @@ class StorageService {
try {
final decoded = jsonDecode(jsonString);
if (decoded is! List) {
debugPrint(
'Warning: Local conversations data is not a list, resetting',
DebugLogger.log(
'Local conversations data is not a list, resetting',
scope: 'storage',
);
return [];
}
@@ -296,20 +326,24 @@ class StorageService {
item.containsKey('updatedAt')) {
conversations.add(Conversation.fromJson(item));
} else {
debugPrint(
'Warning: Skipping invalid conversation: missing required fields',
DebugLogger.log(
'Skipping invalid conversation: missing required fields',
scope: 'storage',
);
}
}
} catch (e) {
debugPrint('Warning: Failed to parse conversation: $e');
DebugLogger.log('Failed to parse conversation: $e', scope: 'storage');
// Continue with other conversations
}
}
return conversations;
} catch (e) {
debugPrint('Error parsing local conversations: $e');
DebugLogger.log(
'Error parsing local conversations: $e',
scope: 'storage',
);
return [];
}
}
@@ -319,7 +353,7 @@ class StorageService {
final json = conversations.map((c) => c.toJson()).toList();
await _prefs.setString(_localConversationsKey, jsonEncode(json));
} catch (e) {
debugPrint('Error saving local conversations: $e');
DebugLogger.log('Error saving local conversations: $e', scope: 'storage');
}
}
@@ -350,21 +384,21 @@ class StorageService {
try {
await _secureCredentialStorage.clearAll();
} catch (e) {
debugPrint('Warning: Failed to clear enhanced storage: $e');
DebugLogger.log('Failed to clear enhanced storage: $e', scope: 'storage');
}
// Clear legacy storage
await _secureStorage.deleteAll();
await _prefs.clear();
debugPrint('DEBUG: All storage cleared');
DebugLogger.log('All storage cleared', scope: 'storage');
}
// Clear only auth-related data (keeping server configs and other settings)
Future<void> clearAuthData() async {
await deleteAuthToken();
await deleteSavedCredentials();
debugPrint('DEBUG: Auth data cleared');
DebugLogger.log('Auth data cleared', scope: 'storage');
}
/// Check if enhanced secure storage is available
@@ -372,7 +406,10 @@ class StorageService {
try {
return await _secureCredentialStorage.isSecureStorageAvailable();
} catch (e) {
debugPrint('Warning: Failed to check enhanced storage availability: $e');
DebugLogger.log(
'Failed to check enhanced storage availability: $e',
scope: 'storage',
);
return false;
}
}

View File

@@ -1,7 +1,7 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart' hide debugPrint;
import 'package:flutter/material.dart';
import '../../core/models/chat_message.dart';
import '../../core/services/persistent_streaming_service.dart';
@@ -14,11 +14,6 @@ import '../../shared/widgets/themed_dialogs.dart';
import '../../shared/theme/theme_extensions.dart';
import '../utils/debug_logger.dart';
void debugPrint(String? message, {int? wrapWidth}) {
if (message == null) return;
DebugLogger.fromLegacy(message, scope: 'streaming/helper');
}
// Keep local verbosity toggle for socket logs
const bool kSocketVerboseLogging = false;
@@ -83,7 +78,10 @@ StreamSubscription<String> attachUnifiedChunkedStreaming({
),
controller: persistentController,
recoveryCallback: () async {
debugPrint('DEBUG: Attempting to recover interrupted stream');
DebugLogger.log(
'Attempting to recover interrupted stream',
scope: 'streaming/helper',
);
},
metadata: {
'conversationId': activeConversationId,

View File

@@ -1,15 +1,10 @@
import 'package:flutter/foundation.dart' hide debugPrint;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:conduit/l10n/app_localizations.dart';
import '../../shared/theme/theme_extensions.dart';
import 'navigation_service.dart';
import '../utils/debug_logger.dart';
void debugPrint(String? message, {int? wrapWidth}) {
if (message == null) return;
DebugLogger.fromLegacy(message, scope: 'errors/user-friendly');
}
/// User-friendly error messages and recovery actions
class UserFriendlyErrorHandler {
static final UserFriendlyErrorHandler _instance =
@@ -347,9 +342,12 @@ class UserFriendlyErrorHandler {
/// Log technical error details for debugging
void _logError(dynamic error) {
if (kDebugMode) {
debugPrint('ERROR: $error');
DebugLogger.log('$error', scope: 'errors/user-friendly');
if (error is Error) {
debugPrint('STACK TRACE: ${error.stackTrace}');
DebugLogger.log(
'STACK TRACE: ${error.stackTrace}',
scope: 'errors/user-friendly',
);
}
}