import 'dart:convert'; import 'dart:io'; import 'package:http/http.dart'; import 'package:http/io_client.dart'; import 'package:flutter/foundation.dart'; // Combined Riderlog providers: /// Hardcoded known-good IPs for hosts where carrier DNS returns broken nodes. /// Confirmed by Python test: 66.116.225.226 = 200 OK, 125.21.240.67 = 404. const _knownGoodIPs = { 'queue.workolik.com': '66.116.225.226', }; /// Creates an IOClient that: /// 1. Bypasses SSL certificate errors /// 2. Forces known-good IPs for hosts where carrier DNS returns broken CDN nodes /// 3. Manually does TLS upgrade with correct SNI (hostname, not IP) IOClient _buildSslBypassClient() { final httpClient = HttpClient() ..badCertificateCallback = (X509Certificate cert, String host, int port) => true; httpClient.connectionFactory = (Uri uri, String? proxyHost, int? proxyPort) async { final host = uri.host; final port = uri.port; // Use known-good IP if available, else resolve normally (prefer IPv4) InternetAddress? target; final knownIP = _knownGoodIPs[host]; if (knownIP != null) { target = InternetAddress(knownIP); debugPrint('[SSL_CLIENT] Using known-good IP: $knownIP for $host'); } else { try { final addresses = await InternetAddress.lookup( host, type: InternetAddressType.IPv4, ); if (addresses.isNotEmpty) target = addresses.first; } catch (_) {} } if (uri.scheme == 'https') { final socketFuture = Socket.connect(target ?? InternetAddress(host), port) .then((plain) => SecureSocket.secure( plain, host: host, // SNI = original hostname for Nginx routing onBadCertificate: (_) => true, supportedProtocols: ['http/1.1'], )) .then((s) => s as Socket); return ConnectionTask.fromSocket(socketFuture, () {}); } return Socket.startConnect(target ?? InternetAddress(host), port); }; return IOClient(httpClient); } class CreateRiderLogProvider { Future?> createRiderLog( String urldata, Map data, ) async { const maxAttempts = 3; try { debugPrint('createRiderLog payload ${json.encode(data)}'); } catch (_) {} for (int attempt = 1; attempt <= maxAttempts; attempt++) { final client = _buildSslBypassClient(); try { final url = Uri.parse(urldata); final response = await client.post( url, body: json.encode(data), headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, ); debugPrint('createRiderLog url $urldata (attempt $attempt)'); debugPrint('createRiderLog status ${response.statusCode}'); debugPrint('createRiderLog response ${response.body}'); if (response.statusCode >= 200 && response.statusCode < 300) { return json.decode(response.body.toString()) as Map; } else { debugPrint( 'createRiderLog failed: HTTP ${response.statusCode} (attempt $attempt/$maxAttempts)', ); // On 404/5xx, wait and retry to potentially hit a different CDN node if (attempt < maxAttempts) { await Future.delayed(const Duration(seconds: 1)); } } } catch (e) { debugPrint('createRiderLog exception (attempt $attempt): $e'); if (attempt < maxAttempts) { await Future.delayed(const Duration(seconds: 1)); } } finally { client.close(); } } debugPrint('createRiderLog failed after $maxAttempts attempts'); return null; } } class UpdateRiderLogProvider { Future?> updateRiderLog( String urldata, Map data, ) async { try { final url = Uri.parse(urldata); final response = await put( url, body: json.encode(data), headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, ); debugPrint('updateRiderLog url: $urldata'); debugPrint('updateRiderLog response: ${response.body}'); if (response.statusCode >= 200 && response.statusCode < 300) { final decoded = json.decode(response.body); if (decoded is Map) { return decoded; } else { debugPrint('⚠️ updateRiderLog: Expected Map but got ${decoded.runtimeType}'); return {}; } } else { debugPrint('❌ updateRiderLog failed with code ${response.statusCode}'); return {}; } } catch (e) { debugPrint('❌ Exception in updateRiderLog: $e'); return {}; } } } class GetRiderLogProvider { Future?> getRiderLog(String urldata) async { Map? getRiderLogResponse; try { final url = Uri.parse(urldata); final response = await get(url, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }); debugPrint('getRiderLog response ${response.body}'); debugPrint('getRiderLog url ${urldata.toString()}'); getRiderLogResponse = json.decode(response.body.toString()) as Map; } catch (e) { debugPrint(e.toString()); } return getRiderLogResponse; } Future?> getRiderCount(String urldata) async { Map? getRiderCountResponse; try { final url = Uri.parse(urldata); final response = await get(url, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }); debugPrint('getRiderCount response ${response.body}'); debugPrint('getRiderCount url ${urldata.toString()}'); getRiderCountResponse = json.decode(response.body.toString()) as Map; } catch (e) { debugPrint(e.toString()); } return getRiderCountResponse; } } class BreakRiderLogProvider { Future?> createBreakRiderLog( String urldata, Map data, ) async { Map? breakLogResponse; try { final url = Uri.parse(urldata); final response = await post( url, body: json.encode(data), headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, ); debugPrint('createBreakRiderLog url $urldata'); debugPrint('createBreakRiderLog response ${response.body}'); breakLogResponse = json.decode(response.body.toString()) as Map; } catch (e) { debugPrint(e.toString()); } return breakLogResponse; } Future?> updateBreakRiderLog( String urldata, Map data, ) async { Map? breakLogResponse; try { final url = Uri.parse(urldata); final response = await put( url, body: json.encode(data), headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, ); debugPrint('updateBreakRiderLog url $urldata'); debugPrint('updateBreakRiderLog response ${response.body}'); breakLogResponse = json.decode(response.body.toString()) as Map; } catch (e) { debugPrint(e.toString()); } return breakLogResponse; } }