Last active
February 1, 2023 08:26
-
-
Save saroar/10784126e6e92f43e80c64a7ee0415a3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import Combine | |
import SwiftUI | |
import FuncNetworking | |
import AddaMeModels | |
import KeychainService | |
import InfoPlist | |
public struct WebsocketClient { | |
public typealias HandShake = () -> () | |
public typealias OnReceive = (_ incomig: Result<URLSessionWebSocketTask.Message, Error>) -> () | |
public typealias Send = (ChatMessageResponse.Item, String) -> () | |
public typealias OnConnect = () -> () | |
public typealias Disconnect = () -> () | |
public typealias HandleData = (_ data: Data) -> () | |
public typealias HandleConversationResponse = (_ lastMessage: ChatMessageResponse.Item) -> () | |
public typealias HandleMessageResponse = (_ message: ChatMessageResponse.Item) -> () | |
public let handshake: HandShake | |
public let onReceive: OnReceive | |
public let send: Send | |
public let onConnect: OnConnect | |
public let disconnect: Disconnect | |
public let handleData: HandleData | |
public let handleConversationResponse: HandleConversationResponse | |
public let handleMessageResponse: HandleMessageResponse | |
private let urlSession = URLSession(configuration: .default) | |
public var socket: URLSessionWebSocketTask! | |
public init( | |
handshake: @escaping HandShake, | |
onReceive: @escaping OnReceive, | |
send: @escaping Send, | |
onConnect: @escaping OnConnect, | |
disconnect: @escaping Disconnect, | |
handleData: @escaping HandleData, | |
handleConversationResponse: @escaping HandleConversationResponse, | |
handleMessageResponse: @escaping HandleMessageResponse | |
) { | |
self.handshake = handshake | |
self.onReceive = onReceive | |
self.send = send | |
self.onConnect = onConnect | |
self.disconnect = disconnect | |
self.handleData = handleData | |
self.handleConversationResponse = handleConversationResponse | |
self.handleMessageResponse = handleMessageResponse | |
} | |
} | |
func token() -> AnyPublisher<String, HTTPError> { | |
guard let token: AuthTokenResponse = KeychainService.loadCodable(for: .token) else { | |
print(#line, "not Authorized Token are missing") | |
return Fail(error: HTTPError.missingTokenFromIOS ) | |
.eraseToAnyPublisher() | |
} | |
return Just(token.accessToken) | |
.setFailureType(to: HTTPError.self) | |
.eraseToAnyPublisher() | |
} | |
public class WebSocketAPI { | |
public var conversations: AnyPublisher<ConversationResponse.Item, Never> { | |
return conversationsSubject.eraseToAnyPublisher() | |
} | |
public var messages: AnyPublisher<ChatMessageResponse.Item, Never> { | |
return messagesSubject.eraseToAnyPublisher() | |
} | |
private var conversationsSubject = PassthroughSubject<ConversationResponse.Item, Never>() | |
private var messagesSubject = PassthroughSubject<ChatMessageResponse.Item, Never>() | |
public var urlSession = URLSession(configuration: .default) | |
public var socket: URLSessionWebSocketTask! | |
private var url = EnvironmentKeys.webSocketURL | |
public init() {} | |
public func stop() { | |
socket.cancel(with: .goingAway, reason: nil) | |
} | |
public func disconnect() { | |
socket.cancel(with: .normalClosure, reason: nil) | |
} | |
public func handshake() { | |
guard let token: AuthTokenResponse = KeychainService.loadCodable(for: .token) else { | |
print(#line, "not Authorized Token are missing") | |
return | |
} | |
var request = URLRequest(url: url) | |
request.addValue( | |
"Bearer \(token)", | |
forHTTPHeaderField: "Authorization" | |
) | |
self.socket = urlSession.webSocketTask(with: request) | |
socket.receive(completionHandler: onReceive) | |
socket.resume() | |
onConnect() | |
} | |
public func onConnect() { | |
guard let currentUSER: User = KeychainService.loadCodable(for: .user) else { | |
return | |
} | |
let onconnect = ChatOutGoingEvent.connect(currentUSER).jsonString | |
socket.send(.string(onconnect!)) { error in | |
if let error = error { | |
print(#line, "Error sending message", error) | |
} | |
} | |
} | |
public func onReceive(_ incoming: Result<URLSessionWebSocketTask.Message, Error>) { | |
socket.receive(completionHandler: onReceive) | |
self.socket.receive { result in | |
switch result { | |
case .success(let message): | |
switch message { | |
case .data(let data): | |
print(#line, data) | |
case .string(let str): | |
print(#line, str) | |
guard let data = str.data(using: .utf8) else { return } | |
self.handle(data) | |
@unknown default: | |
break | |
} | |
case .failure(let error): | |
print(#line, error) | |
self.socket.cancel(with: .goingAway, reason: nil) | |
// self.handshake() | |
return | |
} | |
} | |
} | |
public func send( | |
localMessage: ChatMessageResponse.Item, | |
remoteMessage: String | |
) { | |
self.socket.send(.string(remoteMessage)) { [weak self] error in | |
// if let error = error { | |
// print("Error sending message", error) | |
// } | |
guard error != nil else { | |
print(#line, "cant send remote msg something wrong!") | |
return | |
} | |
self?.messagesSubject.send(localMessage) | |
} | |
} | |
public func handle(_ data: Data) { | |
let chatOutGoingEvent = ChatOutGoingEvent.decode(data: data) | |
switch chatOutGoingEvent { | |
case .connect(_): | |
break | |
case .disconnect(_): | |
break | |
case .conversation(let conversation): | |
print(#line, conversation) | |
self.handleConversationResponse(conversation) | |
case .message(let message): | |
print(#line, message) | |
self.handleMessageResponse(message) | |
case .notice(let msg): | |
print(#line, msg) | |
case .error(let error): | |
print(#line, error) | |
case .none: | |
print(#line, "decode error") | |
} | |
} | |
public func handleConversationResponse(_ lastMessage: ChatMessageResponse.Item) { | |
self.messagesSubject.send(lastMessage) | |
} | |
public func handleMessageResponse(_ message: ChatMessageResponse.Item) { | |
self.messagesSubject.send(message) | |
} | |
} | |
extension WebsocketClient { | |
public static func live(api: WebSocketAPI) -> Self { | |
.init( | |
handshake: api.handshake, | |
onReceive: api.onReceive(_:), | |
send: api.send(localMessage:remoteMessage:), | |
onConnect: api.onConnect, | |
disconnect: api.disconnect, | |
handleData: api.handle(_:), | |
handleConversationResponse: api.handleConversationResponse(_:), | |
handleMessageResponse: api.handleMessageResponse(_:)) | |
} | |
} | |
//ViewModel | |
class SocketViewModel: ObservableObject { | |
@Published var conversations = [String: ConversationResponse.Item]() | |
@Published var messages: [String: [ChatMessageResponse.Item]] = [:] | |
let websocketClient: WebsocketClient | |
init(websocketClient: WebsocketClient) { | |
self.websocketClient = websocketClient | |
self.websocketClient.handshake() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
on your method:
the guard is wrong, should be
guard error == nil else {...