Giter Site home page Giter Site logo

nerzh / action-cable-swift Goto Github PK

View Code? Open in Web Editor NEW
40.0 3.0 11.0 45 KB

ActionCable is a WebSocket server being released with Rails 5 which makes it easy to add real-time features to your app. This Swift client inspired by "Swift-ActionCableClient", but it not support now and I created Action-Cable-Swift. Also web sockets are now separate from the client.

License: MIT License

Swift 100.00%
swift web-sockets rails actioncable swift-client swift-nio websocket-kit starscream

action-cable-swift's People

Contributors

ahbou avatar jannemecek avatar jlcvp avatar nerzh avatar wolframpro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

action-cable-swift's Issues

WSS non Starscream class thread warning(s)

Action Cable Swift- 0.4.0
Web socket kit - 2.14.0
Xcode - 15.0

I have a class setup like the WSS from the non Starscream example. The thread checker always catches at least 1, but sometimes two threading issues related to WSS init MultiThreadedEventLoopGroup.

final class WSS: ACWebSocketProtocol {

  var url: URL
  private var eventLoopGroup: EventLoopGroup
  @Atomic var ws: WebSocket?

  init(stringURL: String, coreCount: Int = System.coreCount) {
      url = URL(string: stringURL)!
      eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: coreCount)
  }

It then directly shows an issue with loopUpAndRunningGroup.wait() inside of MultiThreadEvenLoopGroup class, around line 125:

Thread running at User-interactive quality-of-service class waiting on a lower QoS thread running at Default quality-of-service class. Investigate ways to avoid priority inversions

Haven't seen other issues related to it. Any help or guidance is appreciated.

Socket connected but client.isConnected is false

my code:

if !client.isConnected {
            // reconnect
            client.connect()
            debugPrint("socket not connected")
        }

Could I send the message outside closure?

try? channel.sendMessage(actionName: "speak",
                                     data: ["message": message, "room_id": "1", "somekey": "xxx"], { [weak self] in
                debugPrint("sent complete")
            })

Channel not being subscribed

socket gets connected properly
channel welcome text comes
channel ping comes constantly
but addOnSubscribe closure never gets called

Priority inversion warning

I'm seeing a priority inversion warning when I create the WSS

I don't understand swiftnio well enough to know whether this is a real issue, or a false positive.

I'm creating my WSS on the main thread

let ws: WSS = .init(stringURL:...

Thread Performance Checker: Thread running at QOS_CLASS_USER_INTERACTIVE waiting on a lower QoS thread running at QOS_CLASS_DEFAULT. Investigate ways to avoid priority inversions
PID: 10905, TID: 6703472
Backtrace
=================================================================
3   WebsocketChatDefender               0x0000000104cca774 $s8NIOPosix27MultiThreadedEventLoopGroupC014setupThreadAnddE033_C2B1528F4FBA68A3DBFA89DBAEBE9D4DLL4name06parentF015selectorFactory11initializerAA010SelectabledE0CSS_AcA8SelectorCyAA15NIORegistrationVGyKcyAA9NIOThreadCctFZ + 452
4   WebsocketChatDefender               0x0000000104ccb3c4 $s8NIOPosix27MultiThreadedEventLoopGroupC18threadInitializers15selectorFactoryACSayyAA9NIOThreadCcG_AA8SelectorCyAA15NIORegistrationVGyKctcfcAA010SelectabledE0CyAGcXEfU_ + 556
5   WebsocketChatDefender               0x0000000104cce054 $s8NIOPosix27MultiThreadedEventLoopGroupC18threadInitializers15selectorFactoryACSayyAA9NIOThreadCcG_AA8SelectorCyAA15NIORegistrationVGyKctcfcAA010SelectabledE0CyAGcXEfU_TA + 40
6   libswiftCore.dylib                  0x000000018bcc120c $sSlsE3mapySayqd__Gqd__7ElementQzKXEKlF + 400
7   WebsocketChatDefender               0x0000000104ccb0e8 $s8NIOPosix27MultiThreadedEventLoopGroupC18threadInitializers15selectorFactoryACSayyAA9NIOThreadCcG_AA8SelectorCyAA15NIORegistrationVGyKctcfc + 552
8   WebsocketChatDefender               0x0000000104ccaeb0 $s8NIOPosix27MultiThreadedEventLoopGroupC18threadInitializers15selectorFactoryACSayyAA9NIOThreadCcG_AA8SelectorCyAA15NIORegistrationVGyKctcfC + 72
9   WebsocketChatDefender               0x0000000104ccad8c $s8NIOPosix27MultiThreadedEventLoopGroupC15numberOfThreads15selectorFactoryACSi_AA8SelectorCyAA15NIORegistrationVGyKctcfC + 316
10  WebsocketChatDefender               0x0000000104ccabb0 $s8NIOPosix27MultiThreadedEventLoopGroupC15numberOfThreadsACSi_tcfC + 40
11  WebsocketChatDefender               0x0000000104a9fc80 $s21WebsocketChatDefender3WSSC9stringURL9coreCountACSS_Sitcfc + 628
12  WebsocketChatDefender               0x0000000104a9f9fc $s21WebsocketChatDefender3WSSC9stringURL9coreCountACSS_SitcfC + 72
13  WebsocketChatDefender               0x0000000104a9ef60 $s21WebsocketChatDefender7ManagerCACycfc + 136
14  WebsocketChatDefender               0x0000000104a9eecc $s21WebsocketChatDefender7ManagerCACycfC + 44
15  WebsocketChatDefender               0x0000000104aa6280 $s21WebsocketChatDefender0abC3AppVACycfC + 44
16  WebsocketChatDefender               0x0000000104aa6300 $s21WebsocketChatDefender0abC3AppV7SwiftUI0D0AadEPxycfCTW + 20
17  SwiftUI                             0x000000010a8a3464 OUTLINED_FUNCTION_16 + 72
18  WebsocketChatDefender               0x0000000104aa61e0 $s21WebsocketChatDefender0abC3AppV5$mainyyFZ + 40
19  WebsocketChatDefender               0x0000000104aa6320 main + 12

The `send message` action is not working.

here is an example of generated message which can't be parsed by server,

"{\"identifier\":\"{\\\"channel\\\":\\\"LivestreamChatsChannel\\\",\\\"livestream_id\\\":12}\",\"command\":\"message\",\"data\":\"{\\\"content\\\":\\\"hello!\\\",\\\"action\\\":\\\"chat\\\"}\"}"

Leaked connections when trying to connect to a high latency server

This following snippet of code in the project is creating multiple connections when connecting to high latency servers. The while loop calls self.client?.connect again (thus, creating another websocketclient) if the first call takes more than 200 + self._checksDelay millis to connect/fail

if !self.isConnected() {
self.client?.disconnect()
usleep(200_000)
self.client?.connect()
usleep(self._checksDelay)
self.updateLastPoint()
continue
}

The problem with this busy wait approach is that we don't have a way outside this library code to manage those connections and terminate the duplicates if needed.

I think we Should try to use a Lock before the if !self.isConnected() { check to do this verification only after the connection handshake itself. That way we would have only 2 states possible (connection successful or connection failed), hence avoiding the duplicates

reconnect should fall back gracefully

I love how robust the reconnection is, however if connections fail repeatedly, then the default of attempting every 0.5 seconds is going to hammer a struggling server.

If the reason that the connection is failing is a server in trouble, then this potentially adds something close to a denial of service attack on top of whatever problem exists...

Standard practice would be an exponential fallback - so, waiting (twice?, 1.5x?) as long between each reconnection attempt.
Perhaps to a maximum of a 60 second delay between checks...

I'm happy to have a go if you'd accept a pull request...

addOnMessage Calls multiple times for a single broadcast

Hello @nerzh , First of all, thanks for an amazing library. I'm facing a strange issue while creating a connection. I'm using WS to create a connection. I followed all the instructions and I'm able to create connections, create/subscribe channels, and receive messages. The only problem I'm facing is whenever I create a connection the connection gets created 3 times/6 times in a row and whenever the server sends a broadcast, I receive it 6 times. Can you please explain what is the issue?
Here is my code:-
`import UIKit
import ActionCableSwift

class ChatsListVC: UIViewController {

//MARK: IB Outlets
var ws: WSS = .init(stringURL: "ws://53b6-2405-201-5009-610f-24fa-6b65-905b-b188.ngrok.io/cable")
var clientOptions: ACClientOptions = .init(debug: true, reconnect: true)
var client: ACClient!
var channelOptions: ACChannelOptions!
var channel: ACChannel!


override func viewDidLoad() {
    super.viewDidLoad()
    self.setupActionCable()
}

func setupActionCable() {
    /// web socket client
    //self.ws = .init(stringURL: "ws://localhost:3001/cable")

    /// action cable client
    //self.clientOptions = .init(debug: false, reconnect: true)
    self.client = .init(ws: ws, options: clientOptions)
    /// on server you can get this with env['HTTP_COOKIE']
    client.headers = ["Authorization": appUser.auth_token!]

    /// make channel
    /// buffering - buffering messages if disconnect and flush after reconnect
    let channelOptions: ACChannelOptions = .init(buffering: true, autoSubscribe: false)
    /// params to subscribe passed inside the identifier dictionary
    let identifier: [String: Any] = ["conversation_id": "2"]
    channel = (client.makeChannel(name: "ConversationChannel", identifier: identifier, options: channelOptions))

    // !!! Make sure that the client and channel objects is declared "globally" and lives while your socket connection is needed

    channel?.addOnSubscribe { (channel, optionalMessage) in
        print(optionalMessage)
    }
    channel?.addOnMessage { (channel, optionalMessage) in
        print(optionalMessage)
    }
    channel?.addOnPing { (channel, optionalMessage) in
        print("ping")
    }
    /// Connect
    client.connect()
    
    client.addOnConnected { (headers) in
        try? self.channel.subscribe()
    }
}

`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.