updated the sheet

This commit is contained in:
2026-08-28 18:16:28 +05:30
parent 69f4f3e909
commit 074cc0eccf
43 changed files with 2617 additions and 1201 deletions

View File

@@ -1,260 +1,46 @@
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.
/// ─────────────────────────────────────────────────────────────────────────
/// THE DELIVERY LINE'S RIDER LOG IS THE PARCEL LINE'S RIDER LOG
///
/// **Empty since the delivery line moved to Doormile.** The one entry here
/// pinned `queue.workolik.com` to 66.116.225.226, because some Indian carriers'
/// DNS resolved that host to a CDN node that answered 404. Nothing calls that
/// host any more — every delivery-line write goes to `api.doormile.com` via
/// [DeliveryApi] — so the pin was routing advice about a server this app no
/// longer talks to.
/// ── What this file used to be ──
///
/// It is deliberately not re-pointed at the Doormile host: that IP belongs to
/// the old backend, and pinning it for `api.doormile.com` would send every
/// request to the wrong server with the right SNI. If Doormile ever needs the
/// same workaround, add it here with its own verified address.
const _knownGoodIPs = <String, String>{};
/// A second, complete implementation of duty, breaks and the location
/// heartbeat, posting to the two retired pre-v1 hosts over raw `http`. It survived the migration only because
/// nothing in `lib/` imported it: the delivery shell reaches it through
/// [riderShell], which is production for any tenant on the delivery line.
///
/// It carried two things that had already been deleted from the parcel line:
///
/// • **`_buildSslBypassClient()`** — an `IOClient` whose
/// `badCertificateCallback` returned `true` for *every* certificate, with a
/// hand-rolled `SecureSocket` upgrade and a hardcoded IP pin. Every request
/// it carried — a rider's GPS track, his duty state, his break times — could
/// be read and rewritten by anything on the path. The parcel line removed
/// this; the delivery line kept it.
/// • **The legacy hosts themselves**, which the v1 migration left behind.
///
/// ── Why this is an export and not a rewrite ──
///
/// `lib/providers/Riderlog/riderlog_provider.dart` already does exactly this
/// job against `api.doormile.com`: same four class names, same legacy
/// `{status, details}` envelopes, mapped onto `POST /miler/duty/start`,
/// `PUT /miler/location`, `POST /miler/logs` and the break endpoints. The
/// delivery line's controller calls the same four classes by the same names.
///
/// So there is nothing to port. Re-exporting means one implementation, one duty
/// gate, one telemetry payload and one place where a contract change lands —
/// which is the whole point of having migrated the parcel line at all. The two
/// lines cannot drift, because there is only one of them.
///
/// The `String urldata` first parameter is gone from every method; callers that
/// were building a legacy URL to pass in have had that construction deleted
/// rather than made to compile.
/// ─────────────────────────────────────────────────────────────────────────
library;
/// 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<Socket>(socketFuture, () {});
}
return Socket.startConnect(target ?? InternetAddress(host), port);
};
return IOClient(httpClient);
}
class CreateRiderLogProvider {
Future<Map<String, dynamic>?> createRiderLog(
String urldata,
Map<String, dynamic> 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<String, dynamic>;
} 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<Map<String, dynamic>?> updateRiderLog(
String urldata,
Map<String, dynamic> 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<String, dynamic>) {
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<Map<String, dynamic>?> getRiderLog(String urldata) async {
Map<String, dynamic>? 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<String, dynamic>;
} catch (e) {
debugPrint(e.toString());
}
return getRiderLogResponse;
}
Future<Map<String, dynamic>?> getRiderCount(String urldata) async {
Map<String, dynamic>? 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<String, dynamic>;
} catch (e) {
debugPrint(e.toString());
}
return getRiderCountResponse;
}
}
class BreakRiderLogProvider {
Future<Map<String, dynamic>?> createBreakRiderLog(
String urldata,
Map<String, dynamic> data,
) async {
Map<String, dynamic>? 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<String, dynamic>;
} catch (e) {
debugPrint(e.toString());
}
return breakLogResponse;
}
Future<Map<String, dynamic>?> updateBreakRiderLog(
String urldata,
Map<String, dynamic> data,
) async {
Map<String, dynamic>? 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<String, dynamic>;
} catch (e) {
debugPrint(e.toString());
}
return breakLogResponse;
}
}
export 'package:miler/providers/Riderlog/riderlog_provider.dart'
show
BreakRiderLogProvider,
CreateRiderLogProvider,
GetRiderLogProvider,
UpdateRiderLogProvider,
unawaited;

View File

@@ -1,67 +1,25 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart';
import 'package:http/io_client.dart';
import 'package:http/http.dart' as http;
import 'package:miler/data/api_config.dart';
import 'package:flutter/foundation.dart';
// Combined Deliverylog providers:
/// Hardcoded known-good IPs for hosts where carrier DNS returns broken CDN nodes.
/// Confirmed: 66.116.225.226 = 200 OK, 125.21.240.67 = 404/405.
/// Empty since the delivery line moved to Doormile — see the note on the
/// matching map in `providers/Riderlog/riderlog_provider.dart`. The old entry
/// pinned `queue.workolik.com`, a host nothing calls now, and must not be
/// re-pointed at `api.doormile.com`.
const _knownGoodIPs = <String, String>{};
/// Creates an IOClient that:
/// 1. Bypasses SSL certificate errors
/// 2. Forces known-good IPs to avoid broken CDN nodes from carrier DNS
/// 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;
InternetAddress? target;
final knownIP = _knownGoodIPs[host];
if (knownIP != null) {
target = InternetAddress(knownIP);
} 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,
onBadCertificate: (_) => true,
supportedProtocols: ['http/1.1'],
),
)
.then((s) => s as Socket);
return ConnectionTask.fromSocket<Socket>(socketFuture, () {});
}
return Socket.startConnect(target ?? InternetAddress(host), port);
};
return IOClient(httpClient);
}
/// ── The SSL bypass is gone ──
///
/// This file built its own `IOClient` with `onBadCertificate: (_) => true` and
/// a hand-rolled `SecureSocket` upgrade, so **every certificate was accepted**
/// — a delivery rider's position, his order ids and his session were readable
/// and rewritable by anything on the path. The parcel line deleted the same
/// code (see `providers/Riderlog/riderlog_provider.dart`); the delivery line
/// kept it because nothing in `lib/` imported this file directly.
///
/// It also sent **no `Authorization` header**. The URLs it posts to are v1
/// routes on `api.doormile.com` — resolved through the [DeliveryApi] facade —
/// so every one of these calls could only ever have been answered with a 401.
/// A plain client plus [ApiConfig.authHeaders] fixes both at once.
Future<Map<String, String>> _headers() => ApiConfig.authHeaders();
class CreateDeliveryLogProvider {
Future<Map<String, dynamic>?> createDeliveryLog(
@@ -70,19 +28,12 @@ class CreateDeliveryLogProvider {
bool wrapInArray = true,
}) async {
Map<String, dynamic>? result;
final client = _buildSslBypassClient();
final client = http.Client();
try {
final url = Uri.parse(urldata);
final body = json.encode(wrapInArray ? [data] : data);
final response = await client
.post(
url,
body: body,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
)
.post(url, body: body, headers: await _headers())
.timeout(const Duration(seconds: 10));
debugPrint('createDeliveryLog url $urldata');
debugPrint(body);
@@ -110,18 +61,11 @@ class UpdateDeliveryProvider {
String urldata,
) async {
Map<String, dynamic>? updateDeliveryResponse;
final client = _buildSslBypassClient();
final client = http.Client();
try {
final url = Uri.parse(urldata);
final response = await client
.put(
url,
body: json.encode(data),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
)
.put(url, body: json.encode(data), headers: await _headers())
.timeout(const Duration(seconds: 10));
debugPrint('updateDelivery url $urldata');
debugPrint('updateDelivery status ${response.statusCode}');
@@ -148,18 +92,11 @@ class UpdateDeliveryProvider {
String urldata,
) async {
Map<String, dynamic>? updateDeliveryResponse;
final client = _buildSslBypassClient();
final client = http.Client();
try {
final url = Uri.parse(urldata);
final response = await client
.put(
url,
body: json.encode(data),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
)
.put(url, body: json.encode(data), headers: await _headers())
.timeout(const Duration(seconds: 10));
debugPrint('updateArrived url $urldata');
debugPrint('updateArrived status ${response.statusCode}');
@@ -185,18 +122,11 @@ class UpdateDeliveryProvider {
String urldata,
) async {
Map<String, dynamic>? updateDeliveryResponse;
final client = _buildSslBypassClient();
final client = http.Client();
try {
final url = Uri.parse(urldata);
final response = await client
.put(
url,
body: json.encode(data),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
)
.put(url, body: json.encode(data), headers: await _headers())
.timeout(const Duration(seconds: 10));
debugPrint('updatePicked url $urldata');
debugPrint('updatePicked status ${response.statusCode}');
@@ -222,18 +152,11 @@ class UpdateDeliveryProvider {
String urldata,
) async {
Map<String, dynamic>? updateDeliveryResponse;
final client = _buildSslBypassClient();
final client = http.Client();
try {
final url = Uri.parse(urldata);
final response = await client
.put(
url,
body: json.encode(data),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
)
.put(url, body: json.encode(data), headers: await _headers())
.timeout(const Duration(seconds: 10));
debugPrint('updateActive url $urldata');
debugPrint('updateActive status ${response.statusCode}');
@@ -258,7 +181,7 @@ class UpdateDeliveryProvider {
class GetDeliveryLogProvider {
Future<Map<String, dynamic>?> getDeliveryLog(String urldata) async {
Map<String, dynamic>? result;
final client = _buildSslBypassClient();
final client = http.Client();
try {
final url = Uri.parse(urldata);
final response = await client.get(