2020-05-16 11:21:55 +02:00
|
|
|
//
|
|
|
|
// Upload.swift
|
|
|
|
// CapCollector
|
|
|
|
//
|
|
|
|
// Created by Christoph on 26.04.20.
|
|
|
|
// Copyright © 2020 CH. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
import UIKit
|
|
|
|
import SQLite
|
|
|
|
|
|
|
|
struct Upload {
|
|
|
|
|
2020-08-09 21:04:30 +02:00
|
|
|
static let offlineKey = "offline"
|
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
let serverUrl: URL
|
|
|
|
|
|
|
|
let table = Table("uploads")
|
|
|
|
|
|
|
|
let rowCapId = Expression<Int>("cap")
|
|
|
|
|
|
|
|
let rowCapVersion = Expression<Int>("version")
|
|
|
|
|
|
|
|
init(server: URL) {
|
|
|
|
self.serverUrl = server
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: Paths
|
|
|
|
|
|
|
|
var serverImageUrl: URL {
|
|
|
|
serverUrl.appendingPathComponent("images")
|
|
|
|
}
|
|
|
|
|
|
|
|
private func serverImageUrl(for cap: Int, version: Int = 0) -> URL {
|
|
|
|
serverImageUrl.appendingPathComponent("\(cap)/\(cap)-\(version).jpg")
|
|
|
|
}
|
|
|
|
|
|
|
|
private func serverImageUploadUrl(for cap: Int) -> URL {
|
|
|
|
serverImageUrl.appendingPathComponent("\(cap)")
|
|
|
|
}
|
|
|
|
|
|
|
|
private func serverNameUploadUrl(for cap: Int) -> URL {
|
|
|
|
serverUrl.appendingPathComponent("name/\(cap)")
|
|
|
|
}
|
|
|
|
|
|
|
|
private func serverChangeMainImageUrl(for cap: Int, to newValue: Int) -> URL {
|
|
|
|
serverUrl.appendingPathComponent("switch/\(cap)/\(newValue)")
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: SQLite
|
|
|
|
|
|
|
|
var createQuery: String {
|
|
|
|
table.create(ifNotExists: true) { t in
|
|
|
|
t.column(rowCapId)
|
|
|
|
t.column(rowCapVersion)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-13 21:43:46 +01:00
|
|
|
func existsQuery(for cap: Int, version: Int) -> ScalarQuery<Int> {
|
|
|
|
table.filter(rowCapId == cap && rowCapVersion == version).count
|
|
|
|
}
|
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
func insertQuery(for cap: Int, version: Int) -> Insert {
|
|
|
|
table.insert(rowCapId <- cap, rowCapVersion <- version)
|
|
|
|
}
|
|
|
|
|
|
|
|
func deleteQuery(for cap: Int, version: Int) -> Delete {
|
|
|
|
table.filter(rowCapId == cap && rowCapVersion == version).delete()
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: Uploading data
|
|
|
|
|
|
|
|
func upload(name: String, for cap: Int, completion: @escaping (_ success: Bool) -> Void) {
|
|
|
|
var request = URLRequest(url: serverNameUploadUrl(for: cap))
|
|
|
|
request.httpMethod = "POST"
|
|
|
|
request.httpBody = name.data(using: .utf8)
|
|
|
|
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
|
|
|
if let error = error {
|
|
|
|
self.log("Failed to upload name of cap \(cap): \(error)")
|
|
|
|
completion(false)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
guard let response = response else {
|
|
|
|
self.log("Failed to upload name of cap \(cap): No response")
|
|
|
|
completion(false)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
guard let urlResponse = response as? HTTPURLResponse else {
|
|
|
|
self.log("Failed to upload name of cap \(cap): \(response)")
|
|
|
|
completion(false)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
guard urlResponse.statusCode == 200 else {
|
|
|
|
self.log("Failed to upload name of cap \(cap): Response \(urlResponse.statusCode)")
|
|
|
|
completion(false)
|
|
|
|
return
|
|
|
|
}
|
2020-06-18 22:55:51 +02:00
|
|
|
completion(true)
|
2020-05-16 11:21:55 +02:00
|
|
|
}
|
|
|
|
task.resume()
|
|
|
|
}
|
|
|
|
|
2021-01-13 21:43:46 +01:00
|
|
|
func upload(_ cap: Cap, timeout: TimeInterval = 30) -> Bool {
|
|
|
|
upload(name: cap.name, for: cap.id, timeout: timeout)
|
|
|
|
}
|
|
|
|
|
|
|
|
func upload(name: String, for cap: Int, timeout: TimeInterval = 30) -> Bool {
|
|
|
|
let group = DispatchGroup()
|
|
|
|
group.enter()
|
|
|
|
var result = true
|
|
|
|
upload(name: name, for: cap) { success in
|
|
|
|
if success {
|
|
|
|
self.log("Uploaded cap \(cap)")
|
|
|
|
} else {
|
|
|
|
result = false
|
|
|
|
}
|
|
|
|
group.leave()
|
|
|
|
}
|
|
|
|
guard group.wait(timeout: .now() + timeout) == .success else {
|
|
|
|
log("Timed out uploading cap \(cap)")
|
|
|
|
return false
|
2020-05-16 11:21:55 +02:00
|
|
|
}
|
2021-01-13 21:43:46 +01:00
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func upload(imageAt url: URL, for cap: Int, completion: @escaping (_ count: Int?) -> Void) {
|
2020-05-16 11:21:55 +02:00
|
|
|
var request = URLRequest(url: serverImageUploadUrl(for: cap))
|
|
|
|
request.httpMethod = "POST"
|
|
|
|
let task = URLSession.shared.uploadTask(with: request, fromFile: url) { data, response, error in
|
|
|
|
if let error = error {
|
2021-01-13 21:43:46 +01:00
|
|
|
self.log("Failed to upload image of cap \(cap): \(error)")
|
2020-05-16 11:21:55 +02:00
|
|
|
completion(nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
guard let response = response else {
|
2021-01-13 21:43:46 +01:00
|
|
|
self.log("Failed to upload image of cap \(cap): No response")
|
2020-05-16 11:21:55 +02:00
|
|
|
completion(nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
guard let urlResponse = response as? HTTPURLResponse else {
|
2021-01-13 21:43:46 +01:00
|
|
|
self.log("Failed to upload image of cap \(cap): \(response)")
|
2020-05-16 11:21:55 +02:00
|
|
|
completion(nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
guard urlResponse.statusCode == 200 else {
|
2021-01-13 21:43:46 +01:00
|
|
|
self.log("Failed to upload image of cap \(cap): Response \(urlResponse.statusCode)")
|
2020-05-16 11:21:55 +02:00
|
|
|
completion(nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
guard let d = data, let string = String(data: d, encoding: .utf8), let int = Int(string) else {
|
2021-01-13 21:43:46 +01:00
|
|
|
self.log("Failed to upload image of cap \(cap): Invalid response")
|
2020-05-16 11:21:55 +02:00
|
|
|
completion(nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
completion(int)
|
|
|
|
}
|
|
|
|
task.resume()
|
|
|
|
}
|
|
|
|
|
2021-01-13 21:43:46 +01:00
|
|
|
func upload(imageAt url: URL, of cap: Int, timeout: TimeInterval = 30) -> Int? {
|
|
|
|
let group = DispatchGroup()
|
|
|
|
group.enter()
|
|
|
|
var result: Int? = nil
|
|
|
|
upload(imageAt: url, for: cap) { count in
|
|
|
|
result = count
|
|
|
|
group.leave()
|
|
|
|
}
|
|
|
|
guard group.wait(timeout: .now() + timeout) == .success else {
|
|
|
|
log("Timed out uploading image of \(cap)")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
/**
|
|
|
|
Sets the main image for a cap to a different version.
|
2020-06-18 22:55:51 +02:00
|
|
|
|
2020-05-16 11:21:55 +02:00
|
|
|
- Parameter cap: The id of the cap
|
|
|
|
- Parameter version: The version to set as the main version.
|
2020-06-18 22:55:51 +02:00
|
|
|
- Parameter completion: A callback with the result on completion.
|
2020-05-16 11:21:55 +02:00
|
|
|
*/
|
2020-06-18 22:55:51 +02:00
|
|
|
func setMainImage(for cap: Int, to version: Int, completion: @escaping (_ success: Bool) -> Void) {
|
2020-05-16 11:21:55 +02:00
|
|
|
let url = serverChangeMainImageUrl(for: cap, to: version)
|
2020-06-18 22:55:51 +02:00
|
|
|
let task = URLSession.shared.dataTask(with: url) { data, response, error in
|
2020-05-16 11:21:55 +02:00
|
|
|
if let error = error {
|
|
|
|
self.log("Failed to set main image of cap \(cap) to \(version): \(error)")
|
2020-06-18 22:55:51 +02:00
|
|
|
completion(false)
|
2020-05-16 11:21:55 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
guard let response = response else {
|
|
|
|
self.log("Failed to set main image of cap \(cap) to \(version): No response")
|
2020-06-18 22:55:51 +02:00
|
|
|
completion(false)
|
2020-05-16 11:21:55 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
guard let urlResponse = response as? HTTPURLResponse else {
|
|
|
|
self.log("Failed to set main image of cap \(cap) to \(version): \(response)")
|
2020-06-18 22:55:51 +02:00
|
|
|
completion(false)
|
2020-05-16 11:21:55 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
guard urlResponse.statusCode == 200 else {
|
|
|
|
self.log("Failed to set main image of cap \(cap) to \(version): Response \(urlResponse.statusCode)")
|
2020-06-18 22:55:51 +02:00
|
|
|
completion(false)
|
2020-05-16 11:21:55 +02:00
|
|
|
return
|
|
|
|
}
|
2020-06-18 22:55:51 +02:00
|
|
|
completion(true)
|
2020-05-16 11:21:55 +02:00
|
|
|
}
|
|
|
|
task.resume()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension Upload: Logger { }
|