This repository has been archived by the owner on Jul 21, 2020. It is now read-only.
/
ConstellationClient.swift
145 lines (112 loc) · 4.66 KB
/
ConstellationClient.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//
// ConstellationClient.swift
// Pods
//
// Created by Jack Cook on 8/10/16.
//
//
import Starscream
import SwiftyJSON
/// Used to connect to and communicate with Mixer's liveloading socket.
public class ConstellationClient: WebSocketDelegate {
// MARK: Properties
/// The client's shared instance.
public class var sharedClient: ConstellationClient {
struct Static {
static let instance = ConstellationClient()
}
return Static.instance
}
/// The client's delegate, through which updates are relayed to the app.
fileprivate weak var delegate: ConstellationClientDelegate?
/// All events that the client is currently subscribed to.
fileprivate var events = [ConstellationEvent]()
/// The websocket through which constellation data is sent and received.
fileprivate var socket: WebSocket?
// MARK: Public Methods
/// Makes a connection to constellation through a websocket.
public func connect(_ delegate: ConstellationClientDelegate) {
self.delegate = delegate
socket = WebSocket(url: URL(string: "wss://constellation.mixer.com")!)
socket?.delegate = self
socket?.headers["User-Agent"] = "IOSApp/\(MixerRequest.version) (iOS; \(MixerRequest.deviceName()))"
socket?.connect()
}
/// Disconnects from constellation.
public func disconnect() {
self.socket?.disconnect()
}
/**
Sends a packet to constellation.
:param: packet The packet to be sent.
*/
public func sendPacket(_ packet: ConstellationSendable) {
guard let socket = socket else {
return
}
let packetData = ConstellationPacket.prepareToSend(packet)
socket.write(string: packetData)
}
/**
Subscribes the client to a list of events.
:param: events The list of events to subscribe to.
*/
public func subscribeToEvents(_ events: [ConstellationEvent]) {
self.events.append(contentsOf: events)
let subscribePacket = ConstellationLiveSubscribePacket(events: events)
sendPacket(subscribePacket)
}
/**
Unsubscribes the client from a list of events.
:param: events The list of events to unsubscribe from.
*/
public func unsubscribeFromEvents(_ events: [ConstellationEvent]) {
for (idx, event) in self.events.enumerated() {
if events.contains(where: { $0.description == event.description }) {
self.events.remove(at: idx)
}
}
let unsubscribePacket = ConstellationLiveUnsubscribePacket(events: events)
sendPacket(unsubscribePacket)
}
/// Unsubscribes the client from all events it is currently subscribed to.
public func unsubscribeFromAllEvents() {
let unsubscribePacket = ConstellationLiveUnsubscribePacket(events: events)
sendPacket(unsubscribePacket)
events = [ConstellationEvent]()
}
// MARK: WebSocketDelegate Methods
public func websocketDidConnect(socket: WebSocket) {
delegate?.constellationDidConnect()
}
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
delegate?.constellationDidDisconnect(error)
}
public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
guard let data = text.data(using: String.Encoding.utf8, allowLossyConversion: false) else {
print("unknown error parsing constellation packet: \(text)")
return
}
do {
if let jsonObject = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSDictionary {
let json = JSON(jsonObject)
if let packet = ConstellationPacket.receivePacket(json) {
self.delegate?.constellationReceivedPacket(packet)
}
}
} catch {
print("JSON read failure while parsing constellation packet: \(text)")
}
}
public func websocketDidReceiveData(socket: WebSocket, data: Data) {
}
}
/// The constellation client's delegate, through which information is relayed to the app.
public protocol ConstellationClientDelegate: class {
/// Called when a connection is made to the constellation server.
func constellationDidConnect()
/// Called when the websocket disconnects, whether on purpose or unexpectedly.
func constellationDidDisconnect(_ error: NSError?)
/// Called when a packet has been received and interpreted.
func constellationReceivedPacket(_ packet: ConstellationPacket)
}