@capgo/capacitor-updater 7.39.0 → 7.40.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapgoCapacitorUpdater.podspec +1 -1
- package/Package.swift +2 -2
- package/README.md +70 -199
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +54 -56
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +52 -33
- package/android/src/main/java/ee/forgr/capacitor_updater/CryptoCipher.java +10 -14
- package/android/src/main/java/ee/forgr/capacitor_updater/DeviceIdHelper.java +0 -6
- package/dist/docs.json +112 -668
- package/dist/esm/definitions.d.ts +23 -342
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/history.js +2 -2
- package/dist/esm/history.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +3 -2
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +4 -4
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +2 -2
- package/ios/Sources/CapacitorUpdaterPlugin/CapgoUpdater.swift +151 -107
- package/ios/Sources/CapacitorUpdaterPlugin/CryptoCipher.swift +34 -23
- package/package.json +6 -5
|
@@ -5,11 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import Foundation
|
|
8
|
-
|
|
9
|
-
import ZipArchive
|
|
10
|
-
#else
|
|
11
|
-
import SSZipArchive
|
|
12
|
-
#endif
|
|
8
|
+
import ZIPFoundation
|
|
13
9
|
import Alamofire
|
|
14
10
|
import Compression
|
|
15
11
|
import UIKit
|
|
@@ -159,7 +155,8 @@ import UIKit
|
|
|
159
155
|
case .success:
|
|
160
156
|
self.logger.info("Rate limit statistic sent")
|
|
161
157
|
case let .failure(error):
|
|
162
|
-
self.logger.error("Error sending rate limit statistic
|
|
158
|
+
self.logger.error("Error sending rate limit statistic")
|
|
159
|
+
self.logger.debug("Error: \(error.localizedDescription)")
|
|
163
160
|
}
|
|
164
161
|
semaphore.signal()
|
|
165
162
|
}
|
|
@@ -205,7 +202,8 @@ import UIKit
|
|
|
205
202
|
do {
|
|
206
203
|
try FileManager.default.createDirectory(atPath: source.path, withIntermediateDirectories: true, attributes: nil)
|
|
207
204
|
} catch {
|
|
208
|
-
logger.error("Cannot
|
|
205
|
+
logger.error("Cannot create directory")
|
|
206
|
+
logger.debug("Directory path: \(source.path)")
|
|
209
207
|
throw CustomError.cannotCreateDirectory
|
|
210
208
|
}
|
|
211
209
|
}
|
|
@@ -215,7 +213,8 @@ import UIKit
|
|
|
215
213
|
do {
|
|
216
214
|
try FileManager.default.removeItem(atPath: source.path)
|
|
217
215
|
} catch {
|
|
218
|
-
logger.error("File not removed
|
|
216
|
+
logger.error("File not removed")
|
|
217
|
+
logger.debug("Path: \(source.path)")
|
|
219
218
|
throw CustomError.cannotDeleteDirectory
|
|
220
219
|
}
|
|
221
220
|
}
|
|
@@ -232,43 +231,29 @@ import UIKit
|
|
|
232
231
|
return false
|
|
233
232
|
}
|
|
234
233
|
} catch {
|
|
235
|
-
logger.error("File not moved
|
|
234
|
+
logger.error("File not moved")
|
|
235
|
+
logger.debug("Source: \(source.path), Dest: \(dest.path)")
|
|
236
236
|
throw CustomError.cannotUnflat
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
private func
|
|
241
|
-
|
|
242
|
-
|
|
240
|
+
private func validateZipEntry(path: String, destUnZip: URL) throws {
|
|
241
|
+
// Check for Windows paths
|
|
242
|
+
if path.contains("\\") {
|
|
243
|
+
logger.error("Unzip failed: Windows path not supported")
|
|
244
|
+
logger.debug("Invalid path: \(path)")
|
|
243
245
|
self.sendStats(action: "windows_path_fail")
|
|
246
|
+
throw CustomError.cannotUnzip
|
|
244
247
|
}
|
|
245
248
|
|
|
246
|
-
|
|
247
|
-
let
|
|
248
|
-
let
|
|
249
|
+
// Check for path traversal
|
|
250
|
+
let fileURL = destUnZip.appendingPathComponent(path)
|
|
251
|
+
let canonicalPath = fileURL.standardizedFileURL.path
|
|
252
|
+
let canonicalDir = destUnZip.standardizedFileURL.path
|
|
249
253
|
|
|
250
254
|
if !canonicalPath.hasPrefix(canonicalDir) {
|
|
251
255
|
self.sendStats(action: "canonical_path_fail")
|
|
252
|
-
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
let isDirectory = entry.hasSuffix("/")
|
|
256
|
-
if !isDirectory {
|
|
257
|
-
let folderURL = fileURL.deletingLastPathComponent()
|
|
258
|
-
if !FileManager.default.fileExists(atPath: folderURL.path) {
|
|
259
|
-
do {
|
|
260
|
-
try FileManager.default.createDirectory(at: folderURL, withIntermediateDirectories: true, attributes: nil)
|
|
261
|
-
} catch {
|
|
262
|
-
self.sendStats(action: "directory_path_fail")
|
|
263
|
-
unzipError = error as NSError
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
let newPercent = self.calcTotalPercent(percent: Int(Double(entryNumber) / Double(total) * 100), min: 75, max: 81)
|
|
269
|
-
if newPercent != self.unzipPercent {
|
|
270
|
-
self.unzipPercent = newPercent
|
|
271
|
-
self.notifyDownload(id: id, percent: newPercent)
|
|
256
|
+
throw CustomError.cannotUnzip
|
|
272
257
|
}
|
|
273
258
|
}
|
|
274
259
|
|
|
@@ -280,36 +265,52 @@ import UIKit
|
|
|
280
265
|
self.unzipPercent = 0
|
|
281
266
|
self.notifyDownload(id: id, percent: 75)
|
|
282
267
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
password: nil,
|
|
292
|
-
error: &unzipError,
|
|
293
|
-
delegate: nil,
|
|
294
|
-
progressHandler: { [weak self] (entry, zipInfo, entryNumber, total) in
|
|
295
|
-
DispatchQueue.global(qos: .background).async {
|
|
296
|
-
guard let self = self else { return }
|
|
297
|
-
if !notify {
|
|
298
|
-
return
|
|
299
|
-
}
|
|
300
|
-
self.unzipProgressHandler(entry: entry, zipInfo: zipInfo, entryNumber: entryNumber, total: total, destUnZip: destUnZip, id: id, unzipError: &unzipError)
|
|
301
|
-
}
|
|
302
|
-
},
|
|
303
|
-
completionHandler: { _, _, _ in
|
|
304
|
-
semaphore.signal()
|
|
305
|
-
})
|
|
268
|
+
// Open the archive
|
|
269
|
+
let archive: Archive
|
|
270
|
+
do {
|
|
271
|
+
archive = try Archive(url: sourceZip, accessMode: .read)
|
|
272
|
+
} catch {
|
|
273
|
+
self.sendStats(action: "unzip_fail")
|
|
274
|
+
throw CustomError.cannotUnzip
|
|
275
|
+
}
|
|
306
276
|
|
|
307
|
-
|
|
277
|
+
// Create destination directory
|
|
278
|
+
try FileManager.default.createDirectory(at: destUnZip, withIntermediateDirectories: true, attributes: nil)
|
|
279
|
+
|
|
280
|
+
// Count total entries for progress
|
|
281
|
+
let totalEntries = archive.reduce(0) { count, _ in count + 1 }
|
|
282
|
+
var processedEntries = 0
|
|
283
|
+
|
|
284
|
+
do {
|
|
285
|
+
for entry in archive {
|
|
286
|
+
// Validate entry path for security
|
|
287
|
+
try validateZipEntry(path: entry.path, destUnZip: destUnZip)
|
|
288
|
+
|
|
289
|
+
let destPath = destUnZip.appendingPathComponent(entry.path)
|
|
290
|
+
|
|
291
|
+
// Create parent directories if needed
|
|
292
|
+
let parentDir = destPath.deletingLastPathComponent()
|
|
293
|
+
if !FileManager.default.fileExists(atPath: parentDir.path) {
|
|
294
|
+
try FileManager.default.createDirectory(at: parentDir, withIntermediateDirectories: true, attributes: nil)
|
|
295
|
+
}
|
|
308
296
|
|
|
309
|
-
|
|
297
|
+
// Extract the entry
|
|
298
|
+
_ = try archive.extract(entry, to: destPath, skipCRC32: true)
|
|
299
|
+
|
|
300
|
+
// Update progress
|
|
301
|
+
processedEntries += 1
|
|
302
|
+
if notify && totalEntries > 0 {
|
|
303
|
+
let newPercent = self.calcTotalPercent(percent: Int(Double(processedEntries) / Double(totalEntries) * 100), min: 75, max: 81)
|
|
304
|
+
if newPercent != self.unzipPercent {
|
|
305
|
+
self.unzipPercent = newPercent
|
|
306
|
+
self.notifyDownload(id: id, percent: newPercent)
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
} catch {
|
|
310
311
|
self.sendStats(action: "unzip_fail")
|
|
311
312
|
try? FileManager.default.removeItem(at: destUnZip)
|
|
312
|
-
throw
|
|
313
|
+
throw error
|
|
313
314
|
}
|
|
314
315
|
|
|
315
316
|
if try unflatFolder(source: destUnZip, dest: destPersist) {
|
|
@@ -322,7 +323,8 @@ import UIKit
|
|
|
322
323
|
try FileManager.default.removeItem(at: sourceZip)
|
|
323
324
|
}
|
|
324
325
|
} catch {
|
|
325
|
-
logger.error("Could not delete source zip
|
|
326
|
+
logger.error("Could not delete source zip")
|
|
327
|
+
logger.debug("Path: \(sourceZip.path), Error: \(error)")
|
|
326
328
|
}
|
|
327
329
|
}
|
|
328
330
|
|
|
@@ -397,8 +399,9 @@ import UIKit
|
|
|
397
399
|
latest.comment = comment
|
|
398
400
|
}
|
|
399
401
|
case let .failure(error):
|
|
400
|
-
self.logger.error("Error getting
|
|
401
|
-
|
|
402
|
+
self.logger.error("Error getting latest version")
|
|
403
|
+
self.logger.debug("Response: \(response.value.debugDescription), Error: \(error)")
|
|
404
|
+
latest.message = "Error getting Latest"
|
|
402
405
|
latest.error = "response_error"
|
|
403
406
|
latest.statusCode = response.response?.statusCode ?? 0
|
|
404
407
|
}
|
|
@@ -465,7 +468,8 @@ import UIKit
|
|
|
465
468
|
fileHash = try CryptoCipher.decryptChecksum(checksum: fileHash, publicKey: self.publicKey)
|
|
466
469
|
} catch {
|
|
467
470
|
downloadError = error
|
|
468
|
-
logger.error("
|
|
471
|
+
logger.error("Checksum decryption failed")
|
|
472
|
+
logger.debug("Bundle: \(id), File: \(fileName), Error: \(error)")
|
|
469
473
|
}
|
|
470
474
|
}
|
|
471
475
|
|
|
@@ -494,7 +498,8 @@ import UIKit
|
|
|
494
498
|
self.notifyDownload(id: id, percent: self.calcTotalPercent(percent: Int((Double(completedFiles) / Double(totalFiles)) * 100), min: 10, max: 70))
|
|
495
499
|
} catch {
|
|
496
500
|
downloadError = error
|
|
497
|
-
logger.error("Failed to copy builtin file
|
|
501
|
+
logger.error("Failed to copy builtin file")
|
|
502
|
+
logger.debug("File: \(fileName), Error: \(error.localizedDescription)")
|
|
498
503
|
}
|
|
499
504
|
dispatchGroup.leave()
|
|
500
505
|
} else if self.tryCopyFromCache(from: cacheFilePath, to: destFilePath, expectedHash: fileHash) {
|
|
@@ -566,15 +571,18 @@ import UIKit
|
|
|
566
571
|
|
|
567
572
|
completedFiles += 1
|
|
568
573
|
self.notifyDownload(id: id, percent: self.calcTotalPercent(percent: Int((Double(completedFiles) / Double(totalFiles)) * 100), min: 10, max: 70))
|
|
569
|
-
self.logger.info("
|
|
574
|
+
self.logger.info("Manifest file downloaded and cached")
|
|
575
|
+
self.logger.debug("Bundle: \(id), File: \(fileName), Brotli: \(isBrotli), Encrypted: \(!self.publicKey.isEmpty && !sessionKey.isEmpty)")
|
|
570
576
|
} catch {
|
|
571
577
|
downloadError = error
|
|
572
|
-
self.logger.error("
|
|
578
|
+
self.logger.error("Manifest file download failed")
|
|
579
|
+
self.logger.debug("Bundle: \(id), File: \(fileName), Error: \(error.localizedDescription)")
|
|
573
580
|
}
|
|
574
581
|
case .failure(let error):
|
|
575
582
|
downloadError = error
|
|
576
583
|
self.sendStats(action: "download_manifest_file_fail", versionName: "\(version):\(fileName)")
|
|
577
|
-
self.logger.error("
|
|
584
|
+
self.logger.error("Manifest file download network error")
|
|
585
|
+
self.logger.debug("Bundle: \(id), File: \(fileName), Error: \(error.localizedDescription), Response: \(response.debugDescription)")
|
|
578
586
|
}
|
|
579
587
|
}
|
|
580
588
|
}
|
|
@@ -662,7 +670,8 @@ import UIKit
|
|
|
662
670
|
var status = compression_stream_init(streamPointer, COMPRESSION_STREAM_DECODE, COMPRESSION_BROTLI)
|
|
663
671
|
|
|
664
672
|
guard status != COMPRESSION_STATUS_ERROR else {
|
|
665
|
-
logger.error("
|
|
673
|
+
logger.error("Failed to initialize Brotli stream")
|
|
674
|
+
logger.debug("File: \(fileName), Status: \(status)")
|
|
666
675
|
return nil
|
|
667
676
|
}
|
|
668
677
|
|
|
@@ -684,7 +693,8 @@ import UIKit
|
|
|
684
693
|
if let baseAddress = rawBufferPointer.baseAddress {
|
|
685
694
|
streamPointer.pointee.src_ptr = baseAddress.assumingMemoryBound(to: UInt8.self)
|
|
686
695
|
} else {
|
|
687
|
-
logger.error("
|
|
696
|
+
logger.error("Failed to get base address for Brotli decompression")
|
|
697
|
+
logger.debug("File: \(fileName)")
|
|
688
698
|
status = COMPRESSION_STATUS_ERROR
|
|
689
699
|
return
|
|
690
700
|
}
|
|
@@ -694,7 +704,8 @@ import UIKit
|
|
|
694
704
|
if status == COMPRESSION_STATUS_ERROR {
|
|
695
705
|
let maxBytes = min(32, data.count)
|
|
696
706
|
let hexDump = data.prefix(maxBytes).map { String(format: "%02x", $0) }.joined(separator: " ")
|
|
697
|
-
logger.error("
|
|
707
|
+
logger.error("Brotli decompression failed")
|
|
708
|
+
logger.debug("File: \(fileName), First \(maxBytes) bytes: \(hexDump)")
|
|
698
709
|
break
|
|
699
710
|
}
|
|
700
711
|
|
|
@@ -708,18 +719,19 @@ import UIKit
|
|
|
708
719
|
if status == COMPRESSION_STATUS_END {
|
|
709
720
|
break
|
|
710
721
|
} else if status == COMPRESSION_STATUS_ERROR {
|
|
711
|
-
logger.error("
|
|
722
|
+
logger.error("Brotli process failed")
|
|
723
|
+
logger.debug("File: \(fileName), Status: \(status)")
|
|
712
724
|
if let text = String(data: data, encoding: .utf8) {
|
|
713
725
|
let asciiCount = text.unicodeScalars.filter { $0.isASCII }.count
|
|
714
726
|
let totalCount = text.unicodeScalars.count
|
|
715
727
|
if totalCount > 0 && Double(asciiCount) / Double(totalCount) >= 0.8 {
|
|
716
|
-
logger.
|
|
728
|
+
logger.debug("Input appears to be plain text: \(text)")
|
|
717
729
|
}
|
|
718
730
|
}
|
|
719
731
|
|
|
720
732
|
let maxBytes = min(32, data.count)
|
|
721
733
|
let hexDump = data.prefix(maxBytes).map { String(format: "%02x", $0) }.joined(separator: " ")
|
|
722
|
-
logger.
|
|
734
|
+
logger.debug("Raw data: \(hexDump)")
|
|
723
735
|
|
|
724
736
|
return nil
|
|
725
737
|
}
|
|
@@ -730,7 +742,8 @@ import UIKit
|
|
|
730
742
|
}
|
|
731
743
|
|
|
732
744
|
if input.count == 0 {
|
|
733
|
-
logger.error("
|
|
745
|
+
logger.error("Zero input size for Brotli decompression")
|
|
746
|
+
logger.debug("File: \(fileName)")
|
|
734
747
|
break
|
|
735
748
|
}
|
|
736
749
|
}
|
|
@@ -822,7 +835,8 @@ import UIKit
|
|
|
822
835
|
reachabilityManager?.stopListening()
|
|
823
836
|
|
|
824
837
|
if mainError != nil {
|
|
825
|
-
logger.error("Failed to download
|
|
838
|
+
logger.error("Failed to download bundle")
|
|
839
|
+
logger.debug("Error: \(String(describing: mainError))")
|
|
826
840
|
self.saveBundleInfo(id: id, bundle: BundleInfo(id: id, version: version, status: BundleStatus.ERROR, downloaded: Date(), checksum: checksum, link: link, comment: comment))
|
|
827
841
|
throw mainError!
|
|
828
842
|
}
|
|
@@ -832,7 +846,8 @@ import UIKit
|
|
|
832
846
|
try CryptoCipher.decryptFile(filePath: tempDataPath, publicKey: self.publicKey, sessionKey: sessionKey, version: version)
|
|
833
847
|
try FileManager.default.moveItem(at: tempDataPath, to: finalPath)
|
|
834
848
|
} catch {
|
|
835
|
-
logger.error("Failed decrypt file
|
|
849
|
+
logger.error("Failed to decrypt file")
|
|
850
|
+
logger.debug("Error: \(error)")
|
|
836
851
|
self.saveBundleInfo(id: id, bundle: BundleInfo(id: id, version: version, status: BundleStatus.ERROR, downloaded: Date(), checksum: checksum, link: link, comment: comment))
|
|
837
852
|
cleanDownloadData()
|
|
838
853
|
throw error
|
|
@@ -845,7 +860,8 @@ import UIKit
|
|
|
845
860
|
try self.saveDownloaded(sourceZip: finalPath, id: id, base: self.libraryDir.appendingPathComponent(self.bundleDirectory), notify: true)
|
|
846
861
|
|
|
847
862
|
} catch {
|
|
848
|
-
logger.error("Failed to unzip file
|
|
863
|
+
logger.error("Failed to unzip file")
|
|
864
|
+
logger.debug("Error: \(error)")
|
|
849
865
|
self.saveBundleInfo(id: id, bundle: BundleInfo(id: id, version: version, status: BundleStatus.ERROR, downloaded: Date(), checksum: checksum, link: link, comment: comment))
|
|
850
866
|
// Best-effort cleanup of the decrypted zip file when unzip fails
|
|
851
867
|
do {
|
|
@@ -853,7 +869,8 @@ import UIKit
|
|
|
853
869
|
try FileManager.default.removeItem(at: finalPath)
|
|
854
870
|
}
|
|
855
871
|
} catch {
|
|
856
|
-
logger.error("Could not delete failed zip
|
|
872
|
+
logger.error("Could not delete failed zip")
|
|
873
|
+
logger.debug("Path: \(finalPath.path), Error: \(error)")
|
|
857
874
|
}
|
|
858
875
|
cleanDownloadData()
|
|
859
876
|
throw error
|
|
@@ -876,13 +893,15 @@ import UIKit
|
|
|
876
893
|
let fileManager = FileManager.default
|
|
877
894
|
if !fileManager.fileExists(atPath: tempDataPath.path) {
|
|
878
895
|
if !fileManager.createFile(atPath: tempDataPath.path, contents: Data()) {
|
|
879
|
-
logger.error("Cannot ensure
|
|
896
|
+
logger.error("Cannot ensure temp data file exists")
|
|
897
|
+
logger.debug("Path: \(tempDataPath.path)")
|
|
880
898
|
}
|
|
881
899
|
}
|
|
882
900
|
|
|
883
901
|
if !fileManager.fileExists(atPath: updateInfo.path) {
|
|
884
902
|
if !fileManager.createFile(atPath: updateInfo.path, contents: Data()) {
|
|
885
|
-
logger.error("Cannot ensure
|
|
903
|
+
logger.error("Cannot ensure update info file exists")
|
|
904
|
+
logger.debug("Path: \(updateInfo.path)")
|
|
886
905
|
}
|
|
887
906
|
}
|
|
888
907
|
}
|
|
@@ -894,7 +913,8 @@ import UIKit
|
|
|
894
913
|
do {
|
|
895
914
|
try fileManager.removeItem(at: tempDataPath)
|
|
896
915
|
} catch {
|
|
897
|
-
logger.error("Could not delete
|
|
916
|
+
logger.error("Could not delete temp data file")
|
|
917
|
+
logger.debug("Path: \(tempDataPath), Error: \(error)")
|
|
898
918
|
}
|
|
899
919
|
}
|
|
900
920
|
// Deleting update.dat
|
|
@@ -902,7 +922,8 @@ import UIKit
|
|
|
902
922
|
do {
|
|
903
923
|
try fileManager.removeItem(at: updateInfo)
|
|
904
924
|
} catch {
|
|
905
|
-
logger.error("Could not delete
|
|
925
|
+
logger.error("Could not delete update info file")
|
|
926
|
+
logger.debug("Path: \(updateInfo), Error: \(error)")
|
|
906
927
|
}
|
|
907
928
|
}
|
|
908
929
|
}
|
|
@@ -921,7 +942,8 @@ import UIKit
|
|
|
921
942
|
fileHandle.closeFile()
|
|
922
943
|
}
|
|
923
944
|
} catch {
|
|
924
|
-
logger.error("Failed to write data
|
|
945
|
+
logger.error("Failed to write partial data")
|
|
946
|
+
logger.debug("Byte offset: \(byteOffset), Error: \(error)")
|
|
925
947
|
}
|
|
926
948
|
self.tempData.removeAll() // Clearing tempData to avoid writing the same data multiple times
|
|
927
949
|
}
|
|
@@ -930,7 +952,8 @@ import UIKit
|
|
|
930
952
|
do {
|
|
931
953
|
try "\(version)".write(to: updateInfo, atomically: true, encoding: .utf8)
|
|
932
954
|
} catch {
|
|
933
|
-
logger.error("Failed to save progress
|
|
955
|
+
logger.error("Failed to save download progress")
|
|
956
|
+
logger.debug("Error: \(error)")
|
|
934
957
|
}
|
|
935
958
|
}
|
|
936
959
|
private func getLocalUpdateVersion() -> String { // Return the version that was tried to be downloaded on last download attempt
|
|
@@ -952,7 +975,8 @@ import UIKit
|
|
|
952
975
|
return fileSize.int64Value
|
|
953
976
|
}
|
|
954
977
|
} catch {
|
|
955
|
-
logger.error("Could not retrieve
|
|
978
|
+
logger.error("Could not retrieve download progress size")
|
|
979
|
+
logger.debug("Error: \(error)")
|
|
956
980
|
}
|
|
957
981
|
return 0
|
|
958
982
|
}
|
|
@@ -996,7 +1020,8 @@ import UIKit
|
|
|
996
1020
|
public func delete(id: String, removeInfo: Bool) -> Bool {
|
|
997
1021
|
let deleted: BundleInfo = self.getBundleInfo(id: id)
|
|
998
1022
|
if deleted.isBuiltin() || self.getCurrentBundleId() == id {
|
|
999
|
-
logger.info("Cannot delete
|
|
1023
|
+
logger.info("Cannot delete current or builtin bundle")
|
|
1024
|
+
logger.debug("Bundle ID: \(id)")
|
|
1000
1025
|
return false
|
|
1001
1026
|
}
|
|
1002
1027
|
|
|
@@ -1005,7 +1030,8 @@ import UIKit
|
|
|
1005
1030
|
!next.isDeleted() &&
|
|
1006
1031
|
!next.isErrorStatus() &&
|
|
1007
1032
|
next.getId() == id {
|
|
1008
|
-
logger.info("Cannot delete the next bundle
|
|
1033
|
+
logger.info("Cannot delete the next bundle")
|
|
1034
|
+
logger.debug("Bundle ID: \(id)")
|
|
1009
1035
|
return false
|
|
1010
1036
|
}
|
|
1011
1037
|
|
|
@@ -1013,7 +1039,8 @@ import UIKit
|
|
|
1013
1039
|
do {
|
|
1014
1040
|
try FileManager.default.removeItem(atPath: destPersist.path)
|
|
1015
1041
|
} catch {
|
|
1016
|
-
logger.error("
|
|
1042
|
+
logger.error("Bundle folder not removed")
|
|
1043
|
+
logger.debug("Path: \(destPersist.path)")
|
|
1017
1044
|
// even if, we don;t care. Android doesn't care
|
|
1018
1045
|
if removeInfo {
|
|
1019
1046
|
self.removeBundleInfo(id: id)
|
|
@@ -1026,7 +1053,8 @@ import UIKit
|
|
|
1026
1053
|
} else {
|
|
1027
1054
|
self.saveBundleInfo(id: id, bundle: deleted.setStatus(status: BundleStatus.DELETED.localizedString))
|
|
1028
1055
|
}
|
|
1029
|
-
logger.info("
|
|
1056
|
+
logger.info("Bundle deleted successfully")
|
|
1057
|
+
logger.debug("Version: \(deleted.getVersionName())")
|
|
1030
1058
|
self.sendStats(action: "delete", versionName: deleted.getVersionName())
|
|
1031
1059
|
return true
|
|
1032
1060
|
}
|
|
@@ -1054,7 +1082,8 @@ import UIKit
|
|
|
1054
1082
|
try fileManager.removeItem(at: cacheFolder)
|
|
1055
1083
|
logger.info("Cleaned up delta cache folder")
|
|
1056
1084
|
} catch {
|
|
1057
|
-
logger.error("Failed to cleanup delta cache
|
|
1085
|
+
logger.error("Failed to cleanup delta cache")
|
|
1086
|
+
logger.debug("Error: \(error.localizedDescription)")
|
|
1058
1087
|
}
|
|
1059
1088
|
}
|
|
1060
1089
|
|
|
@@ -1094,13 +1123,16 @@ import UIKit
|
|
|
1094
1123
|
do {
|
|
1095
1124
|
try fileManager.removeItem(at: url)
|
|
1096
1125
|
self.removeBundleInfo(id: id)
|
|
1097
|
-
logger.info("Deleted orphan bundle directory
|
|
1126
|
+
logger.info("Deleted orphan bundle directory")
|
|
1127
|
+
logger.debug("Bundle ID: \(id)")
|
|
1098
1128
|
} catch {
|
|
1099
|
-
logger.error("Failed to delete orphan bundle directory
|
|
1129
|
+
logger.error("Failed to delete orphan bundle directory")
|
|
1130
|
+
logger.debug("Bundle ID: \(id), Error: \(error.localizedDescription)")
|
|
1100
1131
|
}
|
|
1101
1132
|
}
|
|
1102
1133
|
} catch {
|
|
1103
|
-
logger.error("Failed to enumerate bundle directory for cleanup
|
|
1134
|
+
logger.error("Failed to enumerate bundle directory for cleanup")
|
|
1135
|
+
logger.debug("Error: \(error.localizedDescription)")
|
|
1104
1136
|
}
|
|
1105
1137
|
}
|
|
1106
1138
|
|
|
@@ -1131,13 +1163,16 @@ import UIKit
|
|
|
1131
1163
|
|
|
1132
1164
|
do {
|
|
1133
1165
|
try fileManager.removeItem(at: url)
|
|
1134
|
-
logger.info("Deleted orphaned temp unzip folder
|
|
1166
|
+
logger.info("Deleted orphaned temp unzip folder")
|
|
1167
|
+
logger.debug("Folder: \(folderName)")
|
|
1135
1168
|
} catch {
|
|
1136
|
-
logger.error("Failed to delete orphaned temp folder
|
|
1169
|
+
logger.error("Failed to delete orphaned temp folder")
|
|
1170
|
+
logger.debug("Folder: \(folderName), Error: \(error.localizedDescription)")
|
|
1137
1171
|
}
|
|
1138
1172
|
}
|
|
1139
1173
|
} catch {
|
|
1140
|
-
logger.error("Failed to enumerate library directory for temp folder cleanup
|
|
1174
|
+
logger.error("Failed to enumerate library directory for temp folder cleanup")
|
|
1175
|
+
logger.debug("Error: \(error.localizedDescription)")
|
|
1141
1176
|
}
|
|
1142
1177
|
}
|
|
1143
1178
|
|
|
@@ -1213,9 +1248,11 @@ import UIKit
|
|
|
1213
1248
|
if autoDeletePrevious && !fallback.isBuiltin() && fallback.getId() != bundle.getId() {
|
|
1214
1249
|
let res = self.delete(id: fallback.getId())
|
|
1215
1250
|
if res {
|
|
1216
|
-
logger.info("Deleted previous bundle
|
|
1251
|
+
logger.info("Deleted previous bundle")
|
|
1252
|
+
logger.debug("Bundle: \(fallback.toString())")
|
|
1217
1253
|
} else {
|
|
1218
|
-
logger.error("Failed to delete previous bundle
|
|
1254
|
+
logger.error("Failed to delete previous bundle")
|
|
1255
|
+
logger.debug("Bundle: \(fallback.toString())")
|
|
1219
1256
|
}
|
|
1220
1257
|
}
|
|
1221
1258
|
self.setFallbackBundle(fallback: bundle)
|
|
@@ -1296,7 +1333,8 @@ import UIKit
|
|
|
1296
1333
|
}
|
|
1297
1334
|
}
|
|
1298
1335
|
case let .failure(error):
|
|
1299
|
-
self.logger.error("Error
|
|
1336
|
+
self.logger.error("Error setting channel")
|
|
1337
|
+
self.logger.debug("Error: \(error)")
|
|
1300
1338
|
setChannel.error = "Request failed: \(error.localizedDescription)"
|
|
1301
1339
|
}
|
|
1302
1340
|
semaphore.signal()
|
|
@@ -1359,7 +1397,8 @@ import UIKit
|
|
|
1359
1397
|
}
|
|
1360
1398
|
}
|
|
1361
1399
|
|
|
1362
|
-
self.logger.error("Error
|
|
1400
|
+
self.logger.error("Error getting channel")
|
|
1401
|
+
self.logger.debug("Error: \(error)")
|
|
1363
1402
|
getChannel.error = "Request failed: \(error.localizedDescription)"
|
|
1364
1403
|
}
|
|
1365
1404
|
}
|
|
@@ -1449,7 +1488,8 @@ import UIKit
|
|
|
1449
1488
|
}
|
|
1450
1489
|
}
|
|
1451
1490
|
case let .failure(error):
|
|
1452
|
-
self.logger.error("Error
|
|
1491
|
+
self.logger.error("Error listing channels")
|
|
1492
|
+
self.logger.debug("Error: \(error)")
|
|
1453
1493
|
listChannels.error = "Request failed: \(error.localizedDescription)"
|
|
1454
1494
|
}
|
|
1455
1495
|
}
|
|
@@ -1495,9 +1535,11 @@ import UIKit
|
|
|
1495
1535
|
|
|
1496
1536
|
switch response.result {
|
|
1497
1537
|
case .success:
|
|
1498
|
-
self.logger.info("Stats sent
|
|
1538
|
+
self.logger.info("Stats sent successfully")
|
|
1539
|
+
self.logger.debug("Action: \(action), Version: \(versionName)")
|
|
1499
1540
|
case let .failure(error):
|
|
1500
|
-
self.logger.error("Error sending stats
|
|
1541
|
+
self.logger.error("Error sending stats")
|
|
1542
|
+
self.logger.debug("Response: \(response.value?.debugDescription ?? "nil"), Error: \(error.localizedDescription)")
|
|
1501
1543
|
}
|
|
1502
1544
|
semaphore.signal()
|
|
1503
1545
|
}
|
|
@@ -1521,7 +1563,8 @@ import UIKit
|
|
|
1521
1563
|
do {
|
|
1522
1564
|
result = try UserDefaults.standard.getObj(forKey: "\(trueId)\(self.INFO_SUFFIX)", castTo: BundleInfo.self)
|
|
1523
1565
|
} catch {
|
|
1524
|
-
logger.error("Failed to parse
|
|
1566
|
+
logger.error("Failed to parse bundle info")
|
|
1567
|
+
logger.debug("Bundle ID: \(trueId), Error: \(error.localizedDescription)")
|
|
1525
1568
|
result = BundleInfo(id: trueId, version: "", status: BundleStatus.PENDING, checksum: "")
|
|
1526
1569
|
}
|
|
1527
1570
|
}
|
|
@@ -1556,7 +1599,8 @@ import UIKit
|
|
|
1556
1599
|
do {
|
|
1557
1600
|
try UserDefaults.standard.setObj(update, forKey: "\(id)\(self.INFO_SUFFIX)")
|
|
1558
1601
|
} catch {
|
|
1559
|
-
logger.error("Failed to save
|
|
1602
|
+
logger.error("Failed to save bundle info")
|
|
1603
|
+
logger.debug("Bundle ID: \(id), Error: \(error.localizedDescription)")
|
|
1560
1604
|
}
|
|
1561
1605
|
}
|
|
1562
1606
|
UserDefaults.standard.synchronize()
|