0

I use laravel-websocket for get my user online/offline status.

This is my onClose function code in WebSocketHandler.php file:

 public function onClose(ConnectionInterface $connection)
    {

        $allChannels = $this->channelManager->getChannels($connection->app->id);

        foreach ($allChannels as $channelData) {
            $data = $channelData;
        }
        dd($data);

        $this->channelManager->removeFromAllChannels($connection);

        DashboardLogger::disconnection($connection);

        StatisticsLogger::disconnection($connection);
    }

And when the user closes the tab or browser my onClose function gives me $data in console logging which is this response:

BeyondCode\LaravelWebSockets\WebSockets\Channels\PresenceChannel {#719
  #users: array:1 [
    1 => array:9 [
      "id" => 1
      "email" => "sd@sd.com"
      "username" => "BlackHill"
      "type" => 0
      "steam_id" => "76561198107211703"
      "stay_login" => 0
      "email_verified_at" => null
      "created_at" => "2022-03-21T22:54:53.000000Z"
      "updated_at" => "2022-04-23T20:13:19.000000Z"
    ]
  ]
  #sockets: array:1 [
    "161595151.817952840" => "1"
  ]
  #channelName: "presence-users"
  #subscribedConnections: array:1 [
    "161595151.817952840" => BeyondCode\LaravelWebSockets\Server\Logger\ConnectionLogger {#722
      #connection: Ratchet\WebSocket\WsConnection {#703
        #wrappedConn: Ratchet\Server\IoConnection {#691
          #conn: React\Socket\Connection {#650
            +unix: false
            +encryptionEnabled: false
            +stream: stream resource {@698
              timed_out: false
              blocked: false
              eof: false
              stream_type: "tcp_socket/ssl"
              mode: "r+"
              unread_bytes: 0
              seekable: false
              options: array:1 [
                "socket" => array:1 [
                  "backlog" => 511
                ]
              ]
            }
            -input: React\Stream\DuplexResourceStream {#681
              -stream: stream resource @698
              -loop: React\EventLoop\StreamSelectLoop {#449
                -futureTickQueue: React\EventLoop\Tick\FutureTickQueue {#450
                  -queue: SplQueue {#451
                    -flags: 4
                    -dllist: []
                    mode: IT_MODE_FIFO | IT_MODE_KEEP
                    dllist: []
                  }
                }
                -timers: React\EventLoop\Timer\Timers {#452
                  -time: 1889837.7109229
                  -timers: array:2 [
                    "000000003696a05d00000000377ed389" => React\EventLoop\Timer\Timer {#620
                      -interval: 60.0
                      -callback: Closure() {#619
                        class: "BeyondCode\LaravelWebSockets\Console\StartWebSocketServer"
                        this: BeyondCode\LaravelWebSockets\Console\StartWebSocketServer {#443 …}
                      }
                      -periodic: true
                    }
                    "000000003696a04000000000377ed389" => React\EventLoop\Timer\Timer {#625
                      -interval: 10.0
                      -callback: Closure() {#624
                        class: "BeyondCode\LaravelWebSockets\Console\StartWebSocketServer"
                        this: BeyondCode\LaravelWebSockets\Console\StartWebSocketServer {#443 …}
                      }
                      -periodic: true
                    }
                  ]
                  -schedule: array:2 [
                    "000000003696a04000000000377ed389" => 1889838.6927814
                    "000000003696a05d00000000377ed389" => 1889888.6920111
                  ]
                  -sorted: true
                  -useHighResolution: true
                }
                -readStreams: array:1 [
                  683 => stream resource {@683
                    timed_out: false
                    blocked: false
                    eof: false
                    stream_type: "tcp_socket/ssl"
                    mode: "r+"
                    unread_bytes: 0
                    seekable: false
                    options: array:1 [
                      "socket" => array:1 [
                        "backlog" => 511
                      ]
                    ]
                  }
                ]
                -readListeners: array:1 [
                  683 => Closure($master) {#669
                    class: "React\Socket\TcpServer"
                    this: React\Socket\TcpServer {#668 …}
                    use: {
                      $that: React\Socket\TcpServer {#668 …}
                    }
                  }
                ]
                -writeStreams: []
                -writeListeners: []
                -running: true
                -pcntl: false
                -pcntlPoll: false
                -signals: React\EventLoop\SignalsHandler {#453
                  -signals: []
                }
              }
              -bufferSize: 65536
              -buffer: React\Stream\WritableResourceStream {#682
                -stream: stream resource @698
                -loop: React\EventLoop\StreamSelectLoop {#449}
                -softLimit: 65536
                -writeChunkSize: -1
                -listening: false
                -writable: false
                -closed: true
                -data: ""
                #listeners: array:3 [
                  "error" => array:1 [
                    0 => Closure($error) {#683
                      class: "React\Stream\DuplexResourceStream"
                      this: React\Stream\DuplexResourceStream {#681}
                      use: {
                        $that: React\Stream\DuplexResourceStream {#681}
                      }
                    }
                  ]
                  "close" => array:1 [
                    0 => array:2 [
                      0 => React\Stream\DuplexResourceStream {#681}
                      1 => "close"
                    ]
                  ]
                  "drain" => array:1 [
                    0 => Closure() {#684
                      class: "React\Stream\DuplexResourceStream"
                      this: React\Stream\DuplexResourceStream {#681}
                      use: {
                        $that: React\Stream\DuplexResourceStream {#681}
                      }
                    }
                  ]
                ]
                #onceListeners: []
              }
              -readable: false
              -writable: false
              -closing: false
              -listening: false
              #listeners: array:6 [
                "data" => array:1 [
                  0 => Closure() {#685
                    class: "React\Stream\Util"
                    use: {
                      $event: "data"
                      $target: React\Socket\Connection {#650}
                    }
                  }
                ]
                "end" => array:1 [
                  0 => Closure() {#686
                    class: "React\Stream\Util"
                    use: {
                      $event: "end"
                      $target: React\Socket\Connection {#650}
                    }
                  }
                ]
                "error" => array:1 [
                  0 => Closure() {#687
                    class: "React\Stream\Util"
                    use: {
                      $event: "error"
                      $target: React\Socket\Connection {#650}
                    }
                  }
                ]
                "close" => array:2 [
                  0 => Closure() {#688
                    class: "React\Stream\Util"
                    use: {
                      $event: "close"
                      $target: React\Socket\Connection {#650}
                    }
                  }
                  1 => array:2 [
                    0 => React\Socket\Connection {#650}
                    1 => "close"
                  ]
                ]
                "pipe" => array:1 [
                  0 => Closure() {#689
                    class: "React\Stream\Util"
                    use: {
                      $event: "pipe"
                      $target: React\Socket\Connection {#650}
                    }
                  }
                ]
                "drain" => array:1 [
                  0 => Closure() {#690
                    class: "React\Stream\Util"
                    use: {
                      $event: "drain"
                      $target: React\Socket\Connection {#650}
                    }
                  }
                ]
              ]
              #onceListeners: []
            }
            #listeners: array:3 [
              "data" => array:1 [
                0 => Closure($data) {#692
                  class: "Ratchet\Server\IoServer"
                  this: Ratchet\Server\IoServer {#680 …}
                  use: {
                    $conn: React\Socket\Connection {#650}
                  }
                }
              ]
              "close" => array:1 [
                0 => Closure() {#693
                  class: "Ratchet\Server\IoServer"
                  this: Ratchet\Server\IoServer {#680 …}
                  use: {
                    $conn: React\Socket\Connection {#650}
                  }
                }
              ]
              "error" => array:1 [
                0 => Closure(Exception $e) {#694
                  class: "Ratchet\Server\IoServer"
                  this: Ratchet\Server\IoServer {#680 …}
                  use: {
                    $conn: React\Socket\Connection {#650}
                  }
                }
              ]
            ]
            #onceListeners: []
            +"decor": Ratchet\Server\IoConnection {#691}
          }
          +"resourceId": 698
          +"remoteAddress": "127.0.0.1"
          +"httpHeadersReceived": true
          +"controller": Ratchet\WebSocket\WsServer {#626
            -delegate: BeyondCode\LaravelWebSockets\Server\Logger\WebsocketsLogger {#627
              #app: BeyondCode\LaravelWebSockets\WebSockets\WebSocketHandler {#629
                #channelManager: BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManagers\ArrayChannelManager {#630
                  #appId: null
                  #channels: array:1 [
                    "local" => array:1 [
                      "presence-users" => BeyondCode\LaravelWebSockets\WebSockets\Channels\PresenceChannel {#719}
                    ]
                  ]
                }
              }
              #consoleOutput: Illuminate\Console\OutputStyle {#599
                -output: Symfony\Component\Console\Output\ConsoleOutput {#24
                  -stderr: Symfony\Component\Console\Output\StreamOutput {#42
                    -stream: stream resource {@3
                      timed_out: false
                      blocked: true
                      eof: false
                      wrapper_type: "PHP"
                      stream_type: "STDIO"
                      mode: "wb"
                      unread_bytes: 0
                      seekable: false
                      uri: "php://stderr"
                      options: []
                    }
                    -verbosity: 32
                    -formatter: Symfony\Component\Console\Formatter\OutputFormatter {#43
                      -decorated: true
                      -styles: array:4 [
                        "error" => Symfony\Component\Console\Formatter\OutputFormatterStyle {#44
                          -color: Symfony\Component\Console\Color {#45
                            -foreground: "37"
                            -background: "41"
                            -options: []
                          }
                          -foreground: "white"
                          -background: "red"
                          -options: []
                          -href: null
                        }
                        "info" => Symfony\Component\Console\Formatter\OutputFormatterStyle {#46
                          -color: Symfony\Component\Console\Color {#47
                            -foreground: "32"
                            -background: ""
                            -options: []
                          }
                          -foreground: "green"
                          -background: ""
                          -options: []
                          -href: null
                        }
                        "comment" => Symfony\Component\Console\Formatter\OutputFormatterStyle {#48
                          -color: Symfony\Component\Console\Color {#49
                            -foreground: "33"
                            -background: ""
                            -options: []
                          }
                          -foreground: "yellow"
                          -background: ""
                          -options: []
                          -href: null
                        }
                        "question" => Symfony\Component\Console\Formatter\OutputFormatterStyle {#50
                          -color: Symfony\Component\Console\Color {#51
                            -foreground: "30"
                            -background: "46"
                            -options: []
                          }
                          -foreground: "black"
                          -background: "cyan"
                          -options: []
                          -href: null
                        }
                      ]
                      -styleStack: Symfony\Component\Console\Formatter\OutputFormatterStyleStack {#52
                        -styles: []
                        -emptyStyle: Symfony\Component\Console\Formatter\OutputFormatterStyle {#53
                          -color: Symfony\Component\Console\Color {#54
                            -foreground: ""
                            -background: ""
                            -options: []
                          }
                          -foreground: ""
                          -background: ""
                          -options: []
                          -href: null
                        }
                      }
                    }
                  }
                  -consoleSectionOutputs: []
                  -stream: stream resource {@2
                    timed_out: false
                    blocked: true
                    eof: false
                    wrapper_type: "PHP"
                    stream_type: "STDIO"
                    mode: "wb"
                    unread_bytes: 0
                    seekable: false
                    uri: "php://stdout"
                    options: []
                  }
                  -verbosity: 32
                  -formatter: Symfony\Component\Console\Formatter\OutputFormatter {#23
                    -decorated: true
                    -styles: array:5 [
                      "error" => Symfony\Component\Console\Formatter\OutputFormatterStyle {#31
                        -color: Symfony\Component\Console\Color {#32
                          -foreground: "37"
                          -background: "41"
                          -options: []
                        }
                        -foreground: "white"
                        -background: "red"
                        -options: []
                        -href: null
                      }
                      "info" => Symfony\Component\Console\Formatter\OutputFormatterStyle {#33
                        -color: Symfony\Component\Console\Color {#34
                          -foreground: "32"
                          -background: ""
                          -options: []
                        }
                        -foreground: "green"
                        -background: ""
                        -options: []
                        -href: null
                        -handlesHrefGracefully: false
                      }
                      "comment" => Symfony\Component\Console\Formatter\OutputFormatterStyle {#35
                        -color: Symfony\Component\Console\Color {#36
                          -foreground: "33"
                          -background: ""
                          -options: []
                        }
                        -foreground: "yellow"
                        -background: ""
                        -options: []
                        -href: null
                      }
                      "question" => Symfony\Component\Console\Formatter\OutputFormatterStyle {#37
                        -color: Symfony\Component\Console\Color {#38
                          -foreground: "30"
                          -background: "46"
                          -options: []
                        }
                        -foreground: "black"
                        -background: "cyan"
                        -options: []
                        -href: null
                      }
                      "warning" => Symfony\Component\Console\Formatter\OutputFormatterStyle {#709
                        -color: Symfony\Component\Console\Color {#710
                          -foreground: "33"
                          -background: ""
                          -options: []
                        }
                        -foreground: "yellow"
                        -background: ""
                        -options: []
                        -href: null
                        -handlesHrefGracefully: false
                      }
                    ]
                    -styleStack: Symfony\Component\Console\Formatter\OutputFormatterStyleStack {#39
                      -styles: []
                      -emptyStyle: Symfony\Component\Console\Formatter\OutputFormatterStyle {#40
                        -color: Symfony\Component\Console\Color {#41
                          -foreground: ""
                          -background: ""
                          -options: []
                        }
                        -foreground: ""
                        -background: ""
                        -options: []
                        -href: null
                      }
                    }
                  }
                }
                -input: Symfony\Component\Console\Input\ArgvInput {#26
                  -tokens: array:1 [
                    0 => "websockets:serve"
                  ]
                  -parsed: []
                  #definition: Symfony\Component\Console\Input\InputDefinition {#598
                    -arguments: array:1 [
                      "command" => Symfony\Component\Console\Input\InputArgument {#588
                        -name: "command"
                        -mode: 1
                        -default: null
                        -description: "The command to execute"
                      }
                    ]
                    -requiredCount: 1
                    -lastArrayArgument: null
                    -lastOptionalArgument: null
                    -options: array:10 [
                      "host" => Symfony\Component\Console\Input\InputOption {#445
                        -name: "host"
                        -shortcut: null
                        -mode: 4
                        -default: "0.0.0.0"
                        -description: ""
                      }
                      "port" => Symfony\Component\Console\Input\InputOption {#436
                        -name: "port"
                        -shortcut: null
                        -mode: 4
                        -default: "6001"
                        -description: ""
                      }
                      "debug" => Symfony\Component\Console\Input\InputOption {#447
                        -name: "debug"
                        -shortcut: null
                        -mode: 1
                        -default: false
                        -description: "Forces the loggers to be enabled and thereby overriding the app.debug config setting"
                      }
                      "help" => Symfony\Component\Console\Input\InputOption {#589
                        -name: "help"
                        -shortcut: "h"
                        -mode: 1
                        -default: false
                        -description: "Display help for the given command. When no command is given display help for the <info>list</info> command"
                      }
                      "quiet" => Symfony\Component\Console\Input\InputOption {#590
                        -name: "quiet"
                        -shortcut: "q"
                        -mode: 1
                        -default: false
                        -description: "Do not output any message"
                      }
                      "verbose" => Symfony\Component\Console\Input\InputOption {#591
                        -name: "verbose"
                        -shortcut: "v|vv|vvv"
                        -mode: 1
                        -default: false
                        -description: "Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug"
                      }
                      "version" => Symfony\Component\Console\Input\InputOption {#592
                        -name: "version"
                        -shortcut: "V"
                        -mode: 1
                        -default: false
                        -description: "Display this application version"
                      }
                      "ansi" => Symfony\Component\Console\Input\InputOption {#593
                        -name: "ansi"
                        -shortcut: null
                        -mode: 16
                        -default: null
                        -description: "Force (or disable --no-ansi) ANSI output"
                      }
                      "no-interaction" => Symfony\Component\Console\Input\InputOption {#594
                        -name: "no-interaction"
                        -shortcut: "n"
                        -mode: 1
                        -default: false
                        -description: "Do not ask any interactive question"
                      }
                      "env" => Symfony\Component\Console\Input\InputOption {#596
                        -name: "env"
                        -shortcut: null
                        -mode: 4
                        -default: null
                        -description: "The environment the command should run under"
                      }
                    ]
                    -negations: array:1 [
                      "no-ansi" => "ansi"
                    ]
                    -shortcuts: array:7 [
                      "h" => "help"
                      "q" => "quiet"
                      "v" => "verbose"
                      "vv" => "verbose"
                      "vvv" => "verbose"
                      "V" => "version"
                      "n" => "no-interaction"
                    ]
                  }
                  #stream: null
                  #options: []
                  #arguments: array:1 [
                    "command" => "websockets:serve"
                  ]
                  #interactive: true
                }
                -questionHelper: null
                -progressBar: null
                -lineLength: 120
                -bufferedOutput: Symfony\Component\Console\Output\TrimmedBufferOutput {#600
                  -maxLength: 4
                  -buffer: "g>\r\n"
                  -verbosity: 32
                  -formatter: Symfony\Component\Console\Formatter\OutputFormatter {#601
                    -decorated: false
                    -styles: array:4 [
                      "error" => Symfony\Component\Console\Formatter\OutputFormatterStyle {#603
                        -color: Symfony\Component\Console\Color {#32}
                        -foreground: "white"
                        -background: "red"
                        -options: []
                        -href: null
                      }
                      "info" => Symfony\Component\Console\Formatter\OutputFormatterStyle {#604
                        -color: Symfony\Component\Console\Color {#34}
                        -foreground: "green"
                        -background: ""
                        -options: []
                        -href: null
                        -handlesHrefGracefully: false
                      }
                      "comment" => Symfony\Component\Console\Formatter\OutputFormatterStyle {#605
                        -color: Symfony\Component\Console\Color {#36}
                        -foreground: "yellow"
                        -background: ""
                        -options: []
                        -href: null
                      }
                      "question" => Symfony\Component\Console\Formatter\OutputFormatterStyle {#606
                        -color: Symfony\Component\Console\Color {#38}
                        -foreground: "black"
                        -background: "cyan"
                        -options: []
                        -href: null
                      }
                    ]
                    -styleStack: Symfony\Component\Console\Formatter\OutputFormatterStyleStack {#602
                      -styles: []
                      -emptyStyle: Symfony\Component\Console\Formatter\OutputFormatterStyle {#40}
                    }
                  }
                }
                -output: Symfony\Component\Console\Output\ConsoleOutput {#24}
                -output: Symfony\Component\Console\Output\ConsoleOutput {#24}
              }
              #enabled: true
              #verbose: false
            }
            #connections: SplObjectStorage {#632
              storage: []
            }
            -closeFrameChecker: Ratchet\RFC6455\Messaging\CloseFrameChecker {#633
              -validCloseCodes: array:9 [
                0 => 1000
                1 => 1001
                2 => 1002
                3 => 1003
                4 => 1007
                5 => 1008
                6 => 1009
                7 => 1010
                8 => 1011
              ]
            }
            -handshakeNegotiator: Ratchet\RFC6455\Handshake\ServerNegotiator {#634
              -verifier: Ratchet\RFC6455\Handshake\RequestVerifier {#635}
              -_supportedSubProtocols: []
              -_strictSubProtocols: true
              -enablePerMessageDeflate: false
            }
            -ueFlowFactory: Closure() {#638
              class: "Ratchet\WebSocket\WsServer"
              this: Ratchet\WebSocket\WsServer {#626}
              use: {
                $reusableUnderflowException: UnderflowException {#637 …}
              }
            }
            -pongReceiver: Closure() {#636
              class: "Ratchet\WebSocket\WsServer"
              this: Ratchet\WebSocket\WsServer {#626}
            }
            -msgCb: Closure(ConnectionInterface $conn, MessageInterface $msg) {#631
              class: "Ratchet\WebSocket\WsServer"
              this: Ratchet\WebSocket\WsServer {#626}
            }
          }
          +"httpRequest": GuzzleHttp\Psr7\Request {#697
            -method: "GET"
            -requestTarget: null
            -uri: GuzzleHttp\Psr7\Uri {#698
              -scheme: "http"
              -userInfo: ""
              -host: "localhost"
              -port: 6001
              -path: "/app/local"
              -query: "appKey=local&protocol=7&client=js&version=7.0.6&flash=false"
              -fragment: ""
              -composedComponents: null
            }
          +"socketId": "161595151.817952840"
        }
      }
      #consoleOutput: Illuminate\Console\OutputStyle {#599}
      #enabled: true
      #verbose: false
    }
  ]
}

I need to access #users array to apply changes to any user who leaves. In this issue they managed to get channelName but I did not get #users using their solution!

BlackHill
  • 1
  • 1
  • 6

1 Answers1

0

Finally friends! you can get user_info in any handlers just like that:

First, you need to add your chosen channel mode file in your custom handler, in my case its: use BeyondCode\LaravelWebSockets\WebSockets\Channels\PresenceChannel;

and with this magic code, you can get any one of the user_info data and update your user database:

$allChannels = collect($this->channelManager->getChannels($connection->app->id))
            ->flatMap(function (PresenceChannel $presenceChannel) {
                $userId = collect($presenceChannel->getUsers())->pluck('id');
                User::where('id', $userId)->update(['isOnline' => false]);
            });

example with onClose handler (in my case):

    public function onClose(ConnectionInterface $connection)
    {

        $allChannels = collect($this->channelManager->getChannels($connection->app->id))
            ->flatMap(function (PresenceChannel $presenceChannel) {
                $userId = collect($presenceChannel->getUsers())->pluck('id');
                User::where('id', $userId)->update(['isOnline' => false]);
            });

        $this->channelManager->removeFromAllChannels($connection);

        DashboardLogger::disconnection($connection);

        StatisticsLogger::disconnection($connection);
    }

BlackHill
  • 1
  • 1
  • 6