Rev 5 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
//
// ServerHandler.swift
// GyroMouse
//
// Created by Matteo Riva on 07/08/15.
// Copyright © 2015 Matteo Riva. All rights reserved.
//
import Cocoa
import CocoaAsyncSocket
let ServerDidConnectNotification = Notification.Name("ServerDidConnectNotification")
let ServerDidDisconnectNotification = Notification.Name("ServerDidDisconnectNotification")
protocol ServerHandlerDelegate: AnyObject {
func computePointerMovement(grav: (X: Double, Y: Double, Z: Double), rotat: (X: Double, Z: Double), acc: (X: Double, Y: Double, Z: Double), moveVelocity: Double)
func scrollWithRoll(roll: Double, velocity: Double)
func clickButton(isRightButton: Bool, isButtonDown: Bool)
func resetPointerPosition(moveMouse: Bool)
func runAppleScript(_ scriptText: String)
}
class ServerHandler: NSObject, NetServiceDelegate, GCDAsyncSocketDelegate {
weak var delegate: ServerHandlerDelegate?
private var service: NetService?
private var socket: GCDAsyncSocket?
deinit {
delegate = nil
socket?.setDelegate(nil, delegateQueue: nil)
socket = nil
service?.delegate = nil
service = nil
}
//MARK: - Privates
private func sendNotificationWithName(_ name: Notification.Name, userInfo: [String : Any]?) {
let center = NotificationCenter.default
let notif = Notification(name: name, object: self, userInfo: userInfo)
center.post(notif)
}
//MARK: - Publics
func endConnection() {
socket?.disconnect()
}
func startBroadcast() {
// Initialize GCDAsyncSocket
socket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main)
// Start Listening for Incoming Connections
do {
try socket!.accept(onPort: 0)
service = NetService(domain: "local.", type: "_gyroserver._tcp.", name: "", port: Int32(socket!.localPort))
service!.delegate = self
service!.publish()
} catch let error as NSError {
print("Unable to create socket. Error \(error) with user info \(error.userInfo).", terminator: "\n")
}
}
func endBroadcast() {
socket?.setDelegate(nil, delegateQueue: nil)
socket = nil
service?.delegate = nil
service = nil
}
//MARK: - NSNetServiceDelegate
func netServiceDidPublish(_ sender: NetService) {
print("Bonjour Service Published: domain(\(sender.domain)) type(\(sender.type)) name(\(sender.name)) port(\(sender.port))", terminator: "\n")
}
func netService(_ sender: NetService, didNotPublish errorDict: [String : NSNumber]) {
print("Failed to Publish Service: domain(\(sender.domain)) type(\(sender.type)) name(\(sender.name)) port(\(sender.port))", terminator: "\n")
}
//MARK: - GCDAsyncSocketDelegate
func socket(_ sock: GCDAsyncSocket, didAcceptNewSocket newSocket: GCDAsyncSocket) {
print("Accepted New Socket from \(newSocket.connectedHost as Optional):\(newSocket.connectedPort as Optional)", terminator: "\n")
socket = newSocket
// read first packet header from socket
newSocket.readData(toLength: UInt(2 * MemoryLayout<Int32>.size), withTimeout: -1, tag: 0)
let notif = NSUserNotification()
notif.title = "connected".localized
notif.informativeText = "connect_with".localized + ":\(socket!.connectedHost as Optional) " + "completed".localized
notif.deliveryDate = Date()
NSUserNotificationCenter.default.scheduleNotification(notif)
NotificationCenter.default.post(name: ServerDidConnectNotification, object: self)
}
func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Error?) {
if socket == sock {
if err != nil {
print("Socket did disconnect with error \(err as Optional)", terminator: "\n")
} else {
print("Socket did disconnect", terminator: "\n")
}
let notif = NSUserNotification()
notif.title = "disconnected".localized
notif.informativeText = "conn_terminated".localized
notif.deliveryDate = Date()
NSUserNotificationCenter.default.scheduleNotification(notif)
NotificationCenter.default.post(name: ServerDidDisconnectNotification, object: self)
endBroadcast()
startBroadcast()
}
}
func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int) {
var expectedByteCount = -1
var expectedNextTag = -1
if (tag == 0) { // read packet header
let protocolVersion = Int(data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<Int32>.size, as: Int32.self) })
if (protocolVersion == 1) {
expectedNextTag = Int(data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 1 * MemoryLayout<Int32>.size, as: Int32.self) })
if (expectedNextTag == 1) { expectedByteCount = 1 * MemoryLayout<UInt32>.size } // "key" packet type requires 1 uint32
else if (expectedNextTag == 2) { expectedByteCount = 0 } // "backspace" packet type has no payload
else if (expectedNextTag == 3) { expectedByteCount = 0 }// "enter" packet type has no payload
else if (expectedNextTag == 4) { expectedByteCount = 2 * MemoryLayout<Bool>.size } // "click" packet type requires 2 booleans
else if (expectedNextTag == 5) { expectedByteCount = 2 * MemoryLayout<Double>.size } // "scroll" packet type requires 2 doubles
else if (expectedNextTag == 6) { expectedByteCount = 9 * MemoryLayout<Double>.size } // "move" packet type requires 9 doubles
else if (expectedNextTag == 7) { expectedByteCount = 0 } // "reset" packet type has no payload
}
}
else if (tag == 1) { // read "key" packet payload
var key: String = ""
let unicodeScalarValue: UInt32 = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<UInt32>.size, as: UInt32.self) }
let unicodeScalar = UnicodeScalar(unicodeScalarValue)
if (unicodeScalar != nil) {
key.append(Character(unicodeScalar!))
delegate?.runAppleScript("tell app \"System Events\" to keystroke \"" + key + "\"")
}
expectedNextTag = 0 // prepare to read the next packet header
expectedByteCount = 2 * MemoryLayout<Int32>.size
}
else if (tag == 2) { // read "backspace" packet payload
delegate?.runAppleScript("tell app \"System Events\" to key code 51")
expectedNextTag = 0 // prepare to read the next packet header
expectedByteCount = 2 * MemoryLayout<Int32>.size
}
else if (tag == 3) { // read "enter" packet payload
delegate?.runAppleScript("tell app \"System Events\" to keystroke return")
expectedNextTag = 0 // prepare to read the next packet header
expectedByteCount = 2 * MemoryLayout<Int32>.size
}
else if (tag == 4) { // read "click" packet payload
let isRightButton = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<Bool>.size, as: Bool.self) }
let isButtonDown = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 1 * MemoryLayout<Bool>.size, as: Bool.self) }
delegate?.clickButton(isRightButton: isRightButton, isButtonDown: isButtonDown)
expectedNextTag = 0 // prepare to read the next packet header
expectedByteCount = 2 * MemoryLayout<Int32>.size
}
else if (tag == 5) { // read "scroll" packet payload
let roll = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<Double>.size, as: Double.self) }
let scrollVelocity = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 1 * MemoryLayout<Double>.size, as: Double.self) }
delegate?.scrollWithRoll(roll: roll, velocity: scrollVelocity)
expectedNextTag = 0 // prepare to read the next packet header
expectedByteCount = 2 * MemoryLayout<Int32>.size
}
else if (tag == 6) { // read "move" packet payload
let gravX = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 0 * MemoryLayout<Double>.size, as: Double.self) }
let gravY = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 1 * MemoryLayout<Double>.size, as: Double.self) }
let gravZ = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 2 * MemoryLayout<Double>.size, as: Double.self) }
let rotatX = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 3 * MemoryLayout<Double>.size, as: Double.self) }
let rotatZ = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 4 * MemoryLayout<Double>.size, as: Double.self) }
let accX = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 5 * MemoryLayout<Double>.size, as: Double.self) }
let accY = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 6 * MemoryLayout<Double>.size, as: Double.self) }
let accZ = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 7 * MemoryLayout<Double>.size, as: Double.self) }
let moveVelocity = data.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: 8 * MemoryLayout<Double>.size, as: Double.self) }
delegate?.computePointerMovement(grav: (X: gravX, Y: gravY, Z: gravZ), rotat: (X: rotatX, Z: rotatZ), acc: (X: accX, Y: accY, Z: accZ), moveVelocity: moveVelocity)
expectedNextTag = 0 // prepare to read the next packet header
expectedByteCount = 2 * MemoryLayout<Int32>.size
}
else if (tag == 7) { // read "reset" packet payload
delegate?.resetPointerPosition(moveMouse: true)
expectedNextTag = 0 // prepare to read the next packet header
expectedByteCount = 2 * MemoryLayout<Int32>.size
}
// do we know what to read next ?
if (expectedByteCount == -1) {
endConnection()
let alert = NSAlert()
alert.addButton(withTitle: "OK")
alert.messageText = "vers_incomp".localized
alert.informativeText = "incomp_message".localized
alert.alertStyle = .warning
alert.runModal()
}
else if (expectedByteCount == 0) {
socket(sock, didRead: Data(), withTag: expectedNextTag) // no payload, so chain-call ourselves to process the packet directly
}
else {
sock.readData(toLength: UInt(expectedByteCount), withTimeout: -1, tag: expectedNextTag) // read some bytes
}
}
}