Subversion Repositories Mobile Apps.GyroMouse

Rev

Rev 1 | Go to most recent revision | 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 {
16
    func serverDidReceivePacket(_ packet: GyroPacket)
17
}
18
 
19
class ServerHandler: NSObject, NetServiceDelegate, GCDAsyncSocketDelegate {
20
 
21
    weak var delegate: ServerHandlerDelegate?
22
 
23
    private var service: NetService?
24
    private var socket: GCDAsyncSocket?
25
 
26
    private let buildNumber: Int = {
27
        let infoDictionary = Bundle.main.infoDictionary!
28
        let build = infoDictionary[String(kCFBundleVersionKey)] as! String
29
        return Int(build)!
30
    }()
31
 
32
    deinit {
33
        delegate = nil
34
 
35
        socket?.setDelegate(nil, delegateQueue: nil)
36
        socket = nil
37
 
38
        service?.delegate = nil
39
        service = nil
40
    }
41
 
42
    //MARK: - Privates
43
 
44
    private func sendNotificationWithName(_ name: Notification.Name, userInfo: [String : Any]?) {
45
        let center = NotificationCenter.default
46
        let notif = Notification(name: name, object: self, userInfo: userInfo)
47
        center.post(notif)
48
    }
49
 
50
    private func parseHeader(_ data: Data) -> UInt64 {
51
        var headerLength: UInt64 = 0
52
        memcpy(&headerLength, (data as NSData).bytes, MemoryLayout<UInt64>.size)
53
        return headerLength
54
    }
55
 
56
    private func parseBody(_ data: Data) {
57
        let unarchiver = NSKeyedUnarchiver(forReadingWith: data)
58
        let packet = unarchiver.decodeObject(forKey: "packet") as! GyroPacket
59
        unarchiver.finishDecoding()
60
 
61
        if packet.minimumVersion <= buildNumber {
62
            delegate?.serverDidReceivePacket(packet)
63
        } else {
64
            endConnection()
65
            let alert = NSAlert()
66
            alert.addButton(withTitle: "OK")
67
            alert.messageText = "vers_incomp".localized
68
            alert.informativeText = "incomp_message".localized
69
            alert.alertStyle = .warning
70
            alert.runModal()
71
        }
72
    }
73
 
74
    //MARK: - Publics
75
 
76
    func endConnection() {
77
        socket?.disconnect()
78
    }
79
 
80
    func startBroadcast() {
81
        // Initialize GCDAsyncSocket
82
        socket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main)
83
 
84
        // Start Listening for Incoming Connections
85
        do {
86
            try socket!.accept(onPort: 0)
87
            service = NetService(domain: "local.", type: "_gyroserver._tcp.", name: "", port: Int32(socket!.localPort))
88
            service!.delegate = self
89
            service!.publish()
90
        } catch let error as NSError {
91
            print("Unable to create socket. Error \(error) with user info \(error.userInfo).", terminator: "\n")
92
        }
93
    }
94
 
95
    func endBroadcast() {
96
        socket?.setDelegate(nil, delegateQueue: nil)
97
        socket = nil
98
 
99
        service?.delegate = nil
100
        service = nil
101
    }
102
 
103
    //MARK: - NSNetServiceDelegate
104
 
105
    func netServiceDidPublish(_ sender: NetService) {
106
        print("Bonjour Service Published: domain(\(sender.domain)) type(\(sender.type)) name(\(sender.name)) port(\(sender.port))", terminator: "\n")
107
    }
108
 
109
    func netService(_ sender: NetService, didNotPublish errorDict: [String : NSNumber]) {
110
        print("Failed to Publish Service: domain(\(sender.domain)) type(\(sender.type)) name(\(sender.name)) port(\(sender.port))", terminator: "\n")
111
    }
112
 
113
    //MARK: - GCDAsyncSocketDelegate
114
 
115
    func socket(_ sock: GCDAsyncSocket, didAcceptNewSocket newSocket: GCDAsyncSocket) {
116
        print("Accepted New Socket from \(newSocket.connectedHost as Optional):\(newSocket.connectedPort as Optional)", terminator: "\n")
117
 
118
        socket = newSocket
119
 
120
        // Read Data from Socket
121
        newSocket.readData(toLength: UInt(MemoryLayout<UInt64>.size), withTimeout: -1.0, tag: 0)
122
 
123
        let notif = NSUserNotification()
124
        notif.title = "connected".localized
125
        notif.informativeText = "connect_with".localized + ":\(socket!.connectedHost as Optional) " + "completed".localized
126
        notif.deliveryDate = Date()
127
        NSUserNotificationCenter.default.scheduleNotification(notif)
128
        NotificationCenter.default.post(name: ServerDidConnectNotification, object: self)
129
    }
130
 
131
    func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Error?) {
132
        if socket == sock {
133
            if err != nil {
134
                print("Socket did disconnect with error \(err as Optional)", terminator: "\n")
135
            } else {
136
                print("Socket did disconnect", terminator: "\n")
137
            }
138
 
139
            let notif = NSUserNotification()
140
            notif.title = "disconnected".localized
141
            notif.informativeText = "conn_terminated".localized
142
            notif.deliveryDate = Date()
143
            NSUserNotificationCenter.default.scheduleNotification(notif)
144
 
145
            NotificationCenter.default.post(name: ServerDidDisconnectNotification, object: self)
146
 
147
            endBroadcast()
148
            startBroadcast()
149
 
150
        }
151
    }
152
 
153
    func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int) {
154
        if tag == 0 {
155
            let bodyLength = parseHeader(data)
156
            socket?.readData(toLength: UInt(bodyLength), withTimeout: -1, tag: 1)
157
        } else if tag == 1 {
158
            parseBody(data)
159
            socket?.readData(toLength: UInt(MemoryLayout<UInt64>.size), withTimeout: -1, tag: 0)
160
        }
161
    }
162
 
163
}