diff --git a/desktop/src/main/java/org/example/petshopdesktop/api/ApiClient.java b/desktop/src/main/java/org/example/petshopdesktop/api/ApiClient.java index 50a14bce..baf1b99a 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/api/ApiClient.java +++ b/desktop/src/main/java/org/example/petshopdesktop/api/ApiClient.java @@ -4,7 +4,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.example.petshopdesktop.auth.UserSession; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.SequenceInputStream; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; @@ -150,26 +153,33 @@ public class ApiClient { String mimeType = Files.probeContentType(filePath); if (mimeType == null || mimeType.isBlank()) mimeType = "application/octet-stream"; - byte[] fileBytes = Files.readAllBytes(filePath); String fileName = filePath.getFileName().toString(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - out.write(("--" + boundary + "\r\nContent-Disposition: form-data; name=\"" + filePartName + byte[] fileHeader = ("--" + boundary + "\r\nContent-Disposition: form-data; name=\"" + filePartName + "\"; filename=\"" + fileName + "\"\r\nContent-Type: " + mimeType + "\r\n\r\n") - .getBytes(StandardCharsets.UTF_8)); - out.write(fileBytes); - out.write("\r\n".getBytes(StandardCharsets.UTF_8)); + .getBytes(StandardCharsets.UTF_8); + + ByteArrayOutputStream tail = new ByteArrayOutputStream(); + tail.write("\r\n".getBytes(StandardCharsets.UTF_8)); if (textContent != null && !textContent.isBlank()) { - out.write(("--" + boundary + "\r\nContent-Disposition: form-data; name=\"" + textPartName + tail.write(("--" + boundary + "\r\nContent-Disposition: form-data; name=\"" + textPartName + "\"\r\n\r\n" + textContent + "\r\n").getBytes(StandardCharsets.UTF_8)); } - out.write(("--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8)); + tail.write(("--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8)); + + InputStream body = new SequenceInputStream( + java.util.Collections.enumeration(java.util.Arrays.asList( + new ByteArrayInputStream(fileHeader), + Files.newInputStream(filePath), + new ByteArrayInputStream(tail.toByteArray()) + )) + ); HttpRequest.Builder builder = HttpRequest.newBuilder() .uri(URI.create(baseUrl + path)) .header("Content-Type", "multipart/form-data; boundary=" + boundary) - .POST(HttpRequest.BodyPublishers.ofByteArray(out.toByteArray())) - .timeout(Duration.ofSeconds(30)); + .POST(HttpRequest.BodyPublishers.ofInputStream(() -> body)) + .timeout(Duration.ofSeconds(120)); addAuthHeader(builder); HttpResponse response = httpClient.send(builder.build(), HttpResponse.BodyHandlers.ofString()); return handleResponse(response, responseClass); diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/ChatController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/ChatController.java index bf28085d..4417bd23 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/ChatController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/ChatController.java @@ -204,11 +204,18 @@ public class ChatController { } lblChatStatus.setText("Message sent"); }); + } catch (OutOfMemoryError e) { + Platform.runLater(() -> { + txtMessage.setText(content); + btnSend.setDisable(false); + lblChatStatus.setText("File too large to send"); + }); } catch (Exception e) { Platform.runLater(() -> { txtMessage.setText(content); btnSend.setDisable(false); - lblChatStatus.setText("Chat send failed"); + String msg = e.getMessage(); + lblChatStatus.setText(msg != null && !msg.isBlank() ? msg : "Chat send failed"); ActivityLogger.getInstance().logException( "ChatController.sendMessage", e, @@ -223,6 +230,16 @@ public class ChatController { File file = org.example.petshopdesktop.util.FilePickerSupport.pickAnyFile(btnAttachment.getScene().getWindow()); if (file == null) return; + long maxBytes = 5 * 1024 * 1024; + if (file.length() > maxBytes) { + javafx.scene.control.Alert alert = new javafx.scene.control.Alert(javafx.scene.control.Alert.AlertType.WARNING); + alert.setTitle("File Too Large"); + alert.setHeaderText("The selected file exceeds the 5 MB limit."); + alert.setContentText("Please choose a smaller file and try again."); + alert.showAndWait(); + return; + } + selectedAttachmentFile = file; btnAttachment.setText("📎 " + file.getName()); btnAttachment.setStyle("-fx-background-color: #dcfce7; -fx-background-radius: 12; -fx-text-fill: #166534; -fx-cursor: hand;");