| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- import 'dart:io';
- 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 {
- SupabaseClient getSupabaseClient(shelf.Request request) {
- final supabaseUrl = request.headers['supabase-url'];
- if (supabaseUrl == null) {
- throw Exception('Supabase URL not provided in headers');
- }
- final authHeader = request.headers['authorization'];
- if (authHeader == null || !authHeader.startsWith('Bearer ')) {
- throw Exception('Invalid or missing Authorization Bearer token');
- }
- final token = authHeader.substring(7); // Remove 'Bearer ' prefix
- return SupabaseClient(
- supabaseUrl,
- token,
- );
- }
- String getTimestampedFilename(String originalFilename) {
- final timestamp = DateFormat('yyyyMMdd_HHmmss').format(DateTime.now());
- return '${timestamp}_$originalFilename';
- }
- Future<void> uploadToSupabase(
- String filePath, String filename, SupabaseClient supabaseClient,
- {bool timestamped = false,
- required String bucket,
- bool upsert = true}) async {
- try {
- final file = File(filePath);
- final timestampedFilename =
- timestamped ? getTimestampedFilename(filename) : filename;
- await supabaseClient.storage.from(bucket).upload(
- timestampedFilename,
- file,
- fileOptions: FileOptions(
- cacheControl: '3600',
- upsert: upsert,
- ),
- );
- print('File uploaded to Supabase: $timestampedFilename');
- } catch (e) {
- print('Error uploading to Supabase: $e');
- rethrow;
- }
- }
- Future<void> initializeDirectories() async {
- final directories = [
- Directory('./uploaded/raw'),
- Directory('./uploaded/data'),
- ];
- for (var dir in directories) {
- if (!await dir.exists()) {
- await dir.create(recursive: true);
- }
- }
- }
- bool isZipFile(List<int> bytes) {
- if (bytes.length < 4) return false;
- return bytes[0] == 0x50 &&
- bytes[1] == 0x4B &&
- bytes[2] == 0x03 &&
- bytes[3] == 0x04;
- }
- Future<void> processZipFile(String filePath) async {
- final bytes = await File(filePath).readAsBytes();
- final archive = ZipDecoder().decodeBytes(bytes);
- for (final file in archive) {
- final filename = file.name;
- if (file.isFile) {
- final data = file.content as List<int>;
- final outFile = File(path.join('./uploaded/data', filename));
- await outFile.parent.create(recursive: true);
- await outFile.writeAsBytes(data);
- }
- }
- }
- Router get router {
- final router = Router();
- router.get('/', (shelf.Request request) {
- return shelf.Response.ok('Hello World');
- });
- 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');
- }
- 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();
- 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 filename = filenameMatch.group(1);
- if (filename == null) continue;
- final bytes = await part.fold<List<int>>(
- [],
- (prev, element) => [...prev, ...element],
- );
- 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);
- }
- 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);
- }
- });
- return router;
- }
- }
|