import Vapor import Foundation import Clairvoyant import ClairvoyantVapor import ClairvoyantBinaryCodable private var provider: VaporMetricProvider! private var serverStatus: Metric! private let asyncScheduler = MultiThreadedEventLoopGroup(numberOfThreads: 2) private var server: CapServer! func configure(_ app: Application) async throws { let resourceDirectory = URL(fileURLWithPath: app.directory.resourcesDirectory) let publicDirectory = app.directory.publicDirectory let config = Config(loadFrom: resourceDirectory) let authenticator = Authenticator(writers: config.writers) let logURL = config.logURL(possiblyRelativeTo: resourceDirectory) let monitor = MetricObserver(logFileFolder: logURL, logMetricId: "caps.log") MetricObserver.standard = monitor serverStatus = Metric("caps.status", name: "Status", description: "The general status of the service") try await serverStatus.update(.initializing) app.http.server.configuration.port = config.port app.routes.defaultMaxBodySize = .init(stringLiteral: config.maxBodySize) server = CapServer(in: URL(fileURLWithPath: publicDirectory)) provider = .init(observer: monitor, accessManager: config.writers) provider.asyncScheduler = asyncScheduler provider.registerRoutes(app) if config.serveFiles { let middleware = FileMiddleware(publicDirectory: publicDirectory) app.middleware.use(middleware) } // Register routes to the router server.registerRoutes(with: app, authenticator: authenticator) // Initialize the server data do { try server.loadData() } catch { try await serverStatus.update(.initializationFailure) print("[\(df.string(from: Date()))] Server failed to start: \(error)") return } if server.canResizeImages { try await serverStatus.update(.nominal) } else { try await serverStatus.update(.reducedFunctionality) } print("[\(df.string(from: Date()))] Server started (\(server.capCount) caps)") } func shutdown() { print("[\(df.string(from: Date()))] Server shutdown") asyncScheduler.schedule { do { try await asyncScheduler.shutdownGracefully() } catch { print("Failed to shut down MultiThreadedEventLoopGroup: \(error)") } } } func log(_ message: String) { guard let observer = MetricObserver.standard else { print(message) return } asyncScheduler.schedule { await observer.log(message) } } private let df: DateFormatter = { let df = DateFormatter() df.dateStyle = .short df.timeStyle = .short return df }()