import Foundation struct Config: Codable { /// The port where the server runs let port: Int /// The maximum size of the request body let maxBodySize: String /// The path to the log file let logPath: String /// Serve files in the Public directory using Vapor let serveFiles: Bool /// Authentication tokens for remotes allowed to write let writers: [String] var logURL: URL { .init(fileURLWithPath: logPath) } } extension Config { private static func file(in directory: URL) -> URL { directory.appendingPathComponent("config.json") } init(loadFrom directory: URL) { let configFileUrl = Config.file(in: directory) if FileManager.default.fileExists(atPath: configFileUrl.path) { self.init(loadAt: configFileUrl) } else { self.init(standardIn: directory) write(to: configFileUrl) } } private init(loadAt url: URL) { do { let configData = try Data(contentsOf: url) self = try JSONDecoder().decode(Config.self, from: configData) } catch { print("Failed to load configuration from \(url.path): \(error)") print("Using default configuration") self.init(standardIn: url.deletingLastPathComponent()) } } private init(standardIn directory: URL) { let defaultLogPath = directory.appendingPathComponent("logs").path self.init(port: 8000, maxBodySize: "2mb", logPath: defaultLogPath, serveFiles: true, writers: []) } private func write(to url: URL) { do { let configData = try JSONEncoder().encode(self) try configData.write(to: url) print("Configuration written at \(url.path)") } catch { print("Failed to write default configuration to \(url.path)") } } }