Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 46 additions & 7 deletions messenger-client/src/main/java/raven/messenger/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.formdev.flatlaf.util.UIScale;
import raven.messenger.manager.DialogManager;
import raven.messenger.manager.FormsManager;
import raven.messenger.util.ErrorReporter;

import javax.swing.*;
import java.awt.*;
Expand All @@ -24,21 +25,59 @@ private void init() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(UIScale.scale(new Dimension(1200, 700)));
setMinimumSize(UIScale.scale(new Dimension(750, 500)));

// Enhanced window listener with error handling
addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
FormsManager.getInstance().initApplication(Application.this);
try {
FormsManager.getInstance().initApplication(Application.this);
} catch (Exception ex) {
ErrorReporter.handleException("Failed to initialize application", ex, true);
}
}

@Override
public void windowClosing(WindowEvent e) {
// Clean up resources on close
cleanup();
}
});

DialogManager.getInstance().init(this);
setLocationRelativeTo(null);
}

private void cleanup() {
try {
// Add any cleanup logic here
System.out.println("Application cleanup completed");
} catch (Exception e) {
ErrorReporter.handleException("Error during application cleanup", e, false);
}
}

public static void main(String[] args) {
FlatRobotoFont.install();
FlatLaf.registerCustomDefaultsSource("raven.messenger.themes");
UIManager.put("defaultFont", new Font(FlatRobotoFont.FAMILY, Font.PLAIN, 13));
FlatMacDarkLaf.setup();
EventQueue.invokeLater(() -> new Application().setVisible(true));
// Set up global exception handler
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
ErrorReporter.handleException("Uncaught exception in thread: " + thread.getName(),
throwable, true);
});

try {
FlatRobotoFont.install();
FlatLaf.registerCustomDefaultsSource("raven.messenger.themes");
UIManager.put("defaultFont", new Font(FlatRobotoFont.FAMILY, Font.PLAIN, 13));
FlatMacDarkLaf.setup();
EventQueue.invokeLater(() -> {
try {
new Application().setVisible(true);
} catch (Exception e) {
ErrorReporter.handleException("Failed to create application window", e, true);
}
});
} catch (Exception e) {
ErrorReporter.handleException("Failed to initialize application theme", e, true);
}
}
}
}
167 changes: 145 additions & 22 deletions messenger-client/src/main/java/raven/messenger/api/ApiService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,29 @@
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.http.Cookies;
import io.restassured.response.Response;
import raven.messenger.api.exception.GlobalErrorHandler;
import raven.messenger.socket.SocketService;
import raven.messenger.store.CookieManager;
import raven.messenger.util.ErrorReporter;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class ApiService {

private static ApiService instance;

public static final String API_VERSION = "6";

public static final String IP = "http://localhost";

// Enable this for connect to online server
// public static final String IP = "http://52.221.189.33";

// Connection testing constants
private static final int CONNECTION_TIMEOUT = 10;
private static final int SOCKET_TIMEOUT = 30;
private static final int MAX_RETRIES = 3;
private static final long RETRY_DELAY_MS = 1000;

public static ApiService getInstance() {
if (instance == null) {
instance = new ApiService();
Expand All @@ -29,41 +35,158 @@ public static ApiService getInstance() {
}

private ApiService() {
// Configure timeouts
RestAssured.config = RestAssured.config()
.httpClient(io.restassured.config.HttpClientConfig.httpClientConfig()
.setParam("http.connection.timeout", CONNECTION_TIMEOUT * 1000)
.setParam("http.socket.timeout", SOCKET_TIMEOUT * 1000));
}

public boolean init() {
Cookies cookies = getCookie();
installConfig(cookies);
return cookies != null;
try {
Cookies cookies = getCookie();
installConfig(cookies);

// Test backend connection
if (!testBackendConnection()) {
ErrorReporter.reportError("Backend Connection Failed",
"Cannot connect to backend server at: " + IP, false);
return false;
}

return cookies != null;
} catch (Exception e) {
ErrorReporter.handleException("Failed to initialize API service", e, false);
return false;
}
}

public void installConfig(Cookies cookies) {
RestAssured.reset();
RestAssured.requestSpecification = new RequestSpecBuilder()
.setContentType(ContentType.JSON)
.setBaseUri(IP)
.addHeader("VERSION", API_VERSION)
.setBasePath("api")
.setPort(5000)
.setAuth(RestAssured.preemptive().basic("user", "raven-messenger-server"))
.addFilter(new GlobalErrorHandler())
.build();
if (cookies != null) {
CookieManager.getInstance().setCookieString(cookies.toString());
RestAssured.requestSpecification.cookies(cookies);
try {
RestAssured.reset();
RestAssured.requestSpecification = new RequestSpecBuilder()
.setContentType(ContentType.JSON)
.setBaseUri(IP)
.addHeader("VERSION", API_VERSION)
.setBasePath("api")
.setPort(5000)
.setAuth(RestAssured.preemptive().basic("user", "raven-messenger-server"))
.addFilter(new GlobalErrorHandler())
.build();

if (cookies != null) {
CookieManager.getInstance().setCookieString(cookies.toString());
RestAssured.requestSpecification.cookies(cookies);
}
} catch (Exception e) {
ErrorReporter.handleException("Failed to install API configuration", e, false);
}
}

/**
* Test backend connection with retry mechanism
*/
public boolean testBackendConnection() {
for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) {
try {
System.out.println("Testing backend connection (attempt " + attempt + "/" + MAX_RETRIES + ")...");

Response response = RestAssured.given()
.baseUri(IP)
.port(5000)
.basePath("api")
.when()
.get("/health") // You might want to create a health endpoint
.then()
.extract()
.response();

if (response.getStatusCode() == 200) {
System.out.println("✓ Backend connection successful");
return true;
} else {
System.out.println("✗ Backend responded with status: " + response.getStatusCode());
}
} catch (Exception e) {
System.out.println("✗ Connection attempt " + attempt + " failed: " + e.getMessage());

if (attempt < MAX_RETRIES) {
try {
Thread.sleep(RETRY_DELAY_MS);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
break;
}
}
}
}
return false;
}

/**
* Enhanced connection test with detailed diagnostics
*/
public ConnectionTestResult testConnectionWithDiagnostics() {
ConnectionTestResult result = new ConnectionTestResult();

try {
// Test basic connectivity
long startTime = System.currentTimeMillis();
Response response = RestAssured.given()
.when()
.get("/test") // Replace with an actual test endpoint
.then()
.extract()
.response();
long endTime = System.currentTimeMillis();

result.responseTime = endTime - startTime;
result.statusCode = response.getStatusCode();
result.success = response.getStatusCode() == 200;
result.message = "Connection test completed";

} catch (Exception e) {
result.success = false;
result.message = "Connection failed: " + e.getMessage();
result.exception = e;
}

return result;
}

public void closeAll() {
CookieManager.getInstance().clearCookie();
SocketService.getInstance().close();
try {
CookieManager.getInstance().clearCookie();
SocketService.getInstance().close();
System.out.println("API service cleanup completed");
} catch (Exception e) {
ErrorReporter.handleException("Error during API service cleanup", e, false);
}
}

public Cookies getCookie() {
try {
return CookieManager.getInstance().getCookie();
} catch (IOException | ClassNotFoundException e) {
ErrorReporter.handleException("Failed to retrieve cookies", e, false);
return null;
}
}
}

/**
* Inner class for connection test results
*/
public static class ConnectionTestResult {
public boolean success;
public String message;
public long responseTime;
public int statusCode;
public Exception exception;

@Override
public String toString() {
return String.format("Connection Test: %s | Status: %d | Response Time: %dms | Message: %s",
success ? "SUCCESS" : "FAILED", statusCode, responseTime, message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import raven.messenger.api.ApiService;
import raven.messenger.login.Login;
import raven.messenger.manager.FormsManager;
import raven.messenger.util.ErrorReporter;

public class GlobalErrorHandler implements OrderedFilter {

Expand All @@ -17,12 +18,41 @@ public int getOrder() {
}

@Override
public Response filter(FilterableRequestSpecification filterableRequestSpecification, FilterableResponseSpecification filterableResponseSpecification, FilterContext filterContext) {
Response response = filterContext.next(filterableRequestSpecification, filterableResponseSpecification);
if (response.getStatusCode() == 401) {
ApiService.getInstance().closeAll();
FormsManager.getInstance().showForm(new Login(null));
public Response filter(FilterableRequestSpecification request, FilterableResponseSpecification response, FilterContext context) {
try {
Response resp = context.next(request, response);
int statusCode = resp.getStatusCode();

// Log all non-200 responses for debugging
if (statusCode != 200) {
System.err.println("API Error - Status: " + statusCode +
" | URL: " + request.getURI() +
" | Method: " + request.getMethod());

if (statusCode >= 400) {
String responseBody = resp.getBody().asString();
System.err.println("Response body: " + (responseBody.length() > 500 ?
responseBody.substring(0, 500) + "..." : responseBody));
}
}

if (statusCode == 401) {
handleUnauthorized();
} else if (statusCode >= 500) {
ErrorReporter.reportError("Server Error",
"Server returned error: " + statusCode + "\nURL: " + request.getURI(), false);
}

return resp;
} catch (Exception e) {
ErrorReporter.handleException("Error in API request filter", e, false);
throw e;
}
return response;
}
}

private void handleUnauthorized() {
System.err.println("Authentication failed (401), redirecting to login...");
ApiService.getInstance().closeAll();
FormsManager.getInstance().showForm(new Login(null));
}
}
Loading