diff --git a/android/src/main/java/at/alwinschuster/HttpServer/HttpServerModule.java b/android/src/main/java/at/alwinschuster/HttpServer/HttpServerModule.java index 0ec30a9..789eb02 100644 --- a/android/src/main/java/at/alwinschuster/HttpServer/HttpServerModule.java +++ b/android/src/main/java/at/alwinschuster/HttpServer/HttpServerModule.java @@ -52,6 +52,13 @@ public void respond(String requestId, int code, String type, String body) { } } + @ReactMethod + public void respondFile(String requestId, int code, String type, String filePath) { + if (server != null) { + server.respondFile(requestId, code, type, filePath); + } + } + @ReactMethod public void addListener(String eventName) { // Set up any upstream listeners or background tasks as necessary diff --git a/android/src/main/java/at/alwinschuster/HttpServer/Server.java b/android/src/main/java/at/alwinschuster/HttpServer/Server.java index c35c36e..19ddf7b 100644 --- a/android/src/main/java/at/alwinschuster/HttpServer/Server.java +++ b/android/src/main/java/at/alwinschuster/HttpServer/Server.java @@ -10,6 +10,9 @@ import java.util.Map; import java.util.HashMap; import java.util.Random; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import androidx.annotation.Nullable; import android.util.Log; @@ -63,6 +66,24 @@ public void respond(String requestId, int code, String type, String body) { responses.put(requestId, newFixedLengthResponse(Status.lookup(code), type, body)); } + public void respondFile(String requestId, int code, String type, String filePath) { + File file = new File(filePath); + + if (!file.exists()) { + responses.put(requestId, newFixedLengthResponse(Status.NOT_FOUND, MIME_PLAINTEXT, "File not found")); + return; + } + + try { + FileInputStream fis = new FileInputStream(file); + responses.put(requestId, newFixedLengthResponse(Status.lookup(code), type, fis, file.length())); + } catch (FileNotFoundException e) { + responses.put(requestId, newFixedLengthResponse(Status.NOT_FOUND, MIME_PLAINTEXT, "File not found")); + } catch (Exception e) { + responses.put(requestId, newFixedLengthResponse(Status.INTERNAL_ERROR, MIME_PLAINTEXT, e.getMessage())); + } + } + private WritableMap fillRequestMap(IHTTPSession session, String requestId) throws Exception { Method method = session.getMethod(); WritableMap request = Arguments.createMap(); diff --git a/bridgeServer.js b/bridgeServer.js index af40f1a..1f307f8 100644 --- a/bridgeServer.js +++ b/bridgeServer.js @@ -33,6 +33,15 @@ class Response { html(html, code = 200) { return this.send(code, 'text/html', html); } + + sendFile(filePath, type, code = 200) { + if (this.closed) { + throw new Error('Response already sent'); + } + + httpServer.respondFile(this.requestId, code, type, filePath); + this.closed = true; + } } class BridgeServer { diff --git a/httpServer.js b/httpServer.js index f3ce194..8d92b83 100644 --- a/httpServer.js +++ b/httpServer.js @@ -19,5 +19,7 @@ module.exports = { ServerEventEmitter.removeAllListeners('httpServerResponseReceived'); }, - respond: (requestId, code, type, body) => Server.respond(requestId, code, type, body) + respond: (requestId, code, type, body) => Server.respond(requestId, code, type, body), + + respondFile: (requestId, code, type, filePath) => Server.respondFile(requestId, code, type, filePath) } diff --git a/ios/RCTHttpServer.m b/ios/RCTHttpServer.m index 8e5c1aa..692acbe 100644 --- a/ios/RCTHttpServer.m +++ b/ios/RCTHttpServer.m @@ -118,4 +118,38 @@ - (void)initResponseReceivedFor:(GCDWebServer *)server forType:(NSString*)type { completionBlock(requestResponse); } +RCT_EXPORT_METHOD(respondFile: (NSString *) requestId + code: (NSInteger) code + type: (NSString *) type + filePath: (NSString *) filePath) +{ + GCDWebServerCompletionBlock completionBlock = nil; + @synchronized (self) { + completionBlock = [_completionBlocks objectForKey:requestId]; + [_completionBlocks removeObjectForKey:requestId]; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + if (![fileManager fileExistsAtPath:filePath]) { + GCDWebServerDataResponse* errorResponse = [GCDWebServerDataResponse responseWithText:@"File not found"]; + errorResponse.statusCode = 404; + completionBlock(errorResponse); + return; + } + + NSError *error = nil; + NSData *fileData = [NSData dataWithContentsOfFile:filePath options:0 error:&error]; + + if (error) { + GCDWebServerDataResponse* errorResponse = [GCDWebServerDataResponse responseWithText:[error localizedDescription]]; + errorResponse.statusCode = 500; + completionBlock(errorResponse); + return; + } + + GCDWebServerDataResponse* fileResponse = [[GCDWebServerDataResponse alloc] initWithData:fileData contentType:type]; + fileResponse.statusCode = code; + completionBlock(fileResponse); +} + @end diff --git a/package.json b/package.json index 6e557a2..5c882cd 100644 --- a/package.json +++ b/package.json @@ -28,14 +28,12 @@ "scripts": { "semantic-release": "semantic-release" }, - "dependencies": { - "react": "18.2.0" - }, "peerDependencies": { + "react": ">=18", "react-native": ">=0.72" }, "devDependencies": { - "semantic-release": "^22.0.8" + "semantic-release": "^25.0.2" }, "release": { "branches": [ @@ -43,4 +41,4 @@ "next" ] } -} \ No newline at end of file +} diff --git a/react-native-http-bridge-refurbished.podspec b/react-native-http-bridge-refurbished.podspec index 84a6634..bda499d 100644 --- a/react-native-http-bridge-refurbished.podspec +++ b/react-native-http-bridge-refurbished.podspec @@ -15,6 +15,6 @@ Pod::Spec.new do |s| s.source = { :git => "https://github.com/Alwinator/react-native-http-bridge-refurbished.git", :tag => "v#{s.version}" } s.source_files = "ios/**/*.{h,m}" - s.dependency 'React' + s.dependency 'React-Core' s.dependency 'GCDWebServer' end