Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using ->toOthers() results in a "Ably error: Malformed message; invalid connectionKey" #38

Closed
diversitude opened this issue Feb 28, 2024 · 39 comments · Fixed by #50
Closed
Assignees

Comments

@diversitude
Copy link

diversitude commented Feb 28, 2024

Triggering an event using toOthers() with X-Socket-ID in the request header results in an "Ably error: Malformed message; invalid connectionKey"

┆Issue is synchronized with this Jira Task by Unito

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

This is very unlikely to happen. How frequently does this happen? Also, what are the client side errors in laravel-echo ( if any )

@diversitude
Copy link
Author

diversitude commented Feb 28, 2024

No client side errors as the event doesn't dispatch from Laravel- the job fails.
It does work if the incoming request doesn't contain the X-SOCKET-ID header.
The project I'm working on is running Laravel 8.83.27, couid that be an issue?

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

Okay, maybe you are using old ably broadcaster. Are you using pusher-js + echo at client side. Then you will get the same error -> https://faqs.ably.com/why-isnt-the-broadcast-only-to-others-functionality-working-in-laravel-with-the-ably-broadcaster.
To fix this error, you need to install explicitly

composer require ably/laravel-broadcaster

and then install

npm install @ably/laravel-echo ably

at client side.
Since you are planning to migrate to new setup, follow

https://github.com/ably/laravel-broadcaster?tab=readme-ov-file#migrating-from-pusherpusher-compatible-broadcasters

@diversitude
Copy link
Author

I originally followed the Pusher integration, but presence channels weren't behaving as expected.
So I switched to using the ably/laravel-broadcaster and the ably fork of Echo and now presence works as expected- it's just this issue now.
I have run php artisan optimize:clear since I installed the new packages and the issue persists.

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

Ideally, it shouldn't persist. There might be something wrong with authentication being performed, wdyt?

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

Also, make sure you are using php>=8 and followed proper setup.

@diversitude
Copy link
Author

I will keep digging, it's not a show stopper at the moment as the core functionality works and we can implement a workaround for not triggering the callback on the client that fired the request.

We are running PHP 8.2 in our environment.

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

I am not sure how it can work if it doesn't contain X-SOCKET-ID header. X-SOCKET-ID header is ably connection key. You can access the same using

window.Echo.connector.ably.connection.key

And make sure, your client side config. is

import Echo from '@ably/laravel-echo';
import * as Ably from 'ably';

window.Ably = Ably; // make globally accessible to Echo
window.Echo = new Echo({
    broadcaster: 'ably',
});

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

Btw, happy to hear presence is working for you : )

@diversitude
Copy link
Author

I am triggering message send endpoints via RapidAPI and just using the same JWT bearer token and X-SOCKET-ID as my actual UI in the headers.
I will test using the actual axios instance in the app now- hopefully that's the issue.

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

Please note that, only following interceptors are supported to capture X-SOCKET-ID as per official laravel-echo, others will not work
https://github.com/ably-forks/laravel-echo/blob/ddfeba76b73028122b94e58c433e2a7fa2dc3c62/src/echo.ts#L123

@diversitude
Copy link
Author

The issue persists using the axios instance in the app with all headers present.

[2024-02-28 20:09:30] local.ERROR: Ably error: Malformed message; invalid connectionKey. (See https://help.ably.io/error/40006 for help.) {"exception":"[object] (Illuminate\\Broadcasting\\BroadcastException(code: 0): Ably error: Malformed message; invalid connectionKey. (See https://help.ably.io/error/40006 for help.) at /Users/calvin/www/stratosfiaAPI/vendor/ably/laravel-broadcaster/src/AblyBroadcaster.php:187)

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

What is the value of X-Socket-Id ? Can you double check with local connection.key ?

@diversitude
Copy link
Author

Getting e91lyWF6gBZ7fm!m1zfd-NJj6AW1gTIHbt8mI-53d74

@diversitude
Copy link
Author

It is present in the headers in dev tools for all XHR requests

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

Ohkay, can you double check if it's same as window.Echo.connector.ably.connection.key

@diversitude
Copy link
Author

I've wrapped echo as a vue plugin, so it matches the output of console.log("conn key", this.echo.connector.ably.connection.key);

@diversitude
Copy link
Author

`import Echo from '@ably/laravel-echo';
import * as Ably from 'ably';
window.Ably = Ably;

class EchoManager {

constructor() {
    this.echo = null;
    this.apiKey = null;
    this.options = null;
}

init(apiKey, options) {
    if (this.echo) {
        console.warn("Echo instance already initialized.");
        return;
    }
    this.apiKey = apiKey;
    this.options = options;
}

connectEcho() {
    if (this.echo) {
        console.warn("Echo instance already initialized.");
        return;
    }
    this.echo = new Echo({
        broadcaster: 'ably',
        ...this.options,
        auth: {
            headers: {
                Authorization: `Bearer ${localStorage.getItem('x_token')}`,
            },
        },
    });
}

refreshToken() {
    // Update the auth headers for the Pusher connector
    this.echo.connector.options.auth.headers['Authorization'] = `Bearer ${localStorage.getItem('x_token')}`;
    // Optionally, force a disconnect and reconnect if needed to ensure the new token takes effect
    //this.echo.connector.pusher.disconnect(); //NOT SURE IF CORRECT IMPLEMENTATION FOR ABLY FORK 
    //this.echo.connector.pusher.connect();
}


subscribeToChannel(channelName, eventName, callback) {
    if (!this.echo) {
        console.error("Echo instance not initialized.");
        return;
    }

    this.echo.channel(channelName).listen(eventName, callback);
}

subscribeToPrivateChannel(channelName, eventName, callback) {
    if (!this.echo) {
        console.error("Echo instance not initialized.");
        return;
    }

    this.echo.private(channelName).listen(eventName, callback);
}

// Method to subscribe to a presence channel and listen to events
subscribeToPresenceChannel(channelName, events) {
    if (!this.echo) {
        console.error("Echo is not initialized.");
        return;
    }

    const channel = this.echo.join(channelName);

    // 'here' callback provides the initial list of users present in the channel
    if (events.onHere) {
        channel.here((users) => {
            events.onHere(users);
        });
    }

    // 'joining' callback is called when a new user joins the channel
    if (events.onJoining) {
        channel.joining((user) => {
            events.onJoining(user);
        });
    }

    // 'leaving' callback is called when a user leaves the channel
    if (events.onLeaving) {
        channel.leaving((user) => {
            events.onLeaving(user);
        });
    }

    // This example assumes you're using custom events as well
    if (events.onEvent) {
        Object.keys(events.onEvent).forEach(eventName => {
            channel.listen(eventName, (data) => {
                events.onEvent[eventName](data);
            });
        });
    }
}

// Method to leave/unsubscribe from any channel
leaveChannel(channelName) {
    if (!this.echo) {
        console.error("Echo is not initialized.");
        return;
    }
    // Unsubscribe from the channel
    this.echo.leave(channelName);
}

// Method to get the Echo socket ID
getSocketId() {
    if (!this.echo) {
        console.error("Echo is not initialized.");
        return null;
    }
    console.log("conn key", this.echo.connector.ably.connection.key);
    return this.echo.socketId();
}

}

// Vue Plugin
export default {
install(Vue, { apiKey, options }) {
const echoManager = new EchoManager();
echoManager.init(apiKey, options);
Vue.prototype.$echoManager = echoManager;
},
};`

@diversitude
Copy link
Author

The client side code seems to be working fine from what I can see.
I'm tempted to just go through the rigmarole of upgrading the project to Laravel 10 and hope it resolves the issue.

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

Okay, I'm not sure why you are using root api key in your client application. We haven't documented anywhere to set the api-key at client side. We have explicit note not to set it. Since, you have set it server side, you don't need to set it client side. You can remove it from your client code and it will work : )

@diversitude
Copy link
Author

That is not the root api key.
auth: { headers: { Authorization:Bearer ${localStorage.getItem('x_token')}, }, }, is used to set the current JWT token for the client for that my API middleware with authenticate the incoming /broadcast/auth request

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

In the setup section, we set it server side => https://github.com/ably/laravel-broadcaster?tab=readme-ov-file#setup. Client automatically gets JWT from server using this API key. Also, don't set

auth: {
            headers: {
                Authorization: `Bearer ${localStorage.getItem('x_token')}`,
            },
        },

We have also documented not to set auth specific options -> https://github.com/ably-forks/laravel-echo?tab=readme-ov-file#installation

@diversitude
Copy link
Author

oh this.apiKey is a relic from the previous pusher integration. it is redundant

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

Also, this is mostly not needed. ably-laravel-echo automatically makes request to given endpoint using internal http request and retrieves jwt.

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

Please do star the repo, if issue is resolved : )

@diversitude
Copy link
Author

Will get the actual front-end devs to have a look at the UI integration in detail and let you know if we resolve the issue.
Thanks for the prompt responses :) much appreciated!

@sacOO7
Copy link
Collaborator

sacOO7 commented Feb 28, 2024

Btw, do star the repo. I will be available if new queries come up 👍

@sacOO7 sacOO7 self-assigned this Feb 29, 2024
@sacOO7
Copy link
Collaborator

sacOO7 commented Mar 4, 2024

Hi @diversitude let me know if we have update on this. Otherwise we can close the issue and open a new one if needed : )

@sacOO7
Copy link
Collaborator

sacOO7 commented Mar 7, 2024

@diversitude do we have updates on this

@diversitude
Copy link
Author

Have been traveling, back in the codebase today and will provide updates if we've managed to fix it.

@sacOO7
Copy link
Collaborator

sacOO7 commented Mar 9, 2024

Sure, that would be great !

@sacOO7
Copy link
Collaborator

sacOO7 commented Mar 14, 2024

@diversitude let me know if the fix is working for you. For reference, I recommend to go through full documentation under https://github.com/ably-forks/laravel-echo

@sacOO7
Copy link
Collaborator

sacOO7 commented Mar 27, 2024

@diversitude let me know if this issue is resolved. Otherwise, we can close this and you can create a new issue if you find a bug in the future

@diversitude
Copy link
Author

Hey,
Sorry for the delayed response.
I haven't gotten round to bumping the project to Laravel 11 yet- been in the midst of some big feature sprints.
We are still just implementing workarounds on the frontend to not catch events broadcast by the current user.
We can close this and I will re-open if it persists on Laravel 11.

@draxvint
Copy link

draxvint commented Aug 5, 2024

Hi!

I have the same issue. There's no client-side error; the x-socket-id is matching. The error only occurs if the broadcast comes from a logged-in user. I use Laravel 10.

@diversitude Did Laravel 11 fix the issue, or have you found any solution for this?

@sacOO7
Copy link
Collaborator

sacOO7 commented Aug 5, 2024

@diversitude this issue is fixed! Please use the latest version of library.

@sacOO7
Copy link
Collaborator

sacOO7 commented Aug 5, 2024

@draxvint can you please raise a new issue with steps to reproduce the same. Ideally, this issue shouldn't exist. . We have tested and it works in our demo app -> https://github.com/ably-labs/laravel-broadcast-app
It will be great if you can upload sample app on github so that we should be able to reproduce issue from our side.

@sacOO7
Copy link
Collaborator

sacOO7 commented Sep 26, 2024

@diversitude @draxvint Issue has been fixed and released in latest version ( 1.0.6 ) of laravel-broadcaster and laravel-echo. Please update your packages accordingly.

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

Successfully merging a pull request may close this issue.

3 participants