Subversion Repositories Mobile Apps.GyroMouse

Rev

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