@@ -55,23 +55,31 @@ class ModelDownloadTask: NSObject {
55
55
private lazy var downloadSession = URLSession ( configuration: . ephemeral,
56
56
delegate: self ,
57
57
delegateQueue: nil )
58
+ /// Model info retriever in case of retries.
59
+ private let modelInfoRetriever : ModelInfoRetriever
60
+ /// Number of retries in case of model download URL expiry.
61
+ private var numberOfRetries : Int = 1
58
62
/// Telemetry logger.
59
63
private let telemetryLogger : TelemetryLogger ?
60
64
61
65
init ( remoteModelInfo: RemoteModelInfo , appName: String , defaults: UserDefaults ,
66
+ modelInfoRetriever: ModelInfoRetriever ,
62
67
telemetryLogger: TelemetryLogger ? = nil ,
63
68
progressHandler: DownloadHandlers . ProgressHandler ? = nil ,
64
69
completion: @escaping DownloadHandlers . Completion ) {
65
70
self . remoteModelInfo = remoteModelInfo
66
71
self . appName = appName
72
+ self . modelInfoRetriever = modelInfoRetriever
67
73
self . telemetryLogger = telemetryLogger
68
74
self . defaults = defaults
69
75
downloadHandlers = DownloadHandlers (
70
76
progressHandler: progressHandler,
71
77
completion: completion
72
78
)
73
79
}
80
+ }
74
81
82
+ extension ModelDownloadTask {
75
83
/// Asynchronously download model file to device.
76
84
func resumeModelDownload( ) {
77
85
guard downloadStatus == . notStarted else { return }
@@ -116,7 +124,42 @@ extension ModelDownloadTask: URLSessionDownloadDelegate {
116
124
}
117
125
118
126
guard ( 200 ..< 299 ) . contains ( response. statusCode) else {
119
- // TODO: Handle download url expiry + retries.
127
+ /// Possible failure due to download URL expiry.
128
+ if response. statusCode == 400 {
129
+ let currentDateTime = Date ( )
130
+ /// Retry download if allowed.
131
+ guard currentDateTime > remoteModelInfo. urlExpiryTime, numberOfRetries > 0 else {
132
+ downloadStatus = . failed
133
+ downloadHandlers
134
+ . completion ( . failure( . internalError( description: ModelDownloadTask . ErrorDescription
135
+ . expiredModelInfo) ) )
136
+ return
137
+ }
138
+ numberOfRetries -= 1
139
+ modelInfoRetriever. downloadModelInfo { result in
140
+ switch result {
141
+ case let . success( downloadModelInfoResult) :
142
+ switch downloadModelInfoResult {
143
+ /// New model info was downloaded from server.
144
+ case let . modelInfo( remoteModelInfo) :
145
+ self . remoteModelInfo = remoteModelInfo
146
+ self . resumeModelDownload ( )
147
+ /// This should not ever be the case - model info cannot be unmodified within ModelDownloadTask.
148
+ case . notModified:
149
+ DispatchQueue . main. async {
150
+ self . downloadHandlers
151
+ . completion ( . failure( . internalError( description: ModelDownloadTask
152
+ . ErrorDescription. expiredModelInfo) ) )
153
+ }
154
+ }
155
+ case let . failure( downloadError) :
156
+ self . downloadStatus = . failed
157
+ DispatchQueue . main. async {
158
+ self . downloadHandlers. completion ( . failure( downloadError) )
159
+ }
160
+ }
161
+ }
162
+ }
120
163
return
121
164
}
122
165
@@ -196,5 +239,6 @@ extension ModelDownloadTask {
196
239
" Could not get server response for model downloading. "
197
240
static let saveModel : StaticString =
198
241
" Unable to save downloaded remote model file. "
242
+ static let expiredModelInfo = " Unable to update expired model info. "
199
243
}
200
244
}
0 commit comments