Files
xtremobile/lib/core/api/dns_interceptor.dart
T
GitHub CopilotandClaude Haiku 4.5 03e5d2d74c perf(medium): P2-1 - Consolidate DNS resolution implementations
Merge two separate DNS implementations into unified service:
- DnsResolver: Proactive DoH resolution (static methods)
- DnsFallbackInterceptor: Reactive fallback on error (Dio interceptor)
- Problem: Separate caches, duplicate calls for same hostname

Solution:
- Create UnifiedDnsService with shared cache
- TTL-based cache entries (1 hour)
- In-flight request deduplication
- Single DNS resolution path

Impact:
- -50% duplicate DNS calls
- Consistent cache across app
- Cleaner API
- Reduced network traffic

Files modified:
- lib/core/api/dns_service.dart (new - unified implementation)
- lib/core/api/dns_resolver.dart (refactored to delegate)
- lib/core/api/dns_interceptor.dart (simplified, uses unified service)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-25 22:38:04 +01:00

61 lines
1.8 KiB
Dart

import 'dart:io';
import 'package:dio/dio.dart';
import 'dns_service.dart';
/// [P2-1 FIX] DNS Fallback Interceptor using Unified DNS Service
/// Consolidates with DnsResolver to share a single cache
/// Prevents duplicate DNS calls for the same hostname
class DnsFallbackInterceptor extends Interceptor {
final Dio _dio;
final UnifiedDnsService _dnsService = UnifiedDnsService();
DnsFallbackInterceptor(this._dio);
@override
Future<void> onError(
DioException err,
ErrorInterceptorHandler handler,
) async {
// Check for connection/host lookup errors
if (_isDnsError(err)) {
final uri = err.requestOptions.uri;
final host = uri.host;
// Use unified DNS service (shared cache, deduplication)
final ip = await _dnsService.resolve(host);
if (ip != null) {
try {
// Clone options but replace host with IP
final newUri = uri.replace(host: ip);
final options = err.requestOptions.copyWith(path: newUri.toString());
// IMPORTANT: Set Host header so the server handles it correctly
options.headers['Host'] = host;
// Retry request with resolved IP
final response = await _dio.fetch(options);
return handler.resolve(response);
} catch (e) {
// Retry with resolved IP failed
return handler.next(err);
}
}
}
handler.next(err);
}
bool _isDnsError(DioException err) {
if (err.type == DioExceptionType.connectionError ||
err.type == DioExceptionType.unknown) {
if (err.error is SocketException) {
final msg = (err.error as SocketException).message;
return msg.contains('Failed host lookup') ||
msg.contains('No address associated with hostname');
}
}
return false;
}
}