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

pusher:ping not being sent #152

Open
aijorgenson opened this issue May 1, 2024 · 7 comments
Open

pusher:ping not being sent #152

aijorgenson opened this issue May 1, 2024 · 7 comments

Comments

@aijorgenson
Copy link

aijorgenson commented May 1, 2024

I have a web app using the pusher library that regularly sends pusher:ping requests ( https://pusher.com/docs/channels/library_auth_reference/pusher-websockets-protocol/#ping-and-pong-messages ); however, my .NET app is not sending these requests when subscribed to the same channels.

Per the Pusher documentation, it seems like this should be an automatic thing. I'm not able to find anything in the documentation for this package around it.

I have tried both 2.1 and the beta build of the package.

@conceicaomateus
Copy link

Hi!

I'm having the same problem with pusher:ping.

@maiconghidolin
Copy link

Same here

@sundayz
Copy link

sundayz commented Jul 9, 2024

I have the same problem with a Laravel Reverb server. If I understand the Pusher docs correctly, the pusher:ping event is used when the WebSocket implementation doesn't support ping/pong messages? So maybe the problem is that the server isn't detecting that the client supports native websocket pings.

@Erutan409
Copy link

For those (and maybe even more applicable to @sundayz) who are still having this issue, you'll need to modify the library yourself. You'll need to add a pusher event for pong when the server sends pings to inactive connections (this library in this case).

Add some constants for the messages:

namespace PusherClient
{
    class Constants
    {
        public const string PUSHER_MESSAGE_PREFIX = "pusher";
        public const string ERROR = "pusher:error";
        
        public const string PING = "pusher:ping"; // <-- add here
        public const string PONG = "pusher:pong"; // <-- add here

        public const string CONNECTION_ESTABLISHED = "pusher:connection_established";

        public const string CHANNEL_SUBSCRIBE = "pusher:subscribe";
        public const string CHANNEL_UNSUBSCRIBE = "pusher:unsubscribe";
        public const string CHANNEL_SUBSCRIPTION_SUCCEEDED = "pusher_internal:subscription_succeeded";
        public const string CHANNEL_SUBSCRIPTION_ERROR = "pusher_internal:subscription_error";
        public const string CHANNEL_MEMBER_ADDED = "pusher_internal:member_added";
        public const string CHANNEL_MEMBER_REMOVED = "pusher_internal:member_removed";

        public const string INSECURE_SCHEMA = "ws://";
        public const string SECURE_SCHEMA = "wss://";

        public const string PRIVATE_CHANNEL = "private-";
        public const string PRESENCE_CHANNEL = "presence-";
    }
}

Add the pong event:

using Newtonsoft.Json;

namespace PusherClient
{
    internal class PusherPongEvent
    {
        public PusherPongEvent()
        {
        }

        [JsonProperty(PropertyName = "event")] public string Event { get; } = Constants.PONG;
    }
}

Remove the auto-ping configuration:

public async Task ConnectAsync()
{
    _connectionSemaphore = new SemaphoreSlim(0, 1);
    try
    {
        _currentError = null;
        if (_pusher.PusherOptions.TraceLogger != null)
            _pusher.PusherOptions.TraceLogger.TraceInformation($"Connecting to: {_url}");

        ChangeState(ConnectionState.Connecting);

        _websocket = new WebSocket(_url); // <-- removed unnecessary configuration

        await Task.Run(() =>
        {
            _websocket.Error += WebsocketConnectionError;
            _websocket.MessageReceived += WebsocketMessageReceived;
            _websocket.Open();
        }).ConfigureAwait(false);

        var timeoutPeriod = _pusher.PusherOptions.InnerClientTimeout;
        if (!await _connectionSemaphore.WaitAsync(timeoutPeriod).ConfigureAwait(false))
            throw new OperationTimeoutException(timeoutPeriod, Constants.CONNECTION_ESTABLISHED);

        if (_currentError != null) throw _currentError;
    }
    finally
    {
        if (_websocket != null) _websocket.Error -= WebsocketConnectionError;

        _connectionSemaphore.Dispose();
        _connectionSemaphore = null;
    }
}

If you leave the default constructor configuration, it doesn't seem to hurt anything, but probably still a good idea to remove it.

Then add the handling of the ping message, which sends the pong message back:

private void ProcessPusherEvent(string eventName, string rawJson, Dictionary<string, object> message)
{
    var messageData = string.Empty;
    if (message.ContainsKey("data")) messageData = (string)message["data"];

    switch (eventName)
    {
        case Constants.CONNECTION_ESTABLISHED:
            ParseConnectionEstablished(messageData);
            break;

        case Constants.PUSHER_SIGNIN_SUCCESS:
        case Constants.PUSHER_WATCHLIST_EVENT:
            EmitEvent(eventName, rawJson, message);
            break;
        
        case Constants.PING: // <-- added
            SendAsync(DefaultSerializer.Default.Serialize(new PusherPongEvent())).ConfigureAwait(false);
            break;
    }
}

@aijorgenson
Copy link
Author

aijorgenson commented Nov 12, 2024

I just ended up creating a channel that anyone authenticated can subscribe to, and then I send periodic "ping" events to keep the connection alive.

I could be wrong, but I would speculate that Pusher is intentionally not accommodating to projects that choose to self host their own websocket server.

@Erutan409
Copy link

I could be wrong, but I would speculate that Pusher is intentionally not accommodating to projects that choose to self host their own websocket server.

Agreed

@sundayz
Copy link

sundayz commented Nov 12, 2024

For those using the Laravel Reverb websocket server, a fix has been merged on the server side: laravel/reverb#224

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

No branches or pull requests

5 participants