Skip to content

Instantly share code, notes, and snippets.

@lintmachine
Created December 13, 2022 23:02
Show Gist options
  • Save lintmachine/90e8d655168915a27fcb91c870963c1b to your computer and use it in GitHub Desktop.
Save lintmachine/90e8d655168915a27fcb91c870963c1b to your computer and use it in GitHub Desktop.
NWConnection extensions, which add a Combine Publisher interface for sending Data over a network connection.
import Combine
import Foundation
import Network
public extension NWConnection {
func send(content: Data?) -> some Publisher<Void, Error> {
Deferred {
Future<Void, Error> { [weak self] promise in
guard let self = self else { return }
self.send(
content: content,
completion: .contentProcessed { error in
if let error = error {
promise(.failure(error))
} else {
promise(.success(()))
}
}
)
}
}
}
}
extension NWConnection: ConnectablePublisher, Cancellable {
public typealias Output = State
public typealias Failure = Never
public func connect() -> Cancellable {
start(queue: DispatchQueue.main)
return AnyCancellable {
self.cancel()
}
}
public func receive<S>(
subscriber: S
) where S: Subscriber, S.Failure == Never, S.Input == State {
subscriber.receive(
subscription: Subscription(
connection: self,
subscriber: subscriber
)
)
}
class Subscription<S: Subscriber>: Combine.Subscription
where S.Input == State, S.Failure == Never {
private var subscriber: S?
private var connection: NWConnection
init(
connection: NWConnection,
subscriber: S
) {
self.connection = connection
self.subscriber = subscriber
}
func request(_ demand: Subscribers.Demand) {
guard
demand > .none,
let subscriber = subscriber
else {
// no demand
subscriber?.receive(completion: .finished)
cancel()
return
}
var demand = demand
connection.stateUpdateHandler = { state in
demand -= 1
demand += subscriber.receive(state)
if demand == .none {
subscriber.receive(completion: .finished)
self.cancel()
}
}
}
func cancel() {
connection.cancel()
subscriber = nil
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment