Browse Source

Merge pull request #659 from Alamofire/feature/stream_support

Christian Noon 10 years ago
parent
commit
b5cce2c5cd
3 changed files with 195 additions and 0 deletions
  1. 8 0
      Alamofire.xcodeproj/project.pbxproj
  2. 7 0
      Source/Manager.swift
  3. 180 0
      Source/Stream.swift

+ 8 - 0
Alamofire.xcodeproj/project.pbxproj

@@ -59,6 +59,9 @@
 		4C812C641B535F6D0017E0BF /* root-ca-disig.cer in Resources */ = {isa = PBXBuildFile; fileRef = 4C812C5F1B535F6D0017E0BF /* root-ca-disig.cer */; };
 		4C812C651B535F6D0017E0BF /* testssl-expire.disig.sk.cer in Resources */ = {isa = PBXBuildFile; fileRef = 4C812C601B535F6D0017E0BF /* testssl-expire.disig.sk.cer */; };
 		4C812C661B535F6D0017E0BF /* testssl-expire.disig.sk.cer in Resources */ = {isa = PBXBuildFile; fileRef = 4C812C601B535F6D0017E0BF /* testssl-expire.disig.sk.cer */; };
+		4C83F41B1B749E0E00203445 /* Stream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C83F41A1B749E0E00203445 /* Stream.swift */; };
+		4C83F41C1B749E0E00203445 /* Stream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C83F41A1B749E0E00203445 /* Stream.swift */; };
+		4C83F41D1B749E0E00203445 /* Stream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C83F41A1B749E0E00203445 /* Stream.swift */; };
 		4CA028C51B7466C500C84163 /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA028C41B7466C500C84163 /* ResultTests.swift */; };
 		4CA028C61B7466C500C84163 /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA028C41B7466C500C84163 /* ResultTests.swift */; };
 		4CCFA79A1B2BE71600B6F460 /* URLProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CCFA7991B2BE71600B6F460 /* URLProtocolTests.swift */; };
@@ -159,6 +162,7 @@
 		4C812C5E1B535F6D0017E0BF /* intermediate-ca-disig.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = "intermediate-ca-disig.cer"; path = "disig.sk/intermediate-ca-disig.cer"; sourceTree = "<group>"; };
 		4C812C5F1B535F6D0017E0BF /* root-ca-disig.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = "root-ca-disig.cer"; path = "disig.sk/root-ca-disig.cer"; sourceTree = "<group>"; };
 		4C812C601B535F6D0017E0BF /* testssl-expire.disig.sk.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = "testssl-expire.disig.sk.cer"; path = "disig.sk/testssl-expire.disig.sk.cer"; sourceTree = "<group>"; };
+		4C83F41A1B749E0E00203445 /* Stream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Stream.swift; sourceTree = "<group>"; };
 		4CA028C41B7466C500C84163 /* ResultTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultTests.swift; sourceTree = "<group>"; };
 		4CCFA7991B2BE71600B6F460 /* URLProtocolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLProtocolTests.swift; sourceTree = "<group>"; };
 		4CDE2C361AF8932A00BABAE5 /* Manager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Manager.swift; sourceTree = "<group>"; };
@@ -374,6 +378,7 @@
 				4C23EB421B327C5B0090E0BC /* MultipartFormData.swift */,
 				4CDE2C451AF89FF300BABAE5 /* ResponseSerialization.swift */,
 				4C811F8C1B51856D00E0F59A /* ServerTrustPolicy.swift */,
+				4C83F41A1B749E0E00203445 /* Stream.swift */,
 				4CDE2C3F1AF89E0700BABAE5 /* Upload.swift */,
 				4CDE2C421AF89F0900BABAE5 /* Validation.swift */,
 			);
@@ -692,6 +697,7 @@
 				4DD67C251A5C590000ED2280 /* Alamofire.swift in Sources */,
 				4C23EB441B327C5B0090E0BC /* MultipartFormData.swift in Sources */,
 				4C811F8E1B51856D00E0F59A /* ServerTrustPolicy.swift in Sources */,
+				4C83F41C1B749E0E00203445 /* Stream.swift in Sources */,
 				4CDE2C3E1AF89D4900BABAE5 /* Download.swift in Sources */,
 				4CDE2C441AF89F0900BABAE5 /* Validation.swift in Sources */,
 				4C0E5BF91B673D3400816CCC /* Result.swift in Sources */,
@@ -711,6 +717,7 @@
 				4CEC605B1B745C9100E684F4 /* Result.swift in Sources */,
 				E4202FD41B667AA100C997FB /* Alamofire.swift in Sources */,
 				E4202FD51B667AA100C997FB /* MultipartFormData.swift in Sources */,
+				4C83F41D1B749E0E00203445 /* Stream.swift in Sources */,
 				E4202FD61B667AA100C997FB /* ServerTrustPolicy.swift in Sources */,
 				E4202FD71B667AA100C997FB /* Download.swift in Sources */,
 				E4202FD81B667AA100C997FB /* Validation.swift in Sources */,
@@ -730,6 +737,7 @@
 				F897FF4119AA800700AB5182 /* Alamofire.swift in Sources */,
 				4C23EB431B327C5B0090E0BC /* MultipartFormData.swift in Sources */,
 				4C811F8D1B51856D00E0F59A /* ServerTrustPolicy.swift in Sources */,
+				4C83F41B1B749E0E00203445 /* Stream.swift in Sources */,
 				4CDE2C3D1AF89D4900BABAE5 /* Download.swift in Sources */,
 				4CDE2C431AF89F0900BABAE5 /* Validation.swift in Sources */,
 				4C0E5BF81B673D3400816CCC /* Result.swift in Sources */,

+ 7 - 0
Source/Manager.swift

@@ -639,5 +639,12 @@ public class Manager {
                 )
             }
         }
+
+        // MARK: - NSURLSessionStreamDelegate
+
+        var _streamTaskReadClosed: Any?
+        var _streamTaskWriteClosed: Any?
+        var _streamTaskBetterRouteDiscovered: Any?
+        var _streamTaskDidBecomeInputStream: Any?
     }
 }

+ 180 - 0
Source/Stream.swift

@@ -0,0 +1,180 @@
+// Stream.swift
+//
+// Copyright (c) 2014–2015 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+#if !os(watchOS)
+
+@available(iOS 9.0, OSX 10.11, *)
+extension Manager {
+    private enum Streamable {
+        case Stream(String, Int)
+        case NetService(NSNetService)
+    }
+
+    private func stream(streamable: Streamable) -> Request {
+        var streamTask: NSURLSessionStreamTask!
+
+        switch streamable {
+        case .Stream(let hostName, let port):
+            dispatch_sync(queue) {
+                streamTask = self.session.streamTaskWithHostName(hostName, port: port)
+            }
+        case .NetService(let netService):
+            dispatch_sync(queue) {
+                streamTask = self.session.streamTaskWithNetService(netService)
+            }
+        }
+
+        let request = Request(session: session, task: streamTask)
+
+        delegate[request.delegate.task] = request.delegate
+
+        if startRequestsImmediately {
+            request.resume()
+        }
+
+        return request
+    }
+
+    /**
+        Creates a request for bidirectional streaming with the given hostname and port.
+
+        - parameter hostName: The hostname of the server to connect to.
+        - parameter port:     The port of the server to connect to.
+
+        :returns: The created stream request.
+    */
+    public func stream(hostName hostName: String, port: Int) -> Request {
+        return stream(.Stream(hostName, port))
+    }
+
+    /**
+        Creates a request for bidirectional streaming with the given `NSNetService`.
+
+        - parameter netService: The net service used to identify the endpoint.
+
+        - returns: The created stream request.
+    */
+    public func stream(netService netService: NSNetService) -> Request {
+        return stream(.NetService(netService))
+    }
+}
+
+// MARK: -
+
+@available(iOS 9.0, OSX 10.11, *)
+extension Manager.SessionDelegate: NSURLSessionStreamDelegate {
+
+    // MARK: Override Closures
+
+    /// Overrides default behavior for NSURLSessionStreamDelegate method `URLSession:readClosedForStreamTask:`.
+    public var streamTaskReadClosed: ((NSURLSession, NSURLSessionStreamTask) -> Void)? {
+        get {
+            return _streamTaskReadClosed as? (NSURLSession, NSURLSessionStreamTask) -> Void
+        }
+        set {
+            _streamTaskReadClosed = newValue
+        }
+    }
+
+    /// Overrides default behavior for NSURLSessionStreamDelegate method `URLSession:writeClosedForStreamTask:`.
+    public var streamTaskWriteClosed: ((NSURLSession, NSURLSessionStreamTask) -> Void)? {
+        get {
+            return _streamTaskWriteClosed as? (NSURLSession, NSURLSessionStreamTask) -> Void
+        }
+        set {
+            _streamTaskWriteClosed = newValue
+        }
+    }
+
+    /// Overrides default behavior for NSURLSessionStreamDelegate method `URLSession:betterRouteDiscoveredForStreamTask:`.
+    public var streamTaskBetterRouteDiscovered: ((NSURLSession, NSURLSessionStreamTask) -> Void)? {
+        get {
+            return _streamTaskBetterRouteDiscovered as? (NSURLSession, NSURLSessionStreamTask) -> Void
+        }
+        set {
+            _streamTaskBetterRouteDiscovered = newValue
+        }
+    }
+
+    /// Overrides default behavior for NSURLSessionStreamDelegate method `URLSession:streamTask:didBecomeInputStream:outputStream:`.
+    public var streamTaskDidBecomeInputStream: ((NSURLSession, NSURLSessionStreamTask, NSInputStream, NSOutputStream) -> Void)? {
+        get {
+            return _streamTaskDidBecomeInputStream as? (NSURLSession, NSURLSessionStreamTask, NSInputStream, NSOutputStream) -> Void
+        }
+        set {
+            _streamTaskDidBecomeInputStream = newValue
+        }
+    }
+
+    // MARK: Delegate Methods
+
+    /**
+        Tells the delegate that the read side of the connection has been closed.
+
+        - parameter session:    The session.
+        - parameter streamTask: The stream task.
+    */
+    public func URLSession(session: NSURLSession, readClosedForStreamTask streamTask: NSURLSessionStreamTask) {
+        streamTaskReadClosed?(session, streamTask)
+    }
+
+    /**
+        Tells the delegate that the write side of the connection has been closed.
+
+        - parameter session:    The session.
+        - parameter streamTask: The stream task.
+    */
+    public func URLSession(session: NSURLSession, writeClosedForStreamTask streamTask: NSURLSessionStreamTask) {
+        streamTaskWriteClosed?(session, streamTask)
+    }
+
+    /**
+        Tells the delegate that the system has determined that a better route to the host is available.
+
+        - parameter session:    The session.
+        - parameter streamTask: The stream task.
+    */
+    public func URLSession(session: NSURLSession, betterRouteDiscoveredForStreamTask streamTask: NSURLSessionStreamTask) {
+        streamTaskBetterRouteDiscovered?(session, streamTask)
+    }
+
+    /**
+        Tells the delegate that the stream task has been completed and provides the unopened stream objects.
+
+        - parameter session:      The session.
+        - parameter streamTask:   The stream task.
+        - parameter inputStream:  The new input stream.
+        - parameter outputStream: The new output stream.
+    */
+    public func URLSession(
+        session: NSURLSession,
+        streamTask: NSURLSessionStreamTask,
+        didBecomeInputStream inputStream: NSInputStream,
+        outputStream: NSOutputStream)
+    {
+        streamTaskDidBecomeInputStream?(session, streamTask, inputStream, outputStream)
+    }
+}
+
+#endif