Added MQTTStore.

This commit is contained in:
2021-10-25 16:52:34 -04:00
parent f45f667af6
commit 5c92213ee0
8 changed files with 308 additions and 65 deletions

View File

@@ -68,7 +68,12 @@ extension Sensor: FetchableTopic where Reading: BufferInitalizable {
extension MQTTNIO.MQTTClient {
func mqttSubscription(topic: String, qos: MQTTQoS = .atLeastOnce, retainAsPublished: Bool = true, retainHandling: MQTTSubscribeInfoV5.RetainHandling = .sendAlways) -> MQTTSubscribeInfoV5 {
func mqttSubscription(
topic: String,
qos: MQTTQoS = .atLeastOnce,
retainAsPublished: Bool = true,
retainHandling: MQTTSubscribeInfoV5.RetainHandling = .sendAlways
) -> MQTTSubscribeInfoV5 {
.init(topicFilter: topic, qos: qos, retainAsPublished: retainAsPublished, retainHandling: retainHandling)
}
@@ -103,7 +108,6 @@ extension MQTTNIO.MQTTClient {
}
func fetch(setPoint: KeyPath<Topics.SetPoints, String>, setPoints: Topics.SetPoints) -> EventLoopFuture<Double> {
// logger.debug("Fetching data for set point: \(setPoint.topic)")
return fetch(mqttSubscription(topic: setPoints[keyPath: setPoint]))
}

View File

@@ -0,0 +1,95 @@
import Logging
import Foundation
import MQTTNIO
import NIO
// TODO: This works and allows tests to complete, but should potentially be simplified.
typealias PublishTopicHandler<State> = (inout State, Result<MQTTPublishInfo, Error>) -> Void
struct ServerDetails {
let identifier: String
let hostname: String
let port: Int
let version: MQTTClient.Version
let cleanSession: Bool
let useTLS: Bool
let useWebSocket: Bool
let webSocketUrl: String
let username: String?
let password: String?
}
class MQTTStore<State> {
typealias Subscription = (topic: String, onPublish: PublishTopicHandler<State>)
var state: State
var subscriptions: [Subscription]
var client: MQTTClient?
var serverDetails: ServerDetails
var eventLoopGroup: EventLoopGroup
var logger: Logger?
init(
state: State,
subscriptions: [Subscription],
serverDetails: ServerDetails,
eventLoopGroup: EventLoopGroup,
logger: Logger? = nil
) {
self.state = state
self.subscriptions = subscriptions
self.serverDetails = serverDetails
self.eventLoopGroup = eventLoopGroup
self.logger = logger
self.createClient()
}
private func createClient() {
let client = MQTTClient(
host: serverDetails.hostname,
identifier: serverDetails.identifier,
eventLoopGroupProvider: .shared(eventLoopGroup),
logger: logger,
configuration: .init(
version: serverDetails.version,
userName: serverDetails.username,
password: serverDetails.password,
useSSL: serverDetails.useTLS,
useWebSockets: serverDetails.useWebSocket,
webSocketURLPath: serverDetails.webSocketUrl
)
)
for subscription in subscriptions {
client.addPublishListener(
named: subscription.topic,
{ result in subscription.onPublish(&self.state, result) }
)
}
self.client = client
}
func createSubscriptions() -> EventLoopFuture<Void> {
let subscriptionInfo = subscriptions.map { MQTTSubscribeInfo.init(topicFilter: $0.0, qos: .atLeastOnce) }
return client?.subscribe(to: subscriptionInfo).map { _ in } ?? eventLoopGroup.next().makeSucceededVoidFuture()
}
func connect(cleanSession: Bool) -> EventLoopFuture<Bool> {
client?.connect(cleanSession: cleanSession) ?? eventLoopGroup.next().makeSucceededFuture(false)
}
func connectAndSubscribe(cleanSession: Bool) -> EventLoopFuture<Void> {
connect(cleanSession: cleanSession)
.flatMap{ _ in self.createSubscriptions() }
}
func destroy() -> EventLoopFuture<Void> {
guard let client = client else {
return eventLoopGroup.next().makeSucceededVoidFuture()
}
return client.disconnect().map { _ in
try? self.client?.syncShutdownGracefully()
self.client = nil
}
}
}