Wait for device feedback when sending key
This commit is contained in:
parent
f891087705
commit
54c2fda911
@ -9,6 +9,9 @@ final class KeyManagement {
|
||||
|
||||
/// The size of the individual keys in bytes
|
||||
static let keySize = keySecurity / 8
|
||||
|
||||
/// The seconds to wait for a response from the device
|
||||
static let deviceTimeout: Int64 = 20
|
||||
|
||||
/// The connection to the device
|
||||
private var connection: WebSocket?
|
||||
@ -23,7 +26,7 @@ final class KeyManagement {
|
||||
}
|
||||
|
||||
/// The id of the key which was sent to the device
|
||||
private var keyInTransit: UInt16?
|
||||
private var keyInTransit: (id: UInt16, promise: EventLoopPromise<KeyResult>)?
|
||||
|
||||
/// The result transmitted by the device for the sent key
|
||||
var keyResult: KeyResult = .none
|
||||
@ -50,18 +53,26 @@ final class KeyManagement {
|
||||
keyResult = .none
|
||||
}
|
||||
|
||||
func sendKeyToDevice(_ key: Data, keyId: UInt16) -> KeyPostResponse {
|
||||
func sendKeyToDevice(_ key: Data, keyId: UInt16, on eventLoop: EventLoop) -> EventLoopFuture<KeyResult> {
|
||||
guard key.count == KeyManagement.keySize else {
|
||||
return .invalidKeySize
|
||||
return eventLoop.makeSucceededFuture(.invalidPayloadSize)
|
||||
}
|
||||
guard let socket = connection, !socket.isClosed else {
|
||||
connection = nil
|
||||
return .deviceNotConnected
|
||||
return eventLoop.makeSucceededFuture(.deviceNotConnected)
|
||||
}
|
||||
let keyIdData = [UInt8(keyId >> 8), UInt8(keyId & 0xFF)]
|
||||
keyInTransit = keyId
|
||||
let promise = eventLoop.makePromise(of: KeyResult.self)
|
||||
keyInTransit = (keyId, promise)
|
||||
socket.send(keyIdData + key, promise: nil)
|
||||
return .success
|
||||
eventLoop.scheduleTask(in: .seconds(Self.deviceTimeout)) { [weak self] in
|
||||
guard let (storedKeyId, promise) = self?.keyInTransit, storedKeyId == keyId else {
|
||||
return
|
||||
}
|
||||
self?.keyInTransit = nil
|
||||
promise.succeed(.deviceTimedOut)
|
||||
}
|
||||
return promise.futureResult
|
||||
}
|
||||
|
||||
func authenticateDevice(psk: String) {
|
||||
@ -76,22 +87,24 @@ final class KeyManagement {
|
||||
}
|
||||
|
||||
func processDeviceResponse(_ data: ByteBuffer) {
|
||||
guard let (_, promise) = keyInTransit else {
|
||||
print("No key in transit for response from device \(data)")
|
||||
return
|
||||
}
|
||||
defer { keyInTransit = nil }
|
||||
guard data.readableBytes == 1 else {
|
||||
print("Unexpected number of bytes received from device")
|
||||
keyInTransit = nil
|
||||
keyResult = .unexpectedSocketEvent
|
||||
promise.succeed(.unexpectedSocketEvent)
|
||||
return
|
||||
}
|
||||
guard let rawValue = data.getBytes(at: 0, length: 1)?.first else {
|
||||
print("Unreadable data received from device")
|
||||
keyInTransit = nil
|
||||
keyResult = .unexpectedSocketEvent
|
||||
promise.succeed(.unexpectedSocketEvent)
|
||||
return
|
||||
}
|
||||
guard let response = KeyResult(rawValue: rawValue) else {
|
||||
print("Unknown response \(rawValue) received from device")
|
||||
keyInTransit = nil
|
||||
keyResult = .unexpectedSocketEvent
|
||||
promise.succeed(.unexpectedSocketEvent)
|
||||
return
|
||||
}
|
||||
guard keyInTransit != nil else {
|
||||
|
@ -37,28 +37,19 @@ enum KeyResult: UInt8 {
|
||||
|
||||
/// The device is not connected through the socket
|
||||
case notConnected = 10
|
||||
}
|
||||
|
||||
/**
|
||||
A response from the server to a key request.
|
||||
*/
|
||||
enum KeyPostResponse: Int {
|
||||
|
||||
/// The key will be transmitted to the device
|
||||
case success = 0
|
||||
|
||||
/// The key id is out of bounds or otherwise invalid
|
||||
case invalidKeyId = 1
|
||||
|
||||
/// The request did not contain body data with the key
|
||||
case noBodyData = 2
|
||||
|
||||
/// The key contained in the body data has an invalid size
|
||||
case invalidKeySize = 3
|
||||
case noBodyData = 11
|
||||
|
||||
/// The body data could not be read
|
||||
case corruptkeyData = 4
|
||||
case corruptkeyData = 12
|
||||
|
||||
/// The device is not connected
|
||||
case deviceNotConnected = 5
|
||||
case deviceNotConnected = 13
|
||||
|
||||
/// The device did not respond within the timeout
|
||||
case deviceTimedOut = 14
|
||||
|
||||
/// The key was valid and the door will be opened
|
||||
case success = 15
|
||||
}
|
||||
|
@ -11,20 +11,20 @@ extension PublicAPI {
|
||||
}
|
||||
}
|
||||
|
||||
private func handleKeyPost(_ req: Request) -> KeyPostResponse {
|
||||
private func keyTransmission(_ req: Request) -> EventLoopFuture<KeyResult> {
|
||||
guard let keyId = req.parameters.get(PublicAPI.postKeyIdParameter.rawValue, as: UInt16.self) else {
|
||||
return .invalidKeyId
|
||||
return req.eventLoop.makeSucceededFuture(.invalidKeyIndex)
|
||||
}
|
||||
guard let body = req.body.data else {
|
||||
return .noBodyData
|
||||
return req.eventLoop.makeSucceededFuture(.noBodyData)
|
||||
}
|
||||
guard body.readableBytes == KeyManagement.keySize else {
|
||||
return .invalidKeySize
|
||||
return req.eventLoop.makeSucceededFuture(.invalidPayloadSize)
|
||||
}
|
||||
guard let key = body.getData(at: 0, length: KeyManagement.keySize) else {
|
||||
return .corruptkeyData
|
||||
return req.eventLoop.makeSucceededFuture(.corruptkeyData)
|
||||
}
|
||||
return keyManager.sendKeyToDevice(key, keyId: keyId)
|
||||
return keyManager.sendKeyToDevice(key, keyId: keyId, on: req.eventLoop)
|
||||
}
|
||||
|
||||
func routes(_ app: Application) throws {
|
||||
@ -57,6 +57,7 @@ func routes(_ app: Application) throws {
|
||||
return "Success"
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Post a key to the device for unlocking.
|
||||
|
||||
@ -66,9 +67,8 @@ func routes(_ app: Application) throws {
|
||||
A success of this method does not yet signal successful unlocking.
|
||||
The client should request the status by inquiring the device response.
|
||||
*/
|
||||
app.post(PublicAPI.postKey.path, PublicAPI.postKeyIdParameter.pathParameter) { req -> String in
|
||||
let result = handleKeyPost(req)
|
||||
return String(result.rawValue)
|
||||
app.post(PublicAPI.postKey.path, PublicAPI.postKeyIdParameter.pathParameter) { req in
|
||||
keyTransmission(req).map { String($0.rawValue) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user