2019-06-21 11:20:03 -07:00
//
// S e n d A p p O p e r a t i o n . s w i f t
// A l t S t o r e
//
// C r e a t e d b y R i l e y T e s t u t o n 6 / 7 / 1 9 .
// C o p y r i g h t © 2 0 1 9 R i l e y T e s t u t . A l l r i g h t s r e s e r v e d .
//
import Foundation
import Network
2020-09-03 16:39:08 -07:00
import AltStoreCore
2019-06-21 11:20:03 -07:00
@objc ( SendAppOperation )
2020-01-08 12:41:02 -08:00
class SendAppOperation : ResultOperation < ServerConnection >
2019-06-21 11:20:03 -07:00
{
2021-10-25 22:27:30 -07:00
let context : InstallAppOperationContext
2019-06-21 11:20:03 -07:00
private let dispatchQueue = DispatchQueue ( label : " com.altstore.SendAppOperation " )
2020-01-08 12:41:02 -08:00
private var serverConnection : ServerConnection ?
2019-06-21 11:20:03 -07:00
2021-10-25 22:27:30 -07:00
init ( context : InstallAppOperationContext )
2019-06-21 11:20:03 -07:00
{
self . context = context
super . init ( )
self . progress . totalUnitCount = 1
}
override func main ( )
{
super . main ( )
if let error = self . context . error
{
self . finish ( . failure ( error ) )
return
}
2021-10-25 22:27:30 -07:00
guard let resignedApp = self . context . resignedApp , let server = self . context . server else { return self . finish ( . failure ( OperationError . invalidParameters ) ) }
2019-07-28 15:08:13 -07:00
2023-10-18 14:06:10 -05:00
Logger . sideload . notice ( " Sending app \( self . context . bundleIdentifier , privacy : . public ) to AltServer \( server . localizedName ? ? " nil " , privacy : . public ) ... " )
2019-07-28 15:08:13 -07:00
// s e l f . c o n t e x t . r e s i g n e d A p p . f i l e U R L p o i n t s t o t h e a p p b u n d l e , b u t w e w a n t t h e . i p a .
2023-11-29 15:15:36 -06:00
let app = AnyApp ( name : resignedApp . name , bundleIdentifier : self . context . bundleIdentifier , url : resignedApp . fileURL , storeApp : nil )
2019-07-28 15:08:13 -07:00
let fileURL = InstalledApp . refreshedIPAURL ( for : app )
2019-06-21 11:20:03 -07:00
// C o n n e c t t o s e r v e r .
2020-01-08 12:41:02 -08:00
ServerManager . shared . connect ( to : server ) { ( result ) in
2019-06-21 11:20:03 -07:00
switch result
{
case . failure ( let error ) : self . finish ( . failure ( error ) )
2020-01-08 12:41:02 -08:00
case . success ( let serverConnection ) :
self . serverConnection = serverConnection
2019-06-21 11:20:03 -07:00
// S e n d a p p t o s e r v e r .
2020-01-08 12:41:02 -08:00
self . sendApp ( at : fileURL , via : serverConnection ) { ( result ) in
2019-06-21 11:20:03 -07:00
switch result
{
case . failure ( let error ) : self . finish ( . failure ( error ) )
case . success :
self . progress . completedUnitCount += 1
2020-01-08 12:41:02 -08:00
self . finish ( . success ( serverConnection ) )
2019-06-21 11:20:03 -07:00
}
}
}
}
}
}
private extension SendAppOperation
{
2020-01-08 12:41:02 -08:00
func sendApp ( at fileURL : URL , via connection : ServerConnection , completionHandler : @ escaping ( Result < Void , Error > ) -> Void )
2019-06-21 11:20:03 -07:00
{
do
{
guard let appData = try ? Data ( contentsOf : fileURL ) else { throw OperationError . invalidApp }
guard let udid = Bundle . main . object ( forInfoDictionaryKey : Bundle . Info . deviceID ) as ? String else { throw OperationError . unknownUDID }
2020-06-04 19:53:10 -07:00
var request = PrepareAppRequest ( udid : udid , contentSize : appData . count )
if connection . server . connectionType = = . local
{
// B a c k g r o u n d d a e m o n s h a v e l o w m e m o r y l i m i t ( ~ 6 M B a s o f 1 3 . 5 ) ,
// s o s e n d j u s t t h e f i l e U R L r a t h e r t h a n t h e a p p d a t a i t s e l f .
request . fileURL = fileURL
}
2019-06-21 11:20:03 -07:00
2020-01-08 12:41:02 -08:00
connection . send ( request ) { ( result ) in
2019-06-21 11:20:03 -07:00
switch result
{
case . failure ( let error ) : completionHandler ( . failure ( error ) )
case . success :
2020-06-04 19:53:10 -07:00
if connection . server . connectionType = = . local
{
// S e n t f i l e U R L , s o d o n ' t n e e d t o s e n d a n y m o r e .
completionHandler ( . success ( ( ) ) )
}
else
{
2023-10-18 14:06:10 -05:00
Logger . sideload . debug ( " Sending app data ( \( appData . count ) bytes)... " )
2020-06-04 19:53:10 -07:00
connection . send ( appData , prependSize : false ) { ( result ) in
switch result
{
case . failure ( let error ) :
2023-10-18 14:06:10 -05:00
Logger . sideload . error ( " Failed to send app to AltServer \( connection . server . localizedName ? ? " nil " , privacy : . public ) . \( error . localizedDescription , privacy : . public ) " )
2020-06-04 19:53:10 -07:00
completionHandler ( . failure ( error ) )
case . success :
2023-10-18 14:06:10 -05:00
Logger . sideload . notice ( " Finished sending app to AltServer \( connection . server . localizedName ? ? " nil " , privacy : . public ) ! " )
2020-06-04 19:53:10 -07:00
completionHandler ( . success ( ( ) ) )
}
2019-06-21 11:20:03 -07:00
}
}
}
}
}
catch
{
completionHandler ( . failure ( error ) )
}
}
}