Skip to content

Commit

Permalink
Swift 6 fixes with latest NIO (#164)
Browse files Browse the repository at this point in the history
* Revert some swift-format changes

* Use correct EventLoopGroup in tests

* fix p12 test

* swift-format
  • Loading branch information
adam-fowler authored Jan 29, 2025
1 parent 2901abd commit 8886459
Show file tree
Hide file tree
Showing 15 changed files with 124 additions and 82 deletions.
7 changes: 3 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@ let package = Package(
dependencies: [
.package(url: "https://github.com/apple/swift-atomics.git", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-nio.git", from: "2.42.0"),
.package(url: "https://github.com/apple/swift-nio.git", from: "2.80.0"),
.package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.14.0"),
.package(url: "https://github.com/apple/swift-nio-transport-services.git", from: "1.6.0"),
.package(url: "https://github.com/apple/swift-nio-transport-services.git", from: "1.20.0"),
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"),
],
targets: [
.target(
name: "MQTTNIO",
dependencies:
[
dependencies: [
.product(name: "Atomics", package: "swift-atomics"),
.product(name: "Logging", package: "swift-log"),
.product(name: "NIO", package: "swift-nio"),
Expand Down
16 changes: 14 additions & 2 deletions Sources/MQTTNIO/ChannelHandlers/MQTTTaskHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,21 @@ final class MQTTTaskHandler: ChannelInboundHandler, RemovableChannelHandler {

switch packet.type {
case .PUBREC:
_ = connection.sendMessageNoWait(MQTTPubAckPacket(type: .PUBREL, packetId: packet.packetId, reason: .packetIdentifierNotFound))
_ = connection.sendMessageNoWait(
MQTTPubAckPacket(
type: .PUBREL,
packetId: packet.packetId,
reason: .packetIdentifierNotFound
)
)
case .PUBREL:
_ = connection.sendMessageNoWait(MQTTPubAckPacket(type: .PUBCOMP, packetId: packet.packetId, reason: .packetIdentifierNotFound))
_ = connection.sendMessageNoWait(
MQTTPubAckPacket(
type: .PUBCOMP,
packetId: packet.packetId,
reason: .packetIdentifierNotFound
)
)
default:
break
}
Expand Down
1 change: 0 additions & 1 deletion Sources/MQTTNIO/ChannelHandlers/WebSocketHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ final class WebSocketHandler: ChannelDuplexHandler {
}
case .connectionClose:
self.receivedClose(context: context, frame: frame)

default:
break
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import NIOHTTP1
// The HTTP handler to be used to initiate the request.
// This initial request will be adapted by the WebSocket upgrader to contain the upgrade header parameters.
// Channel read will only be called if the upgrade fails.
final class WebSocketInitialRequestHandler: ChannelInboundHandler, RemovableChannelHandler {
final class WebSocketInitialRequestHandler: ChannelInboundHandler, RemovableChannelHandler, Sendable {
public typealias InboundIn = HTTPClientResponsePart
public typealias OutboundOut = HTTPClientRequestPart

Expand Down
28 changes: 15 additions & 13 deletions Sources/MQTTNIO/MQTTClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@
import Atomics
import Dispatch
import Logging
import NIO
import NIOConcurrencyHelpers

#if canImport(Network)
import Network
import NIOTransportServices
#endif
import NIO
import NIOConcurrencyHelpers
#if canImport(NIOSSL)
#if os(macOS) || os(Linux)
import NIOSSL
#endif
import NIOTransportServices

/// Swift NIO MQTT Client
///
Expand Down Expand Up @@ -124,7 +125,6 @@ public final class MQTTClient {
case .createNew:
#if canImport(Network)
switch configuration.tlsConfiguration {
// This should use canImport(NIOSSL), will change when it works with SwiftUI previews.
#if os(macOS) || os(Linux)
case .niossl:
self.eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
Expand Down Expand Up @@ -180,11 +180,13 @@ public final class MQTTClient {
/// - Throws: MQTTError.alreadyShutdown: You have already shutdown the client
public func syncShutdownGracefully() throws {
if let eventLoop = MultiThreadedEventLoopGroup.currentEventLoop {
preconditionFailure("""
BUG DETECTED: syncShutdown() must not be called when on an EventLoop.
Calling syncShutdown() on any EventLoop can lead to deadlocks.
Current eventLoop: \(eventLoop)
""")
preconditionFailure(
"""
BUG DETECTED: syncShutdown() must not be called when on an EventLoop.
Calling syncShutdown() on any EventLoop can lead to deadlocks.
Current eventLoop: \(eventLoop)
"""
)
}
let errorStorageLock = NIOLock()
var errorStorage: Error?
Expand Down Expand Up @@ -403,12 +405,12 @@ public final class MQTTClient {
/// Disconnect from server
/// - Returns: Future waiting on disconnect message to be sent
public func disconnect() -> EventLoopFuture<Void> {
return self.disconnect(packet: MQTTDisconnectPacket())
self.disconnect(packet: MQTTDisconnectPacket())
}

/// Return if client has an active connection to broker
public func isActive() -> Bool {
return self.connection?.channel.isActive ?? false
self.connection?.channel.isActive ?? false
}

/// Add named publish listener. Called whenever a PUBLISH message is received from the server
Expand Down Expand Up @@ -530,7 +532,7 @@ extension MQTTClient {
func resendOnRestart() {
let inflight = self.inflight.packets
self.inflight.clear()
inflight.forEach { packet in
for packet in inflight {
switch packet {
case let publish as MQTTPublishPacket:
let newPacket = MQTTPublishPacket(
Expand Down
3 changes: 1 addition & 2 deletions Sources/MQTTNIO/MQTTConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import NIO
import NIOHTTP1
#if canImport(NIOSSL)
#if os(macOS) || os(Linux)
import NIOSSL
#endif

Expand All @@ -31,7 +31,6 @@ extension MQTTClient {
/// by this variable. It is recommended on iOS you use NIO Transport Services.
public enum TLSConfigurationType {
/// NIOSSL TLS configuration
// This should use canImport(NIOSSL), will change when it works with SwiftUI previews.
#if os(macOS) || os(Linux)
case niossl(TLSConfiguration)
#endif
Expand Down
26 changes: 13 additions & 13 deletions Sources/MQTTNIO/MQTTConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,22 @@
//
//===----------------------------------------------------------------------===//

import NIO
import NIOHTTP1
import NIOWebSocket

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
#if canImport(Network)
import Network
import NIOTransportServices
#endif
import NIO
import NIOHTTP1
#if canImport(NIOSSL)
#if os(macOS) || os(Linux)
import NIOSSL
#endif
import NIOTransportServices
import NIOWebSocket

final class MQTTConnection {
let channel: Channel
Expand Down Expand Up @@ -72,7 +73,7 @@ final class MQTTConnection {
webSocketConfiguration: webSocketConfiguration,
upgradePromise: promise
) {
return channel.pipeline.addHandlers(handlers)
try channel.pipeline.syncOperations.addHandlers(handlers)
}
} else {
return channel.pipeline.addHandlers(handlers)
Expand Down Expand Up @@ -113,7 +114,6 @@ final class MQTTConnection {
switch client.configuration.tlsConfiguration {
case .ts(let config):
options = try config.getNWProtocolTLSOptions()
// This should use canImport(NIOSSL), will change when it works with SwiftUI previews.
#if os(macOS) || os(Linux)
case .niossl:
throw MQTTError.wrongTLSConfig
Expand All @@ -130,7 +130,7 @@ final class MQTTConnection {
return bootstrap
}
#endif
// This should use canImport(NIOSSL), will change when it works with SwiftUI previews.

#if os(macOS) || os(Linux) // canImport(Network)
if let clientBootstrap = ClientBootstrap(validatingGroup: client.eventLoopGroup) {
let tlsConfiguration: TLSConfiguration
Expand Down Expand Up @@ -159,7 +159,7 @@ final class MQTTConnection {
channel: Channel,
webSocketConfiguration: MQTTClient.WebSocketConfiguration,
upgradePromise promise: EventLoopPromise<Void>,
afterHandlerAdded: @escaping () -> EventLoopFuture<Void>
afterHandlerAdded: @escaping () throws -> Void
) -> EventLoopFuture<Void> {
// initial HTTP request handler, before upgrade
let httpHandler = WebSocketInitialRequestHandler(
Expand All @@ -174,10 +174,10 @@ final class MQTTConnection {
requestKey: Data(requestKey).base64EncodedString(),
maxFrameSize: client.configuration.webSocketMaxFrameSize
) { channel, _ in
let future = channel.pipeline.addHandler(WebSocketHandler())
.flatMap { _ in
afterHandlerAdded()
}
let future = channel.eventLoop.makeCompletedFuture {
try channel.pipeline.syncOperations.addHandler(WebSocketHandler())
try afterHandlerAdded()
}
future.cascade(to: promise)
return future
}
Expand Down
9 changes: 8 additions & 1 deletion Sources/MQTTNIO/MQTTCoreTypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,14 @@ public struct MQTTPublishInfo: Sendable {
/// Message payload.
public let payload: ByteBuffer

public init(qos: MQTTQoS, retain: Bool, dup: Bool = false, topicName: String, payload: ByteBuffer, properties: MQTTProperties) {
public init(
qos: MQTTQoS,
retain: Bool,
dup: Bool = false,
topicName: String,
payload: ByteBuffer,
properties: MQTTProperties
) {
self.qos = qos
self.retain = retain
self.dup = dup
Expand Down
2 changes: 1 addition & 1 deletion Sources/MQTTNIO/MQTTListeners.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class MQTTListeners<ReturnType> {
let listeners = self.lock.withLock {
return self.listeners
}
listeners.values.forEach { listener in
for listener in listeners.values {
listener(result)
}
}
Expand Down
7 changes: 3 additions & 4 deletions Sources/MQTTNIO/TSTLSConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import Foundation
import Network
#if canImport(NIOSSL)
#if os(macOS) || os(Linux)
import NIOSSL
#endif

Expand Down Expand Up @@ -98,7 +98,6 @@ public struct TSTLSConfiguration {
/// Create certificate array from already loaded SecCertificate array
public static func certificates(_ secCertificates: [SecCertificate]) -> Self { .init(certificates: secCertificates) }

// This should use canImport(NIOSSL), will change when it works with SwiftUI previews.
#if os(macOS) || os(Linux)
/// Create certificate array from PEM file
public static func pem(_ filename: String) throws -> Self {
Expand Down Expand Up @@ -234,8 +233,8 @@ extension TSTLSConfiguration {
sec_protocol_options_set_local_identity(options.securityProtocolOptions, secClientIdentity)
}

self.applicationProtocols.forEach {
sec_protocol_options_add_tls_application_protocol(options.securityProtocolOptions, $0)
for applicationProtocol in self.applicationProtocols {
sec_protocol_options_add_tls_application_protocol(options.securityProtocolOptions, applicationProtocol)
}

if self.certificateVerification != .fullVerification || self.trustRoots != nil {
Expand Down
13 changes: 8 additions & 5 deletions Tests/MQTTNIOTests/MQTTNIOTests+async.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ import NIO
import NIOFoundationCompat
import NIOHTTP1
import XCTest
#if canImport(NIOSSL)

@testable import MQTTNIO

#if os(macOS) || os(Linux)
import NIOSSL
#endif
@testable import MQTTNIO

@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)
final class AsyncMQTTNIOTests: XCTestCase {
Expand All @@ -36,7 +38,7 @@ final class AsyncMQTTNIOTests: XCTestCase {
host: Self.hostname,
port: 1883,
identifier: identifier,
eventLoopGroupProvider: .createNew,
eventLoopGroupProvider: .shared(MultiThreadedEventLoopGroup.singleton),
logger: Self.logger,
configuration: .init(version: version, timeout: timeout)
)
Expand Down Expand Up @@ -91,7 +93,7 @@ final class AsyncMQTTNIOTests: XCTestCase {
host: Self.hostname,
port: 1883,
identifier: "TestPing",
eventLoopGroupProvider: .createNew,
eventLoopGroupProvider: .shared(MultiThreadedEventLoopGroup.singleton),
logger: Self.logger,
configuration: .init(disablePing: true)
)
Expand Down Expand Up @@ -184,7 +186,8 @@ final class AsyncMQTTNIOTests: XCTestCase {
}

func testMQTTPublishRetain() async throws {
let payloadString = #"{"from":1000000,"to":1234567,"type":1,"content":"I am a beginner in swift and I am studying hard!!测试\n\n test, message","timestamp":1607243024,"nonce":"pAx2EsUuXrVuiIU3GGOGHNbUjzRRdT5b","sign":"ff902e31a6a5f5343d70a3a93ac9f946adf1caccab539c6f3a6"}"#
let payloadString =
#"{"from":1000000,"to":1234567,"type":1,"content":"I am a beginner in swift and I am studying hard!!测试\n\n test, message","timestamp":1607243024,"nonce":"pAx2EsUuXrVuiIU3GGOGHNbUjzRRdT5b","sign":"ff902e31a6a5f5343d70a3a93ac9f946adf1caccab539c6f3a6"}"#
let payload = ByteBufferAllocator().buffer(string: payloadString)

let client = self.createClient(identifier: "testMQTTPublishRetain_publisher")
Expand Down
Loading

0 comments on commit 8886459

Please sign in to comment.