Skip to content

Chat client nyast#46

Open
SandraNelj wants to merge 8 commits intomainfrom
Chat-client-Nyast
Open

Chat client nyast#46
SandraNelj wants to merge 8 commits intomainfrom
Chat-client-Nyast

Conversation

@SandraNelj
Copy link

@SandraNelj SandraNelj commented Nov 28, 2025

Summary by CodeRabbit

  • New Features
    • Redesigned application interface as a chat application with dedicated message display area
    • Send text messages via input field and send button
    • Attach and send files using integrated file browser
    • Send messages quickly using Enter key shortcut
    • Updated application title to "JavaFX Chat App"

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 28, 2025

Walkthrough

The pull request adds a complete JavaFX-based chat application with Ntfy messaging backend integration. It introduces new networking infrastructure (NtfyConnection interface and NtfyConnectionImpl implementation), updates the application model and controller to support bidirectional messaging, refactors the UI to display chat interactions, and adds supporting dependencies (Jackson, dotenv, WireMock) and test utilities.

Changes

Cohort / File(s) Summary
Build & Configuration
.gitignore, pom.xml, src/main/java/module-info.java
Added .env to ignore rules; introduced Jackson databind, dotenv, and WireMock test dependencies; added Maven compiler plugin with Java 25 preview support; updated module requires and opens for java.net.http, Jackson, and dotenv.
Networking & Messaging Layer
src/main/java/com/example/NtfyConnection.java, src/main/java/com/example/NtfyConnectionImpl.java, src/main/java/com/example/NtfyMessageDto.java
Created NtfyConnection interface defining send, receive, and sendFile contracts; implemented NtfyConnectionImpl with HTTP client for Ntfy service interaction (POST to send/file, GET streaming for receive); added NtfyMessageDto record with nested Attachment record for JSON deserialization.
Application Core
src/main/java/com/example/HelloModel.java, src/main/java/com/example/HelloController.java
Refactored HelloModel from greeting to messaging model with NtfyConnection dependency injection, Observable collections, and message lifecycle methods (send, receive, sendFile); updated HelloController to wire UI components, subscribe to model changes, and implement send/attach file actions.
Application Entry & UI
src/main/java/com/example/HelloFX.java, src/main/resources/com/example/hello-view.fxml
Changed main method signature (removed args parameter, made package-private); updated window title to "JavaFX Chat App"; replaced StackPane greeting layout with VBox-based chat UI containing TextArea for messages and HBox with input field, send button, and file attach button.
Utilities
src/main/java/com/example/Singelton.java
Added eager-initialization singleton class with getInstance() accessor.
Tests
src/test/java/com/example/HelloModelTest.java, src/test/java/com/example/NtfyConnectionSpy.java
Introduced NtfyConnectionSpy test double implementing NtfyConnection for message capture; added HelloModelTest with two integration tests verifying send flow and WireMock HTTP verification.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as HelloController
    participant Model as HelloModel
    participant Conn as NtfyConnectionImpl
    participant Ntfy as Ntfy Server

    User->>UI: Click send or press Enter
    UI->>Model: setMessageToSend(text)
    UI->>Model: sendMessage()
    Model->>Conn: send(message)
    Conn->>Ntfy: POST /mytopic
    Ntfy-->>Conn: Response
    Conn-->>Model: true (success)
    Model->>UI: Model updates via listener
    UI->>UI: Append message to chatArea
Loading
sequenceDiagram
    participant Ntfy as Ntfy Server
    participant Conn as NtfyConnectionImpl
    participant Model as HelloModel
    participant UI as HelloController
    participant FX as JavaFX Thread

    Model->>Conn: receive(handler)
    Conn->>Ntfy: GET /mytopic/json (streaming)
    Ntfy-->>Conn: Event stream (NtfyMessageDto lines)
    Conn->>Conn: Parse line as NtfyMessageDto
    Conn->>Conn: Filter event=="message"
    Conn->>Model: handler.accept(messageDto)
    Model->>FX: Platform.runLater()
    FX->>Model: Add to messages list
    Model->>UI: Observable change notification
    UI->>UI: Update chatArea display
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • NtfyConnectionImpl: HTTP streaming implementation with Jackson parsing and error handling requires careful inspection of edge cases (parse failures, connection drops, file validation)
  • HelloModel refactoring: State management with Observable collections, message lifecycle, and Platform.runLater thread-safety needs verification
  • Module-info updates: New opens directive and requires statements should be validated for module visibility
  • HelloController wiring: Event handler chains (button, key press, model subscription) and UI state updates need coherence check
  • Test coverage: WireMock stubbing and integration test logic should be validated for proper verification

Possibly related PRs

  • PR #34: Implements the same JavaFX chat and Ntfy integration with overlapping HelloModel, HelloController, NtfyConnection, and module-info changes
  • PR #33: Removes legacy ChatModel and ChatController while dropping java.net.http, addressing prior networking infrastructure that this PR replaces
  • PR #32: Modifies HelloFX.java entry point and window title; adds java.net.http to module-info with overlapping configuration changes

Poem

🐰 A chat app hops into place,
With Ntfy messages at a quick pace,
Send, receive, and files too—
The network layer knows what to do!
JavaFX talks to the server with grace,
One fluffy feature now fills the space! 💬

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.41% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Chat client nyast' is vague and uses a non-descriptive term ('nyast') that does not convey meaningful information about the changeset. Replace with a clear, descriptive title that summarizes the main change, such as 'Add Ntfy-based chat client with message sending and file transfer'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (17)
.gitignore (1)

3-3: Good security practice: ignore environment files.

Adding .env to .gitignore is correct and necessary to prevent sensitive environment configuration (like HOST_NAME used by NtfyConnectionImpl) from being committed.

As a minor enhancement, consider using the pattern .env* to also catch environment variants (e.g., .env.local, .env.production), depending on your deployment strategy.

src/main/java/com/example/Singelton.java (1)

3-10: Clarify the purpose and naming of Singelton

The eager singleton implementation is fine, but the class/file name is misspelled (Singelton vs Singleton) and the class currently has no state or behavior. Consider either renaming it to Singleton and giving it a clear responsibility (e.g., holding shared config/connection) or removing it until it is needed to avoid dead code.

src/main/resources/com/example/hello-view.fxml (1)

7-19: Chat FXML structure is solid; consider making chat area grow with window

The overall layout and fx:ids look consistent with a chat client. To improve usability on resize, consider adding VBox.vgrow="ALWAYS" to chatArea so it expands vertically with the window instead of remaining fixed at 400px height.

src/test/java/com/example/HelloModelTest.java (1)

13-35: Good coverage of connection wiring; watch for async behavior and consider stronger assertions

The spy-based test nicely ensures HelloModel.sendMessage() delegates to the connection. In sendMessageToFakeServer, if NtfyConnectionImpl.send performs HTTP calls asynchronously, the immediate verify(postRequestedFor(...)) could race and cause flaky tests; ensure sendMessage() blocks until the request is sent or introduce a small wait/retry around verification. You might also consider adding a @DisplayName and, if useful, assertions on request body/headers to more precisely capture the contract.

src/main/java/com/example/HelloFX.java (1)

13-24: Remove unused HOST_NAME lookup and confirm desired main signature

System.getenv("HOST_NAME"); currently has no effect; either wire this value into your connection/model configuration or remove the call to avoid dead code. Also, if you ever intend to launch the app via java com.example.HelloFX or java -jar, the conventional entry point is public static void main(String[] args); the current package-private, no-args main is fine for the JavaFX Maven plugin/launcher but not for a generic Java entry point.

src/main/java/com/example/NtfyConnection.java (1)

6-11: Interface is clear; consider future-proofing error handling

The NtfyConnection contract is straightforward. For future robustness, you may want to think about how callers will distinguish and react to different failure modes: returning boolean (and only declaring FileNotFoundException on sendFile) limits the detail you can propagate. Depending on how NtfyConnectionImpl evolves, a richer result type or a broader checked exception (e.g., IOException) could make debugging and recovery easier.

pom.xml (1)

82-90: Review maven-compiler-plugin preview configuration

You’re compiling with <source>25</source>, <target>25</target> and --enable-preview. If you’re not actively using Java preview features, consider removing --enable-preview to simplify toolchain and avoid needing preview flags at runtime. If you do need it, double‑check the plugin configuration: the canonical syntax is usually <compilerArgs><arg>--enable-preview</arg></compilerArgs> rather than a bare text value, and you may also need to configure your runtime (e.g., surefire, JavaFX plugin) with --enable-preview so tests and the app start without errors.

src/main/java/com/example/NtfyMessageDto.java (1)

5-9: DTO structure is fine; wire in or remove Attachment record

Ignoring unknown properties is a good choice for resilience. The nested Attachment record, however, is not currently referenced as a field of NtfyMessageDto, so Jackson will not populate it from JSON unless another type uses it explicitly. If you intend to support attachments now, consider adding an Attachment (or List<Attachment>) field to NtfyMessageDto; otherwise, you could remove the nested record until it is needed to avoid confusion.

src/test/java/com/example/NtfyConnectionSpy.java (1)

19-22: Consider returning true from sendFile for consistency.

The send() method returns true to simulate success, but sendFile() returns false. If tests call sendFile, they'll incorrectly see a failure. For a spy, consistent success simulation is usually preferable.

     @Override
     public boolean sendFile(Path filePath) throws FileNotFoundException {
-        return false;
+        return true;
     }
src/main/java/com/example/HelloController.java (1)

23-23: Consider reducing visibility of model field.

The model field is declared public, which exposes internal state. Unless this is intentional for testing purposes, prefer package-private or provide a getter.

-    public final HelloModel model = new HelloModel(new NtfyConnectionImpl());
+    final HelloModel model = new HelloModel(new NtfyConnectionImpl());
src/main/java/com/example/NtfyConnectionImpl.java (3)

38-53: Consider adding request timeouts.

HTTP requests without timeouts can hang indefinitely if the server is unresponsive, blocking threads and potentially causing resource exhaustion.

+import java.time.Duration;
+
 public class NtfyConnectionImpl implements NtfyConnection {
-    private final HttpClient http = HttpClient.newHttpClient();
+    private final HttpClient http = HttpClient.newBuilder()
+            .connectTimeout(Duration.ofSeconds(10))
+            .build();

And add .timeout(Duration.ofSeconds(30)) to individual requests for response timeouts.

Also applies to: 55-74


83-93: Async receive has no error handling.

If the HTTP request fails or the stream encounters an error, it's silently ignored. Consider adding .exceptionally() to log or handle failures.

         http.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofLines())
                 .thenAccept(response -> response.body()
                         .map(line -> {
                             try {
                                 return mapper.readValue(line, NtfyMessageDto.class);
                             } catch (JsonProcessingException e) {
                                 return null;
                             }
                         })
                         .filter(msg -> msg != null && msg.event().equals("message"))
-                        .forEach(handler));
+                        .forEach(handler))
+                .exceptionally(ex -> {
+                    System.err.println("Error receiving messages: " + ex.getMessage());
+                    return null;
+                });

16-16: Unused import.

UUID is imported but not used in this class.

-import java.util.UUID;
src/main/java/com/example/HelloModel.java (4)

25-25: Unused field clientId.

The clientId field is generated but never used. Consider removing it or implementing its intended purpose.

-    private final String clientId = UUID.randomUUID().toString();

Also remove the UUID import if no longer needed.


9-11: Unused imports.

URI, HttpRequest, and HttpResponse are imported but not used.

-import java.net.URI;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;

18-20: Stale Javadoc comment.

The Javadoc still references the removed getGreeting() method. Update or remove it to reflect the current model purpose.

 /**
- * Model layer: encapsulates application data and business logic.
+ * Model layer: manages chat messages and communication via NtfyConnection.
  */
-    /**
-     * Returns a greeting based on the current Java and JavaFX versions.
-     */

70-78: Remove trailing blank lines.

Multiple trailing blank lines at the end of the file.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 21c51e8 and 0c3274f.

📒 Files selected for processing (13)
  • .gitignore (1 hunks)
  • pom.xml (2 hunks)
  • src/main/java/com/example/HelloController.java (1 hunks)
  • src/main/java/com/example/HelloFX.java (1 hunks)
  • src/main/java/com/example/HelloModel.java (1 hunks)
  • src/main/java/com/example/NtfyConnection.java (1 hunks)
  • src/main/java/com/example/NtfyConnectionImpl.java (1 hunks)
  • src/main/java/com/example/NtfyMessageDto.java (1 hunks)
  • src/main/java/com/example/Singelton.java (1 hunks)
  • src/main/java/module-info.java (1 hunks)
  • src/main/resources/com/example/hello-view.fxml (1 hunks)
  • src/test/java/com/example/HelloModelTest.java (1 hunks)
  • src/test/java/com/example/NtfyConnectionSpy.java (1 hunks)
🔇 Additional comments (2)
src/main/java/module-info.java (1)

4-8: Verify module name for java-dotenv and openness scope

requires java.net.http; and requires com.fasterxml.jackson.databind; look appropriate, but requires java.dotenv; may not match the actual JPMS/automatic module name of the java-dotenv library. Please confirm the correct module name from the library docs or compiler output, and adjust if necessary. Also, opening the whole com.example package to both javafx.fxml and Jackson is fine for now, but you may later want to restrict reflection exposure to a narrower package if the module grows.

pom.xml (1)

48-63: Validate new dependency versions and alignment with module-info

The added dependencies (Jackson, java-dotenv, WireMock) match the new features and tests. Please confirm that:

  • These are the intended versions (especially wiremock 4.0.0-beta.15, which is a beta and may change behavior), and
  • The JPMS/module names you use in module-info.java (notably for java-dotenv) actually match the artifacts, to avoid module-resolution issues at compile/run time.

Comment on lines +60 to 68
private void attachFile() {
FileChooser chooser = new FileChooser();
chooser.setTitle("Välj fil att bifoga");

File file = chooser.showOpenDialog(sendFileButton.getScene().getWindow());
if (file != null) {
model.sendFile(file);
chatArea.appendText("Du skickade fil: " + file.getName() + "\n");
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing feedback when file send fails.

model.sendFile(file) can fail silently (returns false or throws). The user sees "Du skickade fil:" regardless of outcome. Consider checking the result and providing appropriate feedback.

     @FXML
     private void attachFile() {
         FileChooser chooser = new FileChooser();
         chooser.setTitle("Välj fil att bifoga");

         File file = chooser.showOpenDialog(sendFileButton.getScene().getWindow());
         if (file != null) {
-            model.sendFile(file);
-            chatArea.appendText("Du skickade fil: " + file.getName() + "\n");
+            boolean success = model.sendFile(file);
+            if (success) {
+                chatArea.appendText("Du skickade fil: " + file.getName() + "\n");
+            } else {
+                chatArea.appendText("Kunde inte skicka fil: " + file.getName() + "\n");
+            }
         }
     }

Note: This requires changing HelloModel.sendFile() to return boolean.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/java/com/example/HelloController.java around lines 60 to 68, the
controller currently calls model.sendFile(file) but always appends "Du skickade
fil:" regardless of success; change the call to check the result and only append
success text when sendFile returns true, otherwise append an error message (and
catch exceptions). Update HelloModel.sendFile(...) to return boolean indicating
success/failure (and avoid throwing silently), have the controller handle false
return and any caught exceptions by appending a failure message to chatArea (or
showing an alert) with brief context and the file name.

Comment on lines +56 to +62
public void sendFile(File file) {
try {
connection.sendFile(file.toPath());
} catch (IOException e) {
e.printStackTrace();
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

sendFile provides no feedback on failure.

The method catches IOException and prints a stack trace but returns void, leaving the caller unaware of success or failure. This makes it difficult to provide user feedback in the controller.

-    public void sendFile(File file) {
+    public boolean sendFile(File file) {
         try {
-            connection.sendFile(file.toPath());
+            return connection.sendFile(file.toPath());
         } catch (IOException e) {
             e.printStackTrace();
+            return false;
         }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void sendFile(File file) {
try {
connection.sendFile(file.toPath());
} catch (IOException e) {
e.printStackTrace();
}
}
public boolean sendFile(File file) {
try {
return connection.sendFile(file.toPath());
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
🤖 Prompt for AI Agents
In src/main/java/com/example/HelloModel.java around lines 56-62, the sendFile
method currently swallows IOException and returns void so callers get no
success/failure signal; change the method to propagate the error instead: update
the signature to declare throws IOException, remove the try/catch (or rethrow
the caught exception), and let callers (controllers) handle the exception and
provide user feedback; update any call sites to handle or declare the
IOException accordingly.

Comment on lines +49 to +52
} catch (IOException | InterruptedException e) {
System.out.println("Error sending message!");
return false;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Restore interrupt flag when catching InterruptedException.

Catching InterruptedException without restoring the interrupt status can cause issues with thread pool shutdown and cancellation. The same applies to sendFile().

         } catch (IOException | InterruptedException e) {
+            if (e instanceof InterruptedException) {
+                Thread.currentThread().interrupt();
+            }
             System.out.println("Error sending message!");
             return false;
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (IOException | InterruptedException e) {
System.out.println("Error sending message!");
return false;
}
} catch (IOException | InterruptedException e) {
if (e instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
System.out.println("Error sending message!");
return false;
}
🤖 Prompt for AI Agents
In src/main/java/com/example/NtfyConnectionImpl.java around lines 49 to 52, the
catch block groups IOException and InterruptedException and prints a message
without restoring the interrupt status; split the exceptions so
InterruptedException is caught separately, call
Thread.currentThread().interrupt() to restore the interrupt flag, and rethrow or
return appropriately (while keeping IOException handling as before); apply the
same change in sendFile() so InterruptedException is handled separately and the
thread interrupt flag is restored.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant