upload method

Future<TClientResponse?> upload(
  1. String path, {
  2. required File file,
  3. Map<String, String>? query,
  4. Map<String, String>? fields,
  5. Map<String, String>? headers,
  6. void onUploadProgress(
    1. int sent,
    2. int total
    )?,
  7. OnCancelCallback? onCancelCallback,
  8. void onError(
    1. String message
    )?,
  9. TClientToken? token,
})

File upload with progress

Implementation

Future<TClientResponse?> upload(
  String path, {
  required File file,
  Map<String, String>? query,
  Map<String, String>? fields,
  Map<String, String>? headers,
  void Function(int sent, int total)? onUploadProgress,
  OnCancelCallback? onCancelCallback,
  void Function(String message)? onError,
  TClientToken? token,
}) async {
  try {
    final uri = buildUri(path, query);
    final request = await ioClient.postUrl(uri).timeout(options.sendTimeout);
    setHeaders(request, headers);

    // 1. Boundary တည်ဆောက်ခြင်း
    final boundary =
        '----dart-boundary-${DateTime.now().millisecondsSinceEpoch}';
    request.headers.set(
      HttpHeaders.contentTypeHeader,
      'multipart/form-data; boundary=$boundary',
    );

    // 2. Data အားလုံး၏ Total Size ကို ကြိုတင်တွက်ချက်ခြင်း (Progress အတွက်)
    final filename = file.path.split(Platform.isWindows ? r'\' : '/').last;
    final fileLength = await file.length();

    // Header နှင့် End boundary bytes များ
    final fileHeader = utf8.encode(
      '--$boundary\r\n'
      'Content-Disposition: form-data; name="file"; filename="$filename"\r\n'
      'Content-Type: application/octet-stream\r\n\r\n',
    );
    final endBoundary = utf8.encode('\r\n--$boundary--\r\n');

    int fieldsSize = 0;
    List<List<int>> fieldBytesList = [];
    if (fields != null) {
      fields.forEach((key, value) {
        final part = utf8.encode(
          '--$boundary\r\nContent-Disposition: form-data; name="$key"\r\n\r\n$value\r\n',
        );
        fieldBytesList.add(part);
        fieldsSize += part.length;
      });
    }

    final totalSize =
        fieldsSize + fileHeader.length + fileLength + endBoundary.length;
    request.contentLength =
        totalSize; // Size အတိအကျပေးခြင်းဖြင့် server error ကင်းစေသည်

    int sent = 0;

    // 3. Form Fields များပို့ခြင်း
    for (var bytes in fieldBytesList) {
      request.add(bytes);
      sent += bytes.length;
      onUploadProgress?.call(sent, totalSize);
    }

    // 4. File Header ပို့ခြင်း
    request.add(fileHeader);
    sent += fileHeader.length;

    // 5. File Content ကို Stream ဖြင့်ပို့ခြင်း
    final fileStream = file.openRead();
    await for (final chunk in fileStream) {
      if (token?.isCanceled ?? false) {
        request.abort();
        onCancelCallback?.call(token!.onCancelMessage);
        throw Exception(token!.onCancelMessage);
      }
      request.add(chunk);
      sent += chunk.length;
      onUploadProgress?.call(sent, totalSize);
    }

    // 6. End Boundary ပို့ခြင်း
    request.add(endBoundary);
    sent += endBoundary.length;
    onUploadProgress?.call(sent, totalSize);

    // 7. Response ရယူခြင်း
    final response = await request.close().timeout(options.receiveTimeout);
    final responseBody = await response.transform(utf8.decoder).join();

    return TClientResponse(
      statusCode: response.statusCode,
      headers: getResponseHeaders(response),
      data: responseBody,
    );
  } catch (e) {
    TClientLogger.instance.showLog(e.toString(), tag: 'upload');
    onError?.call(e.toString());
    rethrow;
  }
}