Fix port, begin upload UI
This commit is contained in:
@@ -128,13 +128,23 @@ final class Database {
|
||||
|
||||
var pendingCapUploads: [Cap] {
|
||||
do {
|
||||
return try db.prepare(Cap.table.filter(Cap.columnUploaded == false)).map(Cap.init)
|
||||
return try db.prepare(Cap.table.filter(Cap.columnUploaded == false).order(Cap.columnId.asc)).map(Cap.init)
|
||||
} catch {
|
||||
log("Failed to get pending cap uploads")
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
var hasPendingCapUploads: Bool {
|
||||
do {
|
||||
let query = Cap.table.filter(Cap.columnUploaded == false).count
|
||||
return try db.scalar(query) > 0
|
||||
} catch {
|
||||
log("Failed to get pending cap upload count")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var classifierVersion: Int {
|
||||
set {
|
||||
UserDefaults.standard.set(newValue, forKey: Classifier.userDefaultsKey)
|
||||
@@ -409,24 +419,17 @@ final class Database {
|
||||
// MARK: Downloads
|
||||
|
||||
@discardableResult
|
||||
func downloadMainImage(for cap: Int, completion: @escaping (_ success: Bool) -> Void) -> Bool {
|
||||
return download.mainImage(for: cap) { success in
|
||||
guard success else {
|
||||
completion(false)
|
||||
return
|
||||
func downloadImage(for cap: Int, version: Int = 0, completion: @escaping (_ image: UIImage?) -> Void) -> Bool {
|
||||
return download.image(for: cap, version: version) { image in
|
||||
if version == 0 && image != nil {
|
||||
DispatchQueue.main.async {
|
||||
self.delegate?.database(didLoadImageForCap: cap)
|
||||
}
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
self.delegate?.database(didLoadImageForCap: cap)
|
||||
}
|
||||
completion(true)
|
||||
completion(image)
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func downloadImage(for cap: Int, version: Int, completion: @escaping (_ success: Bool) -> Void) -> Bool {
|
||||
return download.image(for: cap, version: version, completion: completion)
|
||||
}
|
||||
|
||||
func downloadCapNames(completion: @escaping (_ success: Bool) -> Void) {
|
||||
log("Downloading cap names")
|
||||
download.names { names in
|
||||
@@ -496,7 +499,7 @@ final class Database {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
for part in caps.split(intoPartsOf: split) {
|
||||
for id in part {
|
||||
let downloading = self.downloadMainImage(for: id) { _ in
|
||||
let downloading = self.downloadImage(for: id) { _ in
|
||||
group.leave()
|
||||
}
|
||||
if downloading {
|
||||
@@ -658,6 +661,24 @@ final class Database {
|
||||
self.update(count: count, for: cap)
|
||||
}
|
||||
}
|
||||
|
||||
private func uploadNextItem() {
|
||||
let capUploads = self.pendingCapUploads
|
||||
if let id = capUploads.first {
|
||||
|
||||
return
|
||||
}
|
||||
let imageUploads = pendingImageUploads
|
||||
guard imageUploads.count > 0 else {
|
||||
log("No pending image uploads")
|
||||
return
|
||||
}
|
||||
uploadRemainingImages()
|
||||
}
|
||||
|
||||
private func upload(cap: Int) {
|
||||
|
||||
}
|
||||
|
||||
func uploadRemainingData() {
|
||||
guard !isInOfflineMode else {
|
||||
@@ -673,23 +694,33 @@ final class Database {
|
||||
log("\(uploads.count) cap uploads pending")
|
||||
|
||||
var remaining = uploads.count
|
||||
for cap in uploads {
|
||||
upload.upload(name: cap.name, for: cap.id) { success in
|
||||
if success {
|
||||
self.log("Uploaded cap \(cap.id)")
|
||||
self.update(uploaded: true, for: cap.id)
|
||||
} else {
|
||||
self.log("Failed to upload cap \(cap.id)")
|
||||
}
|
||||
|
||||
remaining -= 1
|
||||
if remaining == 0 {
|
||||
DispatchQueue.main.async {
|
||||
self.uploadRemainingImages()
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
let group = DispatchGroup()
|
||||
for cap in uploads {
|
||||
group.enter()
|
||||
self.upload.upload(name: cap.name, for: cap.id) { success in
|
||||
group.leave()
|
||||
if success {
|
||||
self.log("Uploaded cap \(cap.id)")
|
||||
self.update(uploaded: true, for: cap.id)
|
||||
} else {
|
||||
self.log("Failed to upload cap \(cap.id)")
|
||||
return
|
||||
}
|
||||
|
||||
remaining -= 1
|
||||
|
||||
}
|
||||
guard group.wait(timeout: .now() + .seconds(60)) == .success else {
|
||||
self.log("Timed out uploading cap \(cap.id)")
|
||||
return
|
||||
}
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
self.uploadRemainingImages()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func uploadRemainingImages() {
|
||||
@@ -700,16 +731,35 @@ final class Database {
|
||||
}
|
||||
log("\(uploads.count) image uploads pending")
|
||||
|
||||
for (cap, version) in uploads {
|
||||
upload.uploadImage(for: cap, version: version) { count in
|
||||
guard let _ = count else {
|
||||
self.log("Failed to upload version \(version) of cap \(cap)")
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
let group = DispatchGroup()
|
||||
for (id, version) in uploads {
|
||||
guard let cap = self.cap(for: id) else {
|
||||
self.log("No cap \(id) to upload image \(version)")
|
||||
self.removePendingUpload(of: id, version: version)
|
||||
continue
|
||||
}
|
||||
guard cap.uploaded else {
|
||||
self.log("Cap \(id) not uploaded, skipping image upload")
|
||||
continue
|
||||
}
|
||||
group.enter()
|
||||
self.upload.uploadImage(for: id, version: version) { count in
|
||||
group.leave()
|
||||
guard let _ = count else {
|
||||
self.log("Failed to upload version \(version) of cap \(id)")
|
||||
return
|
||||
}
|
||||
self.log("Uploaded version \(version) of cap \(id)")
|
||||
self.removePendingUpload(of: id, version: version)
|
||||
}
|
||||
guard group.wait(timeout: .now() + .seconds(60)) == .success else {
|
||||
self.log("Timed out uploading version \(version) of cap \(id)")
|
||||
return
|
||||
}
|
||||
self.log("Uploaded version \(version) of cap \(cap)")
|
||||
self.removePendingUpload(of: cap, version: version)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
|
@@ -116,59 +116,35 @@ final class Download {
|
||||
- Parameter cap: The id of the cap.
|
||||
- Parameter version: The image version to download.
|
||||
- Parameter completion: A closure with the resulting image
|
||||
- Note: The closure will be called from the main queue.
|
||||
- Returns: `true`, of the file download was started, `false`, if the image is already downloading.
|
||||
*/
|
||||
@discardableResult
|
||||
func mainImage(for cap: Int, completion: @escaping (_ success: Bool) -> Void) -> Bool {
|
||||
let url = serverImageUrl(for: cap)
|
||||
let query = "Main image of cap \(cap)"
|
||||
guard !downloadingMainImages.contains(cap) else {
|
||||
return false
|
||||
func image(for cap: Int, version: Int = 0, completion: @escaping (_ image: UIImage?) -> Void) -> Bool {
|
||||
// Check if main image, and already being downloaded
|
||||
if version == 0 {
|
||||
guard !downloadingMainImages.contains(cap) else {
|
||||
return false
|
||||
}
|
||||
downloadingMainImages.insert(cap)
|
||||
}
|
||||
downloadingMainImages.insert(cap)
|
||||
|
||||
let task = session.downloadTask(with: url) { fileUrl, response, error in
|
||||
DispatchQueue.main.async {
|
||||
self.downloadingMainImages.remove(cap)
|
||||
}
|
||||
guard let fileUrl = self.convertResponse(to: query, fileUrl, response, error) else {
|
||||
completion(false)
|
||||
return
|
||||
}
|
||||
guard app.storage.saveImage(at: fileUrl, for: cap) else {
|
||||
self.log("Request '\(query)' could not move downloaded file")
|
||||
completion(false)
|
||||
return
|
||||
}
|
||||
completion(true)
|
||||
}
|
||||
task.resume()
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
Download an image for a cap.
|
||||
- Parameter cap: The id of the cap.
|
||||
- Parameter version: The image version to download.
|
||||
- Parameter completion: A closure with the resulting image
|
||||
- Returns: `true`, of the file download was started, `false`, if the image is already downloading.
|
||||
*/
|
||||
@discardableResult
|
||||
func image(for cap: Int, version: Int, completion: @escaping (_ success: Bool) -> Void) -> Bool {
|
||||
let url = serverImageUrl(for: cap, version: version)
|
||||
let query = "Image of cap \(cap) version \(version)"
|
||||
let task = session.downloadTask(with: url) { fileUrl, response, error in
|
||||
if version == 0 {
|
||||
DispatchQueue.main.async {
|
||||
self.downloadingMainImages.remove(cap)
|
||||
}
|
||||
}
|
||||
guard let fileUrl = self.convertResponse(to: query, fileUrl, response, error) else {
|
||||
completion(false)
|
||||
completion(nil)
|
||||
return
|
||||
}
|
||||
guard app.storage.saveImage(at: fileUrl, for: cap, version: version) else {
|
||||
guard let image = app.storage.saveImage(at: fileUrl, for: cap, version: version) else {
|
||||
self.log("Request '\(query)' could not move downloaded file")
|
||||
completion(false)
|
||||
completion(nil)
|
||||
return
|
||||
}
|
||||
completion(true)
|
||||
completion(image)
|
||||
}
|
||||
task.resume()
|
||||
return true
|
||||
|
@@ -56,17 +56,17 @@ final class Storage {
|
||||
- parameter version: The version of the image to get
|
||||
- returns: True, if the image was saved
|
||||
*/
|
||||
func saveImage(at url: URL, for cap: Int, version: Int = 0) -> Bool {
|
||||
func saveImage(at url: URL, for cap: Int, version: Int = 0) -> UIImage? {
|
||||
let targetUrl = localImageUrl(for: cap, version: version)
|
||||
do {
|
||||
if fm.fileExists(atPath: targetUrl.path) {
|
||||
try fm.removeItem(at: targetUrl)
|
||||
}
|
||||
try fm.moveItem(at: url, to: targetUrl)
|
||||
return true
|
||||
return UIImage(contentsOfFile: targetUrl.path)
|
||||
} catch {
|
||||
log("Failed to delete or move image \(version) for cap \(cap)")
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user