<commit_before>import Socket
import Foundation
import KituraNet
import func Evergreen.getLogger

#if os(Linux)
    import Dispatch
    import NetService
#endif

fileprivate let logger = getLogger("hap")


public class Server: NSObject, NetServiceDelegate {
    public class Connection: NSObject {
        var context = [String: Any]()
        func listen(socket: Socket, queue: DispatchQueue, application: @escaping Application) {
            let httpParser = HTTPParser(isRequest: true)
            var cryptographer: Cryptographer? = nil
            let request = HTTPServerRequest(socket: socket, httpParser: httpParser)
            let dateFormatter = { () -> DateFormatter in
                let f = DateFormatter()
                f.timeZone = TimeZone(identifier: "GMT")
                f.dateFormat = "EEE',' dd MMM yyyy HH':'mm':'ss zzz"
                f.locale = Locale(identifier: "en_US")
                return f
            }()
            queue.async {
                while !socket.remoteConnectionClosed {
                    var readBuffer = Data()
                    _ = try! socket.read(into: &readBuffer)
                    if let cryptographer = cryptographer {
                        readBuffer = try! cryptographer.decrypt(readBuffer)
                    }
                    _ = readBuffer.withUnsafeBytes {
                        httpParser.execute($0, length: readBuffer.count)
                    }

                    guard httpParser.completed else {
                        break
                    }

                    request.parsingCompleted()
                    var response: Response! = nil
                    DispatchQueue.main.sync {
                        response = application(self, request)
                    }
                    response?.headers["Date"] = dateFormatter.string(from: Date())

                    var writeBuffer = response.serialized()
                    if let cryptographer = cryptographer {
                        writeBuffer = try! cryptographer.encrypt(writeBuffer)
                    }
                    if let response = response as? UpgradeResponse {
                        cryptographer = response.cryptographer
                        // todo?: override response
                    }
                    try! socket.write(from: writeBuffer)
                    httpParser.reset()
                }
                socket.close()
            }
        }
    }
    
    
    let service: NetService
    let socket: Socket
    let queue = DispatchQueue(label: "hap.socket-listener", qos: .utility, attributes: [.concurrent])
    let application: Application

    public init(device: Device, port: Int = 0) throws {
        application = root(device: device)

        socket = try Socket.create(family: .inet, type: .stream, proto: .tcp)
        try socket.listen(on: port)

        service = NetService(domain: "local.", type: "_hap._tcp.", name: device.name, port: socket.listeningPort)
        #if os(macOS)
            let record = device.config.dictionary(key: { $0.key }, value: { $0.value.data(using: .utf8)! })
            service.setTXTRecord(NetService.data(fromTXTRecord: record))
        #elseif os(Linux)
            service.setTXTRecord(device.config)
        #endif

        super.init()
        service.delegate = self
    }
    
    public func start() {
        service.publish()
        logger.info("Listening on port \(self.socket.listeningPort)")
        
        queue.async {
            while self.socket.isListening {
                let client = try! self.socket.acceptClientConnection()
                DispatchQueue.main.async {
                    _ = Connection().listen(socket: client, queue: self.queue, application: self.application)
                }
            }
        }
        
    }
    
    public func stop() {
        service.stop()
        socket.close()
    }
    
    
    #if os(macOS)
        // MARK: Using Network Services
        public func netService(_ sender: NetService, didNotPublish errorDict: [String : NSNumber]) {
            logger.error("didNotPublish: \(errorDict)")
        }
    #elseif os(Linux)
        // MARK: Using Network Services<commit_msg>Log connect / disconnect<commit_after>import Socket
import Foundation
import KituraNet
import func Evergreen.getLogger

#if os(Linux)
    import Dispatch
    import NetService
#endif

fileprivate let logger = getLogger("hap.http")


public class Server: NSObject, NetServiceDelegate {
    public class Connection: NSObject {
        var context = [String: Any]()
        var socket: Socket?
        func listen(socket: Socket, queue: DispatchQueue, application: @escaping Application) {
            self.socket = socket
            let httpParser = HTTPParser(isRequest: true)
            var cryptographer: Cryptographer? = nil
            let request = HTTPServerRequest(socket: socket, httpParser: httpParser)
            let dateFormatter = { () -> DateFormatter in
                let f = DateFormatter()
                f.timeZone = TimeZone(identifier: "GMT")
                f.dateFormat = "EEE',' dd MMM yyyy HH':'mm':'ss zzz"
                f.locale = Locale(identifier: "en_US")
                return f
            }()
            queue.async {
                while !socket.remoteConnectionClosed {
                    var readBuffer = Data()
                    _ = try! socket.read(into: &readBuffer)
                    if let cryptographer = cryptographer {
                        readBuffer = try! cryptographer.decrypt(readBuffer)
                    }
                    _ = readBuffer.withUnsafeBytes {
                        httpParser.execute($0, length: readBuffer.count)
                    }

                    guard httpParser.completed else {
                        break
                    }

                    request.parsingCompleted()
                    var response: Response! = nil
                    DispatchQueue.main.sync {
                        response = application(self, request)
                    }
                    response?.headers["Date"] = dateFormatter.string(from: Date())

                    var writeBuffer = response.serialized()
                    if let cryptographer = cryptographer {
                        writeBuffer = try! cryptographer.encrypt(writeBuffer)
                    }
                    if let response = response as? UpgradeResponse {
                        cryptographer = response.cryptographer
                        // todo?: override response
                    }
                    try! socket.write(from: writeBuffer)
                    httpParser.reset()
                }
                logger.debug("Closed connection to \(socket.remoteHostname)")
                socket.close()
                self.socket = nil
            }
        }
    }
    
    
    let service: NetService
    let socket: Socket
    let queue = DispatchQueue(label: "hap.socket-listener", qos: .utility, attributes: [.concurrent])
    let application: Application

    public init(device: Device, port: Int = 0) throws {
        application = root(device: device)

        socket = try Socket.create(family: .inet, type: .stream, proto: .tcp)
        try socket.listen(on: port)

        service = NetService(domain: "local.", type: "_hap._tcp.", name: device.name, port: socket.listeningPort)
        #if os(macOS)
            let record = device.config.dictionary(key: { $0.key }, value: { $0.value.data(using: .utf8)! })
            service.setTXTRecord(NetService.data(fromTXTRecord: record))
        #elseif os(Linux)
            service.setTXTRecord(device.config)
        #endif

        super.init()
        service.delegate = self
    }
    
    public func start() {
        service.publish()
        logger.info("Listening on port \(self.socket.listeningPort)")
        
        queue.async {
            while self.socket.isListening {
                let client = try! self.socket.acceptClientConnection()
                logger.info("Accepted connection from \(client.remoteHostname)")
                DispatchQueue.main.async {
                    _ = Connection().listen(socket: client, queue: self.queue, application: self.application)
                }
            }
        }
        
    }
    
    public func stop() {
        service.stop()
        socket.close()
    }
    
    
    #if os(macOS)
        // MARK: Using Network Services
        public func netService(_ sender: NetService, didNotPublish errorDict: [String : NSNumber]) {
            logger.error("didNotPublish: \(errorDict)")
        }
    #elseif os(Linux)
        // MARK: Using Network Services
{'fraction_non_alphanumeric': 0.09174734900875979, 'fraction_numerical': 0.001152604887044721, 'mean_word_length': 1.5847482871611558, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2206499', 'n_tokens_mistral': 2226, 'n_tokens_neox': 2098, 'n_words': 524}