Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Missing member data for presence channel #581

Open
erick-innosonian opened this issue Jul 8, 2021 · 1 comment
Open

Missing member data for presence channel #581

erick-innosonian opened this issue Jul 8, 2021 · 1 comment

Comments

@erick-innosonian
Copy link

Describe the bug
I can't get member data when using presence channel.

Versions

composer.json

"laravel/framework": "6.20.22",
"laravel/passport": "9.0",
"predis/predis": "1.1.7",

package.json

laravel-echo-server: 1.6.2
"socket.io-client": "2.4.0",
"laravel-echo": "1.10.0",

Server side

.env

BROADCAST_DRIVER=redis
QUEUE_CONNECTION=sync
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
REDIS_PREFIX=

laravel-echo-server.json

{
	"authHost": "http://localhost:8080",
	"authEndpoint": "/custom/broadcasting/auth",
	"clients": [],
	"database": "redis",
	"databaseConfig": {
		"redis": {},
		"sqlite": {
			"databasePath": "/database/laravel-echo-server.sqlite"
		}
	},
	"devMode": true,
	"host": null,
	"port": "6001",
	"protocol": "http",
	"socketio": {},
	"secureOptions": 67108864,
	"sslCertPath": "",
	"sslKeyPath": "",
	"sslCertChainPath": "",
	"sslPassphrase": "",
	"subscribers": {
		"http": true,
		"redis": true
	}
}

web.php

Route::post('/custom/broadcasting/auth', function (\Illuminate\Http\Request $request) {
    Log::debug('custom auth');
    $user = User::where('id', 1)->first();
    return [$user->name];
});

Route::post('/messages', function (\Illuminate\Http\Request $request) {
    broadcast(new \App\Events\MyEvent($request->clientId, $request->message));
    return [
        'message' => $request->message
    ];
});

MyEvent.php

class MyEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message;
    public $clientID;
    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($clientID, $message)
    {
        $this->message = $message;
        $this->clientID = $clientID;
    }

    public function broadcastOn()
    {
        return new PresenceChannel('chat.' . $this->clientID);
    }
}

config/database.php

    'redis' => [

        'client' => env('REDIS_CLIENT', 'predis'),

        'options' => [
            'cluster' => env('REDIS_CLUSTER', 'redis'),
            'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
        ],

        'default' => [
            'url' => env('REDIS_URL'),
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', '6379'),
            'database' => env('REDIS_DB', '0'),
        ],

        'cache' => [
            'url' => env('REDIS_URL'),
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', '6379'),
            'database' => env('REDIS_CACHE_DB', '1'),
        ],

    ],

client side

bootstrap.js

import Echo from "laravel-echo"
window.io = require('socket.io-client');

window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.hostname + ':8080',
    authEndpoint: '/custom/broadcasting/auth',
    authorizer: (channel, options) => {
        return {
            authorize: (socketId, callback) => {
                axios.post('/custom/broadcasting/auth', {
                    socket_id: socketId,
                    channel_name: channel.name
                })
                    .then(response => {
                        callback(false, response.data);
                    })
                    .catch(error => {
                        callback(true, error);
                    });
            }
        };
    },

});

client.vue

export default {
    props: ['clientId'],
    data: function () {
        return {
            messages: [],
            newMessage: '',
            statusMessage: 'Joined a room',
            isStarted: false,
            members: [],
            checkedMember: '',
        }
    },
    created() {
    },
    computed: {
        channel() {
            var joining = window.Echo.join(`chat.${this.clientId}`)
            console.log(joining);
            return window.Echo.join(`chat.${this.clientId}`)
        }
    },
    mounted() {
        console.log(`Joining to chat.${this.clientId}`)
        console.log('this channel', this.channel);
        this.channel.here((users) => {
            console.log(`Joined chat.${this.clientId}`)
            this.members = users;
            })
            .joining((user) => {
                console.log('Joining ', JSON.stringify(user));
                this.members.put(user)
            })
            .leaving((user) => {
                this.members = this.members.filter(member => user.id !== member.id)
                console.log(`leaved ${user.name}`);
            })
            .error((error) => {
                console.error(error);
            })
            .listen('MyEvent', (e) => {
                console.log(e);
                this.messages.push({
                    message: e.message.message,
                    user: e.user
                });
            });
    },

    methods: {
        addMessage(clientId, message) {
            axios.post('/messages', {
                clientId,
                message
            }).then(response => {
                this.messages.push({
                    message: response.data.message.message,
                    // user: response.data.user
                });
            });
        },

        sendMessage() {
            this.addMessage(this.clientId, this.newMessage);
            this.newMessage = '';
        },

        sendStartMessage() {
            this.statusMessage = 'Started';
            this.isStarted = true;
            this.addMessage(this.clientId, 'start');
        },

        sendStopMessage() {
            this.statusMessage = 'Ready';
            this.isStarted = false;
            this.addMessage(this.clientId, 'stop');
        }
    }
}
</script>

console debug

SocketIoPresenceChannel {events: {…}, listeners: {…}, name: "presence-chat.my-client-id", socket: Socket, options: {…}, …}

ㄴ eventFormatter: EventFormatter {namespace: "App.Events"}
ㄴ events: {presence:subscribed: ƒ, presence:joining: ƒ, presence:leaving: ƒ, App\Events\MyEvent: ƒ}
ㄴ listeners: {presence:subscribed: Array(1), presence:joining: Array(1), presence:leaving: Array(1), App\Events\MyEvent: Array(1)}
name: "presence-chat.my-client-id"
ㄴ options: {auth: {…}, authEndpoint: "/custom/broadcasting/auth", broadcaster: "socket.io", csrfToken: null, host: "localhost:8080", …}
ㄴ socket: Socket {io: Manager, nsp: "/", json: Socket, ids: 0, acks: {…}, …}
__proto__: SocketIoPrivateChannel

If I try with private and public channel, It works.
But If I try with Presence channel, always not working.
laravel echo server said

Event: [object Object]
(node:75981) UnhandledPromiseRejectionWarning: TypeError: Cannot convert undefined or null to object
    at /Users/myname/.nvm/versions/node/v14.5.0/lib/node_modules/laravel-echo-server/dist/channels/presence-channel.js:78:21
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
(node:75981) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 3)

Unable to join channel. Member data for presence channel missing

And wired thing is that I can listen an event.
Could you let me know the problem?

@TemKaa1337
Copy link

TemKaa1337 commented Aug 27, 2021

Try to change this:

Route::post('/custom/broadcasting/auth', function (\Illuminate\Http\Request $request) {
    Log::debug('custom auth');
    $user = User::where('id', 1)->first();
    return [$user->name];
});

To this:

Route::post('/custom/broadcasting/auth', function (\Illuminate\Http\Request $request) {
    Log::debug('custom auth');
    $user = User::where('id', 1)->first();
    return ['channel_data' => ['id' => $user->id, 'user_id' => $user->id]];
});

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants