Files
SideStore/SideStoreApp/Sources/Shared/Connections/ConnectionManager.swift

160 lines
6.2 KiB
Swift
Raw Normal View History

//
// ConnectionManager.swift
// AltServer
//
// Created by Riley Testut on 5/23/19.
// Copyright © 2019 Riley Testut. All rights reserved.
//
2023-03-01 13:15:22 -05:00
import Foundation
import Network
import SideKit
2023-03-02 00:40:11 -05:00
import os.log
2023-03-01 00:48:36 -05:00
public protocol RequestHandler {
func handleAnisetteDataRequest(_ request: AnisetteDataRequest, for connection: Connection, completionHandler: @escaping (Result<AnisetteDataResponse, Error>) -> Void)
func handlePrepareAppRequest(_ request: PrepareAppRequest, for connection: Connection, completionHandler: @escaping (Result<InstallationProgressResponse, Error>) -> Void)
2023-03-01 00:48:36 -05:00
func handleInstallProvisioningProfilesRequest(_ request: InstallProvisioningProfilesRequest, for connection: Connection,
completionHandler: @escaping (Result<InstallProvisioningProfilesResponse, Error>) -> Void)
func handleRemoveProvisioningProfilesRequest(_ request: RemoveProvisioningProfilesRequest, for connection: Connection,
completionHandler: @escaping (Result<RemoveProvisioningProfilesResponse, Error>) -> Void)
2023-03-01 00:48:36 -05:00
func handleRemoveAppRequest(_ request: RemoveAppRequest, for connection: Connection, completionHandler: @escaping (Result<RemoveAppResponse, Error>) -> Void)
2023-03-01 00:48:36 -05:00
func handleEnableUnsignedCodeExecutionRequest(_ request: EnableUnsignedCodeExecutionRequest, for connection: Connection, completionHandler: @escaping (Result<EnableUnsignedCodeExecutionResponse, Error>) -> Void)
}
2023-03-01 00:48:36 -05:00
public protocol ConnectionHandler: AnyObject {
associatedtype ConnectionType = Connection
var connectionHandler: ((ConnectionType) -> Void)? { get set }
var disconnectionHandler: ((ConnectionType) -> Void)? { get set }
2023-03-01 00:48:36 -05:00
func startListening()
func stopListening()
}
2023-03-01 00:48:36 -05:00
public class ConnectionManager<RequestHandlerType: RequestHandler, ConnectionType: NetworkConnection & AnyObject, ConnectionHandlerType: ConnectionHandler> where ConnectionHandlerType.ConnectionType == ConnectionType {
public let requestHandler: RequestHandlerType
public let connectionHandlers: [ConnectionHandlerType]
2023-03-01 00:48:36 -05:00
public var isStarted = false
2023-03-01 00:48:36 -05:00
private var connections = [ConnectionType]()
private let connectionsLock = NSLock()
2023-03-01 00:48:36 -05:00
public init(requestHandler: RequestHandlerType, connectionHandlers: [ConnectionHandlerType]) {
self.requestHandler = requestHandler
self.connectionHandlers = connectionHandlers
2023-03-01 00:48:36 -05:00
for handler in connectionHandlers {
handler.connectionHandler = { [weak self] connection in
self?.prepare(connection)
}
2023-03-01 00:48:36 -05:00
handler.disconnectionHandler = { [weak self] connection in
self?.disconnect(connection)
}
}
}
2023-03-01 00:48:36 -05:00
public func start() {
guard !isStarted else { return }
for connectionHandler in connectionHandlers {
connectionHandler.startListening()
}
2023-03-01 00:48:36 -05:00
isStarted = true
}
2023-03-01 00:48:36 -05:00
public func stop() {
guard isStarted else { return }
for connectionHandler in connectionHandlers {
connectionHandler.stopListening()
}
2023-03-01 00:48:36 -05:00
isStarted = false
}
}
2023-03-01 00:48:36 -05:00
private extension ConnectionManager {
func prepare(_ connection: ConnectionType) {
connectionsLock.lock()
defer { self.connectionsLock.unlock() }
2023-03-01 00:48:36 -05:00
guard !connections.contains(where: { $0 === connection }) else { return }
connections.append(connection)
handleRequest(for: connection)
}
2023-03-01 00:48:36 -05:00
func disconnect(_ connection: ConnectionType) {
connectionsLock.lock()
defer { self.connectionsLock.unlock() }
2023-03-01 00:48:36 -05:00
guard let index = connections.firstIndex(where: { $0 === connection }) else { return }
connections.remove(at: index)
}
2023-03-01 00:48:36 -05:00
func handleRequest(for connection: ConnectionType) {
func finish<T: ServerMessageProtocol>(_ result: Result<T, Error>) {
do {
let response = try result.get()
2023-03-01 00:48:36 -05:00
connection.send(response, shouldDisconnect: true) { result in
2023-03-02 00:40:11 -05:00
os_log("Sent response %@ with result: %@", type: .error , response.identifier, String(describing: result))
}
2023-03-01 00:48:36 -05:00
} catch {
let response = ErrorResponse(error: ALTServerError(error))
2023-03-01 00:48:36 -05:00
connection.send(response, shouldDisconnect: true) { result in
2023-03-02 00:40:11 -05:00
os_log("Sent error response %@ with result: %@", type: .error , response.error.localizedDescription, String(describing: result))
}
}
}
2023-03-01 00:48:36 -05:00
connection.receiveRequest { result in
2023-03-02 00:40:11 -05:00
os_log("Received request with result: %@", type: .info, String(describing: result))
2023-03-01 00:48:36 -05:00
switch result {
case let .failure(error): finish(Result<ErrorResponse, Error>.failure(error))
case let .success(.anisetteData(request)):
self.requestHandler.handleAnisetteDataRequest(request, for: connection) { result in
finish(result)
}
2023-03-01 00:48:36 -05:00
case let .success(.prepareApp(request)):
self.requestHandler.handlePrepareAppRequest(request, for: connection) { result in
finish(result)
}
2023-03-01 00:48:36 -05:00
case .success(.beginInstallation): break
2023-03-01 00:48:36 -05:00
case let .success(.installProvisioningProfiles(request)):
self.requestHandler.handleInstallProvisioningProfilesRequest(request, for: connection) { result in
finish(result)
}
2023-03-01 00:48:36 -05:00
case let .success(.removeProvisioningProfiles(request)):
self.requestHandler.handleRemoveProvisioningProfilesRequest(request, for: connection) { result in
finish(result)
}
2023-03-01 00:48:36 -05:00
case let .success(.removeApp(request)):
self.requestHandler.handleRemoveAppRequest(request, for: connection) { result in
finish(result)
}
2023-03-01 00:48:36 -05:00
case let .success(.enableUnsignedCodeExecution(request)):
self.requestHandler.handleEnableUnsignedCodeExecutionRequest(request, for: connection) { result in
finish(result)
}
2023-03-01 00:48:36 -05:00
case .success(.unknown):
finish(Result<ErrorResponse, Error>.failure(ALTServerError.unknownRequest))
}
}
}
}