Rev 1 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
//
// ClientHandler.swift
// GyroMouse
//
// Created by Matteo Riva on 28/08/15.
// Copyright © 2015 Matteo Riva. All rights reserved.
//
import Foundation
import CocoaAsyncSocket
class ClientHandler: NSObject, NetServiceDelegate, NetServiceBrowserDelegate, GCDAsyncSocketDelegate {
private var socket: GCDAsyncSocket?
private var serviceBrowser: NetServiceBrowser?
private(set) var services = [NetService]()
deinit {
socket?.setDelegate(nil, delegateQueue: nil)
socket = nil
serviceBrowser?.delegate = nil
serviceBrowser = nil
}
//MARK: - Publics
func startBrowsing() {
services = []
// Initialize Service Browser
serviceBrowser = NetServiceBrowser()
// Configure Service Browser
serviceBrowser!.delegate = self
serviceBrowser!.searchForServices(ofType: "_gyroserver._tcp.", inDomain:"local.")
}
func stopBrowsing() {
serviceBrowser?.stop()
serviceBrowser?.delegate = nil
serviceBrowser = nil
services.removeAll()
}
func connectToLocalService(_ service: NetService) {
// Resolve Service
service.delegate = self
service.resolve(withTimeout: 30)
}
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) {
let buffer = NSMutableData()
var int32var: Int32
var uint32var: UInt32
var boolvar: Bool
var doublevar: Double
int32var = 1; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // protocol version
if (type == "key") { // key tapped
if (keyTapped.isEmpty) { return } // consistency check: happens when we hit a backspace
int32var = 1; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // "key" packet type
uint32var = keyTapped.unicodeScalars.first!.value; buffer.append(&uint32var, length: MemoryLayout<UInt32>.size)
}
else if (type == "backspace") { // backspace tapped
int32var = 2; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // "backspace" packet type
// nothing to add
}
else if (type == "enter") { // enter tapped
int32var = 3; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // "enter" packet type
// nothing to add
}
else if (type == "click") { // click
int32var = 4; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // "click" packet type
boolvar = isRightButton; buffer.append(&boolvar, length: MemoryLayout<Bool>.size)
boolvar = isButtonDown; buffer.append(&boolvar, length: MemoryLayout<Bool>.size)
}
else if (type == "scroll") { // page scroll
int32var = 5; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // "scroll" packet type
doublevar = roll; buffer.append(&doublevar, length: MemoryLayout<Double>.size)
doublevar = scrollVelocity; buffer.append(&doublevar, length: MemoryLayout<Double>.size)
}
else if (type == "move") { // movement
int32var = 6; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // "move" packet type
doublevar = grav.X; buffer.append(&doublevar, length: MemoryLayout<Double>.size)
doublevar = grav.Y; buffer.append(&doublevar, length: MemoryLayout<Double>.size)
doublevar = grav.Z; buffer.append(&doublevar, length: MemoryLayout<Double>.size)
doublevar = rotat.X; buffer.append(&doublevar, length: MemoryLayout<Double>.size)
doublevar = rotat.Z; buffer.append(&doublevar, length: MemoryLayout<Double>.size)
doublevar = acc.X; buffer.append(&doublevar, length: MemoryLayout<Double>.size)
doublevar = acc.Y; buffer.append(&doublevar, length: MemoryLayout<Double>.size)
doublevar = acc.Z; buffer.append(&doublevar, length: MemoryLayout<Double>.size)
doublevar = moveVelocity; buffer.append(&doublevar, length: MemoryLayout<Double>.size)
}
else if (type == "reset") { // reset pointer
int32var = 7; buffer.append(&int32var, length: MemoryLayout<Int32>.size) // "click" packet type
// nothing to add
}
// Write Buffer
let bufferData = buffer as Data
print ("Sending \(bufferData.count) bytes packet:", terminator: "")
for i in 0...(bufferData.count - 1) {
let byte: UInt8 = bufferData.withUnsafeBytes { rawBuffer in rawBuffer.load(fromByteOffset: i * MemoryLayout<UInt8>.size, as: UInt8.self) }
print (" " + String(format: "%02X", byte), terminator: "")
}
print ("")
socket?.write(bufferData, withTimeout: -1, tag: 0)
}
func endConnection() {
socket?.disconnect()
socket?.setDelegate(nil, delegateQueue: nil)
socket = nil
}
//MARK: - NSNetServiceBrowserDelegate
func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
// Update Services
services.append(service)
if !moreComing {
NotificationCenter.default.post(Notification(name: GyroMouseShouldRefreshServerListNotification, object: self, userInfo: nil))
}
}
func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool) {
// Update Services
services.remove(at: services.firstIndex(of: service)!)
if !moreComing {
NotificationCenter.default.post(Notification(name: GyroMouseShouldRefreshServerListNotification, object: self, userInfo: nil))
}
}
func netServiceBrowserDidStopSearch(_ browser: NetServiceBrowser) {
stopBrowsing()
}
func netServiceBrowser(_ browser: NetServiceBrowser, didNotSearch errorDict: [String : NSNumber]) {
stopBrowsing()
}
//MARK: - NSNetServiceDelegate
func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber]) {
sender.delegate = nil
}
func netServiceDidResolveAddress(_ sender: NetService) {
// Connect With Service
var isConnected = false
if ((socket == nil) || (socket?.isDisconnected ?? false)) {
// Initialize Socket
socket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main)
// Connect
while (!isConnected && (sender.addresses!.count != 0)) {
do {
try socket!.connect(toAddress: sender.addresses!.first!)
isConnected = true
} catch {
isConnected = false
print("Unable to connect to address. Error \(error) with user info \(error.localizedDescription).", terminator: "\n")
}
}
} else {
isConnected = socket?.isConnected ?? false
}
if (isConnected) {
print("Did Connect with Service: domain(\(sender.domain)) type(\(sender.type)) name(\(sender.name)) port(\(sender.port))", terminator: "\n")
} else {
print("Unable to Connect with Service: domain(\(sender.domain)) type(\(sender.type)) name(\(sender.name)) port(\(sender.port))", terminator: "\n")
NotificationCenter.default.post(Notification(name: GyroMouseConnectionFailedNotification, object: self, userInfo: nil))
}
}
//MARK: - GCDAsyncSocketDelegate
func socket(_ sock: GCDAsyncSocket, didConnectToHost host: String, port: UInt16) {
print("Socket Did Connect to Host: \(host) Port: \(port)", terminator: "\n")
stopBrowsing()
NotificationCenter.default.post(Notification(name: GyroMouseConnectionSuccessNotification, object: self, userInfo: nil))
}
func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Error?) {
socket?.delegate = nil
socket = nil
startBrowsing()
NotificationCenter.default.post(Notification(name: GyroMouseDisconnectedNotification, object: self, userInfo: nil))
if err != nil {
print("Socket Did Disconnect with Error \(err!) with user info \(err!.localizedDescription).", terminator: "\n")
//NotificationCenter.default.post(Notification(name: GyroMouseConnectionFailedNotification, object: self, userInfo: nil))
} else {
print("Socket Did Disconnect", terminator: "\n")
}
}
}