如何在Swift中处理websocket的“请求”和“响应”?

时间:2019-12-20 11:04:45

标签: swift starscream

想象一下,我们有使用websocket的聊天服务。我们正在使用属性request_id作为JSON发送消息。服务器捕获我们的消息,将其保存到数据库中,并通过将传递的id发送回客户端另一个数据来返回消息的request_id。客户必须找出此“响应”与“请求”确切相关,并将数据保存到本地数据库。

例如:

  1. 客户端发送消息:
{
  "request_id": "1st",
  "content": "first message"
}
  1. 服务器接收消息,将其保存并返回新消息的ID
{
  "request_id": "1st",
  "message_id": 123242139857814
}

与Alammofire(使用闭包)不同,Starscream lib不提供这种机制。我正在寻找与CoreData和RxSwift兼容的解决方案。如何在不丢失“请求”上下文的情况下处理服务器的“响应”?

1 个答案:

答案 0 :(得分:0)

有很多方法。例如,您可以使用下一个代码

class Mapping<T: Hashable, U: Hashable> {

    typealias ForwardKey = T
    typealias ForwardValue = U

    typealias ReverseKey = ForwardValue
    typealias ReverseValue = ForwardKey

    typealias KeyPair = (ForwardKey, ReverseKey?)
    typealias ValuePair = (ForwardValue, ReverseValue)

    private var forward: [AnyHashable: AnyHashable]
    private var reverse: [AnyHashable: AnyHashable]
    private let emptyHashable = AnyHashable("")

    init() {
        forward = [:]
        reverse = [:]
    }

    func insert(pair: KeyPair) {
        if let base = pair.1 {
            forward[pair.0] = base
            reverse[base] = pair.0
        } else {
            forward[pair.0] = emptyHashable
        }
    }

    func update(pair: KeyPair) {
        insert(pair: pair)
    }

    subscript(forward key: ForwardKey) -> ForwardValue? {
        return forward.first(where: { $0.key.hashValue == key.hashValue })?.value as? ForwardValue
    }

    subscript(reverse key: ReverseKey) -> ReverseValue? {
        if let result = reverse.first(where: { $0.key.hashValue == key.hashValue })?.value as? ReverseValue {
            return result
        }

        return forward.first(where: { $0.key.hashValue == key.hashValue })?.key as? ReverseValue
    }

}

struct Request: Hashable {
    let requestID: String
    let content: String

    func hash(into hasher: inout Hasher) {
        hasher.combine(requestID)
    }
}

struct Response: Hashable {
    let requestID: String
    let messageID: String

    func hash(into hasher: inout Hasher) {
        hasher.combine(requestID)
    }
}

class WebSocket {

    private var callback: ((Request, Response) -> ())?
    private let mapping = Mapping<Request, Response>()

    func request(_ request: Request, callback: @escaping (Request, Response) -> ()) {
        mapping.insert(pair: (request, nil))
        self.callback = callback

        // Send webSocket message
    }

    // WebSocketDelegate
    // Since you are using Starscream
    func websocketDidReceiveMessage(/*socket: WebSocketClient,*/ text: String) {
        // Parse text to Response
        let response = Response(requestID: "1", messageID: "2")

        if let req = mapping[reverse: response] {
            mapping.update(pair: (req, response))
            callback?(req, response)
        }
    }

}

let webSocket = WebSocket()

webSocket.request(Request(requestID: "1", content: "A")) { request, response in
    print(request) // Request(requestID: "1", content: "A")
    print(response) // Response(requestID: "1", messageID: "2")
}

webSocket.websocketDidReceiveMessage(text: "")