LCOV - code coverage report
Current view: top level - src/workers - http_upload_worker.dart Coverage Total Hit
Test: lcov.info Lines: 100.0 % 34 34
Test Date: 2026-04-30 18:23:23 Functions: - 0 0

            Line data    Source code
       1              : import 'package:flutter/foundation.dart';
       2              : import '../worker.dart';
       3              : 
       4              : export 'request_signing.dart';
       5              : 
       6              : /// HTTP upload worker configuration.
       7              : ///
       8              : /// Supports multipart/form-data file uploads with optional background
       9              : /// URLSession on iOS for uploads that survive app termination.
      10              : @immutable
      11              : final class HttpUploadWorker extends Worker {
      12           11 :   const HttpUploadWorker({
      13              :     required this.url,
      14              :     required this.filePath,
      15              :     this.fileFieldName = 'file',
      16              :     this.fileName,
      17              :     this.mimeType,
      18              :     this.headers = const {},
      19              :     this.additionalFields = const {},
      20              :     this.timeout = const Duration(minutes: 5),
      21              :     this.useBackgroundSession = false,
      22              :     this.requestSigning,
      23              :   });
      24              : 
      25              :   /// The URL to upload to.
      26              :   final String url;
      27              : 
      28              :   /// Path to the file to upload (absolute path).
      29              :   final String filePath;
      30              : 
      31              :   /// Form field name for the file (default: "file").
      32              :   final String fileFieldName;
      33              : 
      34              :   /// Optional custom file name (defaults to actual file name).
      35              :   final String? fileName;
      36              : 
      37              :   /// Optional MIME type (auto-detected if not provided).
      38              :   final String? mimeType;
      39              : 
      40              :   /// Optional HTTP headers to include in the request.
      41              :   final Map<String, String> headers;
      42              : 
      43              :   /// Optional additional form fields to include in the multipart request.
      44              :   final Map<String, String> additionalFields;
      45              : 
      46              :   /// Request timeout (default: 5 minutes).
      47              :   final Duration timeout;
      48              : 
      49              :   /// Use background URLSession for uploads (iOS only).
      50              :   ///
      51              :   /// **v2.3.0+ iOS Feature:**
      52              :   /// When enabled, uploads use `URLSessionConfiguration.background` which:
      53              :   /// - **Survives app termination** - Uploads continue even if app is killed
      54              :   /// - **No time limits** - Can upload for hours (vs 30s foreground limit)
      55              :   /// - **System-managed** - OS handles network changes and retries
      56              :   /// - **Battery efficient** - OS schedules transfers optimally
      57              :   ///
      58              :   /// **Android:**
      59              :   /// This parameter has no effect on Android. WorkManager already handles
      60              :   /// background uploads robustly without special configuration.
      61              :   ///
      62              :   /// **When to use:**
      63              :   /// - ✅ Large files (>10MB) that may take minutes to upload
      64              :   /// - ✅ Uploads that must complete even if user force-quits app
      65              :   /// - ✅ Uploads on unreliable networks (automatic retry)
      66              :   /// - ❌ Small files (<1MB) - foreground session is faster
      67              :   /// - ❌ Immediate uploads that finish in seconds
      68              :   ///
      69              :   /// Example:
      70              :   /// ```dart
      71              :   /// // Large video upload (survives app termination)
      72              :   /// worker: NativeWorker.httpUpload(
      73              :   ///   url: 'https://cdn.example.com/videos',
      74              :   ///   filePath: '/videos/large-video.mp4',
      75              :   ///   useBackgroundSession: true,  // 🚀 Survives termination
      76              :   /// ),
      77              :   /// ```
      78              :   ///
      79              :   /// Default: `false` (backward compatible with existing code)
      80              :   final bool useBackgroundSession;
      81              : 
      82              :   /// HMAC-SHA256 request signing configuration.
      83              :   ///
      84              :   /// When set, each upload request is signed with the specified secret key
      85              :   /// and the signature is injected as a request header (default: `X-Signature`).
      86              :   final RequestSigning? requestSigning;
      87              : 
      88              :   // ═══════════════════════════════════════════════════════════════════════════
      89              :   // BUILDER-STYLE copyWith + convenience methods
      90              :   // ═══════════════════════════════════════════════════════════════════════════
      91              : 
      92              :   /// Returns a copy with the given fields replaced.
      93            1 :   HttpUploadWorker copyWith({
      94              :     String? url,
      95              :     String? filePath,
      96              :     String? fileFieldName,
      97              :     String? fileName,
      98              :     String? mimeType,
      99              :     Map<String, String>? headers,
     100              :     Map<String, String>? additionalFields,
     101              :     Duration? timeout,
     102              :     bool? useBackgroundSession,
     103              :     RequestSigning? requestSigning,
     104              :   }) =>
     105            1 :       HttpUploadWorker(
     106            1 :         url: url ?? this.url,
     107            1 :         filePath: filePath ?? this.filePath,
     108            1 :         fileFieldName: fileFieldName ?? this.fileFieldName,
     109            1 :         fileName: fileName ?? this.fileName,
     110            1 :         mimeType: mimeType ?? this.mimeType,
     111            1 :         headers: headers ?? this.headers,
     112            1 :         additionalFields: additionalFields ?? this.additionalFields,
     113            1 :         timeout: timeout ?? this.timeout,
     114            1 :         useBackgroundSession: useBackgroundSession ?? this.useBackgroundSession,
     115            1 :         requestSigning: requestSigning ?? this.requestSigning,
     116              :       );
     117              : 
     118              :   /// Convenience: add or merge HTTP headers.
     119              :   ///
     120              :   /// ```dart
     121              :   /// worker.withHeaders({'Authorization': 'Bearer $token', 'X-App': '1'})
     122              :   /// ```
     123            2 :   HttpUploadWorker withHeaders(Map<String, String> extra) => copyWith(
     124            3 :         headers: {...headers, ...extra},
     125              :       );
     126              : 
     127              :   /// Convenience: add `Authorization` header.
     128              :   ///
     129              :   /// ```dart
     130              :   /// worker.withAuth(token: myToken)
     131              :   /// worker.withAuth(token: myApiKey, template: 'ApiKey {accessToken}')
     132              :   /// ```
     133            1 :   HttpUploadWorker withAuth({
     134              :     required String token,
     135              :     String template = 'Bearer {accessToken}',
     136              :   }) =>
     137            2 :       withHeaders({
     138            1 :         'Authorization': template.replaceAll('{accessToken}', token),
     139              :       });
     140              : 
     141              :   /// Convenience: sign requests with HMAC-SHA256.
     142            1 :   HttpUploadWorker withSigning(RequestSigning signing) =>
     143            1 :       copyWith(requestSigning: signing);
     144              : 
     145            5 :   @override
     146              :   String get workerClassName => 'HttpUploadWorker';
     147              : 
     148            5 :   @override
     149            5 :   Map<String, dynamic> toMap() => {
     150            5 :         'workerType': 'httpUpload',
     151           10 :         'url': url,
     152           10 :         'filePath': filePath,
     153           10 :         'fileFieldName': fileFieldName,
     154            7 :         if (fileName != null) 'fileName': fileName,
     155            9 :         if (mimeType != null) 'mimeType': mimeType,
     156           10 :         'headers': headers,
     157           10 :         'additionalFields': additionalFields,
     158           15 :         'timeoutMs': timeout.inMilliseconds,
     159           10 :         'useBackgroundSession': useBackgroundSession,
     160            5 :         if (requestSigning != null) 'requestSigning': requestSigning!.toMap(),
     161              :       };
     162              : }
        

Generated by: LCOV version 2.4-0