Skip to content
This repository was archived by the owner on Dec 2, 2022. It is now read-only.

Commit d2037f4

Browse files
committed
Merge pull request #23 from pvzig/feature/client-improvements
Feature/client-improvements
2 parents 5b08fb6 + b87232d commit d2037f4

11 files changed

+123
-42
lines changed

Podfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
PODS:
2-
- Starscream (1.0.2)
2+
- Starscream (1.1.2)
33

44
DEPENDENCIES:
55
- Starscream
66

77
SPEC CHECKSUMS:
8-
Starscream: 40e2c4c1c770d811f24116b8b7dbeb4542c56767
8+
Starscream: 58a12fd35a3cb6aaa105716c2d42765f7c1c732f
99

1010
COCOAPODS: 0.39.0

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ If you want to receive messages from the Slack RTM API, connect to it.
4848
client.connect()
4949
```
5050

51+
You can also set options for a ping/pong interval, timeout interval, and automatic reconnection:
52+
```swift
53+
client.connect(pingInterval: 2, timeout: 10, reconnect: false)
54+
```
55+
5156
Once connected, the client will begin to consume any messages sent by the Slack RTM API.
5257

5358
####Web API Methods
@@ -65,6 +70,9 @@ SlackKit currently supports the a subset of the Slack Web APIs that are availabl
6570
- chat.postMessage
6671
- chat.update
6772
- emoji.list
73+
- files.comments.add
74+
- files.comments.edit
75+
- files.comments.delete
6876
- files.delete
6977
- files.upload
7078
- groups.close
@@ -187,8 +195,8 @@ func itemStarred(item: Item, star: Bool)
187195

188196
#####ReactionEventsDelegate
189197
```swift
190-
func reactionAdded(reaction: String?, item: Item?)
191-
func reactionRemoved(reaction: String?, item: Item?)
198+
func reactionAdded(reaction: String?, item: Item?, itemUser: String?)
199+
func reactionRemoved(reaction: String?, item: Item?, itemUser: String?)
192200
```
193201

194202
#####TeamEventsDelegate

SlackKit.podspec

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ Pod::Spec.new do |s|
1212
s.requires_arc = true
1313
s.source_files = 'SlackKit/Sources/*.swift'
1414
s.frameworks = 'Foundation'
15-
s.dependency 'Starscream', '~> 1.0.2'
15+
s.dependency 'Starscream', '~> 1.1.2'
1616
end
17+

SlackKit/Sources/Channel.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public struct Channel {
4343
internal(set) public var unread: Int?
4444
internal(set) public var unreadCountDisplay: Int?
4545
internal(set) public var hasPins: Bool?
46-
internal(set) public var members = [String]()
46+
internal(set) public var members: [String]?
4747
// Client use
4848
internal(set) public var pinnedItems = [Item]()
4949
internal(set) public var usersTyping = [String]()
@@ -70,11 +70,7 @@ public struct Channel {
7070
unread = channel?["unread_count"] as? Int
7171
unreadCountDisplay = channel?["unread_count_display"] as? Int
7272
hasPins = channel?["has_pins"] as? Bool
73-
74-
if let members = channel?["members"] as? [String] {
75-
self.members = members
76-
}
77-
73+
members = channel?["members"] as? [String]
7874
}
7975

8076
internal init?(id:String?) {

SlackKit/Sources/Client.swift

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public class Client: WebSocketDelegate {
5353
public var teamProfileEventsDelegate: TeamProfileEventsDelegate?
5454

5555
internal var token = "SLACK_AUTH_TOKEN"
56-
56+
5757
public func setAuthToken(token: String) {
5858
self.token = token
5959
}
@@ -63,15 +63,25 @@ public class Client: WebSocketDelegate {
6363
}
6464

6565
internal var webSocket: WebSocket?
66+
internal let api = NetworkInterface()
6667
private var dispatcher: EventDispatcher?
6768

68-
internal let api = NetworkInterface()
69+
private let pingPongQueue = dispatch_queue_create("com.launchsoft.SlackKit", DISPATCH_QUEUE_SERIAL)
70+
internal var ping: Double?
71+
internal var pong: Double?
72+
73+
internal var pingInterval: NSTimeInterval?
74+
internal var timeout: NSTimeInterval?
75+
internal var reconnect: Bool?
6976

7077
required public init(apiToken: String) {
7178
self.token = apiToken
7279
}
7380

74-
public func connect() {
81+
public func connect(pingInterval pingInterval: NSTimeInterval? = nil, timeout: NSTimeInterval? = nil, reconnect: Bool? = nil) {
82+
self.pingInterval = pingInterval
83+
self.timeout = timeout
84+
self.reconnect = reconnect
7585
dispatcher = EventDispatcher(client: self)
7686
webAPI.rtmStart(success: {
7787
(response) -> Void in
@@ -85,19 +95,24 @@ public class Client: WebSocketDelegate {
8595
}, failure:nil)
8696
}
8797

98+
public func disconnect() {
99+
webSocket?.disconnect()
100+
}
101+
88102
//MARK: - Message send
89103
public func sendMessage(message: String, channelID: String) {
90104
if (connected) {
91105
if let data = formatMessageToSlackJsonString(msg: message, channel: channelID) {
92-
let string = NSString(data: data, encoding: NSUTF8StringEncoding)
93-
webSocket?.writeString(string as! String)
106+
if let string = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
107+
webSocket?.writeString(string)
108+
}
94109
}
95110
}
96111
}
97112

98113
private func formatMessageToSlackJsonString(message: (msg: String, channel: String)) -> NSData? {
99114
let json: [String: AnyObject] = [
100-
"id": NSDate().timeIntervalSince1970,
115+
"id": NSDate().slackTimestamp(),
101116
"type": "message",
102117
"channel": message.channel,
103118
"text": message.msg.slackFormatEscaping()
@@ -121,6 +136,52 @@ public class Client: WebSocketDelegate {
121136
sentMessages[ts!.stringValue] = Message(message: message)
122137
}
123138

139+
//MARK: - RTM Ping
140+
private func pingRTMServerAtInterval(interval: NSTimeInterval) {
141+
let delay = dispatch_time(DISPATCH_TIME_NOW, Int64(interval * Double(NSEC_PER_SEC)))
142+
dispatch_after(delay, pingPongQueue, {
143+
if self.connected && self.timeoutCheck() {
144+
self.sendRTMPing()
145+
self.pingRTMServerAtInterval(interval)
146+
} else {
147+
self.disconnect()
148+
}
149+
})
150+
}
151+
152+
private func sendRTMPing() {
153+
if connected {
154+
let json: [String: AnyObject] = [
155+
"id": NSDate().slackTimestamp(),
156+
"type": "ping",
157+
]
158+
do {
159+
let data = try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions.PrettyPrinted)
160+
let string = NSString(data: data, encoding: NSUTF8StringEncoding)
161+
if let writePing = string as? String {
162+
ping = json["id"] as? Double
163+
webSocket?.writeString(writePing)
164+
}
165+
}
166+
catch _ {
167+
168+
}
169+
}
170+
}
171+
172+
private func timeoutCheck() -> Bool {
173+
if let pong = pong, ping = ping, timeout = timeout {
174+
if pong - ping < timeout {
175+
return true
176+
} else {
177+
return false
178+
}
179+
// Ping-pong or timeout not configured
180+
} else {
181+
return true
182+
}
183+
}
184+
124185
//MARK: - Client setup
125186
internal func initialSetup(json: [String: AnyObject]) {
126187
team = Team(team: json["team"] as? [String: AnyObject])
@@ -207,14 +268,21 @@ public class Client: WebSocketDelegate {
207268
}
208269

209270
// MARK: - WebSocketDelegate
210-
public func websocketDidConnect(socket: WebSocket) {}
271+
public func websocketDidConnect(socket: WebSocket) {
272+
if let pingInterval = pingInterval {
273+
pingRTMServerAtInterval(pingInterval)
274+
}
275+
}
211276

212277
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
213278
connected = false
214279
authenticated = false
215280
webSocket = nil
216-
if let delegate = slackEventsDelegate {
217-
delegate.clientDisconnected()
281+
dispatcher = nil
282+
authenticatedUser = nil
283+
slackEventsDelegate?.clientDisconnected()
284+
if reconnect == true {
285+
connect(pingInterval: pingInterval, timeout: timeout, reconnect: reconnect)
218286
}
219287
}
220288

@@ -223,7 +291,9 @@ public class Client: WebSocketDelegate {
223291
return
224292
}
225293
do {
226-
try dispatcher?.dispatch(NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) as! [String: AnyObject])
294+
if let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) as? [String: AnyObject] {
295+
dispatcher?.dispatch(json)
296+
}
227297
}
228298
catch _ {
229299

SlackKit/Sources/ClientExtensions.swift

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,11 @@ import Foundation
2626
extension Client {
2727

2828
//MARK: - User & Channel
29-
public func getChannelOrUserIdByName(name: String) -> String? {
30-
if (name[name.startIndex] == "@") {
31-
return getUserIdByName(name)
32-
} else if (name[name.startIndex] == "C") {
33-
return getChannelIDByName(name)
34-
}
35-
return nil
36-
}
37-
3829
public func getChannelIDByName(name: String) -> String? {
3930
return channels.filter{$0.1.name == stripString(name)}.first?.0
4031
}
4132

42-
public func getUserIdByName(name: String) -> String? {
33+
public func getUserIDByName(name: String) -> String? {
4334
return users.filter{$0.1.name == stripString(name)}.first?.0
4435
}
4536

@@ -54,13 +45,14 @@ extension Client {
5445
}
5546

5647
//MARK: - Utilities
57-
internal func stripString(var string: String) -> String {
48+
internal func stripString(string: String) -> String? {
49+
var strippedString: String?
5850
if string[string.startIndex] == "@" {
59-
string = string.substringFromIndex(string.startIndex.advancedBy(1))
51+
strippedString = string.substringFromIndex(string.startIndex.advancedBy(1))
6052
} else if string[string.startIndex] == "#" {
61-
string = string.substringFromIndex(string.startIndex.advancedBy(1))
53+
strippedString = string.substringFromIndex(string.startIndex.advancedBy(1))
6254
}
63-
return string
55+
return strippedString
6456
}
6557

6658
}
@@ -78,8 +70,8 @@ internal extension String {
7870

7971
public extension NSDate {
8072

81-
func slackTimestamp() -> String {
82-
return NSNumber(double: timeIntervalSince1970).stringValue
73+
func slackTimestamp() -> Double {
74+
return NSNumber(double: timeIntervalSince1970).doubleValue
8375
}
8476

8577
}

SlackKit/Sources/Event.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ internal enum EventType: String {
6262
case FileCommentDeleted = "file_comment_deleted"
6363
case PinAdded = "pin_added"
6464
case PinRemoved = "pin_removed"
65+
case Pong = "pong"
6566
case PresenceChange = "presence_change"
6667
case ManualPresenceChange = "manual_presence_change"
6768
case PrefChange = "pref_change"

SlackKit/Sources/EventDispatcher.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ internal class EventDispatcher {
9696
handler.pinAdded(event)
9797
case .PinRemoved:
9898
handler.pinRemoved(event)
99+
case .Pong:
100+
handler.pong(event)
99101
case .PresenceChange:
100102
handler.presenceChange(event)
101103
case .ManualPresenceChange:
@@ -146,7 +148,7 @@ internal class EventDispatcher {
146148
// Other clients should ignore this event.
147149
break
148150
case .TeamMigrationStarted:
149-
client.connect()
151+
client.connect(pingInterval: client.pingInterval, timeout: client.timeout, reconnect: client.reconnect)
150152
case .ReconnectURL:
151153
// The reconnect_url event is currently unsupported and experimental.
152154
break

SlackKit/Sources/EventHandler.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ internal class EventHandler {
3838
}
3939
}
4040

41+
//MARK: - Pong
42+
func pong(event: Event) {
43+
client.pong = event.replyTo
44+
}
45+
4146
//MARK: - Messages
4247
func messageSent(event: Event) {
4348
if let reply = event.replyTo, message = client.sentMessages[NSNumber(double: reply).stringValue], channel = message.channel, ts = message.ts {
@@ -147,8 +152,8 @@ internal class EventHandler {
147152

148153
func channelLeft(event: Event) {
149154
if let channel = event.channel, id = channel.id, userID = client.authenticatedUser?.id {
150-
if let index = client.channels[id]?.members.indexOf(userID) {
151-
client.channels[id]?.members.removeAtIndex(index)
155+
if let index = client.channels[id]?.members?.indexOf(userID) {
156+
client.channels[id]?.members?.removeAtIndex(index)
152157

153158
if let delegate = client.channelEventsDelegate {
154159
delegate.channelLeft(channel)

SlackKit/Sources/File.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public struct File {
6262
internal(set) public var comments = [String: Comment]()
6363
internal(set) public var reactions = [String: Reaction]()
6464

65-
init?(file:[String: AnyObject]?) {
65+
public init?(file:[String: AnyObject]?) {
6666
id = file?["id"] as? String
6767
created = file?["created"] as? Int
6868
name = file?["name"] as? String
@@ -105,7 +105,7 @@ public struct File {
105105

106106
}
107107

108-
init?(id:String?) {
108+
internal init?(id:String?) {
109109
self.id = id
110110
created = nil
111111
name = nil

0 commit comments

Comments
 (0)