Caps-Server/Sources/App/routes.swift

155 lines
5.0 KiB
Swift
Raw Normal View History

import Routing
import Vapor
2020-05-19 15:19:19 +02:00
2020-05-19 16:13:13 +02:00
// MARK: Paths
2020-05-19 15:19:19 +02:00
private let baseFolder = URL(fileURLWithPath: "/caps")
2020-05-22 21:24:12 +02:00
private let logFile = baseFolder.appendingPathComponent("logs/server.log").path
2020-05-19 16:13:13 +02:00
private let publicFolder = baseFolder.appendingPathComponent("Public")
private let imageFolder = publicFolder.appendingPathComponent("images")
2020-05-25 10:05:16 +02:00
private let nameFile = publicFolder.appendingPathComponent("names.txt")
2020-05-19 16:13:13 +02:00
private let tempImageFile = publicFolder.appendingPathComponent("temp.jpg")
2020-05-19 15:19:19 +02:00
2020-05-19 16:13:13 +02:00
// MARK: Variables
2020-05-19 15:19:19 +02:00
2020-05-19 16:13:13 +02:00
private let fm = FileManager.default
2020-05-19 15:19:19 +02:00
2020-05-25 10:05:16 +02:00
private var caps = [String]()
2020-05-19 15:19:19 +02:00
2020-05-19 16:13:13 +02:00
// MARK: SQLite
2020-05-25 10:05:16 +02:00
func loadCapNames() throws {
let s = try String(contentsOf: nameFile)
2020-05-26 15:43:17 +02:00
caps = s.trimmingCharacters(in: .whitespacesAndNewlines).components(separatedBy: "\n")
2020-05-25 10:05:16 +02:00
log("\(caps.count) caps loaded")
2020-05-19 15:19:19 +02:00
}
2020-05-19 16:13:13 +02:00
// MARK: Helper
2020-05-19 15:19:19 +02:00
private func folder(of cap: Int) -> URL {
imageFolder.appendingPathComponent(String(format: "%04d", cap))
}
private func file(of cap: Int, version: Int) -> URL {
folder(of: cap).appendingPathComponent(String(format: "%04d-%02d.jpg", cap, version))
}
private func countImages(in folder: URL) throws -> Int {
try fm.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil).filter({ $0.pathExtension == "jpg" }).count
}
private func count(of cap: Int) throws -> Int {
let f = folder(of: cap)
guard fm.fileExists(atPath: f.path) else {
2020-05-26 12:39:18 +02:00
return 0
2020-05-19 15:19:19 +02:00
}
return try countImages(in: f)
}
2020-05-19 16:13:13 +02:00
// MARK: Routes
/// Register your application's routes here.
///
/// [Learn More ](https://docs.vapor.codes/3.0/getting-started/structure/#routesswift)
public func routes(_ router: Router) throws {
2020-05-19 15:19:19 +02:00
2020-05-22 21:24:12 +02:00
try Log.set(logFile: logFile)
2020-05-25 10:05:16 +02:00
try loadCapNames()
2020-05-22 21:24:12 +02:00
2020-05-19 15:19:19 +02:00
// Get the name of a cap
router.getCatching("name", Int.parameter) { request -> Data in
let cap = try request.parameters.next(Int.self)
2020-05-28 12:35:38 +02:00
let index = cap - 1
guard index >= 0, index < caps.count else {
log("Trying to get name for invalid cap \(cap) (\(caps.count) caps loaded)")
2020-05-19 15:19:19 +02:00
throw CapError.unknownId
}
2020-05-28 12:35:38 +02:00
return caps[index].data(using: .utf8)!
2020-05-19 15:19:19 +02:00
}
// Set the name of a cap
router.postCatching("name", Int.parameter) { request in
let cap = try request.parameters.next(Int.self)
2020-05-28 12:35:38 +02:00
let index = cap - 1
2020-05-25 10:05:16 +02:00
guard let data = request.http.body.data, let name = String(data: data, encoding: .utf8) else {
2020-05-19 15:19:19 +02:00
throw CapError.invalidBody
}
2020-05-28 12:35:38 +02:00
guard index <= caps.count else {
log("Trying to set name for cap \(cap), but only \(caps.count) caps exist")
2020-05-25 10:05:16 +02:00
throw CapError.unknownId
2020-05-19 15:19:19 +02:00
}
2020-05-25 10:05:16 +02:00
2020-05-28 12:35:38 +02:00
if index == caps.count {
2020-05-25 10:05:16 +02:00
caps.append(name)
// Create image folder
let url = folder(of: cap)
2020-05-26 12:39:18 +02:00
if !fm.fileExists(atPath: url.path) {
try fm.createDirectory(at: url, withIntermediateDirectories: false)
}
2020-05-28 14:34:07 +02:00
log("Added cap \(cap)")
2020-05-25 10:05:16 +02:00
} else {
2020-05-28 12:35:38 +02:00
caps[index] = name
2020-05-28 14:34:07 +02:00
log("Set name for cap \(cap)")
2020-05-25 10:05:16 +02:00
}
try caps.joined(separator: "\n").data(using: .utf8)!.write(to: nameFile)
2020-05-28 14:34:07 +02:00
2020-05-19 15:19:19 +02:00
}
// Upload an image
router.postCatching("images", Int.parameter) { request -> Data in
let cap = try request.parameters.next(Int.self)
guard let data = request.http.body.data else {
throw CapError.invalidBody
}
let c = try count(of: cap)
let f = file(of: cap, version: c)
guard !fm.fileExists(atPath: f.path) else {
2020-05-28 14:34:07 +02:00
log("Image \(c) for cap \(cap) already exists on disk")
2020-05-19 15:19:19 +02:00
throw CapError.dataInconsistency
}
try data.write(to: f)
return "\(c)".data(using: .utf8)!
}
// Get count of a cap
router.getCatching("count", Int.parameter) { request -> Data in
let cap = try request.parameters.next(Int.self)
let c = try count(of: cap)
return "\(c)".data(using: .utf8)!
}
// Get the count of all caps
2020-05-25 10:05:16 +02:00
router.getCatching("counts") { request -> Data in
try (1...caps.count).map { UInt8(try count(of: $0)) }.convertToData()
2020-05-19 15:19:19 +02:00
}
// Set a different version as the main image
router.getCatching("switch", Int.parameter, Int.parameter) { request in
let cap = try request.parameters.next(Int.self)
let version = try request.parameters.next(Int.self)
guard version > 0 else {
2020-05-28 14:34:07 +02:00
log("Not switching cap \(cap) to image \(version)")
2020-05-19 15:19:19 +02:00
return
}
let file1 = file(of: cap, version: 0)
guard fm.fileExists(atPath: file1.path) else {
2020-05-28 14:34:07 +02:00
log("No image 0 for cap \(cap)")
2020-05-19 15:19:19 +02:00
throw CapError.invalidFile
}
let file2 = file(of: cap, version: version)
guard fm.fileExists(atPath: file2.path) else {
2020-05-28 14:34:07 +02:00
log("No image \(version) for cap \(cap)")
2020-05-19 15:19:19 +02:00
throw CapError.invalidFile
}
try fm.moveItem(at: file1, to: tempImageFile)
try fm.moveItem(at: file2, to: file1)
try fm.moveItem(at: tempImageFile, to: file2)
2020-05-28 14:34:07 +02:00
log("Switched cap \(cap) to version \(version)")
}
}