vibetunnel/mac/VibeTunnel/Core/Services/SystemControlHandler.swift

111 lines
4 KiB
Swift

import Foundation
import OSLog
/// Handles system-level control messages
/// IMPORTANT: System:ready message handling
/// This handler specifically processes system:ready messages that were previously
/// handled inline. It ensures connection establishment acknowledgment is properly sent.
/// The handler must be registered during app initialization to handle these messages.
@MainActor
final class SystemControlHandler {
private let logger = Logger(subsystem: BundleIdentifiers.loggerSubsystem, category: "SystemControl")
// MARK: - Properties
private let onSystemReady: () -> Void
// MARK: - Initialization
init(onSystemReady: @escaping () -> Void = {}) {
self.onSystemReady = onSystemReady
logger.info("SystemControlHandler initialized")
// Note: Registration with SharedUnixSocketManager is handled by
// SharedUnixSocketManager.initializeSystemHandler()
}
// MARK: - Message Handling
/// Handle incoming system control messages
func handleMessage(_ data: Data) async -> Data? {
do {
// First decode to get the action
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let action = json["action"] as? String
{
switch action {
case "ready":
return await handleReadyEvent(data)
case "ping":
return await handlePingRequest(data)
default:
logger.error("Unknown system action: \(action)")
return createErrorResponse(for: data, error: "Unknown system action: \(action)")
}
} else {
logger.error("Invalid system message format")
return createErrorResponse(for: data, error: "Invalid message format")
}
} catch {
logger.error("Failed to parse system message: \(error)")
return createErrorResponse(for: data, error: "Failed to parse message: \(error.localizedDescription)")
}
}
// MARK: - Action Handlers
private func handleReadyEvent(_ data: Data) async -> Data? {
do {
_ = try ControlProtocol.decode(data, as: ControlProtocol.SystemReadyMessage.self)
logger.info("System ready event received")
// Call the ready handler
onSystemReady()
// No response needed for events
return nil
} catch {
logger.error("Failed to decode system ready event: \(error)")
return nil
}
}
private func handlePingRequest(_ data: Data) async -> Data? {
do {
let request = try ControlProtocol.decodeSystemPingRequest(data)
logger.debug("System ping request received")
let response = ControlProtocol.systemPingResponse(to: request)
return try ControlProtocol.encode(response)
} catch {
logger.error("Failed to handle ping request: \(error)")
return createErrorResponse(for: data, error: "Failed to process ping: \(error.localizedDescription)")
}
}
// MARK: - Error Handling
private func createErrorResponse(for data: Data, error: String) -> Data? {
do {
// Try to get request ID for proper error response
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let id = json["id"] as? String,
let action = json["action"] as? String
{
// Create error response matching request
let errorResponse: [String: Any] = [
"id": id,
"type": "response",
"category": "system",
"action": action,
"error": error
]
return try JSONSerialization.data(withJSONObject: errorResponse)
}
} catch {
logger.error("Failed to create error response: \(error)")
}
return nil
}
}