139 lines
4.0 KiB
Swift
139 lines
4.0 KiB
Swift
import DatabaseClient
|
|
import Dependencies
|
|
import Elementary
|
|
import Fluent
|
|
import FluentSQLiteDriver
|
|
import ManualDCore
|
|
import NIOSSL
|
|
import ProjectClient
|
|
import Vapor
|
|
import VaporElementary
|
|
@preconcurrency import VaporRouting
|
|
import ViewController
|
|
|
|
// configures your application
|
|
public func configure(
|
|
_ app: Application,
|
|
makeDatabaseClient: @escaping (any Database) -> DatabaseClient = { .live(database: $0) }
|
|
) async throws {
|
|
// Setup the database client.
|
|
let databaseClient = try await setupDatabase(on: app, factory: makeDatabaseClient)
|
|
// Add the global middlewares.
|
|
addMiddleware(to: app, database: databaseClient)
|
|
#if DEBUG
|
|
// Live reload of the application for development when launched with the `./swift-dev` command
|
|
// app.lifecycle.use(BrowserSyncHandler())
|
|
#endif
|
|
// Add our route handlers.
|
|
addRoutes(to: app)
|
|
if app.environment != .testing {
|
|
try await app.autoMigrate()
|
|
}
|
|
// Add our custom cli-commands to the application.
|
|
addCommands(to: app)
|
|
}
|
|
|
|
private func addMiddleware(to app: Application, database databaseClient: DatabaseClient) {
|
|
// cors middleware should come before default error middleware using `at: .beginning`
|
|
let corsConfiguration = CORSMiddleware.Configuration(
|
|
allowedOrigin: .all,
|
|
allowedMethods: [.GET, .POST, .PUT, .OPTIONS, .DELETE, .PATCH],
|
|
allowedHeaders: [
|
|
.accept, .authorization, .contentType, .origin,
|
|
.xRequestedWith, .userAgent, .accessControlAllowOrigin,
|
|
]
|
|
)
|
|
let cors = CORSMiddleware(configuration: corsConfiguration)
|
|
app.middleware.use(cors, at: .beginning)
|
|
|
|
app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
|
|
app.middleware.use(app.sessions.middleware)
|
|
app.middleware.use(DependenciesMiddleware(database: databaseClient))
|
|
}
|
|
|
|
private func setupDatabase(
|
|
on app: Application,
|
|
factory makeDatabaseClient: @escaping (any Database) -> DatabaseClient
|
|
) async throws -> DatabaseClient {
|
|
switch app.environment {
|
|
case .production, .development:
|
|
let dbFileName = Environment.get("SQLITE_FILENAME") ?? "db.sqlite"
|
|
app.databases.use(DatabaseConfigurationFactory.sqlite(.file(dbFileName)), as: .sqlite)
|
|
default:
|
|
app.databases.use(DatabaseConfigurationFactory.sqlite(.memory), as: .sqlite)
|
|
}
|
|
|
|
let databaseClient = makeDatabaseClient(app.db)
|
|
|
|
if app.environment != .testing {
|
|
try await app.migrations.add(databaseClient.migrations.run())
|
|
}
|
|
|
|
return databaseClient
|
|
}
|
|
|
|
private func addRoutes(to app: Application) {
|
|
// Redirect the index path to project route.
|
|
app.get { req in
|
|
req.redirect(to: SiteRoute.View.router.path(for: .project(.index)))
|
|
}
|
|
|
|
app.mount(
|
|
SiteRoute.router,
|
|
middleware: {
|
|
if app.environment == .testing {
|
|
return nil
|
|
} else {
|
|
return $0.middleware()
|
|
}
|
|
},
|
|
use: siteHandler
|
|
)
|
|
}
|
|
|
|
private func addCommands(to app: Application) {
|
|
// #if DEBUG
|
|
// app.asyncCommands.use(SeedCommand(), as: "seed")
|
|
// #endif
|
|
// app.asyncCommands.use(GenerateAdminUserCommand(), as: "generate-admin")
|
|
}
|
|
|
|
extension SiteRoute {
|
|
|
|
fileprivate func middleware() -> [any Middleware]? {
|
|
switch self {
|
|
case .api:
|
|
return nil
|
|
case .health:
|
|
return nil
|
|
case .view(let route):
|
|
return route.middleware
|
|
}
|
|
}
|
|
}
|
|
|
|
extension DuctSizes: Content {}
|
|
|
|
@Sendable
|
|
private func siteHandler(
|
|
request: Request,
|
|
route: SiteRoute
|
|
) async throws -> any AsyncResponseEncodable {
|
|
@Dependency(\.apiController) var apiController
|
|
@Dependency(\.viewController) var viewController
|
|
@Dependency(\.projectClient) var projectClient
|
|
|
|
switch route {
|
|
case .api(let route):
|
|
return try await apiController.respond(route, request: request)
|
|
case .health:
|
|
return HTTPStatus.ok
|
|
// Generating a pdf return's a `Response` instead of `HTML` like other views, so we
|
|
// need to handle it seperately.
|
|
case .view(.project(.detail(let projectID, .pdf))):
|
|
return try await projectClient.generatePdf(projectID)
|
|
case .view(let route):
|
|
return try await viewController.respond(route: route, request: request)
|
|
}
|
|
}
|