Skip to content

Commit

Permalink
feat(utils): readFilesUtility WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
iyifr committed Dec 11, 2024
1 parent b59a956 commit 3136d5b
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 10 deletions.
9 changes: 6 additions & 3 deletions bin/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import 'dart:convert';
import 'dart:io';

import 'package:h4/create.dart';

void main() async {
Expand Down Expand Up @@ -32,4 +29,10 @@ void main() async {

return 'Hi from /api with $username, $password';
});

apiRouter.post("/upload", (event) async {
var files = await readFiles(event, fieldName: 'file', customFilePath: 'uploads');
setResponseHeader(event, header: 'Content-Type', value: 'application/json');
return files;
});
}
76 changes: 69 additions & 7 deletions lib/utils/req_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ Future<FormData> handleMultipartFormdata(
if (fieldName != null) {
if (contentType != null || filename != null) {
// Stream file to temporary storage
final fileInfo = await _streamToStorage(part, filename);
final fileInfo = await _streamToStorage(part, filename, null);

Map<String, dynamic> fieldData = {
'path': fileInfo['path'],
Expand Down Expand Up @@ -189,19 +189,30 @@ String detectEncoding(Uint8List bytes) {
return 'UTF-8';
}

Future<Map<String, dynamic>> _streamToStorage(
Stream<List<int>> dataStream, String? originalFilename) async {
Future<Map<String, dynamic>> _streamToStorage(Stream<List<int>> dataStream,
String? originalFilename, String? customFilePath) async {
// Create unique filename to avoid collisions
final timestamp = DateTime.now().millisecondsSinceEpoch;
final randomId =
DateTime.now().microsecondsSinceEpoch.toString().substring(8);
final safeFilename =
originalFilename?.replaceAll(RegExp(r'[^a-zA-Z0-9.-]'), '_') ?? 'unnamed';
final filename = '${timestamp}_${randomId}_$safeFilename';
final filename = '$timestamp$randomId$safeFilename';

// Use custom path if provided, otherwise use system temp directory
final String filePath;
if (customFilePath != null) {
// Create directory if it doesn't exist
final directory = Directory(customFilePath);
if (!await directory.exists()) {
await directory.create(recursive: true);
}
filePath = path.join(customFilePath, filename);
} else {
final tempDir = Directory.systemTemp;
filePath = path.join(tempDir.path, filename);
}

// Get system temp directory
final tempDir = Directory.systemTemp;
final filePath = path.join(tempDir.path, filename);
final file = File(filePath);

// Stream metrics
Expand Down Expand Up @@ -235,3 +246,54 @@ Future<Map<String, dynamic>> _streamToStorage(
throw CreateError(message: 'Failed to save file: ${e.toString()}');
}
}

Future<List<Map<String, dynamic>>?> readFiles(H4Event event,
{required String fieldName, String? customFilePath}) async {
final HttpRequest request = event.node["value"]!;
final contentType = request.headers.contentType;

if (contentType?.mimeType != 'multipart/form-data') {
throw CreateError(
message: 'Files can only be uploaded using multipart/form-data');
}

final boundary = contentType!.parameters['boundary'];
if (boundary == null) {
throw CreateError(message: 'Missing boundary in multipart/form-data');
}

final mimeTransformer = MimeMultipartTransformer(boundary);
final parts = request.cast<List<int>>().transform(mimeTransformer);
List<Map<String, dynamic>> files = [];

try {
await for (final part in parts) {
final headers = part.headers;
final contentType = headers['content-type'];
final contentDisposition = headers['content-disposition'];
final nameMatch =
RegExp(r'name="([^"]*)"').firstMatch(contentDisposition ?? '');
final currentFieldName = nameMatch?.group(1);
final filenameMatch =
RegExp(r'filename="([^"]*)"').firstMatch(contentDisposition ?? '');
final filename = filenameMatch?.group(1);

// Only process if it matches the requested fieldName and has a filename
if (currentFieldName == fieldName && filename != null) {
final fileInfo = await _streamToStorage(part, filename, customFilePath);
files.add({
'path': fileInfo['path'],
'mimeType': contentType,
'originalname': filename,
'fieldName': fieldName,
'size': fileInfo['size'],
'tempFilename': fileInfo['tempFilename'],
});
}
}

return files.isEmpty ? null : files;
} catch (e) {
throw CreateError(message: 'Failed to read files: ${e.toString()}');
}
}

0 comments on commit 3136d5b

Please sign in to comment.