import Vapor import Fluent import Clairvoyant var server: SQLiteDatabase! // configures your application public func configure(_ app: Application) async throws { let storageFolder = URL(fileURLWithPath: app.directory.resourcesDirectory) let logFolder = storageFolder.appendingPathComponent("logs") let accessManager = AccessTokenManager([]) let monitor = await MetricObserver( logFolder: logFolder, accessManager: accessManager, logMetricId: "schafkopf.log") MetricObserver.standard = monitor let status = try! await Metric( "schafkopf.status", name: "Status", description: "The main status of the server") try? await status.update(.initializing) await monitor.registerRoutes(app) let configPath = URL(fileURLWithPath: app.directory.resourcesDirectory) .appendingPathComponent("config.json") let configuration: Configuration do { configuration = try Configuration(loadFromUrl: configPath) } catch { try? await status.update(.initializationFailure) await monitor.log("Failed to read configuration: \(error)") // Note: If configuration can't be loaded, then the server will run on the wrong port // and access to metrics is impossible, since no tokens are loaded return } configuration.monitoringTokens.map { $0.data(using: .utf8)! }.forEach(accessManager.add) app.http.server.configuration.port = configuration.serverPort // Set target environment app.environment = .production if !configuration.production { app.logger.logLevel = .info log("[DEVELOPMENT] Using in-memory database") app.databases.use(.sqlite(.memory), as: .sqlite) } else { app.logger.logLevel = .notice let dbFile = storageFolder.appendingPathComponent("db.sqlite").path log("[PRODUCTION] Using database at \(dbFile)") app.databases.use(.sqlite(.file(dbFile)), as: .sqlite) } app.migrations.add(UserTableMigration()) app.migrations.add(PasswordResetMigration()) do { try await app.autoMigrate() } catch { await monitor.log("Failed to migrate database: \(error)") try? await status.update(.initializationFailure) return } // serve files from /Public folder app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory)) let db = app.databases.database(.sqlite, logger: .init(label: "Init"), on: app.databases.eventLoopGroup.next())! server = try await SQLiteDatabase(database: db, mail: configuration.mail) // Gracefully shut down by closing potentially open socket DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + .seconds(5)) { _ = app.server.onShutdown.always { _ in server.disconnectAllSockets() } } // register routes routes(app) try? await status.update(.nominal) } func log(_ message: String) { guard let observer = MetricObserver.standard else { print(message) return } Task { await observer.log(message) } }