                        "body": message,
                        "headers": headers ?? [String: String]()] as [String: Any]))
     }
-    
+
     // returns an id to use when unregistering
     public func register(address: String, id: String? = nil, handler: @escaping (JSON) -> ()) throws -> String {
         let _id = id ?? uuid()

        do {
            try send(JSON(["type": "ping"]))
        } catch let error {
            //TODO: better
            print("ping failed: \(error)")
        }
    }

    func uuid() -> String {
        return NSUUID().uuidString
    }
    
    public func send(to address: String,
                     message: [String: Any],
                     headers: [String: String]? = nil,
                     callback: ((JSON) -> ())? = nil) throws {
        var msg: [String: Any] = ["type": "send", "address": address, "body": message, "headers": headers ?? [String: String]()]
        
        if let cb = callback {
            let replyAddress = uuid()
            replyHandlers[replyAddress] = {[unowned self] m in

// TODO: error handler
// TODO: handle replies

public enum EventBusError: Error {
    case serverError(message: String)
    case unknownMessage(message: JSON)
    case unknownError(error: Error)
}

public class EventBus {
    private let socket: Socket

    private let readQueue = DispatchQueue(label: "read")
    private let workQueue = DispatchQueue(label: "work", attributes: [.concurrent])

    private var errorHandler: ((EventBusError) -> ())? = nil
    private var handlers = [String : [String : (JSON) -> ()]]()
    private var replyHandlers = [String: (JSON) -> ()]()

    private var open = false

    public init(host: String, port: Int, pingEvery: Int = 5000) throws {
        self.socket = try Socket.create()
        try self.socket.connect(to: host, port: Int32(port))
