diff --git a/Package.swift b/Package.swift index efe709f..b516923 100644 --- a/Package.swift +++ b/Package.swift @@ -8,7 +8,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/vapor/vapor.git", from: "4.0.0"), - .package(url: "https://github.com/christophhagen/clairvoyant.git", from: "0.4.0"), + .package(url: "https://github.com/christophhagen/clairvoyant.git", from: "0.5.0"), ], targets: [ .target( diff --git a/Sources/App/DeviceManager.swift b/Sources/App/DeviceManager.swift index f4cc5a0..cce1cfd 100644 --- a/Sources/App/DeviceManager.swift +++ b/Sources/App/DeviceManager.swift @@ -33,27 +33,31 @@ final class DeviceManager { /// A promise to finish the request once the device responds or times out private var requestInProgress: EventLoopPromise? - init(deviceKey: Data, remoteKey: Data, deviceTimeout: Int64) { + init(deviceKey: Data, remoteKey: Data, deviceTimeout: Int64) async { self.deviceKey = deviceKey self.remoteKey = remoteKey self.deviceTimeout = deviceTimeout - self.deviceConnectedMetric = .init( + self.deviceConnectedMetric = try! await .init( "sesame.connected", name: "Device connected", description: "Shows if the device is connected via WebSocket") - self.messagesToDeviceMetric = .init( + self.messagesToDeviceMetric = try! await .init( "sesame.messages", name: "Forwarded Messages", description: "The number of messages transmitted to the device") } private func updateDeviceConnectionMetric() { - deviceConnectedMetric.update(deviceIsConnected) + Task { + try? await deviceConnectedMetric.update(deviceIsConnected) + } } private func updateMessageCountMetric() { - let lastValue = messagesToDeviceMetric.lastValue()?.value ?? 0 - messagesToDeviceMetric.update(lastValue + 1) + Task { + let lastValue = await messagesToDeviceMetric.lastValue()?.value ?? 0 + try? await messagesToDeviceMetric.update(lastValue + 1) + } } // MARK: API @@ -70,7 +74,8 @@ final class DeviceManager { guard requestInProgress == nil else { return eventLoop.makeSucceededFuture(.operationInProgress) } - requestInProgress = eventLoop.makePromise(of: DeviceResponse.self) + let result = eventLoop.makePromise(of: DeviceResponse.self) + self.requestInProgress = result socket.send(message.bytes, promise: nil) updateMessageCountMetric() eventLoop.scheduleTask(in: .seconds(deviceTimeout)) { [weak self] in @@ -80,7 +85,7 @@ final class DeviceManager { self?.requestInProgress = nil promise.succeed(.deviceTimedOut) } - return requestInProgress!.futureResult + return result.futureResult } func authenticateDevice(hash: String) { diff --git a/Sources/App/configure.swift b/Sources/App/configure.swift index 147515e..3e6bb98 100755 --- a/Sources/App/configure.swift +++ b/Sources/App/configure.swift @@ -9,21 +9,21 @@ enum ServerError: Error { } // configures your application -public func configure(_ app: Application) throws { +public func configure(_ app: Application) async throws { let storageFolder = URL(fileURLWithPath: app.directory.resourcesDirectory) let logFolder = storageFolder.appendingPathComponent("logs") let accessManager = AccessTokenManager([]) - let monitor = MetricObserver( + let monitor = await MetricObserver( logFolder: logFolder, accessManager: accessManager, logMetricId: "sesame.log") MetricObserver.standard = monitor - let status = Metric("sesame.status") - status.update(.initializing) + let status = try await Metric("sesame.status") + try await status.update(.initializing) - monitor.registerRoutes(app) + await monitor.registerRoutes(app) let configUrl = storageFolder.appendingPathComponent("config.json") let config = try Config(loadFrom: configUrl) @@ -35,7 +35,11 @@ public func configure(_ app: Application) throws { let keyFile = storageFolder.appendingPathComponent(config.keyFileName) let (deviceKey, remoteKey) = try loadKeys(at: keyFile) - deviceManager = DeviceManager(deviceKey: deviceKey, remoteKey: remoteKey, deviceTimeout: config.deviceTimeout) + deviceManager = await DeviceManager( + deviceKey: deviceKey, + remoteKey: remoteKey, + deviceTimeout: config.deviceTimeout) + try routes(app) // Gracefully shut down by closing potentially open socket @@ -45,7 +49,7 @@ public func configure(_ app: Application) throws { } } - status.update(.nominal) + try await status.update(.nominal) } private func loadKeys(at url: URL) throws -> (deviceKey: Data, remoteKey: Data) { @@ -69,6 +73,11 @@ private func loadKeys(at url: URL) throws -> (deviceKey: Data, remoteKey: Data) } func log(_ message: String) { - MetricObserver.standard?.log(message) - print(message) + guard let observer = MetricObserver.standard else { + print(message) + return + } + Task { + await observer.log(message) + } } diff --git a/Sources/Run/main.swift b/Sources/Run/main.swift index 373be5f..4e625fb 100644 --- a/Sources/Run/main.swift +++ b/Sources/Run/main.swift @@ -1,9 +1,15 @@ import App import Vapor -var env = try Environment.detect() +var env = Environment.production //.detect() try LoggingSystem.bootstrap(from: &env) let app = Application(env) defer { app.shutdown() } -try configure(app) + +private let semaphore = DispatchSemaphore(value: 0) +Task { + try await configure(app) + semaphore.signal() +} +semaphore.wait() try app.run() diff --git a/Tests/AppTests/AppTests.swift b/Tests/AppTests/AppTests.swift index f352e9b..7ec1983 100644 --- a/Tests/AppTests/AppTests.swift +++ b/Tests/AppTests/AppTests.swift @@ -43,10 +43,10 @@ final class AppTests: XCTestCase { XCTAssertEqual(content, input.content) } - func testMessageTransmission() throws { + func testMessageTransmission() async throws { let app = Application(.testing) defer { app.shutdown() } - try configure(app) + try await configure(app) // How to open a socket via request? }