Subversion Repositories Mobile Apps.GyroMouse

Rev

Rev 1 | Details | Compare with Previous | 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
 
13
class ClientHandler: NSObject, NetServiceDelegate, NetServiceBrowserDelegate, GCDAsyncSocketDelegate {
14
 
15
    private var socket: GCDAsyncSocket?
16
    private var serviceBrowser: NetServiceBrowser?
17
 
18
    private(set) var services = [NetService]()
19
 
20
    deinit {
21
        socket?.setDelegate(nil, delegateQueue: nil)
22
        socket = nil
23
 
24
        serviceBrowser?.delegate = nil
25
        serviceBrowser = nil
26
    }
27
 
28
    //MARK: - Publics
29
 
30
    func startBrowsing() {
31
 
32
        services = []
33
 
34
        // Initialize Service Browser
35
        serviceBrowser = NetServiceBrowser()
36
 
37
        // Configure Service Browser
38
        serviceBrowser!.delegate = self
39
        serviceBrowser!.searchForServices(ofType: "_gyroserver._tcp.", inDomain:"local.")
40
    }
41
 
42
    func stopBrowsing() {
43
        serviceBrowser?.stop()
44
        serviceBrowser?.delegate = nil
45
        serviceBrowser = nil
46
        services.removeAll()
47
    }
48
 
49
    func connectToLocalService(_ service: NetService) {
50
 
51
        // Resolve Service
52
        service.delegate = self
53
        service.resolve(withTimeout: 30)
54
    }
55
 
7 pmbaty 56
    func sendPacket(_ type: String, keyTapped: String, isButtonDown: Bool, isRightButton: Bool, roll: Double, scrollVelocity: Double, grav: (X: Double, Y: Double, Z: Double), rotat: (X: Double, Z: Double), acc: (X: Double, Y: Double, Z: Double), moveVelocity: Double) {
1 pmbaty 57
        let buffer = NSMutableData()
7 pmbaty 58
        var int32var: Int32
59
        var uint32var: UInt32
60
        var boolvar: Bool
61
        var doublevar: Double
62
        int32var = 1; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // protocol version
63
        if (type == "key") { // key tapped
64
            if (keyTapped.isEmpty) { return } // consistency check: happens when we hit a backspace
65
            int32var = 1; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // "key" packet type
66
            uint32var = keyTapped.unicodeScalars.first!.value; buffer.append(&uint32var, length: MemoryLayout<UInt32>.size)
67
        }
68
        else if (type == "backspace") { // backspace tapped
69
            int32var = 2; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // "backspace" packet type
70
            // nothing to add
71
        }
72
        else if (type == "enter") { // enter tapped
73
            int32var = 3; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // "enter" packet type
74
            // nothing to add
75
        }
76
        else if (type == "click") { // click
77
            int32var = 4; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // "click" packet type
78
            boolvar = isRightButton; buffer.append(&boolvar, length: MemoryLayout<Bool>.size)
79
            boolvar = isButtonDown;  buffer.append(&boolvar, length: MemoryLayout<Bool>.size)
80
        }
81
        else if (type == "scroll") { // page scroll
82
            int32var = 5; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // "scroll" packet type
83
            doublevar = roll;           buffer.append(&doublevar, length: MemoryLayout<Double>.size)
84
            doublevar = scrollVelocity; buffer.append(&doublevar, length: MemoryLayout<Double>.size)
85
        }
86
        else if (type == "move") { // movement
87
            int32var = 6; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // "move" packet type
88
            doublevar = grav.X;       buffer.append(&doublevar, length: MemoryLayout<Double>.size)
89
            doublevar = grav.Y;       buffer.append(&doublevar, length: MemoryLayout<Double>.size)
90
            doublevar = grav.Z;       buffer.append(&doublevar, length: MemoryLayout<Double>.size)
91
            doublevar = rotat.X;      buffer.append(&doublevar, length: MemoryLayout<Double>.size)
92
            doublevar = rotat.Z;      buffer.append(&doublevar, length: MemoryLayout<Double>.size)
93
            doublevar = acc.X;        buffer.append(&doublevar, length: MemoryLayout<Double>.size)
94
            doublevar = acc.Y;        buffer.append(&doublevar, length: MemoryLayout<Double>.size)
95
            doublevar = acc.Z;        buffer.append(&doublevar, length: MemoryLayout<Double>.size)
96
            doublevar = moveVelocity; buffer.append(&doublevar, length: MemoryLayout<Double>.size)
97
        }
98
        else if (type == "reset") { // reset pointer
99
            int32var = 7; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // "click" packet type
100
            // nothing to add
101
        }
1 pmbaty 102
 
103
        // Write Buffer
7 pmbaty 104
        let bufferData = buffer as Data
105
        print ("Sending \(bufferData.count) bytes packet:", terminator: "")
106
        for i in 0...(bufferData.count - 1) {
107
            let byte: UInt8 = bufferData.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: i * MemoryLayout<UInt8>.size, as: UInt8.self) }
108
            print (" " + String(format: "%02X", byte), terminator: "")
109
        }
110
        print ("")
111
        socket?.write(bufferData, withTimeout: -1, tag: 0)
1 pmbaty 112
    }
113
 
114
    func endConnection() {
115
        socket?.disconnect()
116
        socket?.setDelegate(nil, delegateQueue: nil)
117
        socket = nil
118
    }
119
 
120
    //MARK: - NSNetServiceBrowserDelegate
121
 
122
    func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
123
        // Update Services
124
        services.append(service)
125
 
126
        if !moreComing {
7 pmbaty 127
            NotificationCenter.default.post(Notification(name: GyroMouseShouldRefreshServerListNotification, object: self, userInfo: nil))
1 pmbaty 128
        }
129
    }
130
 
131
    func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool) {
132
        // Update Services
133
        services.remove(at: services.firstIndex(of: service)!)
134
 
135
        if !moreComing {
7 pmbaty 136
            NotificationCenter.default.post(Notification(name: GyroMouseShouldRefreshServerListNotification, object: self, userInfo: nil))
1 pmbaty 137
        }
138
    }
139
 
140
    func netServiceBrowserDidStopSearch(_ browser: NetServiceBrowser) {
141
        stopBrowsing()
142
    }
143
 
144
    func netServiceBrowser(_ browser: NetServiceBrowser, didNotSearch errorDict: [String : NSNumber]) {
145
        stopBrowsing()
146
    }
147
 
148
    //MARK: - NSNetServiceDelegate
149
 
150
    func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber]) {
151
        sender.delegate = nil
152
    }
153
 
154
    func netServiceDidResolveAddress(_ sender: NetService) {
155
        // Connect With Service
7 pmbaty 156
        var isConnected = false
157
 
158
        if ((socket == nil) || (socket?.isDisconnected ?? false)) {
159
            // Initialize Socket
160
            socket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main)
161
 
162
            // Connect
163
            while (!isConnected && (sender.addresses!.count != 0)) {
164
                do {
165
                    try socket!.connect(toAddress: sender.addresses!.first!)
166
                    isConnected = true
167
                } catch {
168
                    isConnected = false
169
                    print("Unable to connect to address. Error \(error) with user info \(error.localizedDescription).", terminator: "\n")
170
                }
171
            }
172
        } else {
173
            isConnected = socket?.isConnected ?? false
174
        }
175
 
176
        if (isConnected) {
1 pmbaty 177
            print("Did Connect with Service: domain(\(sender.domain)) type(\(sender.type)) name(\(sender.name)) port(\(sender.port))", terminator: "\n")
178
        } else {
179
            print("Unable to Connect with Service: domain(\(sender.domain)) type(\(sender.type)) name(\(sender.name)) port(\(sender.port))", terminator: "\n")
7 pmbaty 180
            NotificationCenter.default.post(Notification(name: GyroMouseConnectionFailedNotification, object: self, userInfo: nil))
1 pmbaty 181
        }
182
    }
183
 
184
    //MARK: - GCDAsyncSocketDelegate
185
 
186
    func socket(_ sock: GCDAsyncSocket, didConnectToHost host: String, port: UInt16) {
187
        print("Socket Did Connect to Host: \(host) Port: \(port)", terminator: "\n")
188
 
189
        stopBrowsing()
7 pmbaty 190
        NotificationCenter.default.post(Notification(name: GyroMouseConnectionSuccessNotification, object: self, userInfo: nil))
1 pmbaty 191
    }
192
 
193
    func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Error?) {
194
        socket?.delegate = nil
195
        socket = nil
196
 
197
        startBrowsing()
7 pmbaty 198
        NotificationCenter.default.post(Notification(name: GyroMouseDisconnectedNotification, object: self, userInfo: nil))
1 pmbaty 199
 
200
        if err != nil {
201
            print("Socket Did Disconnect with Error \(err!) with user info \(err!.localizedDescription).", terminator: "\n")
7 pmbaty 202
            //NotificationCenter.default.post(Notification(name: GyroMouseConnectionFailedNotification, object: self, userInfo: nil))
1 pmbaty 203
        } else {
204
            print("Socket Did Disconnect", terminator: "\n")
205
        }
206
    }
207
 
208
}