feat: Begins using swift argument parser and creating cli client dependency
All checks were successful
CI / Run Tests (push) Successful in 4m27s
All checks were successful
CI / Run Tests (push) Successful in 4m27s
This commit is contained in:
@@ -9,16 +9,16 @@ import NIO
|
||||
public extension DependencyValues {
|
||||
|
||||
/// A dependency that is responsible for managing the connection to
|
||||
/// an MQTT broker.
|
||||
/// an MQTT broker, listen to topics, and publish values back to the
|
||||
/// broker.
|
||||
var mqtt: MQTTManager {
|
||||
get { self[MQTTManager.self] }
|
||||
set { self[MQTTManager.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the interface needed for the ``MQTTConnectionService``.
|
||||
/// Represents the interface needed to connect, listen, and publish to an MQTT broker.
|
||||
///
|
||||
/// See ``MQTTConnectionManagerLive`` module for live implementation.
|
||||
@DependencyClient
|
||||
public struct MQTTManager: Sendable {
|
||||
|
||||
@@ -28,6 +28,8 @@ public struct MQTTManager: Sendable {
|
||||
public var connect: @Sendable () async throws -> Void
|
||||
|
||||
/// Create a stream of connection events.
|
||||
///
|
||||
/// - SeeAlso: ``Event``
|
||||
public var connectionStream: @Sendable () throws -> AsyncStream<Event>
|
||||
|
||||
private var _listen: @Sendable ([String], MQTTQoS) async throws -> ListenStream
|
||||
@@ -38,10 +40,24 @@ public struct MQTTManager: Sendable {
|
||||
/// Shutdown the connection to the MQTT broker.
|
||||
public var shutdown: @Sendable () -> Void
|
||||
|
||||
/// Perform an operation with the underlying MQTTClient, this can be useful in
|
||||
/// tests, so this module needs imported with `@_spi(Testing) import` to use this method.
|
||||
private var _withClient: @Sendable ((MQTTClient) async throws -> Void) async throws -> Void
|
||||
|
||||
public init(
|
||||
connect: @escaping @Sendable () async throws -> Void,
|
||||
connectionStream: @escaping @Sendable () throws -> AsyncStream<MQTTManager.Event>,
|
||||
listen: @escaping @Sendable ([String], MQTTQoS) async throws -> MQTTManager.ListenStream,
|
||||
publish: @escaping @Sendable (MQTTManager.PublishRequest) async throws -> Void,
|
||||
shutdown: @escaping @Sendable () -> Void,
|
||||
withClient: @escaping @Sendable ((MQTTClient) async throws -> Void) async throws -> Void = { _ in unimplemented() }
|
||||
) {
|
||||
self.connect = connect
|
||||
self.connectionStream = connectionStream
|
||||
self._listen = listen
|
||||
self.publish = publish
|
||||
self.shutdown = shutdown
|
||||
self._withClient = withClient
|
||||
}
|
||||
|
||||
/// Create an async stream that listens for changes to the given topics.
|
||||
///
|
||||
/// - Parameters:
|
||||
@@ -77,18 +93,20 @@ public struct MQTTManager: Sendable {
|
||||
_ payload: ByteBuffer,
|
||||
to topicName: String,
|
||||
qos: MQTTQoS,
|
||||
retain: Bool = false
|
||||
retain: Bool = false,
|
||||
properties: MQTTProperties = .init()
|
||||
) async throws {
|
||||
try await publish(.init(
|
||||
topicName: topicName,
|
||||
payload: payload,
|
||||
qos: qos,
|
||||
retain: retain
|
||||
retain: retain,
|
||||
properties: properties
|
||||
))
|
||||
}
|
||||
|
||||
/// Perform an operation with the underlying MQTTClient, this can be useful in
|
||||
/// tests, so this module needs imported with `@_spi(Testing) import` to use this method.
|
||||
/// tests, so this module needs imported with `@_spi(Internal) import MQTTManager` to use this method.
|
||||
@_spi(Internal)
|
||||
public func withClient(
|
||||
_ callback: @Sendable (MQTTClient) async throws -> Void
|
||||
@@ -98,7 +116,7 @@ public struct MQTTManager: Sendable {
|
||||
|
||||
/// Represents connection events that clients can listen for and
|
||||
/// react accordingly.
|
||||
public enum Event: Sendable {
|
||||
public enum Event: Equatable, Sendable {
|
||||
case connected
|
||||
case disconnected
|
||||
case shuttingDown
|
||||
@@ -106,7 +124,7 @@ public struct MQTTManager: Sendable {
|
||||
|
||||
/// Represents the parameters required to publish a new value to the
|
||||
/// MQTT broker.
|
||||
public struct PublishRequest: Equatable, Sendable {
|
||||
public struct PublishRequest: Sendable {
|
||||
|
||||
/// The topic to publish the new value to.
|
||||
public let topicName: String
|
||||
@@ -120,6 +138,8 @@ public struct MQTTManager: Sendable {
|
||||
/// The retain flag for the request.
|
||||
public let retain: Bool
|
||||
|
||||
public let properties: MQTTProperties
|
||||
|
||||
/// Create a new publish request.
|
||||
///
|
||||
/// - Parameters:
|
||||
@@ -131,12 +151,14 @@ public struct MQTTManager: Sendable {
|
||||
topicName: String,
|
||||
payload: ByteBuffer,
|
||||
qos: MQTTQoS,
|
||||
retain: Bool
|
||||
retain: Bool,
|
||||
properties: MQTTProperties
|
||||
) {
|
||||
self.topicName = topicName
|
||||
self.payload = payload
|
||||
self.qos = qos
|
||||
self.retain = retain
|
||||
self.properties = properties
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +186,7 @@ public extension MQTTManager {
|
||||
.removeDuplicates()
|
||||
.eraseToStream()
|
||||
},
|
||||
_listen: { topics, qos in
|
||||
listen: { topics, qos in
|
||||
try await manager.listen(to: topics, qos: qos)
|
||||
},
|
||||
publish: { request in
|
||||
@@ -174,19 +196,20 @@ public extension MQTTManager {
|
||||
return
|
||||
}
|
||||
logger?.trace("Begin publishing to topic: \(topic)")
|
||||
defer { logger?.trace("Done publishing to topic: \(topic)") }
|
||||
defer { logger?.debug("Done publishing to topic: \(topic)") }
|
||||
try await client.publish(
|
||||
to: request.topicName,
|
||||
payload: request.payload,
|
||||
qos: request.qos,
|
||||
retain: request.retain
|
||||
)
|
||||
retain: request.retain,
|
||||
properties: request.properties
|
||||
).get()
|
||||
},
|
||||
shutdown: {
|
||||
Task { try await client.shutdown() }
|
||||
manager.shutdown()
|
||||
},
|
||||
_withClient: { callback in
|
||||
withClient: { callback in
|
||||
try await callback(client)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -107,42 +107,6 @@ actor TopicListenerStream {
|
||||
onShutdownHandler = { task.cancel() }
|
||||
}
|
||||
|
||||
// TODO: remove.
|
||||
func listen(
|
||||
_ topics: [String],
|
||||
_ qos: MQTTQoS = .atLeastOnce
|
||||
) async throws -> Stream {
|
||||
var sleepTimes = 0
|
||||
|
||||
while !client.isActive() {
|
||||
guard sleepTimes < 10 else {
|
||||
throw TopicListenerError.connectionTimeout
|
||||
}
|
||||
try? await Task.sleep(for: .milliseconds(100))
|
||||
sleepTimes += 1
|
||||
}
|
||||
|
||||
client.logger.trace("Client is active, begin subscribing to topics.")
|
||||
|
||||
try await subscribe()
|
||||
|
||||
client.logger.trace("Done subscribing, begin listening to topics.")
|
||||
|
||||
client.addPublishListener(named: name) { result in
|
||||
switch result {
|
||||
case let .failure(error):
|
||||
self.logger?.error("Received error while listening: \(error)")
|
||||
case let .success(publishInfo):
|
||||
if topics.contains(publishInfo.topicName) {
|
||||
self.logger?.debug("Recieved new value for topic: \(publishInfo.topicName)")
|
||||
self.continuation.yield(publishInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stream
|
||||
}
|
||||
|
||||
private func setIsShuttingDown() {
|
||||
shuttingDown = true
|
||||
onShutdownHandler = nil
|
||||
|
||||
Reference in New Issue
Block a user