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
|
/// The size of the individual keys in bytes
|
||||||
static let keySize = keySecurity / 8
|
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
|
/// The connection to the device
|
||||||
private var connection: WebSocket?
|
private var connection: WebSocket?
|
||||||
@ -23,7 +26,7 @@ final class KeyManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The id of the key which was sent to the device
|
/// 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
|
/// The result transmitted by the device for the sent key
|
||||||
var keyResult: KeyResult = .none
|
var keyResult: KeyResult = .none
|
||||||
@ -50,18 +53,26 @@ final class KeyManagement {
|
|||||||
keyResult = .none
|
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 {
|
guard key.count == KeyManagement.keySize else {
|
||||||
return .invalidKeySize
|
return eventLoop.makeSucceededFuture(.invalidPayloadSize)
|
||||||
}
|
}
|
||||||
guard let socket = connection, !socket.isClosed else {
|
guard let socket = connection, !socket.isClosed else {
|
||||||
connection = nil
|
connection = nil
|
||||||
return .deviceNotConnected
|
return eventLoop.makeSucceededFuture(.deviceNotConnected)
|
||||||
}
|
}
|
||||||
let keyIdData = [UInt8(keyId >> 8), UInt8(keyId & 0xFF)]
|
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)
|
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) {
|
func authenticateDevice(psk: String) {
|
||||||
@ -76,22 +87,24 @@ final class KeyManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func processDeviceResponse(_ data: ByteBuffer) {
|
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 {
|
guard data.readableBytes == 1 else {
|
||||||
print("Unexpected number of bytes received from device")
|
print("Unexpected number of bytes received from device")
|
||||||
keyInTransit = nil
|
promise.succeed(.unexpectedSocketEvent)
|
||||||
keyResult = .unexpectedSocketEvent
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard let rawValue = data.getBytes(at: 0, length: 1)?.first else {
|
guard let rawValue = data.getBytes(at: 0, length: 1)?.first else {
|
||||||
print("Unreadable data received from device")
|
print("Unreadable data received from device")
|
||||||
keyInTransit = nil
|
promise.succeed(.unexpectedSocketEvent)
|
||||||
keyResult = .unexpectedSocketEvent
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard let response = KeyResult(rawValue: rawValue) else {
|
guard let response = KeyResult(rawValue: rawValue) else {
|
||||||
print("Unknown response \(rawValue) received from device")
|
print("Unknown response \(rawValue) received from device")
|
||||||
keyInTransit = nil
|
promise.succeed(.unexpectedSocketEvent)
|
||||||
keyResult = .unexpectedSocketEvent
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard keyInTransit != nil else {
|
guard keyInTransit != nil else {
|
||||||
|
@ -37,28 +37,19 @@ enum KeyResult: UInt8 {
|
|||||||
|
|
||||||
/// The device is not connected through the socket
|
/// The device is not connected through the socket
|
||||||
case notConnected = 10
|
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
|
/// The request did not contain body data with the key
|
||||||
case noBodyData = 2
|
case noBodyData = 11
|
||||||
|
|
||||||
/// The key contained in the body data has an invalid size
|
|
||||||
case invalidKeySize = 3
|
|
||||||
|
|
||||||
/// The body data could not be read
|
/// The body data could not be read
|
||||||
case corruptkeyData = 4
|
case corruptkeyData = 12
|
||||||
|
|
||||||
/// The device is not connected
|
/// 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 {
|
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 {
|
guard let body = req.body.data else {
|
||||||
return .noBodyData
|
return req.eventLoop.makeSucceededFuture(.noBodyData)
|
||||||
}
|
}
|
||||||
guard body.readableBytes == KeyManagement.keySize else {
|
guard body.readableBytes == KeyManagement.keySize else {
|
||||||
return .invalidKeySize
|
return req.eventLoop.makeSucceededFuture(.invalidPayloadSize)
|
||||||
}
|
}
|
||||||
guard let key = body.getData(at: 0, length: KeyManagement.keySize) else {
|
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 {
|
func routes(_ app: Application) throws {
|
||||||
@ -57,6 +57,7 @@ func routes(_ app: Application) throws {
|
|||||||
return "Success"
|
return "Success"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Post a key to the device for unlocking.
|
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.
|
A success of this method does not yet signal successful unlocking.
|
||||||
The client should request the status by inquiring the device response.
|
The client should request the status by inquiring the device response.
|
||||||
*/
|
*/
|
||||||
app.post(PublicAPI.postKey.path, PublicAPI.postKeyIdParameter.pathParameter) { req -> String in
|
app.post(PublicAPI.postKey.path, PublicAPI.postKeyIdParameter.pathParameter) { req in
|
||||||
let result = handleKeyPost(req)
|
keyTransmission(req).map { String($0.rawValue) }
|
||||||
return String(result.rawValue)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user