Files
VibeCoding/webrtc_controller_ios/web_rtc_controller_ios/Signaling/SignalingClient.swift

125 lines
3.8 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Foundation
protocol SignalingClientDelegate: AnyObject {
func signalingDidConnect()
func signalingDidDisconnect()
func signaling(didFail error: String)
func signaling(didReceive message: SignalMessage)
}
/// WebSocket URLSessionWebSocketTask
/// REGISTERdeviceType = CONTROLLER
/// 线
final class SignalingClient: NSObject {
weak var delegate: SignalingClientDelegate?
private let serverUrl: String
private let deviceId: String
private var session: URLSession?
private var task: URLSessionWebSocketTask?
private var manuallyClosed = false
init(serverUrl: String, deviceId: String) {
self.serverUrl = serverUrl
self.deviceId = deviceId
super.init()
}
func connect() {
guard let url = URL(string: serverUrl) else {
notifyError("无效的服务器地址: \(serverUrl)")
return
}
manuallyClosed = false
let config = URLSessionConfiguration.default
config.timeoutIntervalForRequest = 15
session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
task = session?.webSocketTask(with: url)
task?.resume()
receiveLoop()
}
func disconnect() {
manuallyClosed = true
task?.cancel(with: .normalClosure, reason: "Disconnecting".data(using: .utf8))
task = nil
session?.invalidateAndCancel()
session = nil
}
func send(_ message: SignalMessage) {
guard let task else { return }
guard let data = try? JSONEncoder().encode(message),
let json = String(data: data, encoding: .utf8) else { return }
task.send(.string(json)) { error in
if let error {
NSLog("[Signaling] send error: \(error.localizedDescription)")
}
}
}
var isConnected: Bool { task != nil }
// MARK: - Private
private func registerDevice() {
var msg = SignalMessage()
msg.type = "REGISTER"
msg.fromDeviceId = deviceId
msg.deviceType = "CONTROLLER"
send(msg)
}
private func receiveLoop() {
task?.receive { [weak self] result in
guard let self else { return }
switch result {
case .success(let wsMessage):
if case .string(let text) = wsMessage,
let data = text.data(using: .utf8),
let message = try? JSONDecoder().decode(SignalMessage.self, from: data) {
DispatchQueue.main.async {
self.delegate?.signaling(didReceive: message)
}
}
self.receiveLoop()
case .failure(let error):
if !self.manuallyClosed {
self.notifyError(error.localizedDescription)
}
}
}
}
private func notifyError(_ text: String) {
DispatchQueue.main.async {
self.delegate?.signaling(didFail: text)
}
}
}
// MARK: - URLSessionWebSocketDelegate
extension SignalingClient: URLSessionWebSocketDelegate {
func urlSession(_ session: URLSession,
webSocketTask: URLSessionWebSocketTask,
didOpenWithProtocol protocol: String?) {
registerDevice()
DispatchQueue.main.async {
self.delegate?.signalingDidConnect()
}
}
func urlSession(_ session: URLSession,
webSocketTask: URLSessionWebSocketTask,
didCloseWith closeCode: URLSessionWebSocketTask.CloseCode,
reason: Data?) {
guard !manuallyClosed else { return }
DispatchQueue.main.async {
self.delegate?.signalingDidDisconnect()
}
}
}