mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-14 17:23:25 +01:00
[AltKit] Replaces dedicated AltKit module with shared files across targets
Treating AltKit as a full module resulted in more complexity than necessary, when we really just wanted to share some files between different targets. Now we can share individual files across modules as-needed without AltKit overhead.
This commit is contained in:
23
Shared/Connections/ALTConnection.h
Normal file
23
Shared/Connections/ALTConnection.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// ALTConnection.h
|
||||
// AltKit
|
||||
//
|
||||
// Created by Riley Testut on 6/1/20.
|
||||
// Copyright © 2020 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NS_SWIFT_NAME(Connection)
|
||||
@protocol ALTConnection <NSObject>
|
||||
|
||||
- (void)sendData:(NSData *)data completionHandler:(void (^)(BOOL, NSError * _Nullable))completionHandler NS_REFINED_FOR_SWIFT;
|
||||
- (void)receiveDataWithExpectedSize:(NSInteger)expectedSize completionHandler:(void (^)(NSData * _Nullable, NSError * _Nullable))completionHandler NS_SWIFT_NAME(__receiveData(expectedSize:completionHandler:));
|
||||
|
||||
- (void)disconnect;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
113
Shared/Connections/Connection.swift
Normal file
113
Shared/Connections/Connection.swift
Normal file
@@ -0,0 +1,113 @@
|
||||
//
|
||||
// Connection.swift
|
||||
// AltKit
|
||||
//
|
||||
// Created by Riley Testut on 6/1/20.
|
||||
// Copyright © 2020 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Network
|
||||
|
||||
public extension Connection
|
||||
{
|
||||
func send(_ data: Data, completionHandler: @escaping (Result<Void, ALTServerError>) -> Void)
|
||||
{
|
||||
self.__send(data) { (success, error) in
|
||||
let result = Result(success, error).mapError { (error) -> ALTServerError in
|
||||
guard let nwError = error as? NWError else { return ALTServerError(error) }
|
||||
return ALTServerError(.lostConnection, underlyingError: nwError)
|
||||
}
|
||||
|
||||
completionHandler(result)
|
||||
}
|
||||
}
|
||||
|
||||
func receiveData(expectedSize: Int, completionHandler: @escaping (Result<Data, ALTServerError>) -> Void)
|
||||
{
|
||||
self.__receiveData(expectedSize: expectedSize) { (data, error) in
|
||||
let result = Result(data, error).mapError { (error) -> ALTServerError in
|
||||
guard let nwError = error as? NWError else { return ALTServerError(error) }
|
||||
return ALTServerError(.lostConnection, underlyingError: nwError)
|
||||
}
|
||||
|
||||
completionHandler(result)
|
||||
}
|
||||
}
|
||||
|
||||
func send<T: Encodable>(_ response: T, shouldDisconnect: Bool = false, completionHandler: @escaping (Result<Void, ALTServerError>) -> Void)
|
||||
{
|
||||
func finish(_ result: Result<Void, ALTServerError>)
|
||||
{
|
||||
completionHandler(result)
|
||||
|
||||
if shouldDisconnect
|
||||
{
|
||||
// Add short delay to prevent us from dropping connection too quickly.
|
||||
DispatchQueue.global().asyncAfter(deadline: .now() + 1.0) {
|
||||
self.disconnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
let data = try JSONEncoder().encode(response)
|
||||
let responseSize = withUnsafeBytes(of: Int32(data.count)) { Data($0) }
|
||||
|
||||
self.send(responseSize) { (result) in
|
||||
switch result
|
||||
{
|
||||
case .failure(let error): finish(.failure(error))
|
||||
case .success:
|
||||
self.send(data) { (result) in
|
||||
switch result
|
||||
{
|
||||
case .failure(let error): finish(.failure(error))
|
||||
case .success: finish(.success(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
finish(.failure(.init(.invalidResponse, underlyingError: error)))
|
||||
}
|
||||
}
|
||||
|
||||
func receiveRequest(completionHandler: @escaping (Result<ServerRequest, ALTServerError>) -> Void)
|
||||
{
|
||||
let size = MemoryLayout<Int32>.size
|
||||
|
||||
print("Receiving request size from connection:", self)
|
||||
self.receiveData(expectedSize: size) { (result) in
|
||||
do
|
||||
{
|
||||
let data = try result.get()
|
||||
|
||||
let expectedSize = Int(data.withUnsafeBytes { $0.load(as: Int32.self) })
|
||||
print("Receiving request from connection: \(self)... (\(expectedSize) bytes)")
|
||||
|
||||
self.receiveData(expectedSize: expectedSize) { (result) in
|
||||
do
|
||||
{
|
||||
let data = try result.get()
|
||||
let request = try JSONDecoder().decode(ServerRequest.self, from: data)
|
||||
|
||||
print("Received request:", request)
|
||||
completionHandler(.success(request))
|
||||
}
|
||||
catch
|
||||
{
|
||||
completionHandler(.failure(ALTServerError(error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
completionHandler(.failure(ALTServerError(error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
Shared/Connections/ConnectionManager.swift
Normal file
160
Shared/Connections/ConnectionManager.swift
Normal file
@@ -0,0 +1,160 @@
|
||||
//
|
||||
// ConnectionManager.swift
|
||||
// AltServer
|
||||
//
|
||||
// Created by Riley Testut on 5/23/19.
|
||||
// Copyright © 2019 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Network
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
func handleRemoveAppRequest(_ request: RemoveAppRequest, for connection: Connection, completionHandler: @escaping (Result<RemoveAppResponse, Error>) -> Void)
|
||||
}
|
||||
|
||||
public protocol ConnectionHandler: AnyObject
|
||||
{
|
||||
var connectionHandler: ((Connection) -> Void)? { get set }
|
||||
var disconnectionHandler: ((Connection) -> Void)? { get set }
|
||||
|
||||
func startListening()
|
||||
func stopListening()
|
||||
}
|
||||
|
||||
public class ConnectionManager<RequestHandlerType: RequestHandler>
|
||||
{
|
||||
public let requestHandler: RequestHandlerType
|
||||
public let connectionHandlers: [ConnectionHandler]
|
||||
|
||||
public var isStarted = false
|
||||
|
||||
private var connections = [Connection]()
|
||||
|
||||
public init(requestHandler: RequestHandlerType, connectionHandlers: [ConnectionHandler])
|
||||
{
|
||||
self.requestHandler = requestHandler
|
||||
self.connectionHandlers = connectionHandlers
|
||||
|
||||
for handler in connectionHandlers
|
||||
{
|
||||
handler.connectionHandler = { [weak self] (connection) in
|
||||
self?.prepare(connection)
|
||||
}
|
||||
|
||||
handler.disconnectionHandler = { [weak self] (connection) in
|
||||
self?.disconnect(connection)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func start()
|
||||
{
|
||||
guard !self.isStarted else { return }
|
||||
|
||||
for connectionHandler in self.connectionHandlers
|
||||
{
|
||||
connectionHandler.startListening()
|
||||
}
|
||||
|
||||
self.isStarted = true
|
||||
}
|
||||
|
||||
public func stop()
|
||||
{
|
||||
guard self.isStarted else { return }
|
||||
|
||||
for connectionHandler in self.connectionHandlers
|
||||
{
|
||||
connectionHandler.stopListening()
|
||||
}
|
||||
|
||||
self.isStarted = false
|
||||
}
|
||||
}
|
||||
|
||||
private extension ConnectionManager
|
||||
{
|
||||
func prepare(_ connection: Connection)
|
||||
{
|
||||
guard !self.connections.contains(where: { $0 === connection }) else { return }
|
||||
self.connections.append(connection)
|
||||
|
||||
self.handleRequest(for: connection)
|
||||
}
|
||||
|
||||
func disconnect(_ connection: Connection)
|
||||
{
|
||||
guard let index = self.connections.firstIndex(where: { $0 === connection }) else { return }
|
||||
self.connections.remove(at: index)
|
||||
}
|
||||
|
||||
func handleRequest(for connection: Connection)
|
||||
{
|
||||
func finish<T: ServerMessageProtocol>(_ result: Result<T, Error>)
|
||||
{
|
||||
do
|
||||
{
|
||||
let response = try result.get()
|
||||
connection.send(response, shouldDisconnect: true) { (result) in
|
||||
print("Sent response \(response) with result:", result)
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
let response = ErrorResponse(error: ALTServerError(error))
|
||||
connection.send(response, shouldDisconnect: true) { (result) in
|
||||
print("Sent error response \(response) with result:", result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
connection.receiveRequest() { (result) in
|
||||
print("Received request with result:", result)
|
||||
|
||||
switch result
|
||||
{
|
||||
case .failure(let error): finish(Result<ErrorResponse, Error>.failure(error))
|
||||
|
||||
case .success(.anisetteData(let request)):
|
||||
self.requestHandler.handleAnisetteDataRequest(request, for: connection) { (result) in
|
||||
finish(result)
|
||||
}
|
||||
|
||||
case .success(.prepareApp(let request)):
|
||||
self.requestHandler.handlePrepareAppRequest(request, for: connection) { (result) in
|
||||
finish(result)
|
||||
}
|
||||
|
||||
case .success(.beginInstallation): break
|
||||
|
||||
case .success(.installProvisioningProfiles(let request)):
|
||||
self.requestHandler.handleInstallProvisioningProfilesRequest(request, for: connection) { (result) in
|
||||
finish(result)
|
||||
}
|
||||
|
||||
case .success(.removeProvisioningProfiles(let request)):
|
||||
self.requestHandler.handleRemoveProvisioningProfilesRequest(request, for: connection) { (result) in
|
||||
finish(result)
|
||||
}
|
||||
|
||||
case .success(.removeApp(let request)):
|
||||
self.requestHandler.handleRemoveAppRequest(request, for: connection) { (result) in
|
||||
finish(result)
|
||||
}
|
||||
|
||||
case .success(.unknown):
|
||||
finish(Result<ErrorResponse, Error>.failure(ALTServerError(.unknownRequest)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
54
Shared/Connections/NetworkConnection.swift
Normal file
54
Shared/Connections/NetworkConnection.swift
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// NetworkConnection.swift
|
||||
// AltKit
|
||||
//
|
||||
// Created by Riley Testut on 6/1/20.
|
||||
// Copyright © 2020 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Network
|
||||
|
||||
public class NetworkConnection: NSObject, Connection
|
||||
{
|
||||
public let nwConnection: NWConnection
|
||||
|
||||
public init(_ nwConnection: NWConnection)
|
||||
{
|
||||
self.nwConnection = nwConnection
|
||||
}
|
||||
|
||||
public func __send(_ data: Data, completionHandler: @escaping (Bool, Error?) -> Void)
|
||||
{
|
||||
self.nwConnection.send(content: data, completion: .contentProcessed { (error) in
|
||||
completionHandler(error == nil, error)
|
||||
})
|
||||
}
|
||||
|
||||
public func __receiveData(expectedSize: Int, completionHandler: @escaping (Data?, Error?) -> Void)
|
||||
{
|
||||
self.nwConnection.receive(minimumIncompleteLength: expectedSize, maximumLength: expectedSize) { (data, context, isComplete, error) in
|
||||
guard data != nil || error != nil else {
|
||||
return completionHandler(nil, ALTServerError(.lostConnection))
|
||||
}
|
||||
|
||||
completionHandler(data, error)
|
||||
}
|
||||
}
|
||||
|
||||
public func disconnect()
|
||||
{
|
||||
switch self.nwConnection.state
|
||||
{
|
||||
case .cancelled, .failed: break
|
||||
default: self.nwConnection.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension NetworkConnection
|
||||
{
|
||||
override public var description: String {
|
||||
return "\(self.nwConnection.endpoint) (Network)"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user