<commit_before>//
//  Server.swift
//  TvOSConnectivity
//
//  Created by <NAME> on 5/12/16.
//
//

import Foundation

@objc protocol ServerDelegate {
    optional func server(server: Server, didReceiveMessage message: [String : AnyObject])
    optional func server(server: Server, didReceiveTextMessage text: String)
    optional func server(server: Server, didReceiveMessageData messageData: NSData)
    optional func server(server: Server, didPublishService service: NSNetService)
    optional func server(server: Server, didAcceptNewUser socket: GCDAsyncSocket)
    optional func server(server: Server, didDisconnectedUser socket: GCDAsyncSocket, withError err: NSError!)
}

class Server: NSObject, NSNetServiceDelegate, NSNetServiceBrowserDelegate, GCDAsyncSocketDelegate {
    
    //TODO: check if we can use timeout different of -1.0
    //TODO: implement header
    //TODO: test p2p btw sockets
    
    var delegate: ServerDelegate?
    private(set) var service: NSNetService?
    private(set) var socket: GCDAsyncSocket?
    private(set) var connectedSockets : [GCDAsyncSocket]?
    
    func startService(name: String, onPort port: UInt16, inDomain domain: String = "local.") {
        self.socket = GCDAsyncSocket(delegate: self, delegateQueue: dispatch_get_main_queue())
        do {
            try self.socket?.acceptOnPort(port)
            self.service = NSNetService(domain: domain, type: "_\(name)._tcp.", name: name, port: Int32(port))
            self.service?.delegate = self
            self.service?.publish()
            self.connectedSockets = []
            self.delegate?.server?(self, didPublishService: self.service!)
        } catch let error as NSError {
            print("Failed to create server socket. Error \(error)")
        }
    }
    
    func stopService() {
        self.service?.stop()
        self.socket?.disconnect()
        self.connectedSockets?.removeAll()
        
        self.service = nil
        self.socket = nil
        self.connectedSockets = nil
    }
    
    func send(clientSocket: GCDAsyncSocket, messageData: NSData) {
        clientSocket.writeData(messageData, withTimeout: -1.0, tag: 0)
    }
    func send(clientSocket: GCDAsyncSocket, message: [String : AnyObject]) {
        if let data:NSData = NSKeyedArchiver.archivedDataWithRootObject(message) {
            send(clientSocket, messageData: data)
        }
    }
    func send(clientSocket: GCDAsyncSocket, textMessage: String) {
        if let data = textMessage.dataUsingEncoding(NSUTF8StringEncoding) {
            send(clientSocket, messageData: data)
        }
    }
    
    func broadcastData(messageData: NSData) {
        for client in connectedSockets! {
            send(client, messageData: messageData)
        }
    }
    func broadcast(message: [String : AnyObject]) {
        if let data:NSData = NSKeyedArchiver.archivedDataWithRootObject(message) {
            broadcastData(data)
        }
    }
    func broadcastText(textMessage: String) {
        if let data = textMessage.dataUsingEncoding(NSUTF8StringEncoding) {
            broadcastData(data)
        }
    }
    
    func netServiceDidPublish(sender: NSNetService) {
        print("Service published: domain: \(sender.domain) type: \(sender.type) name: \(sender.name) hostName: \(sender.hostName)  port: \(sender.port)")
    }
    
    func netService(sender: NSNetService, didNotPublish errorDict: [String : NSNumber]) {
        print("Failed to publish service: domain: \(sender.domain) type: \(sender.type) name: \(sender.name) - \(errorDict)")<commit_msg>implemented listen method and improved broadcast methods on Server.swift<commit_after>//
//  Server.swift
//  TvOSConnectivity
//
//  Created by <NAME> on 5/12/16.
//
//

import Foundation

@objc protocol ServerDelegate {
    optional func server(server: Server, didReceiveMessage message: [String : AnyObject])
    optional func server(server: Server, didReceiveTextMessage text: String)
    optional func server(server: Server, didReceiveMessageData messageData: NSData)
    optional func server(server: Server, didStartListenning port: UInt16)
    optional func server(server: Server, didPublishService service: NSNetService)
    optional func server(server: Server, didAcceptNewUser socket: GCDAsyncSocket)
    optional func server(server: Server, didDisconnectedUser socket: GCDAsyncSocket, withError err: NSError!)
}

class Server: NSObject, NSNetServiceDelegate, NSNetServiceBrowserDelegate, GCDAsyncSocketDelegate {
    
    //TODO: check if we can use timeout different of -1.0
    //TODO: implement header messages
    
    var delegate: ServerDelegate?
    private(set) var service: NSNetService?
    private(set) var socket: GCDAsyncSocket?
    private(set) var connectedSockets : [GCDAsyncSocket]?
    
    func listen(onPort port: UInt16) {
        createSocketAndListen(onPort: port)
    }
    
    func startService(name: String, onPort port: UInt16, inDomain domain: String = "local.") {
        createSocketAndListen(onPort: port, name: name, inDomain: domain)
    }
    
    private func createSocketAndListen(onPort port: UInt16, name: String? = nil, inDomain domain: String? = nil) {
        self.socket = GCDAsyncSocket(delegate: self, delegateQueue: dispatch_get_main_queue())
        do {
            try self.socket?.acceptOnPort(port)
            self.delegate?.server?(self, didStartListenning: port)
            self.connectedSockets = []
            if name != nil && domain != nil {
                self.service = NSNetService(domain: domain!, type: "_\(name)._tcp.", name: name!, port: Int32(port))
                self.service?.delegate = self
                self.service?.publish()
                self.delegate?.server?(self, didPublishService: self.service!)
            }
        } catch let error as NSError {
            print("Failed to create server socket. Error \(error)")
        }
    }
    
    func stopService() {
        self.service?.stop()
        self.socket?.disconnect()
        self.connectedSockets?.removeAll()
        
        self.service = nil
        self.socket = nil
        self.connectedSockets = nil
    }
    
    func send(clientSocket: GCDAsyncSocket, messageData: NSData, withTimeout timeout: NSTimeInterval = -1.0) {
        clientSocket.writeData(messageData, withTimeout: timeout, tag: 0)
    }
    func send(clientSocket: GCDAsyncSocket, message: [String : AnyObject], withTimeout timeout: NSTimeInterval = -1.0) {
        if let data:NSData = NSKeyedArchiver.archivedDataWithRootObject(message) {
            send(clientSocket, messageData: data, withTimeout: timeout)
        }
    }
    func send(clientSocket: GCDAsyncSocket, textMessage: String, withTimeout timeout: NSTimeInterval = -1.0) {
        if let data = textMessage.dataUsingEncoding(NSUTF8StringEncoding) {
            send(clientSocket, messageData: data, withTimeout: timeout)
        }
    }
    
    func broadcast(messageData messageData: NSData, withTimeout timeout: NSTimeInterval = -1.0) {
        for client in connectedSockets! {
            send(client, messageData: messageData, withTimeout: timeout)
        }
    }
    func broadcast(message message: [String : AnyObject], withTimeout timeout: NSTimeInterval = -1.0) {
        if let data:NSData = NSKeyedArchiver.archivedDataWithRootObject(message) {
            broadcast(messageData: data, withTimeout: timeout)
        }
    }
    func broadcast(textMessage textMessage: String, withTimeout timeout: NSTimeInterval = -1.0) {
        if let data = textMessage.dataUsingEncoding(NSUTF8StringEncoding) {
            broadcast(messageData: data, withTimeout: timeout)
        }
    }
    
    func netServiceDidPublish(sender: NSNetService) {
        print("Service published: domain: \(sender.domain) type: \(sender.type) name: \(sender.name) hostName: \(sender.hostName)  port: \(sender.port)")
    }
    
    func netService(sender: NSNetService, didNotPublish errorDict: [String : NSNumber]) {
        print("Failed to publish service: domain: \(sender.domain) type: \(sender.type) name: \(sender.name) - \(errorDict)")
{'fraction_non_alphanumeric': 0.10127364906640286, 'fraction_numerical': 0.006059107209101027, 'mean_word_length': 3.0339152119700747, 'pattern_counts': {'":': 0, '<': 5, '<?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': '4987555', 'n_tokens_mistral': 2290, 'n_tokens_neox': 2261, 'n_words': 581}