Преглед изворни кода

each route will have a handler

Fares пре 10 месеци
родитељ
комит
6a4454e487

+ 13 - 0
.vscode/launch.json

@@ -0,0 +1,13 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "shelf",
+            "request": "launch",
+            "type": "dart"
+        }
+    ]
+}

+ 2 - 3
bin/server.dart

@@ -1,14 +1,13 @@
 import 'dart:io';
 
-import 'package:file_upload_processor/file_upload_api.dart';
+import 'package:file_upload_processor/routes/main_router.dart';
 import 'package:shelf/shelf.dart' as shelf;
 import 'package:shelf/shelf_io.dart' as shelf_io;
 
 void main() async {
-  final api = FileUploadApi();
   final handler = const shelf.Pipeline()
       .addMiddleware(shelf.logRequests())
-      .addHandler(api.router);
+      .addHandler(MainRouter().router);
 
   final server = await shelf_io.serve(handler, InternetAddress.anyIPv4, 8080);
   print('Server running on port ${server.port}');

+ 1 - 1
docker-compose.yml

@@ -10,7 +10,7 @@ services:
       - uploaded_data:/app/uploaded
     restart: unless-stopped
     healthcheck:
-      test: ["CMD", "curl", "-f", "http://localhost:8080/"]
+      test: ["CMD", "curl", "-f", "http://127.0.0.1:8080/health"]
       interval: 30s
       timeout: 10s
       retries: 3

+ 7 - 0
lib/handlers/base_api.dart

@@ -0,0 +1,7 @@
+import 'package:shelf/shelf.dart' as shelf;
+
+abstract class BaseApi {
+  BaseApi(shelf.Request this.request);
+  final shelf.Request request;
+  response();
+}

+ 54 - 62
lib/file_upload_api.dart → lib/handlers/file_upload_api.dart

@@ -1,15 +1,16 @@
 import 'dart:io';
+import 'package:file_upload_processor/handlers/base_api.dart';
 import 'package:intl/intl.dart';
 import 'package:mime/mime.dart';
 import 'package:shelf/shelf.dart' as shelf;
-//import 'package:shelf/shelf_io.dart' as shelf_io;
-import 'package:shelf_router/shelf_router.dart';
 import 'package:path/path.dart' as path;
 import 'package:http_parser/http_parser.dart';
 import 'package:archive/archive.dart';
 import 'package:supabase/supabase.dart';
 
-class FileUploadApi {
+class FileUploadApi extends BaseApi {
+  FileUploadApi(shelf.Request request) : super(request);
+
   SupabaseClient getSupabaseClient(shelf.Request request) {
     final supabaseUrl = request.headers['supabase-url'];
     if (supabaseUrl == null) {
@@ -96,77 +97,68 @@ class FileUploadApi {
     }
   }
 
-  Router get router {
-    final router = Router();
-
-    router.get('/', (shelf.Request request) {
-      return shelf.Response.ok('Hello World');
-    });
+  @override
+  response() async {
+    final supabaseClient = getSupabaseClient(request);
+    await initializeDirectories();
 
-    router.post('/upload', (shelf.Request request) async {
-      final supabaseClient = getSupabaseClient(request);
-      await initializeDirectories();
+    final contentType = request.headers['content-type'];
+    if (contentType == null ||
+        !contentType.toLowerCase().startsWith('multipart/form-data')) {
+      return shelf.Response.badRequest(
+          body: 'Content-Type must be multipart/form-data');
+    }
 
-      final contentType = request.headers['content-type'];
-      if (contentType == null ||
-          !contentType.toLowerCase().startsWith('multipart/form-data')) {
-        return shelf.Response.badRequest(
-            body: 'Content-Type must be multipart/form-data');
+    try {
+      final mediaType = MediaType.parse(contentType);
+      final boundary = mediaType.parameters['boundary'];
+      if (boundary == null) {
+        return shelf.Response.badRequest(body: 'Boundary not found');
       }
 
-      try {
-        final mediaType = MediaType.parse(contentType);
-        final boundary = mediaType.parameters['boundary'];
-        if (boundary == null) {
-          return shelf.Response.badRequest(body: 'Boundary not found');
-        }
+      final transformer = MimeMultipartTransformer(boundary);
+      final bodyBytes = await request.read().expand((e) => e).toList();
+      final stream = Stream.fromIterable([bodyBytes]);
+      final parts = await transformer.bind(stream).toList();
 
-        final transformer = MimeMultipartTransformer(boundary);
-        final bodyBytes = await request.read().expand((e) => e).toList();
-        final stream = Stream.fromIterable([bodyBytes]);
-        final parts = await transformer.bind(stream).toList();
+      for (var part in parts) {
+        final contentDisposition = part.headers['content-disposition'];
+        if (contentDisposition == null) continue;
 
-        for (var part in parts) {
-          final contentDisposition = part.headers['content-disposition'];
-          if (contentDisposition == null) continue;
+        final filenameMatch =
+            RegExp(r'filename="([^"]*)"').firstMatch(contentDisposition);
+        if (filenameMatch == null) continue;
 
-          final filenameMatch =
-              RegExp(r'filename="([^"]*)"').firstMatch(contentDisposition);
-          if (filenameMatch == null) continue;
+        final filename = filenameMatch.group(1);
+        if (filename == null) continue;
 
-          final filename = filenameMatch.group(1);
-          if (filename == null) continue;
+        final bytes = await part.fold<List<int>>(
+          [],
+          (prev, element) => [...prev, ...element],
+        );
 
-          final bytes = await part.fold<List<int>>(
-            [],
-            (prev, element) => [...prev, ...element],
-          );
+        final rawFilePath = path.join('./uploaded/raw', filename);
+        await File(rawFilePath).writeAsBytes(bytes);
 
-          final rawFilePath = path.join('./uploaded/raw', filename);
-          await File(rawFilePath).writeAsBytes(bytes);
-
-          if (isZipFile(bytes)) {
-            await processZipFile(rawFilePath);
-          } else {
-            final dataFilePath = path.join('./uploaded/data', filename);
-            await File(rawFilePath).copy(dataFilePath);
-          }
-          await uploadToSupabase(rawFilePath, filename, supabaseClient,
-              bucket: 'csvhich_archive', timestamped: true, upsert: false);
+        if (isZipFile(bytes)) {
+          await processZipFile(rawFilePath);
+        } else {
+          final dataFilePath = path.join('./uploaded/data', filename);
+          await File(rawFilePath).copy(dataFilePath);
         }
-
-        return shelf.Response.ok('File processed and uploaded successfully');
-      } catch (e, stackTrace) {
-        print('Error: $e\n$stackTrace');
-        return shelf.Response.internalServerError(
-            body: 'Error processing upload: $e');
-      } finally {
-        supabaseClient.dispose();
-        await File('./uploaded/raw').delete(recursive: true);
-        await File('./uploaded/data').delete(recursive: true);
+        await uploadToSupabase(rawFilePath, filename, supabaseClient,
+            bucket: 'csvhich_archive', timestamped: true, upsert: false);
       }
-    });
 
-    return router;
+      return shelf.Response.ok('File processed and uploaded successfully');
+    } catch (e, stackTrace) {
+      print('Error: $e\n$stackTrace');
+      return shelf.Response.internalServerError(
+          body: 'Error processing upload: $e');
+    } finally {
+      supabaseClient.dispose();
+      await File('./uploaded/raw').delete(recursive: true);
+      await File('./uploaded/data').delete(recursive: true);
+    }
   }
 }

+ 8 - 0
lib/handlers/health_api.dart

@@ -0,0 +1,8 @@
+import 'package:file_upload_processor/handlers/base_api.dart';
+import 'package:shelf/shelf.dart' as shelf;
+
+class HealthApi extends BaseApi {
+  HealthApi(shelf.Request request) : super(request);
+  @override
+  response() async => shelf.Response.ok('Hello World: ${request.url}');
+}

+ 16 - 0
lib/routes/main_router.dart

@@ -0,0 +1,16 @@
+import 'package:file_upload_processor/handlers/file_upload_api.dart';
+import 'package:file_upload_processor/handlers/health_api.dart';
+import 'package:shelf/shelf.dart' as shelf;
+import 'package:shelf_router/shelf_router.dart';
+
+class MainRouter {
+  Router get router {
+    final router = Router();
+
+    router.get(
+        '/health', (shelf.Request request) => HealthApi(request).response());
+    router.post('/upload',
+        (shelf.Request request) => FileUploadApi(request).response());
+    return router;
+  }
+}