TCPTransports/TCPTransport.swift
| /* | 
| Copyright (C) 2018 Apple Inc. All Rights Reserved. | 
| See LICENSE.txt for this sample’s licensing information | 
| Abstract: | 
| Generic TCP transport API adopted by each concrete implementation. | 
| */ | 
| import Foundation | 
| /// This protocol describes an object that can manage a TCP connection in some | 
| /// unspecified way. Concrete implementations might use BSD Sockets, | 
| /// CFSocketStream, or whatever. | 
| /// | 
| /// For the sake of simplicity this protocol defines that all work must be | 
| /// confined to a single queue. All methods must be called from that queue and | 
| /// all delegate methods will be called back on that queue. The sample as a | 
| /// whole always uses the main queue, but you could take the code and use it in | 
| /// a program that has other queues. | 
| /// | 
| /// Another simplification is that this protocol does not implement flow control: | 
| /// | 
| /// * On the read side, there’s no way to stop the transport from reading all | 
| /// the data off the connection. | 
| /// | 
| /// * On the write side, there’s no indication that data has backed up in the | 
| /// send buffer, so if the client issues an unbounded number of sends then the | 
| /// transport will buffer an unbounded amount of data | 
| /// | 
| /// In the use case illustrated by this sample — a simple interactive chat app | 
| /// based on a line-based protocol — this isn’t a problem. In other scenarios, | 
| /// like sending a large file, this would be disasterous. In that case you | 
| /// won’t be able to use this protocol or its implementations directly. | 
| /// | 
| /// This protocol sends and receives lines. Each implementation is responsible | 
| /// for framing those lines on the wire. In fact, each implementation uses the | 
| /// code in `LineFraming.swift` to frame the lines using the standard terminator | 
| /// used in network protocols (CR LF). It would be relatively easy to change | 
| /// this protocol to use some other message format (something encoded in binary) | 
| /// and then change an implementation to use a different framing and | 
| /// unframing type. In fact, you could even make `TCPTransport` generic in that | 
| /// type. I didn’t do this because I was trying to keep things simple. | 
| protocol TCPTransport : AnyObject { | 
| /// A dispatch queue to which the queue is confined. Specifically: | 
| /// | 
| /// * The client must call any methods like `start()` and `stop()` on that | 
| /// queue. | 
| /// | 
| /// * The object will call all delegate methods on that queue. | 
| /// | 
| /// This is typically under the client’s control, set via the initialiser | 
| /// function. The transport typically uses this internally but that’s not | 
| /// required. | 
|     var queue: DispatchQueue { get } | 
| /// A delegate object, methods on which are called to indicate events on the | 
| /// transport. | 
|     var delegate: TCPTransportDelegate? { get set } | 
| /// A high-level summary of the state of the transport. | 
|     var transportState: TCPTransportState { get } | 
| /// Starts the TCP connection; can only be called once, in the | 
| /// `.initialised` state. | 
| func start() | 
| /// Sends a message over the transport. Can only be called in the | 
| /// `.started` state. | 
| /// | 
| /// - Parameter message: The message to sent, as a single line of text. | 
| func send(message: String) | 
| /// Stops the transport. Can be called in any state, including the | 
| /// `.stopped` state. Once the transport is stopped it cannot be restarted. | 
| /// | 
| /// - warning: If you start the transport you must ensure that it has | 
| /// stopped before releasing your last reference to it. | 
| /// | 
| /// The stream stops in two different ways: | 
| /// | 
| /// * You calling this method | 
| /// | 
| /// * The stream stopping on its own, in which case it calls the | 
| /// `didStop(transport:)` delegate callback | 
| /// | 
| /// As it’s safe to call `stop()` in the `.stopped` state, it’s a good idea | 
| /// to call `stop()` before releasing your primary reference. | 
| func stop() | 
| } | 
| /// The delegate protocol for `TCPTransport`. | 
| protocol TCPTransportDelegate : AnyObject { | 
| /// Called after the transports has started, that is, when the TCP | 
| /// connection comes up. The state will be `.started`. | 
| /// | 
| /// - Parameter transport: The associated transport object. | 
| func didStart(transport: TCPTransport) | 
| /// Called when a message arrives over the transport. The state will be | 
| /// `.started`. | 
| /// | 
| /// - Parameters: | 
| /// - message: The newly arrived message. | 
| /// - transport: The associated transport object. | 
| func didReceive(message: String, transport: TCPTransport) | 
| /// Called when the transport stops of its own accord. By the time this is | 
| /// called, the transport is in the `.stopped` state. The associated error | 
| /// value should give you some indication as to why it stopped. A nil value | 
| /// means it stopped because of EOF. | 
| /// | 
| /// - important: This is not called if the transport stops because you | 
| /// called `.stop()`. | 
| /// | 
| /// - Parameter transport: The associated transport object. | 
| func didStop(transport: TCPTransport) | 
| } | 
| /// The possible transport states. | 
| /// | 
| /// - initialised: The transport has been created by not started. | 
| /// - starting: The transport is starting up, that is, the TCP connection is | 
| /// connecting. | 
| /// - started: The transport has started up, that is, the TCP connection is in | 
| /// place. | 
| /// - stopped: The transport has stopped. If the error is nil the transport | 
| /// stopped because either the client called `stop()` or an EOF on the TCP | 
| /// connection. If the error is not nil, something went wrong with the TCP | 
| /// connection. | 
| enum TCPTransportState { | 
| case initialised | 
| case starting | 
| case started | 
| case stopped(Error?) | 
| } | 
Copyright © 2018 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2018-05-10