TM-SGNL-iOS/SignalServiceKit/Devices/ProvisioningSocket.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

111 lines
3.9 KiB
Swift

//
// Copyright 2019 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public protocol ProvisioningSocketDelegate: AnyObject {
func provisioningSocket(_ provisioningSocket: ProvisioningSocket, didReceiveProvisioningUuid provisioningUuid: String)
func provisioningSocket(_ provisioningSocket: ProvisioningSocket, didReceiveEnvelope envelope: ProvisioningProtoProvisionEnvelope)
func provisioningSocket(_ provisioningSocket: ProvisioningSocket, didError error: Error)
}
// MARK: -
public class ProvisioningSocket {
public let id = UUID()
public weak var delegate: ProvisioningSocketDelegate?
let socket: SSKWebSocket
public init(webSocketFactory: WebSocketFactory) {
// TODO: Should we (sometimes?) use the unidentified service?
let request = WebSocketRequest(
signalService: .mainSignalServiceIdentified,
urlPath: "v1/websocket/provisioning/",
urlQueryItems: [URLQueryItem(name: "agent", value: OWSDeviceProvisioner.userAgent)],
extraHeaders: [:]
)
let webSocket = webSocketFactory.buildSocket(request: request, callbackScheduler: DispatchQueue.main)!
self.socket = webSocket
webSocket.delegate = self
}
public convenience init() {
self.init(webSocketFactory: SSKEnvironment.shared.webSocketFactoryRef)
}
public var state: SSKWebSocketState {
return socket.state
}
public func disconnect(code: URLSessionWebSocketTask.CloseCode?) {
heartBeatTimer?.invalidate()
heartBeatTimer = nil
socket.disconnect(code: code)
}
var heartBeatTimer: Timer?
public func connect() {
if heartBeatTimer == nil {
heartBeatTimer = Timer.scheduledTimer(withTimeInterval: 30, repeats: true) { [weak self] _ in
guard let self = self else { return }
guard self.state == .open else { return }
self.socket.writePing()
}
}
socket.connect()
}
}
extension ProvisioningSocket: SSKWebSocketDelegate {
public func websocketDidConnect(socket: SSKWebSocket) {
}
public func websocketDidDisconnectOrFail(socket: SSKWebSocket, error: Error) {
delegate?.provisioningSocket(self, didError: error)
}
public func websocket(_ socket: SSKWebSocket, didReceiveData data: Data) {
let message: WebSocketProtoWebSocketMessage
do {
message = try WebSocketProtoWebSocketMessage(serializedData: data)
} catch {
owsFailDebug("Failed to deserialize message: \(error)")
return
}
guard let request = message.request else {
owsFailDebug("unexpected message: \(message)")
return
}
do {
try handleRequest(request)
try socket.sendResponse(for: request, status: 200, message: "OK")
} catch {
owsFailDebug("error: \(error)")
}
}
private func handleRequest(_ request: WebSocketProtoWebSocketRequestMessage) throws {
switch (request.verb, request.path) {
case ("PUT", "/v1/address"):
guard let body = request.body else {
throw OWSAssertionError("body was unexpectedly nil")
}
let uuidProto = try ProvisioningProtoProvisioningUuid(serializedData: body)
delegate?.provisioningSocket(self, didReceiveProvisioningUuid: uuidProto.uuid)
case ("PUT", "/v1/message"):
guard let body = request.body else {
throw OWSAssertionError("body was unexpectedly nil")
}
let envelopeProto = try ProvisioningProtoProvisionEnvelope(serializedData: body)
delegate?.provisioningSocket(self, didReceiveEnvelope: envelopeProto)
default:
throw OWSAssertionError("unexpected request: \(request)")
}
}
}