import Combine import Foundation protocol RocketChatClientProtocol { func authorizedURL(url: URL) -> URL func getRooms(updatedSince: Date?) -> AnyPublisher func getSubscriptions(updatedSince: Date?) -> AnyPublisher func getHistory(rid: String, t: String, latest: Date) -> AnyPublisher func syncMessages(rid: String, updatedSince: Date) -> AnyPublisher func sendMessage(id: String, rid: String, msg: String) -> AnyPublisher func sendRead(rid: String) -> AnyPublisher } final class RocketChatClient: NSObject { @Dependency private var serverProvider: ServerProviding private var server: Server { serverProvider.server } private lazy var session = URLSession( configuration: .default, delegate: URLSesionClientCertificateHandling( certificate: server.certificate, password: server.password ), delegateQueue: nil ) private var adapters: [RequestAdapter] { [ TokenAdapter(server: server), JSONAdapter() ] } private func dataTask(for request: T) -> AnyPublisher { let url = server.url.appending(path: request.path).appending(queryItems: request.queryItems) var urlRequest = adapters.reduce(URLRequest(url: url), { $1.adapt($0) }) urlRequest.httpMethod = request.method.rawValue urlRequest.httpBody = request.body return session.dataTaskPublisher(for: urlRequest) .tryMap { (data, response) in guard let httpResponse = response as? HTTPURLResponse, 200...299 ~= httpResponse.statusCode else { throw RocketChatError.unauthorized } return try data.decode(T.Response.self) } .mapError { error in if let error = error as? DecodingError { return .decoding(error: error) } if let error = error as? RocketChatError { return error } return .unknown(error: error) } .eraseToAnyPublisher() } } extension RocketChatClient: RocketChatClientProtocol { func authorizedURL(url: URL) -> URL { adapters.reduce(server.url.appending(path: url.relativePath), { $1.adapt($0) }) } func getRooms(updatedSince: Date?) -> AnyPublisher { let request = RoomsRequest(updatedSince: updatedSince) return dataTask(for: request) } func getSubscriptions(updatedSince: Date?) -> AnyPublisher { let request = SubscriptionsRequest(updatedSince: updatedSince) return dataTask(for: request) } func getHistory(rid: String, t: String, latest: Date) -> AnyPublisher { let request = HistoryRequest(roomId: rid, roomType: t, latest: latest) return dataTask(for: request) } func syncMessages(rid: String, updatedSince: Date) -> AnyPublisher { let request = MessagesRequest(lastUpdate: updatedSince, roomId: rid) return dataTask(for: request) } func sendMessage(id: String, rid: String, msg: String) -> AnyPublisher { let request = SendMessageRequest(id: id, rid: rid, msg: msg) return dataTask(for: request) } func sendRead(rid: String) -> AnyPublisher { let request = ReadRequest(rid: rid) return dataTask(for: request) } }