Read config from file
This commit is contained in:
parent
4274dfde4c
commit
52cb76d4c8
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
||||
Package.resolved
|
||||
.swiftpm
|
||||
.build
|
||||
Resources/config.json
|
||||
|
6
Resources/config_example.json
Normal file
6
Resources/config_example.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"port": 6003,
|
||||
"keyFileName": "keys",
|
||||
"deviceTimeout": 20,
|
||||
"authenticationTokens" : [],
|
||||
}
|
@ -3,11 +3,40 @@ import Foundation
|
||||
struct Config {
|
||||
|
||||
/// The port where the server runs
|
||||
static let port = 6003
|
||||
let port: Int
|
||||
|
||||
/// The name of the file in the `Resources` folder containing the device authentication token
|
||||
static let keyFileName = "keys"
|
||||
let keyFileName: String
|
||||
|
||||
/// The seconds to wait for a response from the device
|
||||
static let deviceTimeout: Int64 = 20
|
||||
let deviceTimeout: Int64
|
||||
|
||||
/// The authentication tokens to use for monitoring of the service
|
||||
let authenticationTokens: Set<String>
|
||||
}
|
||||
|
||||
extension Config: Codable {
|
||||
|
||||
}
|
||||
|
||||
extension Config {
|
||||
|
||||
init(loadFrom url: URL) throws {
|
||||
guard FileManager.default.fileExists(atPath: url.path) else {
|
||||
fatalError("No configuration file found")
|
||||
}
|
||||
let data: Data
|
||||
do {
|
||||
data = try Data(contentsOf: url)
|
||||
} catch {
|
||||
print("Failed to read config data: \(error)")
|
||||
throw error
|
||||
}
|
||||
do {
|
||||
self = try JSONDecoder().decode(Config.self, from: data)
|
||||
} catch {
|
||||
print("Failed to decode config data: \(error)")
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ final class DeviceManager {
|
||||
|
||||
private var isOpeningNewConnection = false
|
||||
|
||||
private let deviceTimeout: Int64
|
||||
|
||||
/// Indicator for device availability
|
||||
var deviceIsConnected: Bool {
|
||||
deviceIsAuthenticated && !(connection?.isClosed ?? true)
|
||||
@ -26,9 +28,10 @@ final class DeviceManager {
|
||||
/// A promise to finish the request once the device responds or times out
|
||||
private var requestInProgress: EventLoopPromise<DeviceResponse>?
|
||||
|
||||
init(deviceKey: Data, remoteKey: Data) {
|
||||
init(deviceKey: Data, remoteKey: Data, deviceTimeout: Int64) {
|
||||
self.deviceKey = deviceKey
|
||||
self.remoteKey = remoteKey
|
||||
self.deviceTimeout = deviceTimeout
|
||||
}
|
||||
|
||||
// MARK: API
|
||||
@ -47,7 +50,7 @@ final class DeviceManager {
|
||||
}
|
||||
requestInProgress = eventLoop.makePromise(of: DeviceResponse.self)
|
||||
socket.send(message.bytes, promise: nil)
|
||||
eventLoop.scheduleTask(in: .seconds(Config.deviceTimeout)) { [weak self] in
|
||||
eventLoop.scheduleTask(in: .seconds(deviceTimeout)) { [weak self] in
|
||||
guard let promise = self?.requestInProgress else {
|
||||
return
|
||||
}
|
||||
|
@ -9,11 +9,31 @@ enum ServerError: Error {
|
||||
|
||||
// configures your application
|
||||
public func configure(_ app: Application) throws {
|
||||
app.http.server.configuration.port = Config.port
|
||||
|
||||
let storageFolder = URL(fileURLWithPath: app.directory.resourcesDirectory)
|
||||
let keyFile = storageFolder.appendingPathComponent(Config.keyFileName)
|
||||
let authContent: [Data] = try String(contentsOf: keyFile)
|
||||
let logFolder = storageFolder.appendingPathComponent("logs")
|
||||
|
||||
|
||||
let configUrl = storageFolder.appendingPathComponent("config.json")
|
||||
let config = try Config(loadFrom: configUrl)
|
||||
|
||||
app.http.server.configuration.port = config.port
|
||||
|
||||
let keyFile = storageFolder.appendingPathComponent(config.keyFileName)
|
||||
|
||||
let (deviceKey, remoteKey) = try loadKeys(at: keyFile)
|
||||
deviceManager = DeviceManager(deviceKey: deviceKey, remoteKey: remoteKey, deviceTimeout: config.deviceTimeout)
|
||||
try routes(app)
|
||||
|
||||
// Gracefully shut down by closing potentially open socket
|
||||
DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + .seconds(5)) {
|
||||
_ = app.server.onShutdown.always { _ in
|
||||
deviceManager.removeDeviceConnection()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func loadKeys(at url: URL) throws -> (deviceKey: Data, remoteKey: Data) {
|
||||
let authContent: [Data] = try String(contentsOf: url)
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
.components(separatedBy: "\n")
|
||||
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
|
||||
@ -29,15 +49,5 @@ public func configure(_ app: Application) throws {
|
||||
guard authContent.count == 2 else {
|
||||
throw ServerError.invalidAuthenticationFileContent
|
||||
}
|
||||
let deviceKey = authContent[0]
|
||||
let remoteKey = authContent[1]
|
||||
deviceManager = DeviceManager(deviceKey: deviceKey, remoteKey: remoteKey)
|
||||
try routes(app)
|
||||
|
||||
// Gracefully shut down by closing potentially open socket
|
||||
DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + .seconds(5)) {
|
||||
_ = app.server.onShutdown.always { _ in
|
||||
deviceManager.removeDeviceConnection()
|
||||
}
|
||||
}
|
||||
return (deviceKey: authContent[0], remoteKey: authContent[1])
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user