175 lines
5.7 KiB
Swift
Executable File
175 lines
5.7 KiB
Swift
Executable File
import Vapor
|
|
|
|
// MARK: Paths
|
|
|
|
private let baseFolder = URL(fileURLWithPath: "/caps")
|
|
|
|
private let logFile = baseFolder.appendingPathComponent("logs/server.log").path
|
|
|
|
private let publicFolder = baseFolder.appendingPathComponent("Public")
|
|
|
|
private let imageFolder = publicFolder.appendingPathComponent("images")
|
|
|
|
private let nameFile = publicFolder.appendingPathComponent("names.txt")
|
|
|
|
private let tempImageFile = publicFolder.appendingPathComponent("temp.jpg")
|
|
|
|
// MARK: Variables
|
|
|
|
private let fm = FileManager.default
|
|
|
|
private var caps = [String]()
|
|
|
|
// MARK: SQLite
|
|
|
|
func loadCapNames() throws {
|
|
let s = try String(contentsOf: nameFile)
|
|
caps = s.trimmingCharacters(in: .whitespacesAndNewlines).components(separatedBy: "\n")
|
|
log("\(caps.count) caps loaded")
|
|
}
|
|
|
|
// MARK: Helper
|
|
|
|
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 {
|
|
return 0
|
|
}
|
|
return try countImages(in: f)
|
|
}
|
|
|
|
// MARK: Routes
|
|
|
|
/// Register your application's routes here.
|
|
///
|
|
/// [Learn More →](https://docs.vapor.codes/3.0/getting-started/structure/#routesswift)
|
|
func routes(_ app: Application) throws {
|
|
|
|
try Log.set(logFile: logFile)
|
|
try loadCapNames()
|
|
|
|
// Get the name of a cap
|
|
app.getCatching("name", ":n") { request -> Data in
|
|
guard let cap = request.parameters.get("n", as: Int.self) else {
|
|
log("Invalid body data")
|
|
throw Abort(.badRequest)
|
|
}
|
|
let index = cap - 1
|
|
guard index >= 0, index < caps.count else {
|
|
log("Trying to get name for invalid cap \(cap) (\(caps.count) caps loaded)")
|
|
throw CapError.unknownId
|
|
}
|
|
return caps[index].data(using: .utf8)!
|
|
}
|
|
|
|
// Set the name of a cap
|
|
app.postCatching("name", ":n") { request in
|
|
guard let cap = request.parameters.get("n", as: Int.self) else {
|
|
log("Invalid parameter for cap")
|
|
throw Abort(.badRequest)
|
|
}
|
|
let index = cap - 1
|
|
guard let buffer = request.body.data, let name = String(data: Data(buffer: buffer), encoding: .utf8) else {
|
|
log("Invalid body data")
|
|
throw CapError.invalidBody
|
|
}
|
|
guard index <= caps.count else {
|
|
log("Trying to set name for cap \(cap), but only \(caps.count) caps exist")
|
|
throw CapError.unknownId
|
|
}
|
|
|
|
if index == caps.count {
|
|
caps.append(name)
|
|
// Create image folder
|
|
let url = folder(of: cap)
|
|
if !fm.fileExists(atPath: url.path) {
|
|
try fm.createDirectory(at: url, withIntermediateDirectories: false)
|
|
}
|
|
log("Added cap \(cap)")
|
|
} else {
|
|
caps[index] = name
|
|
log("Set name for cap \(cap)")
|
|
}
|
|
try caps.joined(separator: "\n").data(using: .utf8)!.write(to: nameFile)
|
|
|
|
}
|
|
|
|
// Upload an image
|
|
app.postCatching("images", ":n") { request -> Data in
|
|
guard let cap = request.parameters.get("n", as: Int.self) else {
|
|
log("Invalid parameter for cap")
|
|
throw Abort(.badRequest)
|
|
}
|
|
guard let buffer = request.body.data else {
|
|
log("Invalid body data")
|
|
throw CapError.invalidBody
|
|
}
|
|
let data = Data(buffer: buffer)
|
|
let c = try count(of: cap)
|
|
let f = file(of: cap, version: c)
|
|
guard !fm.fileExists(atPath: f.path) else {
|
|
log("Image \(c) for cap \(cap) already exists on disk")
|
|
throw CapError.dataInconsistency
|
|
}
|
|
try data.write(to: f)
|
|
return "\(c)".data(using: .utf8)!
|
|
}
|
|
|
|
// Get count of a cap
|
|
app.getCatching("count", ":c") { request -> Data in
|
|
guard let cap = request.parameters.get("c", as: Int.self) else {
|
|
log("Invalid parameter for cap")
|
|
throw Abort(.badRequest)
|
|
}
|
|
let c = try count(of: cap)
|
|
return "\(c)".data(using: .utf8)!
|
|
}
|
|
|
|
// Get the count of all caps
|
|
app.getCatching("counts") { request -> Data in
|
|
Data(try (1...caps.count).map({ UInt8(try count(of: $0)) }))
|
|
}
|
|
|
|
// Set a different version as the main image
|
|
app.getCatching("switch", ":n", ":v") { request in
|
|
guard let cap = request.parameters.get("n", as: Int.self) else {
|
|
log("Invalid parameter for cap")
|
|
throw Abort(.badRequest)
|
|
}
|
|
guard let version = request.parameters.get("v", as: Int.self) else {
|
|
log("Invalid parameter for cap version")
|
|
throw Abort(.badRequest)
|
|
}
|
|
guard version > 0 else {
|
|
log("Not switching cap \(cap) to image \(version)")
|
|
return
|
|
}
|
|
let file1 = file(of: cap, version: 0)
|
|
guard fm.fileExists(atPath: file1.path) else {
|
|
log("No image 0 for cap \(cap)")
|
|
throw CapError.invalidFile
|
|
}
|
|
let file2 = file(of: cap, version: version)
|
|
guard fm.fileExists(atPath: file2.path) else {
|
|
log("No image \(version) for cap \(cap)")
|
|
throw CapError.invalidFile
|
|
}
|
|
try fm.moveItem(at: file1, to: tempImageFile)
|
|
try fm.moveItem(at: file2, to: file1)
|
|
try fm.moveItem(at: tempImageFile, to: file2)
|
|
log("Switched cap \(cap) to version \(version)")
|
|
}
|
|
}
|