Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions KoreBotSDK.podspec
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'KoreBotSDK'
s.version = '0.1.0'
s.version = '0.1.1'
s.license = {:type => 'MIT', :file => 'KoreBotSDK/LICENSE' }
s.summary = 'KoreBotSDK lets a user interact with Kore bots'
s.homepage = 'https://kore.ai'
Expand All @@ -26,7 +26,7 @@ Pod::Spec.new do |s|

ss.dependency 'Mantle', '2.0.2'
ss.dependency 'AFNetworking', '3.2.0'
ss.dependency 'SocketRocket'
ss.dependency 'Starscream', '~> 3.0.2'

ss.ios.frameworks = 'SystemConfiguration'
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -718,8 +718,8 @@
"${BUILT_PRODUCTS_DIR}/KoreBotSDK/KoreBotSDK.framework",
"${BUILT_PRODUCTS_DIR}/Mantle/Mantle.framework",
"${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework",
"${BUILT_PRODUCTS_DIR}/SocketRocket/SocketRocket.framework",
"${BUILT_PRODUCTS_DIR}/SquareMosaicLayout/SquareMosaicLayout.framework",
"${BUILT_PRODUCTS_DIR}/Starscream/Starscream.framework",
"${BUILT_PRODUCTS_DIR}/TOWebViewController/TOWebViewController.framework",
"${BUILT_PRODUCTS_DIR}/gRPC/GRPCClient.framework",
"${BUILT_PRODUCTS_DIR}/gRPC-Core/grpc.framework",
Expand All @@ -738,8 +738,8 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KoreBotSDK.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Mantle.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SocketRocket.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SquareMosaicLayout.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Starscream.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TOWebViewController.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GRPCClient.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/grpc.framework",
Expand Down
21 changes: 9 additions & 12 deletions KoreBotSDK/Library/KoreBotSDK/KoreBotSDK/Library/BotClient.swift
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//

import UIKit
import SocketRocket
import Starscream

public enum BotClientConnectionState : Int {
case NONE
Expand Down Expand Up @@ -242,8 +242,8 @@ open class BotClient: NSObject, RTMPersistentConnectionDelegate {

// MARK: functions
fileprivate func rtmConnectionWithBotInfoModel(_ botInfo: BotInfoModel, isReconnect: Bool) -> RTMPersistentConnection {
if (self.connection != nil && (self.connection.websocket.readyState == .OPEN || self.connection.websocket.readyState == .CONNECTING)) {
return self.connection
if connection != nil {
return connection
} else {
let rtmConnection: RTMPersistentConnection = RTMPersistentConnection(botInfo: botInfo, botInfoParameters: self.botInfoParameters, tryReconnect: isReconnect)
rtmConnection.connectionDelegate = self
Expand All @@ -253,16 +253,13 @@ open class BotClient: NSObject, RTMPersistentConnectionDelegate {
}

open func sendMessage(_ message: String!, options: AnyObject!) {
if (self.connection == nil) {
guard let socket = connection.socket else {
NSLog("WebSocket connection not available")
} else {
switch self.connection.websocket.readyState {
case .OPEN:
self.connection.sendMessageModel(message, options: [] as AnyObject?)
break
default:
break
}
return
}

if socket.isConnected {
connection.sendMessageModel(message, options: [] as AnyObject?)
}
}

Expand Down
116 changes: 72 additions & 44 deletions KoreBotSDK/Library/KoreBotSDK/KoreBotSDK/Library/RTM/RTMPersistentConnection.swift
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//

import UIKit
import SocketRocket
import Starscream
import Mantle

@objc public protocol RTMPersistentConnectionDelegate {
Expand All @@ -19,10 +19,11 @@ import Mantle
@objc optional func didReceiveMessageAck(_ ack: Ack)
}

open class RTMPersistentConnection : NSObject, SRWebSocketDelegate {
open class RTMPersistentConnection : NSObject, WebSocketDelegate, WebSocketPongDelegate {

var botInfo: BotInfoModel!
fileprivate var botInfoParameters: NSDictionary! = nil
var websocket: SRWebSocket! = nil
private(set) public var socket: WebSocket?
var connectionDelegate: RTMPersistentConnectionDelegate?

fileprivate let timerSource: DispatchSourceTimer
Expand All @@ -45,95 +46,118 @@ open class RTMPersistentConnection : NSObject, SRWebSocketDelegate {
if (self.tryReconnect == true) {
url.append("&isReconnect=true")
}
self.websocket = SRWebSocket(urlRequest: URLRequest(url: URL(string: url)! as URL) as URLRequest!)
self.websocket.delegate = self
self.websocket.open()

socket = WebSocket(url: URL(string: url)!)
socket?.delegate = self
socket?.pongDelegate = self
socket?.connect()
}

open func disconnect() {
if (self.websocket != nil) {
self.websocket.close()
if let socket = socket {
socket.disconnect()
}
}

// MARK: WebSocketDelegate methods
open func webSocketDidOpen(_ webSocket: SRWebSocket!) {
public func websocketDidConnect(socket: WebSocketClient) {
self.connectionDelegate?.rtmConnectionDidOpen()
let intervalInNSec = pingInterval * Double(NSEC_PER_SEC)
let startTime = DispatchTime.now() + Double(intervalInNSec) / Double(NSEC_PER_SEC)

timerSource.scheduleRepeating(deadline: startTime, interval: pingInterval, leeway: .nanoseconds(Int(NSEC_PER_SEC / 10)))
timerSource.setEventHandler { [unowned self] in

guard let socket = self.socket else {
return
}
if self.receivedLastPong == false {
// we did not receive the last pong
// abort the socket so that we can spin up a new connection
self.websocket.close()
} else if self.websocket.readyState == .CLOSED || self.websocket.readyState == .CLOSING {
self.websocket.close()
socket.disconnect()
} else if !socket.isConnected {
socket.disconnect()
} else {
// we got a pong recently
// send another ping
self.receivedLastPong = false
try? self.websocket.sendPing(nil)
socket.write(ping: Data())
}
}
timerSource.resume()
}

open func webSocket(_ webSocket: SRWebSocket!, didFailWithError error: NSError!) {
public func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {
if let error = error as NSError? {
self.connectionDelegate?.rtmConnectionDidFailWithError(error)
}
else {
self.connectionDelegate?.rtmConnectionDidClose(0, reason: "unknown")
}

}

open func webSocket(_ webSocket: SRWebSocket, didCloseWithCode code: Int, reason: String, wasClean: Bool) {
self.connectionDelegate?.rtmConnectionDidClose(code, reason: reason as String)
public func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {
processMessage(text)
}

open func webSocket(_ webSocket: SRWebSocket!, didReceivePong pongPayload: Data!) {
public func websocketDidReceiveData(socket: WebSocketClient, data: Data) {
if let text = String(data: data, encoding: .utf8) {
processMessage(text)
}
}

public func websocketDidReceivePong(socket: WebSocketClient, data: Data?) {
self.receivedLastPong = true
}

open func webSocket(_ webSocket: SRWebSocket!, didReceiveMessage message: Any!) {
let responseObject = self.convertStringToDictionary(message as! String)!
if (responseObject["type"]! as! String == "ready") {

private func processMessage (_ text: String) {

guard let responseObject = self.convertStringToDictionary(text) else {
return
}

guard let type = responseObject["type"] as? String else {
return
}

if (type == "ready") {
self.connectionDelegate?.self.rtmConnectionReady()
} else if (responseObject["ok"] != nil) {
}
else if (responseObject["ok"] != nil) {
let ack: Ack = try! (MTLJSONAdapter.model(of: Ack.self, fromJSONDictionary: responseObject ) as! Ack)
self.connectionDelegate?.didReceiveMessageAck!(ack)
} else if (responseObject["type"]! as! String == "bot_response") {
}
else if (type == "bot_response") {
print("received: \(responseObject)")
let array: NSArray = responseObject["message"] as! NSArray
if (array.count > 0) {

if let message = responseObject["message"] as? NSArray {
if (message.count > 0) {
let botMessageModel: BotMessageModel = try! (MTLJSONAdapter.model(of: BotMessageModel.self, fromJSONDictionary: responseObject ) as! BotMessageModel)
self.connectionDelegate?.didReceiveMessage!(botMessageModel)
}
}
}

open func webSocketShouldConvertTextFrameToString() -> ObjCBool {
return true
}

// MARK: sending message
open func sendMessageModel(_ message: String, options: AnyObject?) {
switch (self.websocket.readyState) {
case .CONNECTING:
print("Socket is in CONNECTING state")
break
case .CLOSED:
self.start()
print("Socket is in CLOSED state")
break
case .CLOSING:
print("Socket is in CLOSING state")
break
case .OPEN:
print("Socket is in OPEN state")

guard let socket = socket else {
print("Socket is not initialised")
start()
return
}

if socket.isConnected {
print("Socket is connected")
let parameters: NSMutableDictionary = NSMutableDictionary()
let messageObject = ["body":message, "attachments":[]] as [String : Any];
parameters.setObject(messageObject, forKey: "message" as NSCopying)
parameters.setObject("/bot.message", forKey: "resourceid" as NSCopying)
if (self.botInfoParameters != nil) {
parameters.setObject(self.botInfoParameters, forKey: "botInfo" as NSCopying)
if (botInfoParameters != nil) {
parameters.setObject(botInfoParameters, forKey: "botInfo" as NSCopying)
}
let uuid: String = Constants.getUUID()
parameters.setObject(uuid, forKey: "id" as NSCopying)
Expand All @@ -142,9 +166,13 @@ open class RTMPersistentConnection : NSObject, SRWebSocketDelegate {

var error : NSError?
let jsonData = try! JSONSerialization.data(withJSONObject: parameters, options: JSONSerialization.WritingOptions.prettyPrinted)
self.websocket.send(jsonData)
break
socket.write(data: jsonData)
}
else {
print("Socket is not connected")
start()
}

}

// MARK: helpers
Expand Down