Rev 5 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | pmbaty | 1 | // |
2 | // ServerHandler.swift |
||
3 | // GyroMouse |
||
4 | // |
||
5 | // Created by Matteo Riva on 07/08/15. |
||
6 | // Copyright © 2015 Matteo Riva. All rights reserved. |
||
7 | // |
||
8 | |||
9 | import Cocoa |
||
10 | import CocoaAsyncSocket |
||
11 | |||
12 | let ServerDidConnectNotification = Notification.Name("ServerDidConnectNotification") |
||
13 | let ServerDidDisconnectNotification = Notification.Name("ServerDidDisconnectNotification") |
||
14 | |||
15 | protocol ServerHandlerDelegate: AnyObject { |
||
7 | pmbaty | 16 | func computePointerMovement(grav: (X: Double, Y: Double, Z: Double), rotat: (X: Double, Z: Double), acc: (X: Double, Y: Double, Z: Double), moveVelocity: Double) |
17 | func scrollWithRoll(roll: Double, velocity: Double) |
||
18 | func clickButton(isRightButton: Bool, isButtonDown: Bool) |
||
19 | func resetPointerPosition(moveMouse: Bool) |
||
20 | func runAppleScript(_ scriptText: String) |
||
1 | pmbaty | 21 | } |
22 | |||
23 | class ServerHandler: NSObject, NetServiceDelegate, GCDAsyncSocketDelegate { |
||
24 | |||
25 | weak var delegate: ServerHandlerDelegate? |
||
26 | |||
27 | private var service: NetService? |
||
28 | private var socket: GCDAsyncSocket? |
||
29 | |||
30 | deinit { |
||
31 | delegate = nil |
||
32 | |||
33 | socket?.setDelegate(nil, delegateQueue: nil) |
||
34 | socket = nil |
||
35 | |||
36 | service?.delegate = nil |
||
37 | service = nil |
||
38 | } |
||
39 | |||
40 | //MARK: - Privates |
||
41 | |||
42 | private func sendNotificationWithName(_ name: Notification.Name, userInfo: [String : Any]?) { |
||
43 | let center = NotificationCenter.default |
||
44 | let notif = Notification(name: name, object: self, userInfo: userInfo) |
||
45 | center.post(notif) |
||
46 | } |
||
7 | pmbaty | 47 | |
1 | pmbaty | 48 | //MARK: - Publics |
49 | |||
50 | func endConnection() { |
||
51 | socket?.disconnect() |
||
52 | } |
||
53 | |||
54 | func startBroadcast() { |
||
55 | // Initialize GCDAsyncSocket |
||
56 | socket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main) |
||
57 | |||
58 | // Start Listening for Incoming Connections |
||
59 | do { |
||
60 | try socket!.accept(onPort: 0) |
||
61 | service = NetService(domain: "local.", type: "_gyroserver._tcp.", name: "", port: Int32(socket!.localPort)) |
||
62 | service!.delegate = self |
||
63 | service!.publish() |
||
64 | } catch let error as NSError { |
||
65 | print("Unable to create socket. Error \(error) with user info \(error.userInfo).", terminator: "\n") |
||
66 | } |
||
67 | } |
||
68 | |||
69 | func endBroadcast() { |
||
70 | socket?.setDelegate(nil, delegateQueue: nil) |
||
71 | socket = nil |
||
72 | |||
73 | service?.delegate = nil |
||
74 | service = nil |
||
75 | } |
||
76 | |||
77 | //MARK: - NSNetServiceDelegate |
||
78 | |||
79 | func netServiceDidPublish(_ sender: NetService) { |
||
80 | print("Bonjour Service Published: domain(\(sender.domain)) type(\(sender.type)) name(\(sender.name)) port(\(sender.port))", terminator: "\n") |
||
81 | } |
||
82 | |||
83 | func netService(_ sender: NetService, didNotPublish errorDict: [String : NSNumber]) { |
||
84 | print("Failed to Publish Service: domain(\(sender.domain)) type(\(sender.type)) name(\(sender.name)) port(\(sender.port))", terminator: "\n") |
||
85 | } |
||
86 | |||
87 | //MARK: - GCDAsyncSocketDelegate |
||
88 | |||
89 | func socket(_ sock: GCDAsyncSocket, didAcceptNewSocket newSocket: GCDAsyncSocket) { |
||
90 | print("Accepted New Socket from \(newSocket.connectedHost as Optional):\(newSocket.connectedPort as Optional)", terminator: "\n") |
||
91 | |||
92 | socket = newSocket |
||
93 | |||
7 | pmbaty | 94 | // read first packet header from socket |
95 | newSocket.readData(toLength: UInt(2 * MemoryLayout<Int32>.size), withTimeout: -1, tag: 0) |
||
1 | pmbaty | 96 | |
97 | let notif = NSUserNotification() |
||
98 | notif.title = "connected".localized |
||
99 | notif.informativeText = "connect_with".localized + ":\(socket!.connectedHost as Optional) " + "completed".localized |
||
100 | notif.deliveryDate = Date() |
||
101 | NSUserNotificationCenter.default.scheduleNotification(notif) |
||
102 | NotificationCenter.default.post(name: ServerDidConnectNotification, object: self) |
||
103 | } |
||
104 | |||
105 | func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Error?) { |
||
106 | if socket == sock { |
||
107 | if err != nil { |
||
108 | print("Socket did disconnect with error \(err as Optional)", terminator: "\n") |
||
109 | } else { |
||
110 | print("Socket did disconnect", terminator: "\n") |
||
111 | } |
||
112 | |||
113 | let notif = NSUserNotification() |
||
114 | notif.title = "disconnected".localized |
||
115 | notif.informativeText = "conn_terminated".localized |
||
116 | notif.deliveryDate = Date() |
||
117 | NSUserNotificationCenter.default.scheduleNotification(notif) |
||
118 | |||
119 | NotificationCenter.default.post(name: ServerDidDisconnectNotification, object: self) |
||
120 | |||
121 | endBroadcast() |
||
122 | startBroadcast() |
||
123 | |||
124 | } |
||
125 | } |
||
126 | |||
127 | func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int) { |
||
7 | pmbaty | 128 | var expectedByteCount = -1 |
129 | var expectedNextTag = -1 |
||
130 | |||
131 | if (tag == 0) { // read packet header |
||
132 | let protocolVersion = Int(data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<Int32>.size, as: Int32.self) }) |
||
133 | if (protocolVersion == 1) { |
||
134 | expectedNextTag = Int(data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 1 * MemoryLayout<Int32>.size, as: Int32.self) }) |
||
135 | if (expectedNextTag == 1) { expectedByteCount = 1 * MemoryLayout<UInt32>.size } // "key" packet type requires 1 uint32 |
||
136 | else if (expectedNextTag == 2) { expectedByteCount = 0 } // "backspace" packet type has no payload |
||
137 | else if (expectedNextTag == 3) { expectedByteCount = 0 }// "enter" packet type has no payload |
||
138 | else if (expectedNextTag == 4) { expectedByteCount = 2 * MemoryLayout<Bool>.size } // "click" packet type requires 2 booleans |
||
139 | else if (expectedNextTag == 5) { expectedByteCount = 2 * MemoryLayout<Double>.size } // "scroll" packet type requires 2 doubles |
||
140 | else if (expectedNextTag == 6) { expectedByteCount = 9 * MemoryLayout<Double>.size } // "move" packet type requires 9 doubles |
||
141 | else if (expectedNextTag == 7) { expectedByteCount = 0 } // "reset" packet type has no payload |
||
142 | } |
||
1 | pmbaty | 143 | } |
7 | pmbaty | 144 | else if (tag == 1) { // read "key" packet payload |
145 | var key: String = "" |
||
146 | let unicodeScalarValue: UInt32 = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<UInt32>.size, as: UInt32.self) } |
||
147 | let unicodeScalar = UnicodeScalar(unicodeScalarValue) |
||
148 | if (unicodeScalar != nil) { |
||
149 | key.append(Character(unicodeScalar!)) |
||
150 | delegate?.runAppleScript("tell app \"System Events\" to keystroke \"" + key + "\"") |
||
151 | } |
||
152 | expectedNextTag = 0 // prepare to read the next packet header |
||
153 | expectedByteCount = 2 * MemoryLayout<Int32>.size |
||
154 | } |
||
155 | else if (tag == 2) { // read "backspace" packet payload |
||
156 | delegate?.runAppleScript("tell app \"System Events\" to key code 51") |
||
157 | expectedNextTag = 0 // prepare to read the next packet header |
||
158 | expectedByteCount = 2 * MemoryLayout<Int32>.size |
||
159 | } |
||
160 | else if (tag == 3) { // read "enter" packet payload |
||
161 | delegate?.runAppleScript("tell app \"System Events\" to keystroke return") |
||
162 | expectedNextTag = 0 // prepare to read the next packet header |
||
163 | expectedByteCount = 2 * MemoryLayout<Int32>.size |
||
164 | } |
||
165 | else if (tag == 4) { // read "click" packet payload |
||
166 | let isRightButton = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<Bool>.size, as: Bool.self) } |
||
167 | let isButtonDown = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 1 * MemoryLayout<Bool>.size, as: Bool.self) } |
||
168 | delegate?.clickButton(isRightButton: isRightButton, isButtonDown: isButtonDown) |
||
169 | expectedNextTag = 0 // prepare to read the next packet header |
||
170 | expectedByteCount = 2 * MemoryLayout<Int32>.size |
||
171 | } |
||
172 | else if (tag == 5) { // read "scroll" packet payload |
||
173 | let roll = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<Double>.size, as: Double.self) } |
||
174 | let scrollVelocity = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 1 * MemoryLayout<Double>.size, as: Double.self) } |
||
175 | delegate?.scrollWithRoll(roll: roll, velocity: scrollVelocity) |
||
176 | expectedNextTag = 0 // prepare to read the next packet header |
||
177 | expectedByteCount = 2 * MemoryLayout<Int32>.size |
||
178 | } |
||
179 | else if (tag == 6) { // read "move" packet payload |
||
180 | let gravX = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<Double>.size, as: Double.self) } |
||
181 | let gravY = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 1 * MemoryLayout<Double>.size, as: Double.self) } |
||
182 | let gravZ = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 2 * MemoryLayout<Double>.size, as: Double.self) } |
||
183 | let rotatX = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 3 * MemoryLayout<Double>.size, as: Double.self) } |
||
184 | let rotatZ = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 4 * MemoryLayout<Double>.size, as: Double.self) } |
||
185 | let accX = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 5 * MemoryLayout<Double>.size, as: Double.self) } |
||
186 | let accY = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 6 * MemoryLayout<Double>.size, as: Double.self) } |
||
187 | let accZ = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 7 * MemoryLayout<Double>.size, as: Double.self) } |
||
188 | let moveVelocity = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 8 * MemoryLayout<Double>.size, as: Double.self) } |
||
189 | delegate?.computePointerMovement(grav: (X: gravX, Y: gravY, Z: gravZ), rotat: (X: rotatX, Z: rotatZ), acc: (X: accX, Y: accY, Z: accZ), moveVelocity: moveVelocity) |
||
190 | expectedNextTag = 0 // prepare to read the next packet header |
||
191 | expectedByteCount = 2 * MemoryLayout<Int32>.size |
||
192 | } |
||
193 | else if (tag == 7) { // read "reset" packet payload |
||
194 | delegate?.resetPointerPosition(moveMouse: true) |
||
195 | expectedNextTag = 0 // prepare to read the next packet header |
||
196 | expectedByteCount = 2 * MemoryLayout<Int32>.size |
||
197 | } |
||
198 | |||
199 | // do we know what to read next ? |
||
200 | if (expectedByteCount == -1) { |
||
201 | endConnection() |
||
202 | let alert = NSAlert() |
||
203 | alert.addButton(withTitle: "OK") |
||
204 | alert.messageText = "vers_incomp".localized |
||
205 | alert.informativeText = "incomp_message".localized |
||
206 | alert.alertStyle = .warning |
||
207 | alert.runModal() |
||
208 | } |
||
209 | else if (expectedByteCount == 0) { |
||
210 | socket(sock, didRead: Data(), withTag: expectedNextTag) // no payload, so chain-call ourselves to process the packet directly |
||
211 | } |
||
212 | else { |
||
213 | sock.readData(toLength: UInt(expectedByteCount), withTimeout: -1, tag: expectedNextTag) // read some bytes |
||
214 | } |
||
1 | pmbaty | 215 | } |
216 | } |