Skip to content

Commit

Permalink
Allow retrieval of metadata from NWConnection (#163)
Browse files Browse the repository at this point in the history
* Allow retrieval of metadata for a specific protocol from the underlying `NWConnection`

* Address review comments

* Address review comment

* Add availability annotation to tests

* Rename `NIOTSChannelIsNotATransportServicesChannel ` to `NIOTSChannelIsNotANIOTSConnectionChannel `
  • Loading branch information
dnadoba authored Oct 19, 2022
1 parent de5ea3d commit c0d9a14
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 0 deletions.
57 changes: 57 additions & 0 deletions Sources/NIOTransportServices/NIOTSConnectionChannel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -893,4 +893,61 @@ extension NIOTSConnectionChannel {
return SynchronousOptions(channel: self)
}
}


public struct NIOTSConnectionNotInitialized: Error, Hashable {
public init() {}
}

public struct NIOTSChannelIsNotANIOTSConnectionChannel: Error, Hashable {
public init() {}
}

@available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *)
extension NIOTSConnectionChannel {
fileprivate func metadata(definition: NWProtocolDefinition) throws -> NWProtocolMetadata? {
guard let nwConnection = self.nwConnection else {
throw NIOTSConnectionNotInitialized()
}
return nwConnection.metadata(definition: definition)
}
}

@available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *)
extension Channel {
/// Retrieves the metadata for a specific protocol from the underlying ``NWConnection``
/// - Throws: If `self` isn't a `NIOTS` channel with a `NWConnection` this method will throw
/// ``NIOTSChannelIsNotATransportServicesChannel`` or ``NIOTSConnectionNotInitialized``.
public func getMetadata(definition: NWProtocolDefinition) -> EventLoopFuture<NWProtocolMetadata?> {
guard let channel = self as? NIOTSConnectionChannel else {
return self.eventLoop.makeFailedFuture(NIOTSChannelIsNotANIOTSConnectionChannel())
}
if self.eventLoop.inEventLoop {
return self.eventLoop.makeCompletedFuture {
try channel.metadata(definition: definition)
}
} else {
return self.eventLoop.submit {
try channel.metadata(definition: definition)
}
}
}

/// Retrieves the metadata for a specific protocol from the underlying ``NWConnection``
/// - Precondition: Must be called on the `EventLoop` the `Channel` is running on.
/// - Throws: If `self` isn't a `NIOTS` channel with a `NWConnection` this method will throw
/// ``NIOTSChannelIsNotATransportServicesChannel`` or ``NIOTSConnectionNotInitialized``.
public func getMetadataSync(
definition: NWProtocolDefinition,
file: StaticString = #fileID,
line: UInt = #line
) throws -> NWProtocolMetadata? {
self.eventLoop.preconditionInEventLoop(file: file, line: line)
guard let channel = self as? NIOTSConnectionChannel else {
throw NIOTSChannelIsNotANIOTSConnectionChannel()
}
return try channel.metadata(definition: definition)
}
}

#endif
1 change: 1 addition & 0 deletions Tests/NIOTransportServicesTests/NIOTSBootstrapTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ final class NIOTSBootstrapTests: XCTestCase {
XCTFail("can't connect to server1")
return
}
XCTAssertNotNil(try client1.getMetadata(definition: NWProtocolTCP.definition).wait() as? NWProtocolTCP.Metadata)
XCTAssertNoThrow(try client1.writeAndFlush(buffer).wait())

// The TLS connection won't actually succeed but it takes Network.framework a while to tell us, we don't
Expand Down
54 changes: 54 additions & 0 deletions Tests/NIOTransportServicesTests/NIOTSChannelMetadataTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2022 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

#if canImport(Network)
import Network
import NIOCore
import XCTest
@testable import NIOTransportServices

@available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *)
final class NIOTSChannelMetadataTests: XCTestCase {
func testThrowsIfCalledOnWrongChannel() throws {
let eventLoopGroup = NIOTSEventLoopGroup()
defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) }
let listenerBootsrap = NIOTSListenerBootstrap(group: eventLoopGroup)
let listenerChannel = try listenerBootsrap.bind(host: "localhost", port: 0).wait()
defer { XCTAssertNoThrow(try listenerChannel.close().wait()) }

XCTAssertThrowsError(try listenerChannel.getMetadata(definition: NWProtocolTLS.definition).wait()) { error in
XCTAssertTrue(error is NIOTSChannelIsNotANIOTSConnectionChannel, "unexpected error \(error)")
}
try! listenerChannel.eventLoop.submit {
XCTAssertThrowsError(try listenerChannel.getMetadataSync(definition: NWProtocolTLS.definition)) { error in
XCTAssertTrue(error is NIOTSChannelIsNotANIOTSConnectionChannel, "unexpected error \(error)")
}
}.wait()

}
func testThowsIfCalledOnANonInitializedChannel() {
let eventLoopGroup = NIOTSEventLoopGroup()
defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) }
let channel = NIOTSConnectionChannel(eventLoop: eventLoopGroup.next() as! NIOTSEventLoop, tcpOptions: .init(), tlsOptions: .init())
XCTAssertThrowsError(try channel.getMetadata(definition: NWProtocolTLS.definition).wait()) { error in
XCTAssertTrue(error is NIOTSConnectionNotInitialized, "unexpected error \(error)")
}
try! channel.eventLoop.submit {
XCTAssertThrowsError(try channel.getMetadataSync(definition: NWProtocolTLS.definition)) { error in
XCTAssertTrue(error is NIOTSConnectionNotInitialized, "unexpected error \(error)")
}
}.wait()
}
}
#endif

0 comments on commit c0d9a14

Please sign in to comment.