Added health endpoint

This commit is contained in:
Armin Ronacher 2025-06-16 17:17:40 +02:00
parent a803b5ae7d
commit 420ec3117c
9 changed files with 24 additions and 13 deletions

View file

@ -291,7 +291,7 @@ final class RustServer: ServerProtocol {
// MARK: - Private Methods
private func performHealthCheck(maxAttempts: Int, delaySeconds: Double) async -> Bool {
let healthURL = URL(string: "http://127.0.0.1:\(port)/health")!
let healthURL = URL(string: "http://127.0.0.1:\(port)/api/health")!
for attempt in 1...maxAttempts {
do {
@ -490,4 +490,4 @@ enum RustServerError: LocalizedError {
return "Server port is not configured"
}
}
}
}

View file

@ -82,7 +82,7 @@ public final class ServerMonitor {
guard isRunning else { return false }
do {
let url = URL(string: "http://127.0.0.1:\(port)/health")!
let url = URL(string: "http://127.0.0.1:\(port)/api/health")!
let request = URLRequest(url: url, timeoutInterval: 2.0)
let (_, response) = try await URLSession.shared.data(for: request)

View file

@ -80,7 +80,7 @@ class SessionMonitor {
private func fetchSessions() async {
do {
// First check if server is running
let healthURL = URL(string: "http://127.0.0.1:\(serverPort)/health")!
let healthURL = URL(string: "http://127.0.0.1:\(serverPort)/api/health")!
let healthRequest = URLRequest(url: healthURL, timeoutInterval: 2.0)
do {

View file

@ -66,7 +66,7 @@ public class TunnelClient {
// MARK: - Health Check
public func checkHealth() async throws -> TunnelSession.HealthResponse {
let request = buildRequest(path: "/health", method: .get)
let request = buildRequest(path: "/api/health", method: .get)
let (data, response) = try await httpClient.data(for: request, body: nil)
guard response.status == .ok else {

View file

@ -129,7 +129,7 @@ public final class TunnelServer {
router.add(middleware: LogRequestsMiddleware(.info))
// Health check endpoint
router.get("/health") { _, _ -> HTTPResponse.Status in
router.get("/api/health") { _, _ -> HTTPResponse.Status in
.ok
}

View file

@ -969,7 +969,7 @@ struct DebugSettingsView: View {
guard isServerRunning else { return false }
do {
let url = URL(string: "http://127.0.0.1:\(serverPort)/health")!
let url = URL(string: "http://127.0.0.1:\(serverPort)/api/health")!
var request = URLRequest(url: url)
request.timeoutInterval = 1.0 // Quick timeout for heartbeat

View file

@ -117,7 +117,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
// Test the server after a short delay
try await Task.sleep(for: .milliseconds(500))
if let url = URL(string: "http://127.0.0.1:\(serverManager.port)/health") {
if let url = URL(string: "http://127.0.0.1:\(serverManager.port)/api/health") {
let (_, response) = try await URLSession.shared.data(from: url)
if let httpResponse = response as? HTTPURLResponse {
print("Server health check response: \(httpResponse.statusCode)")

View file

@ -29,7 +29,7 @@ struct TunnelClientTests {
sessions: 3,
version: "1.0.0"
)
try mockClient.configureJSON(healthResponse, for: "/health")
try mockClient.configureJSON(healthResponse, for: "/api/health")
// Act
let result = try await tunnelClient.checkHealth()
@ -40,7 +40,7 @@ struct TunnelClientTests {
#expect(result.version == "1.0.0")
// Verify request
#expect(mockClient.wasRequested(path: "/health"))
#expect(mockClient.wasRequested(path: "/api/health"))
let lastRequest = mockClient.lastRequest()!
#expect(lastRequest.request.method == .get)
#expect(lastRequest.request.headerFields[.authorization] == "Bearer \(testAPIKey)")
@ -49,7 +49,7 @@ struct TunnelClientTests {
@Test("Health check handles server error")
func testHealthCheckServerError() async throws {
// Arrange
mockClient.configure(for: "/health", response: .serverError)
mockClient.configure(for: "/api/health", response: .serverError)
// Act & Assert
await #expect(throws: TunnelClientError.httpError(statusCode: 500)) {
@ -291,7 +291,7 @@ struct TunnelClientTests {
@Test("All requests include authentication header")
func testAuthenticationHeader() async throws {
// Arrange
mockClient.configure(for: "/health", response: .success)
mockClient.configure(for: "/api/health", response: .success)
mockClient.configure(for: "/api/sessions", response: .success)
// Act
@ -365,4 +365,4 @@ struct TunnelClientTests {
}
}
}
}
}

View file

@ -245,6 +245,7 @@ pub fn start_server(
}
let response = match (method, path.as_str()) {
(&Method::GET, "/api/health") => handle_health(),
(&Method::GET, "/api/sessions") => handle_list_sessions(&control_path),
(&Method::POST, "/api/sessions") => handle_create_session(&control_path, &mut req),
(&Method::POST, "/api/cleanup-exited") => handle_cleanup_exited(&control_path),
@ -312,6 +313,16 @@ fn json_response<T: Serialize>(status: StatusCode, data: &T) -> Response<String>
.unwrap()
}
fn handle_health() -> Response<String> {
let response = ApiResponse {
success: Some(true),
message: Some("OK".to_string()),
error: None,
session_id: None,
};
json_response(StatusCode::OK, &response)
}
fn handle_list_sessions(control_path: &PathBuf) -> Response<String> {
match sessions::list_sessions(control_path) {
Ok(sessions) => {