@craft-native/ios 0.0.197 → 0.0.199
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/package.json
CHANGED
|
@@ -25,6 +25,7 @@ struct CraftLiveActivityWidget: Widget {
|
|
|
25
25
|
metrics(context).font(.caption.monospacedDigit())
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
+
.foregroundStyle(.white)
|
|
28
29
|
.padding()
|
|
29
30
|
.activityBackgroundTint(Color(red: 0.07, green: 0.10, blue: 0.16))
|
|
30
31
|
.activitySystemActionForegroundColor(.white)
|
|
@@ -515,7 +515,7 @@ enum CraftNativeMedia {
|
|
|
515
515
|
static func local(_ address: String) -> URL? {
|
|
516
516
|
guard !address.isEmpty else { return nil }
|
|
517
517
|
let url = file(for: address)
|
|
518
|
-
return
|
|
518
|
+
return ((try? url.resourceValues(forKeys: [.fileSizeKey]).fileSize) ?? 0) > 0 ? url : nil
|
|
519
519
|
}
|
|
520
520
|
|
|
521
521
|
static func describe(_ address: String, _ url: URL) -> [String: Any] {
|
|
@@ -545,11 +545,23 @@ enum CraftNativeMedia {
|
|
|
545
545
|
/// A finished download moved into place (atomically, so a half-written
|
|
546
546
|
/// file is never played), or a refusal with the server's status.
|
|
547
547
|
static func store(_ address: String, at location: URL, response: HTTPURLResponse) -> Result<Any, CraftNativeActionError> {
|
|
548
|
-
guard
|
|
548
|
+
guard response.statusCode == 200 else {
|
|
549
549
|
return .success(["ok": false, "url": address, "status": response.statusCode])
|
|
550
550
|
}
|
|
551
551
|
let fm = FileManager.default
|
|
552
|
+
// Commit and prune share a lock; neither can remove a file being committed.
|
|
553
|
+
lock.lock()
|
|
554
|
+
defer { lock.unlock() }
|
|
555
|
+
let staging = root.appendingPathComponent(UUID().uuidString + ".part")
|
|
556
|
+
defer { try? fm.removeItem(at: staging) }
|
|
552
557
|
do {
|
|
558
|
+
let size = (try location.resourceValues(forKeys: [.fileSizeKey])).fileSize ?? 0
|
|
559
|
+
// URLSession normally rejects a truncated transfer; also guard this boundary.
|
|
560
|
+
let expected = response.expectedContentLength
|
|
561
|
+
let encoded = response.value(forHTTPHeaderField: "Content-Encoding")
|
|
562
|
+
if size <= 0 || (encoded == nil && expected >= 0 && Int64(size) != expected) {
|
|
563
|
+
return .failure(CraftNativeActionError(code: "NETWORK_ERROR", message: "media.keep received an incomplete file"))
|
|
564
|
+
}
|
|
553
565
|
var folder = root
|
|
554
566
|
if !fm.fileExists(atPath: folder.path) {
|
|
555
567
|
try fm.createDirectory(at: folder, withIntermediateDirectories: true)
|
|
@@ -558,7 +570,6 @@ enum CraftNativeMedia {
|
|
|
558
570
|
try? folder.setResourceValues(values)
|
|
559
571
|
}
|
|
560
572
|
let target = file(for: address)
|
|
561
|
-
let staging = root.appendingPathComponent(UUID().uuidString + ".part")
|
|
562
573
|
try fm.moveItem(at: location, to: staging)
|
|
563
574
|
_ = try? fm.removeItem(at: target)
|
|
564
575
|
try fm.moveItem(at: staging, to: target)
|
|
@@ -571,10 +582,13 @@ enum CraftNativeMedia {
|
|
|
571
582
|
|
|
572
583
|
/// Removes every copy whose address is not in `keep`; answers how many.
|
|
573
584
|
static func prune(keep: [String]) -> Int {
|
|
585
|
+
lock.lock()
|
|
586
|
+
defer { lock.unlock() }
|
|
574
587
|
let wanted = Set(keep.map { file(for: $0).lastPathComponent })
|
|
575
588
|
let files = (try? FileManager.default.contentsOfDirectory(at: root, includingPropertiesForKeys: nil)) ?? []
|
|
576
589
|
var removed = 0
|
|
577
|
-
|
|
590
|
+
let active = Set(inFlight.keys.map { file(for: $0).lastPathComponent })
|
|
591
|
+
for url in files where !wanted.contains(url.lastPathComponent) && !active.contains(url.lastPathComponent) {
|
|
578
592
|
if (try? FileManager.default.removeItem(at: url)) != nil { removed += 1 }
|
|
579
593
|
}
|
|
580
594
|
return removed
|