diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Package.swift b/Package.swift index e11f7fb..bc255c9 100755 --- a/Package.swift +++ b/Package.swift @@ -1,13 +1,23 @@ -// swift-tools-version:5.0 +// swift-tools-version:5.2 import PackageDescription let package = Package( name: "CapCollectorServer", + platforms: [ + .macOS(.v10_15) + ], dependencies: [ - .package(url: "https://github.com/vapor/vapor.git", .upToNextMinor(from: "3.3.0")), + .package(url: "https://github.com/vapor/vapor.git", from: "4.0.0"), ], targets: [ - .target(name: "App", dependencies: ["Vapor"]), + .target(name: "App", + dependencies: [.product(name: "Vapor", package: "vapor")], + swiftSettings: [ + // Enable better optimizations when building in Release configuration. Despite the use of + // the `.unsafeFlags` construct required by SwiftPM, this flag is recommended for Release + // builds. See for details. + .unsafeFlags(["-cross-module-optimization"], .when(configuration: .release)) + ]), .target(name: "Run", dependencies: ["App"]), .testTarget(name: "AppTests", dependencies: ["App"]), ] diff --git a/Sources/App/Router+Extensions.swift b/Sources/App/Router+Extensions.swift index 9eb1368..153794e 100644 --- a/Sources/App/Router+Extensions.swift +++ b/Sources/App/Router+Extensions.swift @@ -7,37 +7,37 @@ import Vapor -extension Router { +extension Application { - func getCatching(_ path: PathComponentsRepresentable..., call: @escaping (Request) throws -> T) { - self.get(path) { (request: Request) -> HTTPResponse in + func getCatching(_ path: PathComponent..., call: @escaping (Request) throws -> T) { + self.get(path) { (request: Request) -> Response in catching(path, request: request, closure: call) } } - func postCatching(_ path: PathComponentsRepresentable..., call: @escaping (Request) throws -> T) { - self.post(path) { (request: Request) -> HTTPResponse in + func postCatching(_ path: PathComponent..., call: @escaping (Request) throws -> T) { + self.post(path) { (request: Request) -> Response in catching(path, request: request, closure: call) } } } -private func catching(_ path: PathComponentsRepresentable..., request: Request, closure: @escaping (Request) throws -> T) -> HTTPResponse { +private func catching(_ path: [PathComponent], request: Request, closure: @escaping (Request) throws -> T) -> Response { - let route = path.convertToPathComponents().map { $0.string }.joined(separator: "/") + let route = path.map { $0.string }.joined(separator: "/") do { let data = try closure(request) if let d = data as? Data { - return HTTPResponse(status: .ok, body: d) + return Response(status: .ok, body: .init(data: d)) } else { - return HTTPResponse(status: .ok) + return Response(status: .ok) } } catch let error as CapError { log("\(route): Error \(error)") - return HTTPResponse(status: error.response) + return Response(status: error.response) } catch { log("\(route): Unhandled error: \(error)") - return HTTPResponse(status: .internalServerError) + return Response(status: .internalServerError) } } diff --git a/Sources/App/boot.swift b/Sources/App/boot.swift deleted file mode 100755 index 382f98a..0000000 --- a/Sources/App/boot.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Routing -import Vapor - -/// Called after your application has initialized. -/// -/// [Learn More →](https://docs.vapor.codes/3.0/getting-started/structure/#bootswift) -public func boot(_ app: Application) throws { - // your code here -} diff --git a/Sources/App/configure.swift b/Sources/App/configure.swift index 264849b..6db8263 100755 --- a/Sources/App/configure.swift +++ b/Sources/App/configure.swift @@ -1,17 +1,10 @@ import Vapor -/// Called before your application initializes. -/// -/// [Learn More →](https://docs.vapor.codes/3.0/getting-started/structure/#configureswift) -public func configure( - _ config: inout Config, - _ env: inout Environment, - _ services: inout Services -) throws { +// configures your application +public func configure(_ app: Application) throws { + // uncomment to serve files from /Public folder + // app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory)) // Register routes to the router - let router = EngineRouter.default() - try routes(router) - services.register(router, as: Router.self) - + try routes(app) // Configure the rest of your application here } diff --git a/Sources/App/routes.swift b/Sources/App/routes.swift index 9282757..7227dc9 100755 --- a/Sources/App/routes.swift +++ b/Sources/App/routes.swift @@ -1,4 +1,3 @@ -import Routing import Vapor // MARK: Paths @@ -56,14 +55,17 @@ private func count(of cap: Int) throws -> Int { /// Register your application's routes here. /// /// [Learn More →](https://docs.vapor.codes/3.0/getting-started/structure/#routesswift) -public func routes(_ router: Router) throws { +func routes(_ app: Application) throws { try Log.set(logFile: logFile) try loadCapNames() // Get the name of a cap - router.getCatching("name", Int.parameter) { request -> Data in - let cap = try request.parameters.next(Int.self) + 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)") @@ -73,10 +75,14 @@ public func routes(_ router: Router) throws { } // Set the name of a cap - router.postCatching("name", Int.parameter) { request in - let cap = try request.parameters.next(Int.self) + 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 data = request.http.body.data, let name = String(data: data, encoding: .utf8) else { + 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 { @@ -101,11 +107,16 @@ public func routes(_ router: Router) throws { } // 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 { + 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 { @@ -117,21 +128,30 @@ public func routes(_ router: Router) throws { } // Get count of a cap - router.getCatching("count", Int.parameter) { request -> Data in - let cap = try request.parameters.next(Int.self) + 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 - router.getCatching("counts") { request -> Data in - try (1...caps.count).map { UInt8(try count(of: $0)) }.convertToData() + 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 - 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) + 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 diff --git a/Sources/Run/main.swift b/Sources/Run/main.swift index e7416b7..373be5f 100755 --- a/Sources/Run/main.swift +++ b/Sources/Run/main.swift @@ -1,26 +1,9 @@ import App -import Service import Vapor -import Foundation -// The contents of main are wrapped in a do/catch block because any errors that get raised to the top level will crash Xcode -do { - var config = Config.default() - var env = try Environment.detect() - var services = Services.default() - - try App.configure(&config, &env, &services) - - let app = try Application( - config: config, - environment: env, - services: services - ) - - try App.boot(app) - - try app.run() -} catch { - print(error) - exit(1) -} +var env = try Environment.detect() +try LoggingSystem.bootstrap(from: &env) +let app = Application(env) +defer { app.shutdown() } +try configure(app) +try app.run()