Subversion Repositories Mobile Apps.GyroMouse

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
//
2
//  ClientHandler.swift
3
//  GyroMouse
4
//
5
//  Created by Matteo Riva on 28/08/15.
6
//  Copyright © 2015 Matteo Riva. All rights reserved.
7
//
8
 
9
import Foundation
10
import CocoaAsyncSocket
11
 
12
let ServerDiscoveredServicesDidChangeNotification = Notification.Name("ServerDiscoveredServicesDidChangeNotification")
13
let ClientDidCompleteLocalConnectionNotification = Notification.Name("ClientDidCompleteLocalConnectionNotification")
14
let ClientDidFailLocalConnectionNotification = Notification.Name("ClientDidFailLocalConnectionNotification")
15
let ClientDidDisconnectNotification = Notification.Name("ClientDidDisconnectNotification")
16
 
17
class ClientHandler: NSObject, NetServiceDelegate, NetServiceBrowserDelegate, GCDAsyncSocketDelegate {
18
 
19
    private var socket: GCDAsyncSocket?
20
    private var serviceBrowser: NetServiceBrowser?
21
 
22
    private(set) var services = [NetService]()
23
 
24
    deinit {
25
        socket?.setDelegate(nil, delegateQueue: nil)
26
        socket = nil
27
 
28
        serviceBrowser?.delegate = nil
29
        serviceBrowser = nil
30
    }
31
 
32
    //MARK: - Privates
33
 
34
    private func sendNotificationWithName(_ name: Notification.Name, userInfo: [String : Any]?) {
35
        let center = NotificationCenter.default
36
        let notif = Notification(name: name, object: self, userInfo: userInfo)
37
        center.post(notif)
38
    }
39
 
40
    private func connectWithService(_ service: NetService) -> Bool {
41
        var isConnected = false
42
 
43
        // Copy Service Addresses
44
        let addresses = service.addresses!
45
 
46
        if socket == nil || socket?.isDisconnected ?? false {
47
            // Initialize Socket
48
            socket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main)
49
 
50
            // Connect
51
            while !isConnected && addresses.count != 0 {
52
                let address = addresses.first!
53
 
54
                do {
55
                    try socket!.connect(toAddress: address)
56
                    isConnected = true
57
                } catch {
58
                    isConnected = false
59
                    print("Unable to connect to address. Error \(error) with user info \(error.localizedDescription).", terminator: "\n")
60
                }
61
            }
62
 
63
        } else {
64
            isConnected = socket?.isConnected ?? false
65
        }
66
 
67
        return isConnected
68
    }
69
 
70
    //MARK: - Publics
71
 
72
    func startBrowsing() {
73
 
74
        services = []
75
 
76
        // Initialize Service Browser
77
        serviceBrowser = NetServiceBrowser()
78
 
79
        // Configure Service Browser
80
        serviceBrowser!.delegate = self
81
        serviceBrowser!.searchForServices(ofType: "_gyroserver._tcp.", inDomain:"local.")
82
    }
83
 
84
    func stopBrowsing() {
85
        serviceBrowser?.stop()
86
        serviceBrowser?.delegate = nil
87
        serviceBrowser = nil
88
        services.removeAll()
89
    }
90
 
91
    func connectToLocalService(_ service: NetService) {
92
 
93
        // Resolve Service
94
        service.delegate = self
95
        service.resolve(withTimeout: 30)
96
 
97
    }
98
 
99
    func sendPacket(_ packet: GyroPacket) {
100
        // Encode Packet Data
101
        let packetData = NSMutableData()
102
        let archiver = NSKeyedArchiver(forWritingWith: packetData)
103
        archiver.encode(packet, forKey: "packet")
104
        archiver.finishEncoding()
105
 
106
        // Initialize Buffer
107
        let buffer = NSMutableData()
108
 
109
        // Fill Buffer
110
        var headerLength = UInt64(packetData.length)
111
        buffer.append(&headerLength, length: MemoryLayout<UInt64>.size)
112
        buffer.append(packetData.bytes, length: packetData.length)
113
 
114
        // Write Buffer
115
        socket?.write(buffer as Data, withTimeout: -1, tag: 0)
116
    }
117
 
118
    func endConnection() {
119
        socket?.disconnect()
120
        socket?.setDelegate(nil, delegateQueue: nil)
121
        socket = nil
122
    }
123
 
124
    //MARK: - NSNetServiceBrowserDelegate
125
 
126
    func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
127
        // Update Services
128
        services.append(service)
129
 
130
        if !moreComing {
131
            sendNotificationWithName(ServerDiscoveredServicesDidChangeNotification, userInfo: nil)
132
        }
133
    }
134
 
135
    func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool) {
136
        // Update Services
137
        services.remove(at: services.firstIndex(of: service)!)
138
 
139
        if !moreComing {
140
            sendNotificationWithName(ServerDiscoveredServicesDidChangeNotification, userInfo: nil)
141
        }
142
    }
143
 
144
    func netServiceBrowserDidStopSearch(_ browser: NetServiceBrowser) {
145
        stopBrowsing()
146
    }
147
 
148
    func netServiceBrowser(_ browser: NetServiceBrowser, didNotSearch errorDict: [String : NSNumber]) {
149
        stopBrowsing()
150
    }
151
 
152
    //MARK: - NSNetServiceDelegate
153
 
154
    func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber]) {
155
        sender.delegate = nil
156
    }
157
 
158
    func netServiceDidResolveAddress(_ sender: NetService) {
159
        // Connect With Service
160
        if connectWithService(sender) {
161
            print("Did Connect with Service: domain(\(sender.domain)) type(\(sender.type)) name(\(sender.name)) port(\(sender.port))", terminator: "\n")
162
        } else {
163
            print("Unable to Connect with Service: domain(\(sender.domain)) type(\(sender.type)) name(\(sender.name)) port(\(sender.port))", terminator: "\n")
164
            sendNotificationWithName(ClientDidFailLocalConnectionNotification, userInfo: nil)
165
        }
166
    }
167
 
168
    //MARK: - GCDAsyncSocketDelegate
169
 
170
    func socket(_ sock: GCDAsyncSocket, didConnectToHost host: String, port: UInt16) {
171
        print("Socket Did Connect to Host: \(host) Port: \(port)", terminator: "\n")
172
 
173
        // Start Reading
174
        sock.readData(toLength: UInt(MemoryLayout<UInt64>.size), withTimeout: -1, tag: 0)
175
 
176
        stopBrowsing()
177
        sendNotificationWithName(ClientDidCompleteLocalConnectionNotification, userInfo: nil)
178
    }
179
 
180
    func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Error?) {
181
        socket?.delegate = nil
182
        socket = nil
183
 
184
        startBrowsing()
185
        sendNotificationWithName(ClientDidDisconnectNotification, userInfo: nil)
186
 
187
        if err != nil {
188
            print("Socket Did Disconnect with Error \(err!) with user info \(err!.localizedDescription).", terminator: "\n")
189
            sendNotificationWithName(ClientDidFailLocalConnectionNotification, userInfo: nil)
190
        } else {
191
            print("Socket Did Disconnect", terminator: "\n")
192
        }
193
    }
194
 
195
}