Fix uploads, add server key entry
This commit is contained in:
@ -49,6 +49,15 @@ struct Cap {
|
||||
self.mainImage = data.mainImage
|
||||
self.classifierVersion = data.classifierVersion
|
||||
}
|
||||
|
||||
var data: CapData {
|
||||
.init(id: id,
|
||||
name: name,
|
||||
count: imageCount,
|
||||
mainImage: mainImage,
|
||||
classifierVersion: classifierVersion,
|
||||
color: color)
|
||||
}
|
||||
|
||||
mutating func update(with data: CapData) {
|
||||
self.name = data.name
|
||||
|
@ -52,10 +52,10 @@ final class Database: ObservableObject {
|
||||
let serverUrl: URL
|
||||
|
||||
@AppStorage("authKey")
|
||||
private var serverAuthenticationKey: String?
|
||||
private var serverAuthenticationKey: String = ""
|
||||
|
||||
var hasServerAuthentication: Bool {
|
||||
serverAuthenticationKey != nil
|
||||
serverAuthenticationKey != ""
|
||||
}
|
||||
|
||||
@Published
|
||||
@ -120,7 +120,6 @@ final class Database: ObservableObject {
|
||||
diskCapacity: Database.imageCacheStorage,
|
||||
directory: cacheDirectory)
|
||||
loadCaps()
|
||||
|
||||
}
|
||||
|
||||
@Published
|
||||
@ -323,7 +322,9 @@ final class Database: ObservableObject {
|
||||
func save(newCap name: String) -> Cap {
|
||||
let cap = Cap(id: nextCapId, name: name, classifier: serverClassifierVersion)
|
||||
caps[cap.id] = cap
|
||||
#warning("Upload new cap")
|
||||
DispatchQueue.main.async {
|
||||
self.changedCaps.insert(cap.id)
|
||||
}
|
||||
return cap
|
||||
}
|
||||
|
||||
@ -350,14 +351,9 @@ final class Database: ObservableObject {
|
||||
}
|
||||
log("Saved \(url.lastPathComponent) for upload")
|
||||
caps[capId]?.imageCount += 1
|
||||
updateImageUploadCounts()
|
||||
return true
|
||||
}
|
||||
|
||||
private func updateImageUploadCounts() {
|
||||
|
||||
}
|
||||
|
||||
private func loadImageUploadCounts() -> [Int : Int] {
|
||||
var result = [Int : Int]()
|
||||
pendingImageUploads.forEach { url in
|
||||
@ -376,9 +372,10 @@ final class Database: ObservableObject {
|
||||
// MARK: Uploads
|
||||
|
||||
func startRegularUploads() {
|
||||
guard uploadTimer != nil else {
|
||||
guard uploadTimer == nil else {
|
||||
return
|
||||
}
|
||||
log("Starting upload timer")
|
||||
DispatchQueue.main.async {
|
||||
self.uploadTimer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: self.uploadTimerElapsed)
|
||||
}
|
||||
@ -392,13 +389,19 @@ final class Database: ObservableObject {
|
||||
|
||||
private func uploadAll() async {
|
||||
guard !isUploading else {
|
||||
log("Already uploading")
|
||||
return
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
self.isUploading = true
|
||||
}
|
||||
await uploadAllChangedCaps()
|
||||
log("Starting uploads")
|
||||
let uploaded = await uploadAllChangedCaps()
|
||||
DispatchQueue.main.async {
|
||||
self.changedCaps.subtract(uploaded)
|
||||
}
|
||||
await uploadAllImages()
|
||||
log("Uploads finished")
|
||||
DispatchQueue.main.async {
|
||||
self.isUploading = false
|
||||
}
|
||||
@ -428,18 +431,22 @@ final class Database: ObservableObject {
|
||||
log("No server authentication to upload to server")
|
||||
return
|
||||
}
|
||||
updateImageUploadCounts()
|
||||
for url in pendingImageUploads {
|
||||
guard let capId = capId(from: url) else {
|
||||
log("Unexpected image \(url.lastPathComponent) in upload folder")
|
||||
continue
|
||||
}
|
||||
guard await upload(imageAt: url, for: capId) else {
|
||||
guard fm.fileExists(atPath: url.path) else {
|
||||
log("Missing image \(url.lastPathComponent) in upload folder")
|
||||
continue
|
||||
}
|
||||
guard await upload(imageAt: url, for: capId) else {
|
||||
log("Failed to upload image \(url.lastPathComponent)")
|
||||
continue
|
||||
}
|
||||
log("Uploaded image \(url.lastPathComponent)")
|
||||
do {
|
||||
try fm.removeItem(at: url)
|
||||
updateImageUploadCounts()
|
||||
} catch {
|
||||
log("Failed to remove uploaded image \(url.lastPathComponent): \(error)")
|
||||
}
|
||||
@ -448,16 +455,20 @@ final class Database: ObservableObject {
|
||||
|
||||
@discardableResult
|
||||
private func upload(imageAt url: URL, for cap: Int) async -> Bool {
|
||||
guard let key = serverAuthenticationKey else {
|
||||
guard hasServerAuthentication else {
|
||||
return false
|
||||
}
|
||||
guard let data = try? Data(contentsOf: url) else {
|
||||
return false
|
||||
}
|
||||
let url = serverUrl
|
||||
.appendingPathComponent("images")
|
||||
.appendingPathComponent("\(cap)?key=\(key)")
|
||||
.appendingPathComponent("\(cap)")
|
||||
var request = URLRequest(url: url)
|
||||
request.addValue(serverAuthenticationKey, forHTTPHeaderField: "key")
|
||||
request.httpMethod = "POST"
|
||||
do {
|
||||
let (_, response) = try await URLSession.shared.upload(for: request, fromFile: url)
|
||||
let (_, response) = try await URLSession.shared.upload(for: request, from: data)
|
||||
guard let httpResponse = response as? HTTPURLResponse else {
|
||||
log("Unexpected response for upload of image \(url.lastPathComponent): \(response)")
|
||||
return false
|
||||
@ -477,43 +488,45 @@ final class Database: ObservableObject {
|
||||
changedCaps.count
|
||||
}
|
||||
|
||||
private func uploadAllChangedCaps() async {
|
||||
private func uploadAllChangedCaps() async -> Set<Int> {
|
||||
guard hasServerAuthentication else {
|
||||
log("No server authentication to upload to server")
|
||||
return
|
||||
return .init()
|
||||
}
|
||||
var uploaded = Set<Int>()
|
||||
for capId in changedCaps {
|
||||
guard let cap = caps[capId] else {
|
||||
log("Missing cap \(capId) to upload")
|
||||
uploaded.insert(capId)
|
||||
continue
|
||||
}
|
||||
guard await upload(cap: cap) else {
|
||||
continue
|
||||
}
|
||||
log("Uploaded cap \(capId)")
|
||||
uploaded.insert(capId)
|
||||
}
|
||||
changedCaps.subtract(uploaded)
|
||||
return uploaded
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
private func upload(cap: Cap) async -> Bool {
|
||||
guard let key = serverAuthenticationKey else {
|
||||
guard hasServerAuthentication else {
|
||||
return false
|
||||
}
|
||||
let data: Data
|
||||
do {
|
||||
/// `Cap` and `CapData` have equivalent JSON layout
|
||||
data = try encoder.encode(cap)
|
||||
data = try encoder.encode(cap.data)
|
||||
} catch {
|
||||
log("Failed to encode cap \(cap.id) for upload: \(error)")
|
||||
return false
|
||||
}
|
||||
let url = serverUrl
|
||||
.appendingPathComponent("images")
|
||||
.appendingPathComponent("\(cap)?key=\(key)")
|
||||
.appendingPathComponent("cap")
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "POST"
|
||||
request.addValue(serverAuthenticationKey, forHTTPHeaderField: "key")
|
||||
do {
|
||||
let (_, response) = try await URLSession.shared.upload(for: request, from: data)
|
||||
guard let httpResponse = response as? HTTPURLResponse else {
|
||||
@ -524,7 +537,9 @@ final class Database: ObservableObject {
|
||||
log("Failed to upload cap \(cap.id): Response \(httpResponse.statusCode)")
|
||||
return false
|
||||
}
|
||||
changedCaps.remove(cap.id)
|
||||
DispatchQueue.main.async {
|
||||
self.changedCaps.remove(cap.id)
|
||||
}
|
||||
return true
|
||||
} catch {
|
||||
log("Failed to upload cap \(cap.id): \(error)")
|
||||
|
Reference in New Issue
Block a user