mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-12 00:03:27 +01:00
Change AltStore naming to SideStore
This commit is contained in:
@@ -1,71 +0,0 @@
|
||||
//
|
||||
// Server.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Riley Testut on 6/20/19.
|
||||
// Copyright © 2019 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Network
|
||||
|
||||
enum ConnectionError: LocalizedError
|
||||
{
|
||||
case serverNotFound
|
||||
case connectionFailed
|
||||
case connectionDropped
|
||||
|
||||
var failureReason: String? {
|
||||
switch self
|
||||
{
|
||||
case .serverNotFound: return NSLocalizedString("Could not find AltServer.", comment: "")
|
||||
case .connectionFailed: return NSLocalizedString("Could not connect to AltServer.", comment: "")
|
||||
case .connectionDropped: return NSLocalizedString("The connection to AltServer was dropped.", comment: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Server
|
||||
{
|
||||
enum ConnectionType
|
||||
{
|
||||
case wireless
|
||||
case wired
|
||||
case local
|
||||
case manual
|
||||
}
|
||||
}
|
||||
|
||||
struct Server: Equatable
|
||||
{
|
||||
var identifier: String? = nil
|
||||
var service: NetService? = nil
|
||||
|
||||
var isPreferred = false
|
||||
var connectionType: ConnectionType = .wireless
|
||||
|
||||
var machServiceName: String?
|
||||
}
|
||||
|
||||
extension Server
|
||||
{
|
||||
// Defined in extension so we can still use the automatically synthesized initializer.
|
||||
init?(service: NetService, txtData: Data) // TODO: this is all that's needed for a server connection
|
||||
{
|
||||
let txtDictionary = NetService.dictionary(fromTXTRecord: txtData)
|
||||
guard let identifierData = txtDictionary["serverID"], let identifier = String(data: identifierData, encoding: .utf8) else {
|
||||
NSLog("Ahh, no serverID in TXT record for service: \(service)")
|
||||
return nil
|
||||
}
|
||||
|
||||
self.service = service
|
||||
self.identifier = identifier
|
||||
}
|
||||
|
||||
init?(service: NetService)
|
||||
{
|
||||
self.service = service
|
||||
self.connectionType = .manual
|
||||
self.identifier = String(data: "yolo".data(using: .utf8)!, encoding: .utf8)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
//
|
||||
// ServerConnection.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Riley Testut on 1/7/20.
|
||||
// Copyright © 2020 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Network
|
||||
|
||||
import AltStoreCore
|
||||
|
||||
class ServerConnection
|
||||
{
|
||||
var server: Server
|
||||
var connection: Connection
|
||||
|
||||
init(server: Server, connection: Connection)
|
||||
{
|
||||
self.server = server
|
||||
self.connection = connection
|
||||
}
|
||||
|
||||
func send<T: Encodable>(_ payload: T, prependSize: Bool = true, completionHandler: @escaping (Result<Void, Error>) -> Void)
|
||||
{
|
||||
do
|
||||
{
|
||||
let data: Data
|
||||
|
||||
if let payload = payload as? Data
|
||||
{
|
||||
data = payload
|
||||
}
|
||||
else
|
||||
{
|
||||
data = try JSONEncoder().encode(payload)
|
||||
}
|
||||
|
||||
func process<T>(_ result: Result<T, ALTServerError>) -> Bool
|
||||
{
|
||||
switch result
|
||||
{
|
||||
case .success: return true
|
||||
case .failure(let error):
|
||||
completionHandler(.failure(error))
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if prependSize
|
||||
{
|
||||
let requestSize = Int32(data.count)
|
||||
let requestSizeData = withUnsafeBytes(of: requestSize) { Data($0) }
|
||||
|
||||
self.connection.send(requestSizeData) { (result) in
|
||||
guard process(result) else { return }
|
||||
|
||||
self.connection.send(data) { (result) in
|
||||
guard process(result) else { return }
|
||||
completionHandler(.success(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.connection.send(data) { (result) in
|
||||
guard process(result) else { return }
|
||||
completionHandler(.success(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
print("Invalid request.", error)
|
||||
completionHandler(.failure(ALTServerError(.invalidRequest)))
|
||||
}
|
||||
}
|
||||
|
||||
func receiveResponse(completionHandler: @escaping (Result<ServerResponse, Error>) -> Void)
|
||||
{
|
||||
let size = MemoryLayout<Int32>.size
|
||||
|
||||
self.connection.receiveData(expectedSize: size) { (result) in
|
||||
do
|
||||
{
|
||||
let data = try result.get()
|
||||
|
||||
let expectedBytes = Int(data.withUnsafeBytes { $0.load(as: Int32.self) })
|
||||
self.connection.receiveData(expectedSize: expectedBytes) { (result) in
|
||||
do
|
||||
{
|
||||
let data = try result.get()
|
||||
|
||||
let response = try AltStoreCore.JSONDecoder().decode(ServerResponse.self, from: data)
|
||||
completionHandler(.success(response))
|
||||
}
|
||||
catch
|
||||
{
|
||||
completionHandler(.failure(ALTServerError(error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
completionHandler(.failure(ALTServerError(error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,366 +0,0 @@
|
||||
//
|
||||
// ServerManager.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Riley Testut on 5/30/19.
|
||||
// Copyright © 2019 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Network
|
||||
|
||||
import AltStoreCore
|
||||
|
||||
class ServerManager: NSObject
|
||||
{
|
||||
static let shared = ServerManager()
|
||||
|
||||
private(set) var isDiscovering = false
|
||||
private(set) var discoveredServers = [Server]()
|
||||
|
||||
private let serviceBrowser = NetServiceBrowser()
|
||||
private var services = Set<NetService>()
|
||||
|
||||
private let dispatchQueue = DispatchQueue(label: "io.altstore.ServerManager")
|
||||
|
||||
private var connectionListener: NWListener?
|
||||
private var incomingConnections: [NWConnection]?
|
||||
private var incomingConnectionsSemaphore: DispatchSemaphore?
|
||||
|
||||
private override init()
|
||||
{
|
||||
super.init()
|
||||
|
||||
self.serviceBrowser.delegate = self
|
||||
self.serviceBrowser.includesPeerToPeer = false
|
||||
}
|
||||
}
|
||||
|
||||
extension ServerManager
|
||||
{
|
||||
func startDiscovering()
|
||||
{
|
||||
guard !self.isDiscovering else { return }
|
||||
self.isDiscovering = true
|
||||
|
||||
self.serviceBrowser.searchForServices(ofType: ALTServerServiceType, inDomain: "")
|
||||
|
||||
self.startListeningForWiredConnections()
|
||||
|
||||
// Print log mentioning that we are manually adding this
|
||||
NSLog("Manually adding server")
|
||||
let ianTestService = NetService(domain: "69.69.0.1", type: "_altserver._tcp", name: "AltStore", port: 43311)
|
||||
|
||||
if let server = Server(service: ianTestService)
|
||||
{
|
||||
self.addDiscoveredServer(server)
|
||||
} else {
|
||||
NSLog("Check for manual server failed!!")
|
||||
}
|
||||
}
|
||||
|
||||
func stopDiscovering()
|
||||
{
|
||||
guard self.isDiscovering else { return }
|
||||
self.isDiscovering = false
|
||||
|
||||
self.discoveredServers.removeAll()
|
||||
self.services.removeAll()
|
||||
self.serviceBrowser.stop()
|
||||
|
||||
self.stopListeningForWiredConnection()
|
||||
}
|
||||
|
||||
func connect(to server: Server, completion: @escaping (Result<ServerConnection, Error>) -> Void)
|
||||
{
|
||||
DispatchQueue.global().async {
|
||||
func finish(_ result: Result<Connection, Error>)
|
||||
{
|
||||
switch result
|
||||
{
|
||||
case .failure(let error): completion(.failure(error))
|
||||
case .success(let connection):
|
||||
let serverConnection = ServerConnection(server: server, connection: connection)
|
||||
completion(.success(serverConnection))
|
||||
}
|
||||
}
|
||||
|
||||
switch server.connectionType
|
||||
{
|
||||
case .local: self.connectToLocalServer(server, completion: finish(_:))
|
||||
case .wired:
|
||||
guard let incomingConnectionsSemaphore = self.incomingConnectionsSemaphore else { return
|
||||
finish(.failure(ALTServerError(.connectionFailed))) }
|
||||
|
||||
print("Waiting for incoming connection...")
|
||||
|
||||
let notificationCenter = CFNotificationCenterGetDarwinNotifyCenter()
|
||||
|
||||
switch server.connectionType
|
||||
{
|
||||
case .wired: CFNotificationCenterPostNotification(notificationCenter, .wiredServerConnectionStartRequest, nil, nil, true)
|
||||
case .local, .wireless, .manual: break
|
||||
}
|
||||
|
||||
_ = incomingConnectionsSemaphore.wait(timeout: .now() + 10.0)
|
||||
|
||||
if let connection = self.incomingConnections?.popLast()
|
||||
{
|
||||
self.connectToRemoteServer(server, connection: connection, completion: finish(_:))
|
||||
}
|
||||
else
|
||||
{
|
||||
finish(.failure(ALTServerError(.connectionFailed)))
|
||||
}
|
||||
|
||||
case .wireless:
|
||||
guard let service = server.service else { return finish(.failure(ALTServerError(.connectionFailed))) }
|
||||
|
||||
print("Connecting to mDNS service:", service)
|
||||
|
||||
let connection = NWConnection(to: .service(name: service.name, type: service.type, domain: service.domain, interface: nil), using: .tcp)
|
||||
self.connectToRemoteServer(server, connection: connection, completion: finish(_:))
|
||||
case .manual:
|
||||
guard let service = server.service else { return finish(.failure(ALTServerError(.connectionFailed))) }
|
||||
|
||||
connectNetmuxd()
|
||||
|
||||
print("Connecting to manual service:", service.domain)
|
||||
print("Port: ", String(service.port.description))
|
||||
|
||||
let connection = NWConnection(host: NWEndpoint.Host(service.domain), port: NWEndpoint.Port(String(service.port))!, using: .tcp)
|
||||
self.connectToRemoteServer(server, connection: connection, completion: finish(_:))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension ServerManager
|
||||
{
|
||||
func addDiscoveredServer(_ server: Server)
|
||||
{
|
||||
var server = server
|
||||
server.isPreferred = (server.identifier == UserDefaults.standard.preferredServerID)
|
||||
|
||||
guard !self.discoveredServers.contains(server) else { return }
|
||||
|
||||
self.discoveredServers.append(server)
|
||||
}
|
||||
|
||||
func makeListener() -> NWListener
|
||||
{
|
||||
let listener = try! NWListener(using: .tcp, on: NWEndpoint.Port(rawValue: ALTDeviceListeningSocket)!)
|
||||
listener.newConnectionHandler = { [weak self] (connection) in
|
||||
self?.incomingConnections?.append(connection)
|
||||
self?.incomingConnectionsSemaphore?.signal()
|
||||
}
|
||||
listener.stateUpdateHandler = { (state) in
|
||||
switch state
|
||||
{
|
||||
case .ready: break
|
||||
case .waiting, .setup: print("Listener socket waiting...")
|
||||
case .cancelled: print("Listener socket cancelled.")
|
||||
case .failed(let error): print("Listener socket failed:", error)
|
||||
@unknown default: break
|
||||
}
|
||||
}
|
||||
|
||||
return listener
|
||||
}
|
||||
|
||||
func startListeningForWiredConnections()
|
||||
{
|
||||
self.incomingConnections = []
|
||||
self.incomingConnectionsSemaphore = DispatchSemaphore(value: 0)
|
||||
|
||||
self.connectionListener = self.makeListener()
|
||||
self.connectionListener?.start(queue: self.dispatchQueue)
|
||||
}
|
||||
|
||||
func stopListeningForWiredConnection()
|
||||
{
|
||||
self.connectionListener?.cancel()
|
||||
self.connectionListener = nil
|
||||
|
||||
self.incomingConnections = nil
|
||||
self.incomingConnectionsSemaphore = nil
|
||||
}
|
||||
|
||||
func connectToRemoteServer(_ server: Server, connection: NWConnection, completion: @escaping (Result<Connection, Error>) -> Void)
|
||||
{
|
||||
connection.stateUpdateHandler = { [unowned connection] (state) in
|
||||
switch state
|
||||
{
|
||||
case .failed(let error):
|
||||
print("Failed to connect to service \(server.service?.name ?? "").", error)
|
||||
completion(.failure(ConnectionError.connectionFailed))
|
||||
|
||||
case .cancelled:
|
||||
completion(.failure(OperationError.cancelled))
|
||||
|
||||
case .ready:
|
||||
let connection = NetworkConnection(connection)
|
||||
completion(.success(connection))
|
||||
|
||||
case .waiting: break
|
||||
case .setup: break
|
||||
case .preparing: break
|
||||
@unknown default: break
|
||||
}
|
||||
}
|
||||
print("Connected to server!")
|
||||
connection.start(queue: self.dispatchQueue)
|
||||
}
|
||||
|
||||
func connectToLocalServer(_ server: Server, completion: @escaping (Result<Connection, Error>) -> Void)
|
||||
{
|
||||
guard let machServiceName = server.machServiceName else { return completion(.failure(ConnectionError.connectionFailed)) }
|
||||
|
||||
let xpcConnection = NSXPCConnection.makeConnection(machServiceName: machServiceName)
|
||||
|
||||
let connection = XPCConnection(xpcConnection)
|
||||
connection.connect { (result) in
|
||||
switch result
|
||||
{
|
||||
case .failure(let error):
|
||||
print("Could not connect to AltDaemon XPC service \(machServiceName).", error)
|
||||
completion(.failure(error))
|
||||
|
||||
case .success: completion(.success(connection))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ServerManager: NetServiceBrowserDelegate
|
||||
{
|
||||
func netServiceBrowserWillSearch(_ browser: NetServiceBrowser)
|
||||
{
|
||||
print("Discovering servers...")
|
||||
|
||||
// Send a post request to JitStreamer to deal with the devil
|
||||
connectNetmuxd()
|
||||
}
|
||||
|
||||
func netServiceBrowserDidStopSearch(_ browser: NetServiceBrowser)
|
||||
{
|
||||
print("Stopped discovering servers.")
|
||||
}
|
||||
|
||||
func netServiceBrowser(_ browser: NetServiceBrowser, didNotSearch errorDict: [String : NSNumber])
|
||||
{
|
||||
print("Failed to discovering servers.", errorDict)
|
||||
}
|
||||
|
||||
func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool)
|
||||
{
|
||||
service.delegate = self
|
||||
|
||||
if let txtData = service.txtRecordData(), let server = Server(service: service, txtData: txtData)
|
||||
{
|
||||
self.addDiscoveredServer(server)
|
||||
}
|
||||
else
|
||||
{
|
||||
service.resolve(withTimeout: 3)
|
||||
self.services.insert(service)
|
||||
}
|
||||
}
|
||||
|
||||
func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool)
|
||||
{
|
||||
if let index = self.discoveredServers.firstIndex(where: { $0.service == service })
|
||||
{
|
||||
self.discoveredServers.remove(at: index)
|
||||
}
|
||||
|
||||
self.services.remove(service)
|
||||
}
|
||||
}
|
||||
|
||||
extension ServerManager: NetServiceDelegate
|
||||
{
|
||||
func netServiceDidResolveAddress(_ service: NetService)
|
||||
{
|
||||
guard let data = service.txtRecordData(), let server = Server(service: service, txtData: data) else { return }
|
||||
self.addDiscoveredServer(server)
|
||||
}
|
||||
|
||||
func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber])
|
||||
{
|
||||
print("Error resolving net service \(sender).", errorDict)
|
||||
}
|
||||
|
||||
func netService(_ sender: NetService, didUpdateTXTRecord data: Data)
|
||||
{
|
||||
let txtDict = NetService.dictionary(fromTXTRecord: data)
|
||||
print("Service \(sender) updated TXT Record:", txtDict)
|
||||
}
|
||||
}
|
||||
|
||||
func connectNetmuxd() {
|
||||
|
||||
// declare the parameter as a dictionary that contains string as key and value combination. considering inputs are valid
|
||||
|
||||
let parameters: [String: Any] = ["nothing": 0]
|
||||
|
||||
// create the url with URL
|
||||
let url = URL(string: "http://69.69.0.1/netmuxd/")!
|
||||
|
||||
// create the session object
|
||||
let session = URLSession.shared
|
||||
|
||||
// now create the URLRequest object using the url object
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "POST" //set http method as POST
|
||||
|
||||
// add headers for the request
|
||||
request.addValue("application/json", forHTTPHeaderField: "Content-Type") // change as per server requirements
|
||||
request.addValue("application/json", forHTTPHeaderField: "Accept")
|
||||
|
||||
do {
|
||||
// convert parameters to Data and assign dictionary to httpBody of request
|
||||
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
|
||||
} catch let error {
|
||||
print(error.localizedDescription)
|
||||
return
|
||||
}
|
||||
|
||||
// create dataTask using the session object to send data to the server
|
||||
let task = session.dataTask(with: request) { data, response, error in
|
||||
|
||||
if let error = error {
|
||||
print("Post Request Error: \(error.localizedDescription)")
|
||||
return
|
||||
}
|
||||
|
||||
// ensure there is valid response code returned from this HTTP response
|
||||
guard let httpResponse = response as? HTTPURLResponse,
|
||||
(200...299).contains(httpResponse.statusCode)
|
||||
else {
|
||||
print("Invalid Response received from the server")
|
||||
return
|
||||
}
|
||||
|
||||
// ensure there is data returned
|
||||
guard let responseData = data else {
|
||||
print("nil Data received from the server")
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
// create json object from data or use JSONDecoder to convert to Model stuct
|
||||
if let jsonResponse = try JSONSerialization.jsonObject(with: responseData, options: .mutableContainers) as? [String: Any] {
|
||||
print(jsonResponse)
|
||||
// handle json response
|
||||
} else {
|
||||
print("data maybe corrupted or in wrong format")
|
||||
throw URLError(.badServerResponse)
|
||||
}
|
||||
} catch let error {
|
||||
print(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
// perform the task
|
||||
task.resume()
|
||||
}
|
||||
Reference in New Issue
Block a user