فهرست منبع

Added state tracking and prevention of retain cycles so that the HttpServerIO disposes properly (and immediately)

Patrick Culligan 9 سال پیش
والد
کامیت
3516571e42
1فایلهای تغییر یافته به همراه33 افزوده شده و 15 حذف شده
  1. 33 15
      Sources/HttpServerIO.swift

+ 33 - 15
Sources/HttpServerIO.swift

@@ -15,8 +15,8 @@ public class HttpServerIO {
     
     private var socket = Socket(socketFileDescriptor: -1)
     private var sockets = Set<Socket>()
-    
-    public private(set) var running = false
+    public private(set) var state = HttpServerIOState.Stopped
+    public var operating: Bool { get { return self.state == .Running } }
     
     public func port() throws -> Int {
         return Int(try socket.port())
@@ -31,30 +31,37 @@ public class HttpServerIO {
     }
     
     public func start(port: in_port_t = 8080, forceIPv4: Bool = false, priority: Int = DISPATCH_QUEUE_PRIORITY_BACKGROUND) throws {
+        guard !self.operating else { return }
         stop()
+        self.state = .Starting
         self.socket = try Socket.tcpSocketForListen(port, forceIPv4: forceIPv4)
-        self.running = true
-        dispatch_async(dispatch_get_global_queue(priority, 0)) {
-            while let socket = try? self.socket.acceptClientSocket() {
-                dispatch_async(dispatch_get_global_queue(priority, 0), {
-                    self.sockets.insert(socket)
-                    self.handleConnection(socket)
-                    self.sockets.remove(socket)
+        dispatch_async(dispatch_get_global_queue(priority, 0)) { [weak self] in
+            guard let sself = self else { return }
+            guard sself.operating else { return }
+            while let socket = try? sself.socket.acceptClientSocket() {
+                dispatch_async(dispatch_get_global_queue(priority, 0), { [weak self] in
+                    guard let sself = self else { return }
+                    guard sself.operating else { return }
+                    sself.sockets.insert(socket)
+                    sself.handleConnection(socket)
+                    sself.sockets.remove(socket)
                 })
             }
-            self.stop()
-            self.running = false
+            sself.stop()
         }
+        self.state = .Running
     }
     
     public func stop() {
+        guard self.operating else { return }
+        self.state = .Stopping
         // Shutdown connected peers because they can live in 'keep-alive' or 'websocket' loops.
         for socket in self.sockets {
             socket.shutdwn()
         }
         self.sockets.removeAll(keepCapacity: true)
         socket.release()
-        self.running = false
+        self.state = .Stopped
     }
     
     public func dispatch(request: HttpRequest) -> ([String: String], HttpRequest -> HttpResponse) {
@@ -63,7 +70,7 @@ public class HttpServerIO {
     
     private func handleConnection(socket: Socket) {
         let parser = HttpParser()
-        while let request = try? parser.readHttpRequest(socket) {
+        while self.operating, let request = try? parser.readHttpRequest(socket) {
             let request = request
             request.address = try? socket.peername()
             let (params, handler) = self.dispatch(request)
@@ -71,7 +78,9 @@ public class HttpServerIO {
             let response = handler(request)
             var keepConnection = parser.supportsKeepAlive(request.headers)
             do {
-                keepConnection = try self.respond(socket, response: response, keepAlive: keepConnection)
+                if self.operating {
+                    keepConnection = try self.respond(socket, response: response, keepAlive: keepConnection)
+                }
             } catch {
                 print("Failed to send response: \(error)")
                 break
@@ -103,6 +112,8 @@ public class HttpServerIO {
     }
     
     private func respond(socket: Socket, response: HttpResponse, keepAlive: Bool) throws -> Bool {
+        guard self.operating else { return false }
+
         try socket.writeUTF8("HTTP/1.1 \(response.statusCode()) \(response.reasonPhrase())\r\n")
         
         let content = response.content()
@@ -130,8 +141,15 @@ public class HttpServerIO {
     }
 }
 
-#if os(Linux)
+public enum HttpServerIOState: Int{
+    case Starting
+    case Running
+    case Stopping
+    case Stopped
+}
 
+#if os(Linux)
+    
 let DISPATCH_QUEUE_PRIORITY_BACKGROUND = 0
 
 private class dispatch_context {