Coder Social home page Coder Social logo

pusher-websocket-java's Introduction

Pusher Channels Java Client

Build Status codecov Maven Central

Pusher Channels client library for Java targeting Android and general Java.

Supported platforms

  • Java SE - supports versions 8, 11 and 17
  • Oracle JDK
  • OpenJDK
  • Android 7 and above. 5 and 6 will require desugaring.

TOC

This README covers the following topics:

Installation

The compiled library is available in two ways:

Maven

The pusher-java-client is available in Maven Central.

<dependencies>
    <dependency>
      <groupId>com.pusher</groupId>
      <artifactId>pusher-java-client</artifactId>
      <version>2.4.4</version>
    </dependency>
</dependencies>

Gradle

dependencies {
  implementation 'com.pusher:pusher-java-client:2.4.4'
}

Download

You can download a version of the .jar directly from https://repo1.maven.org/maven2/com/pusher/pusher-java-client/

Source

You can build the project from the source in this repository. See Library development environment for more information on build environment.

API Overview

Here's the API in a nutshell.

// Create a new Pusher instance
PusherOptions options = new PusherOptions().setCluster(YOUR_APP_CLUSTER);
Pusher pusher = new Pusher(YOUR_APP_KEY, options);

pusher.connect(new ConnectionEventListener() {
    @Override
    public void onConnectionStateChange(ConnectionStateChange change) {
        System.out.println("State changed to " + change.getCurrentState() +
                           " from " + change.getPreviousState());
    }

    @Override
    public void onError(String message, String code, Exception e) {
        System.out.println("There was a problem connecting!");
    }
}, ConnectionState.ALL);

// Subscribe to a channel
Channel channel = pusher.subscribe("my-channel");

// Bind to listen for events called "my-event" sent to "my-channel"
channel.bind("my-event", new SubscriptionEventListener() {
    @Override
    public void onEvent(PusherEvent event) {
        System.out.println("Received event with data: " + event.toString());
    }
});

// Disconnect from the service
pusher.disconnect();

// Reconnect, with all channel subscriptions and event bindings automatically recreated
pusher.connect();
// The state change listener is notified when the connection has been re-established,
// the subscription to "my-channel" and binding on "my-event" still exist.

More information in reference format can be found below.

The Pusher constructor

The standard constructor take an application key which you can get from the app's API Access section in the Pusher Channels dashboard.

PusherOptions options = new PusherOptions().setCluster(YOUR_APP_CLUSTER);
Pusher pusher = new Pusher(YOUR_APP_KEY, options);

If you are going to use private or presence channels then you will need to provide an ChannelAuthorizer to be used when authenticating subscriptions. In order to do this you need to pass in a PusherOptions object which has had an ChannelAuthorizer set.

HttpChannelAuthorizer channelAuthorizer = new HttpChannelAuthorizer("http://example.com/some_auth_endpoint");
PusherOptions options = new PusherOptions().setCluster(YOUR_APP_CLUSTER).setChannelAuthorizer(channelAuthorizer);
Pusher pusher = new Pusher(YOUR_APP_KEY, options);

See the documentation on Authorizing Users for more information.

If you need finer control over the endpoint then the setHost, setWsPort and setWssPort methods can be employed.

Connecting

In order to send and receive messages you need to connect to Channels.

PusherOptions options = new PusherOptions().setCluster(YOUR_APP_CLUSTER);
Pusher pusher = new Pusher(YOUR_APP_KEY, options);
pusher.connect();

The PusherOptions object

Most of the functionality of this library is configured through the PusherOptions object. You configure it by calling methods with parameters on the object before passing it to the Pusher object. Below is a table containing all of the methods you can call.

Method Parameter Description
setEncrypted Boolean Sets whether the connection should be made with TLS or not.
setChannelAuthorizer ChannelAuthorizer Sets the channel authorizer to be used when authorizing private and presence channels.
setHost String The host to which connections will be made.
setWsPort int The port to which unencrypted connections will be made. Automatically set correctly.
setWssPort int The port to which encrypted connections will be made. Automatically set correctly.
setCluster String Sets the cluster the client will connect to, thereby setting the Host and Port correctly.
setActivityTimeout long The number of milliseconds of inactivity at which a "ping" will be triggered to check the connection. The default value is 120,000.
setPongTimeout long The number of milliseconds the client waits to receive a "pong" response from the server before disconnecting. The default value is 30,000.
setMaxReconnectionAttempts int Number of reconnection attempts that will be made when pusher.connect() is called, after which the client will give up.
setMaxReconnectGapInSeconds int The delay in two reconnection extends exponentially (1, 2, 4, .. seconds) This property sets the maximum inbetween two reconnection attempts.
setProxy Proxy Specify a proxy, e.g. options.setProxy( new Proxy( Proxy.Type.HTTP, new InetSocketAddress( "proxyaddress", 80 ) ) )

Reconnecting

The connect method is also used to re-connect in case the connection has been lost, for example if an Android device loses reception. Note that the state of channel subscriptions and event bindings will be preserved while disconnected and re-negotiated with the server once a connection is re-established.

Disconnecting

pusher.disconnect();

After disconnection the Pusher instance will release any internally allocated resources (threads and network connections)

Listening to connection events

Implement the ConnectionEventListener interface to receive connection state change events:

PusherOptions options = new PusherOptions().setCluster(YOUR_APP_CLUSTER);
Pusher pusher = new Pusher(YOUR_APP_KEY, options);
pusher.connect(new ConnectionEventListener() {
    @Override
    public void onConnectionStateChange(ConnectionStateChange change) {
        System.out.println("State changed to " + change.getCurrentState() +
                           " from " + change.getPreviousState());
    }

    @Override
    public void onError(String message, String code, Exception e) {
        System.out.println("There was a problem connecting!");
    }
});

A series of ConnectionState members can be passed after the listener in this call to filter the states which will receive notification, e.g.

// MyConnectionEventListener is notified only of transitions to the disconnected state
pusher.connect(new MyConnectionEventListener(), ConnectionState.DISCONNECTED);

For more information see connection states.

Subscribing to channels

Channels uses the concept of channels as a way of subscribing to data. They are identified and subscribed to by a simple name. Events are bound to on a channels and are also identified by name. To listen to an event you need to implemented the ChannelEventListener interface (see Binding and handling events).

As mentioned above, channel subscriptions need only be registered once per Pusher instance. They are preserved across disconnection and re-established with the server on reconnect. They should NOT be re-registered. They may, however, be registered with a Pusher instance before the first call to connect - they will be completed with the server as soon as a connection becomes available.

Public channels

Channel channel = pusher.subscribe("my-channel");

If you wish to be informed when the subscription succeeds, pass an implementation of the ChannelEventListener interface:

Channel channel = pusher.subscribe("my-channel", new ChannelEventListener() {
    @Override
    public void onSubscriptionSucceeded(String channelName) {
        System.out.println("Subscribed to channel: " + channelName);
    }

    // Other ChannelEventListener methods
});

If you wish to be informed for subscription count events, use the bind function to listen to event type pusher:subscription_count:

Channel channel = pusher.subscribe("my-channel");
channel.bind("pusher:subscription_count", new SubscriptionEventListener() {
    @Override
    public void onEvent(PusherEvent event) {
        System.out.println("Received event with data: " + event.toString());
        System.out.println("Subscription Count is: " + channel.getCount());
    }
});

Private channels

It's possible to subscribe to private channels that provide a mechanism for authorizing channel subscriptions. In order to do this you need to provide a ChannelAuthorizer when creating the Pusher instance (see The Pusher constructor above).

The library provides a HttpChannelAuthorizer implementation of ChannelAuthorizer which makes an HTTP POST request to an authorization endpoint. However, you can implement your own authorization mechanism if required.

Private channels are subscribed to as follows:

PrivateChannel privateChannel = pusher.subscribePrivate( "private-channel" );

In addition to the events that are possible on public channels a private channel exposes an onAuthenticationFailure. This is called if the ChannelAuthorizer does not successfully authorize the subscription:

PrivateChannel channel = pusher.subscribePrivate("private-channel",
    new PrivateChannelEventListener() {
        @Override
        public void onAuthenticationFailure(String message, Exception e) {
            System.out.println(
                String.format("Authentication failure due to [%s], exception was [%s]", message, e)
            );
        }

        // Other ChannelEventListener methods
    });

Private encrypted channels

Similar to Private channels, you can also subscribe to a private encrypted channel. This library now fully supports end-to-end encryption. This means that only you and your connected clients will be able to read your messages. Pusher cannot decrypt them.

Like the private channel, you must provide your own authorization endpoint, with your own encryption master key. There is a demonstration endpoint to look at using nodejs.

To get started you need to subscribe to your channel, provide a PrivateEncryptedChannelEventListener, and a list of the events you are interested in, for example:

PrivateEncryptedChannel privateEncryptedChannel =
	pusher.subscribePrivateEncrypted("private-encrypted-channel", listener, "my-event");

In addition to the events that are possible on public channels the PrivateEncryptedChannelEventListener also has the following methods:

  • onAuthenticationFailure(String message, Exception e) - This is called if the ChannelAuthorizer does not successfully authorize the subscription:
  • onDecryptionFailure(String event, String reason); - This is called if the message cannot be decrypted. The decryption will attempt to refresh the shared secret key once from the ChannelAuthorizer.

There is a working example in the repo which you can use with the demonstration authorization endpoint

Presence channels

Presence channels are private channels which provide additional events exposing who is currently subscribed to the channel. Since they extend private channels they also need to be authorized (see authorizing channel subscriptions).

Presence channels can be subscribed to as follows:

PresenceChannel presenceChannel = pusher.subscribePresence( "presence-channel" );

Presence channels provide additional events relating to users joining (subscribing) and leaving (unsubscribing) the presence channel. It is possible to listen to these events by implementing the PresenceChannelEventListener.

PresenceChannel channel = pusher.subscribePresence("presence-channel",
    new PresenceChannelEventListener() {
        @Override
        public void onUsersInformationReceived(String channelName, Set<User> users) {
            for (User user : users) {
                userSubscribed(channelName, user);
            }
        }

        @Override
        public void userSubscribed(String channelName, User user) {
            System.out.println(
                String.format("A new user joined channel [%s]: %s, %s",
                              channelName, user.getId(), user.getInfo())
            );

            if (user.equals(channel.getMe())) {
                System.out.println("me");
            }
        }

        @Override
        public void userUnsubscribed(String channelName, User user) {
            System.out.println(
                String.format("A user left channel [%s]: %s %s",
                              channelName, user.getId(), user.getInfo())
            );
        }

        // Other ChannelEventListener methods
    });

The User object

Note: In the Pusher Channels documentation a User may be referred to as a Member.

The User object has two main methods.

getId fetches a unique identifier for the user on the presence channel.

getInfo fetches a string representing arbitrary additional information about the user in the form of a JSON hash, e.g.

{"user_name":"Mr. User","user_score":1357}

The following example using the Gson library to handle deserialization:

String jsonInfo = user.getInfo();
Gson gson = new Gson();
UserInfo info = gson.fromJson(jsonInfo, UserInfo.class);

For more information on defining the user id and user info on the server see Implementing the authorization endpoint for a presence channel documentation.

Client event authenticity

Channels now provides a 'user-id' with client events sent from the server. With presence channels, your authorization endpoint provides your user with a user-id. Previously, it was up to you to include this user-id in every client-event triggered by your clients. Now, when a client of yours triggers a client event, Channels will append their user-id to their triggered message, so that the other clients in the channel receive it. This allows you to trust that a given user really did trigger a given payload.

If youโ€™d like to make use of this feature, youโ€™ll need to extract the user-id from the message delivered by Channels. To do this, call getUserId() on the event payload your event handler gets called with, like so:

channel.bind("client-my-event", new SubscriptionEventListener() {
    @Override
    public void onEvent(PusherEvent event) {
        System.out.println("Received event with userId: " + event.getUserId());
    }
});

Binding and handling events

There are two types of events that occur on channel subscriptions.

  1. Protocol related events such as those triggered when a subscription succeeds
  2. Application events that have been triggered by code within your application

ChannelEventListener

The ChannelEventListener is an interface that is informed of both protocol related events and application data events. A ChannelEventListener can be used when initially subscribing to a channel.

Channel channel = pusher.subscribe("my-channel", new ChannelEventListener() {
    @Override
    public void onSubscriptionSucceeded(String channelName) {
        System.out.println("Subscribed!");
    }

    @Override
    public void onEvent(PusherEvent event) {
        // Called for incoming events names "foo", "bar" or "baz"
    }
}, "foo", "bar", "baz");

The ChannelEventListener interface extends the SubscriptionEventListener interface.

SubscriptionEventListener

Events triggered by your application are received by the onEvent method on the SubscriptionEventListener interface implementation. If you are only related to application events you can bind to events on Channel objects.

Channel channel = pusher.subscribe("my-channel");
channel.bind("my-event", new ChannelEventListener() {
    @Override
    public void onEvent(PusherEvent event) {
        // Called for incoming events named "my-event"
    }
});

The event data is accessible by calling the getData() method on the event. From there you can handle the data as you like. Since we encourage data to be in JSON here's an example that uses Gson object deserialization:

public class Example implements ChannelEventListener {
    public Example() {
        Pusher pusher = new Pusher(YOUR_APP_KEY);
        pusher.subscribe("my-channel", this);
        pusher.connect();
    }

    @Override
    public void onEvent(PusherEvent event) {
        Gson gson = new Gson();
        EventExample exampleEvent = gson.fromJson(event.getData(), EventExample.class);
    }
}

class EventExample {
    private int value1 = 1;
    private String value2 = "abc";
    private transient int value3 = 3;

    EventExample() { }
}

Unbinding event listeners

You can unbind from an event:

channel.unbind("my_event", listener);

Example

public class Example implements ChannelEventListener {
    private final Pusher pusher;
    private final Channel channel;

    public Example() {
        pusher = new Pusher(YOUR_APP_KEY);
        channel = pusher.subscribe("my-channel", this, "my_event");

        pusher.connect();
    }

    public void listenToOtherEvent() {
        channel.bind("my_other_event", this);
    }

    public void stopListeningToOtherEvent() {
        channel.unbind("my_other_event", this);
    }
}

Triggering events

Once a private or presence subscription has been authorized (see authorizing users) and the subscription has succeeded, it is possible to trigger events on those channels.

channel.trigger("client-myEvent", "{\"myName\":\"Bob\"}");

Events triggered by clients are called client events. Because they are being triggered from a client which may not be trusted there are a number of enforced rules when using them. Some of these rules include:

  • Event names must have a client- prefix
  • Rate limits
  • You can only trigger an event when the subscription has succeeded

For full details see the client events documentation.

PrivateChannel channel = pusher.subscribePrivate("private-channel",
    new PrivateChannelEventListener() {
        @Override
        public void onSubscriptionSucceeded(String channelName) {
            channel.trigger("client-myEvent", "{\"myName\":\"Bob\"}");
        }

        // Other PrivateChannelEventListener methods
    });

Accessing the connection socket ID

Once connected you can access a unique identifier for the current client's connection. This is known as the socket_id.

You can access the value once the connection has been established as follows:

String socketId = pusher.getConnection().getSocketId();

For more information on how and why there is a socket_id see the documentation on authorizing users and excluding recipients.

Helper Methods

Getting a channel from string

Basic channels

Channel channel = pusher.getChannel("my-channel");

The library will raise an exception if the parameter to Pusher#getChannel is prefixed with "private-" or "presence-".

Private channels

PrivateChannel channel = pusher.getPrivateChannel("private-channel");

The library will raise an exception if the parameter to Pusher#getPrivateChannel is not prefixed with "private-".

Presence channels

PresenceChannel channel = pusher.getPresenceChannel("presence-channel");

The library will raise an exception if the parameter to Pusher#getPresenceChannel is not prefixed with "presence-".

Check if a channel has subscribed

Channel channel = pusher.getChannel("my-channel");
channel.isSubscribed(); // => `true`/`false`

JavaDocs

The JavaDocs can be found here: http://pusher.github.com/pusher-websocket-java/

Library Development Environment

If you'd like to tweak this library there are ways to use your local code rather than the official. This is a rough guide on how to do so.

Prerequisites

  • A Java Virtual Machine.
  • Gradle, the build system used for the project, is downloaded by the Gradle Wrapper (gradlew) which is included in the repo.
  • On Windows ./gradlew.bat should be used, on Linux ./gradle.

Cloning the project

  • Clone the project: git clone https://github.com/pusher/pusher-websocket-java
  • Change to the top level directory for the project: cd pusher-websocket-java

Android Studio

  • In your app project's settings.gradle add the following lines:
include ':pusher-websocket-java'
project(':pusher-websocket-java').projectDir = new File('<PATH_TO_THIS_PROJECT>/pusher-websocket-java')
  • Add the following line to your application's build.gradle where you would normally add the actual pusher-websocket-java SDK:
dependencies {
    implementation project(':pusher-websocket-java')
}

Eclipse Project

Assuming you are using Eclipse, follow these steps:

  • Run gradlew eclipse. This will generate the .classpath and .project files
  • You can now load the project in Eclipse by navigating to Import project and pointing it to the root directory of the existing project.

Build

From the top level directory execute:

  • gradlew test to execute the tests.
  • gradlew javadoc to generate the JavaDoc. The docs will be output to the build/docs/javadoc/ directory.
  • gradlew assemble assemble all artifacts but does not run any tests.
  • gradlew build to build all jars and execute all tests & verification. The jars will be output to the build/libs directory.

Run the Example Application

After running gradlew clean assemble change to the build/libs directory and run java -jar pusher-websocket-java-with-dependencies-<version>-jar-with-dependencies.jar. This will run the example application.

By default the example will connect to a sample application and subscribe to the channel my-channel, listening to events on my-event. If you want to change these defaults, they can be specified on the command line:

java -jar pusher-websocket-java-with-dependencies-<version>-jar-with-dependencies.jar [appKey] [channelName] [eventName]

pusher-websocket-java's People

Contributors

adamcavanagh1 avatar adamshone avatar benjamin-tang-pusher avatar creativepsyco avatar daniellevass avatar danielrbrowne avatar hamchapman avatar jackfranklin avatar jameshfisher avatar jpatel531 avatar kn100 avatar leggetter avatar marekoid avatar mdpye avatar plackemacher avatar proggen-com avatar pusher-ci avatar rdpfeffer avatar realtybaron avatar roccozanni avatar scottyab avatar siggijons avatar singhashmeet avatar sonologico avatar terrettaz avatar trevorrjohn avatar tylermccraw avatar willsewell avatar zimbatm avatar zmarkan 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  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  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  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

pusher-websocket-java's Issues

Setting custom host gives ClassCastException

Hello,
I tried setting a custom host in the PusherOptions but its giving me an exception.
With the default host there's no problem.

PusherOptions options = new PusherOptions()
            .setHost("my.custom.host")
            .setWsPort(8080)
            .setWssPort(8080)
            .setEncrypted(sslToggle.isChecked());
Pusher pusher = new Pusher(API_KEY, options);

This is the stacktrace I get:

07-16 11:49:31.429    1403-1416/pushertest E/AndroidRuntime๏น• FATAL EXCEPTION: pusher-java-client eventQueue
    Process: pushertest, PID: 1403
    java.lang.ClassCastException: com.google.gson.internal.StringMap cannot be cast to java.lang.String
            at com.pusher.client.connection.websocket.WebSocketConnection.handleConnectionMessage(WebSocketConnection.java:167)
            at com.pusher.client.connection.websocket.WebSocketConnection.handleInternalEvent(WebSocketConnection.java:158)
            at com.pusher.client.connection.websocket.WebSocketConnection.handleEvent(WebSocketConnection.java:150)
            at com.pusher.client.connection.websocket.WebSocketConnection.access$600(WebSocketConnection.java:26)
            at com.pusher.client.connection.websocket.WebSocketConnection$6.run(WebSocketConnection.java:230)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
            at java.lang.Thread.run(Thread.java:841)

Thanks

How to set server ping timeout?

Say user A and user B are subscribed to a presenceChannel.

A disables his wifi.
B's presenceChannel.getUsers().size() still shows 2, even after one or two minutes.

B will receive a userUnsubscribed event only after 7 mins.

The below

options.setActivityTimeout(long ms);
options.setPongTimeout(long ms);

Sets client timeouts, so they dont help.

Is there a way to shorten the server ping timeputs, so that B receives a quick userUnsubscribed event?

onAuthenticationFailure: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

My code

public void loadPuser() {
        String url ="https://goon.com/notification";
        String pusher_key = getString(R.string.pusher_key);
        HttpAuthorizer authorizer = new HttpAuthorizer(url);
        PusherOptions options = new PusherOptions().setAuthorizer(authorizer);
        pusher = new Pusher(pusher_key, options);
        pusher.connect(new ConnectionEventListener() {
            @Override
            public void onConnectionStateChange(ConnectionStateChange change) {
                Log.d("pusher-connect",
                        "State changed to " + change.getCurrentState()
                                + " from " + change.getPreviousState());
                if (change.getCurrentState().toString().equals("CONNECTED")) {
                    isConnecting = true;
                    Log.d("pusher-connect", "true");
                } else {
                    Log.d("pusher-connect", "false");
                    isConnecting = false;
                }
            }

            @Override
            public void onError(String message, String code, Exception e) {
                Log.d("pusher-connect", "There was a problem connecting!");
            }
        }, ConnectionState.ALL);
        channel = pusher.subscribePresence("presence-client_" + user_id,
                presenceChannelEventListener);
        channel.bind("client-chat-insert", presenceChannelEventListener);
    }
PresenceChannelEventListener presenceChannelEventListener = new PresenceChannelEventListener() {
        @Override
        public void onEvent(String presenceChannel, String eventName,
                final String data) {
            Log.d("pusher-service", presenceChannel);
            Log.d("pusher-service", "eventName: " + eventName);
            Log.d("pusher-service", "data: " + data);
            updateNotification(data);

        }

        @Override
        public void onSubscriptionSucceeded(String presenceChannel) {
            Log.d("pusher-service", "onSubscriptionSucceeded: " + presenceChannel);

        }

        @Override
        public void onAuthenticationFailure(String message, Exception arg1) {
            Log.d("pusher-service", "onAuthenticationFailure: " + message);

        }

        @Override
        public void userSubscribed(String channelName, final User user) {
            Log.d("pusher-service",
                    "userSubscribed: "
                            + String.format(
                                    "A new user joined channel [%s]: %s, %s",
                                    channelName, user.getId(), user.getInfo()));

            if (user.equals(channel.getMe())) {
                Log.d("pusher-servic", "userSubscribed: me");
            }
        }

        @Override
        public void userUnsubscribed(String channelName, User user) {
            Log.d("pusher-service",
                    "userUnsubscribed: "
                            + String.format("A user left channel [%s]: %s %s",
                                    channelName, user.getId(), user.getInfo()));
        }

        @Override
        public void onUsersInformationReceived(String channelName,
                Set<User> users) {
            for (User user : users) {
                userSubscribed(channelName, user);
            }

        }
    };

java.lang.IllegalArgumentException in ConnectionStateChange

Exception Type: java.lang.IllegalArgumentException

Reason: Attempted to create an connection state update where both previous and current state are: DISCONNECTED

Line 20 in com.pusher.client.connection.ConnectionStateChange.
Line 148 in com.pusher.client.connection.websocket.WebSocketConnection.???
Line 22 in com.pusher.client.connection.websocket.WebSocketConnection.???

At least I do not understand how this could be prevented. Stacktrace has been obfuscated by ProGuard.

Pusher disconnects after few days of connection

As a part of my server-side technology, I need to keep pusher client connected for a very long time, weeks and months. After some time, hovewer, I see this in my server log "Please reconnect immediately ; code: 4200"

Shouldn't this be handled by the library? Otherwise what is the best practice here? Should I handle this error and reconnect manually?

From the pusher protocol description, this is quite generic error, and does not provide any details (I presume the issue is not in my code).

Cannot receive private messages - but can successfully authenticate a private subscription

Not entirely sure where the problem lies, but here is my issue:

  1. I can verify all private channel requests (right now I'm just naively approving all to remove any issues).

  2. I have PrivateChannelEventListener#onSubscriptionSucceeded implemented and am seeing a successful connection in logcat

  3. I also subscribe to a public channel and can see all those messages dumped to logcat - both subscription notifications and received messages

  4. However, in my PrivateChannelEventListener#onEvent I am not receiving any data. I know the connection is successful ala Item 2, but not receiving data.

  5. If I force-stop the app I can see "Vacated: Channel: private-foobar" in the Web Debug Console - so its pretty clear the private channel connection is successful.

I am sending messages via a Ruby console:

Pusher['public'].trigger('events', {message: "Hello"})

This is received via my public channel subscription:

However, this is NOT:

Pusher['private-foobar'].trigger('events', {message: "private message"})

Is there a way for me to enable a lower-level of debugging?

Here is my Java code - thank you for any help you can provide:

HttpAuthorizer authorizer = new HttpAuthorizer(Constants.API_BASE_URL + "/pusher/authenticate");
PusherOptions options = new PusherOptions().setAuthorizer(authorizer);
pusher = new Pusher(Constants.PUSHER_APP_KEY, options);

pusher.connect(new ConnectionEventListener() {
    @Override
    public void onConnectionStateChange(ConnectionStateChange change) {
        Log.i("Pusher", "Connection State Change: " + change.toString());
    }

    @Override
    public void onError(String message, String code, Exception e) {
        Log.i("Pusher", String.format("Connection Error: [%s], exception was [%s]", message, e));
    }
}, ConnectionState.ALL);

PrivateChannel channel = pusher.subscribePrivate("private-foobar",
        new PrivateChannelEventListener() {
            @Override
            public void onAuthenticationFailure(String message, Exception e) {
                Log.i("Pusher", String.format("Authentication failure due to [%s], exception was [%s]", message, e));
            }
            @Override
            public void onSubscriptionSucceeded(String s) {
                Log.i("Pusher", "Private connection succeeded");
            }

            @Override
            public void onEvent(String channel, String event, String data) {
                Log.i("Pusher", data);
            }
        });

// Also subscribe to a public channel
Channel publicChannel = pusher.subscribe("public");
publicChannel.bind("events", new ChannelEventListener() {
    @Override
    public void onSubscriptionSucceeded(String s) {
    }

    @Override
    public void onEvent(String channel, String event, String data) {
        Log.i("PusherPublic", String.format("channel=%s, event=%s, data=%s", channel, event, data));
    }
});

Can't Use Gradle Dependency or JAR

If I include pusher as a dependency in my project, the build fails because it cannot find websockets 1.3.1 If I use the JAR, it won't build because you include GSON as a part of your project, and that conflicts with the GSON dependency I have in my project.

I'd love to use pusher, but users shouldn't have to resort to building the project themselves in order to get it to work, especially with the proliferation of platforms like Gradle.

Can not connect to pusher on android 2.3.x

Hi guys,

I'm trying to use your lib in my app. It works quite well on two android devices running android 4.0+, but it doesn't connect on two android 2.3.x devices.

No exception is thrown, it just goes from DISCONNECTED to CONNECTING and then from CONNECTING to DISCONNECTED and thats it.

However this might not have to do with android versions, it just smells that way?

Does your lib support android versions below 4.0? How can I figure out what and why is happening?

Thanks, Nemanja

Pusher stops receiving events when App goes to background or the device display sleeps

I am using pusher java client 0.3.1 with dependencies for my app on an Android Version 4.1.1 or a Android Version 4.0.4 device connected through wifi.
Pusher stops receiving events (and disconnects) when the device display goes to sleep mode.
Is there a way to get around this? My app can have long time of inactivity but I would like to make sure that it gets pusher notifications.

Thanks for your insights!

UnresolvedAddressException with WebSocket library

I cannot tell the exact steps to reproduce this, but my Android application crashes for a great number of users with the following Exception:

java.nio.channels.UnresolvedAddressException
at java.nio.SocketChannelImpl.validateAddress(SocketChannelImpl.java:422)
at java.nio.SocketChannelImpl.connect(SocketChannelImpl.java:154)
at org.java_websocket.client.WebSocketClient.void run()(SourceFile:188)
at java.lang.Thread.run(Thread.java:856)java.nio.channels.UnresolvedAddressException
at java.nio.SocketChannelImpl.validateAddress(SocketChannelImpl.java:422)
at java.nio.SocketChannelImpl.connect(SocketChannelImpl.java:154)
at org.java_websocket.client.WebSocketClient.void run()(SourceFile:188)
at java.lang.Thread.run(Thread.java:856)

And there's no way to handle this yet.

I'm not sure how this is affected by this issue and its solution:
leggetter#8

For this problem, that solution does not seem to work, at least.

Pusher is extremely slow on Android for subscriptions

Hi I am using pusher to authenticate private channels. However, its extremely slow. The iOS library takes about 3 secs to subscribe successfully to the channels. However, the java client takes about 30~secs to complete the subscription process. Are there any specific reasons which might be causing this?

Can't bind to special pusher: events

This used to work before the 0.1.2-beta upgrade. Instead of doing, for example:

pusher.subscribePresence(channelName, this);

I would do

final PresenceChannel channel = pusher.subscribePresence(channelName);
channel.bind("pusher:subscription_succeeded", this);
channel.bind("pusher:subscription_error", this);
channel.bind("pusher:member_added", this);
channel.bind("pusher:member_removed", this);

As documented here. This seemed to work, but it's not anymore, as I'm not receiving these events. If I use the first variant (with two parameters to subscribePresence) it works, but then I can't unbind or change the listener (because calling subscribePresence again results in an exception).

java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to java.lang.String

Hi, I've implemented custom pusher server, and set up Android client with custom hostname and port. When trying to connect to pusher server, it returned this response

{"event":"pusher:connection_established","data":{"socket_id":"7ac1e2c9-fe64-420a-a3c4-b64cd9272d28"}}

and app chrashed.

I found the problem to be String dataString = (String) jsonObject.get("data");

private void handleConnectionMessage(String message) {
System.out.println(message);
Map jsonObject = new Gson().fromJson(message, Map.class);
String dataString = (String) jsonObject.get("data");
Map dataMap = new Gson().fromJson(dataString, Map.class);
socketId = (String) dataMap.get("socket_id");

    updateState(ConnectionState.CONNECTED);
}

If instead of casting to String, we replace with String dataString = jsonObject.get("data").toString();

the problem goes away.

Cheers

Callbacks for member_added and member_removed

Are the messages pusher_internal:member_added and pusher_internal:member_removed actually forwarded to Pusher's callbacks userSubscribed(...) and userUnsubscribed(...)?

I have not seen this correct behaviour yet and the demo shows that you should call userSubscribed(...) manually in onUsersInformationReceived(...).

But what are we going to do with userUnsubscribed(...)?

"eventQueue" thread pool is not shutdown

Currently we do not have a shutdown() method on the Pusher, and terminating the thread on disconnect is not correct either.
However, if we can't terminate the thread them the JVM will not quit.

This is probably being masked by Android's lifecycle management in most cases where it's in use (though I don't know where those threads are going, I hope they're being forcefully terminated eventually), but if the library were to be used in a traditional Java setting it would be a real pain.

Exception when trying to deal with authentication failures

When authentication on the server (via HttpAuthorizer) fails, you should return HTTP 403 as suggested in the documentation:
http://pusher.com/docs/authenticating_users#/lang=drupal

But if you try to add a description of the reason as a simple String, then PresenceChannelImpl.toSubscribeMessage() fails with the following Exception that cannot be caught conveniently:
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING ...

Because this is no JSON, obviously. But what exactly to return when it fails?

Could you make the returned message available somewhere for processing so that you can give the user a specific reason on client side? Or what is the intended behaviour if authentication fails?

Cannot connect

Hi there

My client doesn't seem to connect to the Pusher app. A state change from DISCONNECTED to CONNECTING occurs, but then nothing happens. What can I do to debug?

final Pusher pusher = new Pusher(ConstApi.PUSHER_APPID);
        pusher.connect(new ConnectionEventListener()
        {
          @Override
          public void onConnectionStateChange(ConnectionStateChange change)
          {
              Logging.logMessage(String.format("Pusherapp connection state changed from [%s] to [%s]", change.getPreviousState(), change.getCurrentState()));
          }

          @Override
          public void onError(String message, String code, Exception e)
          {
              Logging.logMessage(message);
              Logging.logException(e);
          }
        }, ConnectionState.ALL);

        Channel channel = pusher.subscribe(ConstApi.PUSHER_TRADECHANNNEL);
        channel.bind(ConstApi.PUSHER_TRADEEVENT, new ChannelEventListener()
        {
          @Override
          public void onSubscriptionSucceeded(String channelName)
          {
              Logging.logMessage("Subscribed to Pusherapp channel: " + channelName);
          }

          @Override
          public void onEvent(String channel, String event, String data)
          {
              System.out.println(data);
          }
        });

Pusher Channel already subcscribed

Is there any method to check if pusher is already subscribed.Because in pusher jar ver 0.0.3 an exception was thrown whenever a pusher is resubscribed.And also to clarify ,when pusher is reconnected again or it just maintain its previous state without resubscribing?

ERROR : androidRunTime com.pusher.client.Pusher pusher.java 87

Hi, when I execute my APP I receive this error:

ERROR : androidRunTime com.pusher.client.Pusher pusher.java 87

And the app not working fine.

I have added the jar file in my library project: pusher-java-client-0.3.1.jar and the connection is simple:

Pusher pusher = new Pusher(API_KEY);

When the app arrive to this line give me the error.

androidRunTime com.pusher.client.Pusher pusher.java 87
androidRunTime com.pusher.client.Pusher pusher.java 68
androidRunTime com.pusher.client.Pusher pusher.java 57

IF someone can help me!!
Thanks!!!

How to judge if subscribed?

I can not find any function to judge if subscribed ?

AndroidRuntime  E  Caused by: java.lang.IllegalArgumentException: Already subscribed to a channel with name com.pusher.android.example
 AndroidRuntime  E    at com.pusher.client.channel.impl.ChannelManager.validateArgumentsAndBindEvents(ChannelManager.java:142)
 AndroidRuntime  E    at com.pusher.client.channel.impl.ChannelManager.subscribeTo(ChannelManager.java:40)
  AndroidRuntime  E    at com.pusher.client.Pusher.subscribe(Pusher.java:172)

it's very easy to appear๏ผŒ I used push-java-client on Android, I subscribe a channel on onCreate function, when a quit the activity, and into the actiivty again, the crash appear.

FATAL EXCEPTION: pusher-java-client eventQueue

Hi all

My project using pusher chat client-server

My code activity


package com.lestgo;

import java.util.ArrayList;
import java.util.Random;
import java.util.Set;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.ListActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;

import com.androidquery.AQuery;
import com.lestgo.chat.AwesomeAdapter;
import com.lestgo.chat.Message;
import com.pusher.client.Pusher;
import com.pusher.client.PusherOptions;
import com.pusher.client.channel.PresenceChannel;
import com.pusher.client.channel.PresenceChannelEventListener;
import com.pusher.client.channel.User;
import com.pusher.client.connection.ConnectionEventListener;
import com.pusher.client.connection.ConnectionState;
import com.pusher.client.connection.ConnectionStateChange;
import com.pusher.client.util.HttpAuthorizer;

public class ChatActivity extends ListActivity {

    private Pusher pusher;
    PresenceChannel channel;

    SharedPreferences preferences;
    String api_url = "";
    String api_key = "";
    String lestgo_id = "";
    String userInfor = "";
    Intent intent;

    ArrayList<Message> messages;
    AwesomeAdapter adapter;
    EditText edtMessage;
    static String sender;
    PresenceChannelEventListener presenceChannelEventListener = new PresenceChannelEventListener() {
        @Override
        public void onEvent(String presenceChannel, String eventName,
                String data) {
            Log.d("presenceChannel", presenceChannel);
            Log.d("eventName", eventName);
            Log.d("data", data);
            edtMessage.setText("OK");

        }

        @Override
        public void onSubscriptionSucceeded(String presenceChannel) {
            Log.d("onSubscriptionSucceeded", presenceChannel);

        }

        @Override
        public void onAuthenticationFailure(String message, Exception arg1) {
            Log.d("onAuthenticationFailure", message);

        }

        @Override
        public void userSubscribed(String channelName, User user) {
            Log.d("userSubscribed", String.format(
                    "A new user joined channel [%s]: %s, %s", channelName,
                    user.getId(), user.getInfo()));
            userInfor = user.getInfo();

            if (user.equals(channel.getMe())) {
                Log.d("userSubscribed", "me");
            }
        }

        @Override
        public void userUnsubscribed(String channelName, User user) {
            Log.d("userUnsubscribed", String.format(
                    "A user left channel [%s]: %s %s", channelName,
                    user.getId(), user.getInfo()));
        }

        @Override
        public void onUsersInformationReceived(String channelName,
                Set<User> users) {
            for (User user : users) {
                userSubscribed(channelName, user);
            }

        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat);

        preferences = getSharedPreferences("LesgoApp", Activity.MODE_PRIVATE);
        api_key = preferences.getString("api_key", api_key);
        api_url = getString(R.string.api_url, api_url);
        lestgo_id = preferences.getString("lestgo_id", lestgo_id);
        edtMessage = (EditText) this.findViewById(R.id.text);
        loadPuser();
        this.setTitle(sender);
        messages = new ArrayList<Message>();
        messages.add(new Message("Hello", false));
        adapter = new AwesomeAdapter(this, messages);
        setListAdapter(adapter);
        intent = getIntent();
    }

    public void sendMessage(View v) {
        String message = edtMessage.getText().toString().trim();
        if (message.length() > 0) {
            edtMessage.setText("");
            addNewMessage(new Message(message, true));
            send(message);
        }
    }

    void addNewMessage(Message m) {
        messages.add(m);
        adapter = new AwesomeAdapter(this, messages);
        setListAdapter(adapter);
        getListView().setSelection(messages.size() - 1);
    }

    public void LoadMessage(String data) {
        try {
            JSONObject jsonObject = new JSONObject(data);
            String message = jsonObject.optString("body", "");
            String clientName = jsonObject.optJSONObject("user").optString(
                    "name");
            String clientUrl = jsonObject.optJSONObject("user").optString(
                    "avatar");
            Log.d("message", message);


        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void loadPuser() {
        String url = api_url + "/api/notification?api_key=" + api_key;
        String pusher_key = getString(R.string.pusher_key);
        HttpAuthorizer authorizer = new HttpAuthorizer(url);
        PusherOptions options = new PusherOptions().setAuthorizer(authorizer);
        pusher = new Pusher(pusher_key, options);
        pusher.connect(new ConnectionEventListener() {
            @Override
            public void onConnectionStateChange(ConnectionStateChange change) {
                Log.d("pusher connect",
                        "State changed to " + change.getCurrentState()
                                + " from " + change.getPreviousState());
            }

            @Override
            public void onError(String message, String code, Exception e) {
                Log.d("pusher connect", "There was a problem connecting!");
            }
        }, ConnectionState.ALL);
        pusher.connect();
        channel = pusher.subscribePresence("presence-client_" + lestgo_id,
                presenceChannelEventListener);
        channel.bind("client-chat-insert", presenceChannelEventListener);
    }

    public void send(String message) {

        JSONObject objectMeetup = new JSONObject();
        try {
            objectMeetup.put("id", intent.getStringExtra("meetupId"));
            objectMeetup.put("title", intent.getStringExtra("meetupName"));

        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        JSONObject objectMessage = new JSONObject();
        try {
            objectMessage.put("body", message);
            objectMessage.put("type", "message");
            objectMessage.put("created", "2014-08-21T02:36:41.406Z");
            objectMessage.put("meetup", objectMeetup);
            objectMessage.put("user", new JSONObject(userInfor));

        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        channel.trigger("client-chat-insert", objectMessage.toString());

    }

}

if server send a message then [edtMessage.setText("OK")]

being seen the problem: FATAL EXCEPTION: pusher-java-client eventQueue

Help.......

Dependency error with java-websocket

I am trying to add this library to my Android app using Gradle, but I am encountering this error:

$ ./gradlew app:dependencies

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring project ':app'.
> Could not resolve all dependencies for configuration ':app:_debugCompile'.
   > Could not find org.java-websocket:java-websocket:1.3.1.
     Searched in the following locations:
         https://jcenter.bintray.com/org/java-websocket/java-websocket/1.3.1/java-websocket-1.3.1.pom
         https://jcenter.bintray.com/org/java-websocket/java-websocket/1.3.1/java-websocket-1.3.1.jar
         file:/usr/local/opt/android-sdk/extras/android/m2repository/org/java-websocket/java-websocket/1.3.1/java-websocket-1.3.1.pom
         file:/usr/local/opt/android-sdk/extras/android/m2repository/org/java-websocket/java-websocket/1.3.1/java-websocket-1.3.1.jar
         file:/usr/local/opt/android-sdk/extras/google/m2repository/org/java-websocket/java-websocket/1.3.1/java-websocket-1.3.1.pom
         file:/usr/local/opt/android-sdk/extras/google/m2repository/org/java-websocket/java-websocket/1.3.1/java-websocket-1.3.1.jar
     Required by:
         MyApplication:app:unspecified > com.pusher:pusher-java-client:0.3.3

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 1.15 secs

Pretty basic here, this is with a new app. I looked on maven.org and there is no java-websocket version 1.3.1. There is a version 1.3.0, but I am not sure how this is working for anyone at the moment.

Here is my sample app:

https://github.com/tjohn/pusher

onAuthenticationFailure [Unable to parse response from Authorizer:]

Hi all,

My code

HttpAuthorizer authorizer = new HttpAuthorizer(
                "http://letsgo.enguys.com/app_dev.php/api/notification?api_key=OWUwNmI0NjU4Yzg2MTAzZTM5ZGU1ZWQ5Mzg3NjUwMzdkNTgwYmZhNw==");
        PusherOptions options = new PusherOptions().setAuthorizer(authorizer);
        pusher = new Pusher("5dcb515f80650272b207", options);
        pusher.connect(new ConnectionEventListener() {
            @Override
            public void onConnectionStateChange(ConnectionStateChange change) {
                Log.d("pusher connect",
                        "State changed to " + change.getCurrentState()
                                + " from " + change.getPreviousState());
            }

            @Override
            public void onError(String message, String code, Exception e) {
                Log.d("pusher connect", "There was a problem connecting!");
            }
        }, ConnectionState.ALL);
        pusher.connect();
        subscribePresence();

function subscribePresence

public void subscribePresence() {
        channel = pusher.subscribePresence("presence-client_105",
                new PresenceChannelEventListener() {
                    @Override
                    public void onEvent(String arg0, String arg1, String arg2) {
                        Log.d("onEvent1", arg0);
                        Log.d("onEvent2", arg1);
                        Log.d("onEvent3", arg2);

                    }

                    @Override
                    public void onSubscriptionSucceeded(String arg0) {
                        Log.d("onSubscriptionSucceeded", arg0);

                    }

                    @Override
                    public void onAuthenticationFailure(String arg0,
                            Exception arg1) {
                        Log.d("onAuthenticationFailure", arg0);

                    }

                    @Override
                    public void userSubscribed(String channelName, User user) {
                        Log.d("userSubscribed", String.format(
                                "A new user joined channel [%s]: %s, %s",
                                channelName, user.getId(), user.getInfo()));

                        if (user.equals(channel.getMe())) {
                            Log.d("userSubscribed", "me");
                        }
                    }

                    @Override
                    public void userUnsubscribed(String channelName, User user) {
                        Log.d("userUnsubscribed", String.format(
                                "A user left channel [%s]: %s %s", channelName,
                                user.getId(), user.getInfo()));
                    }

                    @Override
                    public void onUsersInformationReceived(String channelName,
                            Set<User> users) {
                        for (User user : users) {
                            userSubscribed(channelName, user);
                        }

                    }
                });
}

in PresenceChannelEventListener return onAuthenticationFailure

Log message

Unable to parse response from Authorizer: {"auth":"5dcb515f80650272b207:da186908d4196b68cf9b4f1158918e56af6456e9c33e311ff10ca4f78a2e5990","channel_data":"{\"user_id\":105,\"user_info\":{\"id\":105,\"name\":\"Ho\\u00e0ng Qu\\u1ed1c Kh\\u00e1nh\",\"avatar\":\"https:\\\/\\\/fbcdn-sphotos-d-a.akamaihd.net\\\/hphotos-ak-xap1\\\/t31.0-8\\\/10365448_636973116370820_7140221020852906316_o.jpg\"}}"}

Help me!!

HttpAuthorizer only accepts auth responses with status 200 OK

Currently, the HttpAuthorizer only accepts auth responses that have the HTTP status 200 OK. See https://github.com/pusher/pusher-websocket-java/blob/master/src/main/java/com/pusher/client/util/HttpAuthorizer.java#L141.

If an auth endpoint returns a correct auth signature but the response status is 201 Created, the HttpAuhorizer will simply fail the authorization. I went through the documentation of auth signatures but couldn't find any references to what status code the auth endpoint is expected to return.

If the only valid status code is 200 OK, I'd think it would be great to add it to the documentation. If, 201 OK is considered a valid status code as well, I'd be happy to create a pull request for it.

Cheers!

Unable to authenticate user over a private channel

Hi I am currently facing some issue when trying to authorize a private channel, public channel is fine.

HttpAuthorizer httpAuthorizer = new HttpAuthorizer(API_HOST + "/pusher");
Map<String, String> queryStringParams = new HashMap<String, String>();
queryStringParams.put("token", "random_token");
httpAuthorizer.setQueryStringParameters(queryStringParams);
PusherOptions pusherOptions = new PusherOptions().setAuthorizer(httpAuthorizer);
pusherClient = new Pusher(PUSHER_APP_KEY, pusherOptions);
pusherClient.subscribePrivate("private-user-xx");
pusherClient.connect();
Expected HMAC SHA256 hex digest of 41025.3119666:private-user-xx, but got d3cee7111181b0f479c620c2b7c0eba6890e0a343bc8f137f2232c9b5dfeb9ea

The signature was made on the server side by using pusher-js pusher-rest-node

Pusher should unsubscribe from all channels when disconnecting

When calling pusher.disconnect() and creating a new Pusher instance, the new instance shouldn't be subscribed to any channels. If I do this:

pusher = new Pusher(APP_KEY);
pusher.connect(connectionListener, ConnectionState.ALL);
pusher.subscribePrivate("some-channel", eventListener);
pusher.disconnect();
// wait for onConnectionStateChange telling me I'm DISCONNECTED
pusher = new Pusher(APP_KEY);
pusher.connect(connectionListener, ConnectionState.ALL);
pusher.subscribePrivate("some-channel", eventListener);

The last line will throw an exception, telling me I'm already subscribed to some-channel. This is very confusing and annoying.

The PusherOptions#readVersionFromProperties() leaks InputStream

The input stream opened in The PusherOptions#readVersionFromProperties is never closed.
StrictMode is annoying reporting on this. It looks like easy to fix.

E/StrictMode(10629): A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
E/StrictMode(10629): java.lang.Throwable: Explicit termination method 'end' not called
E/StrictMode(10629):    at dalvik.system.CloseGuard.open(CloseGuard.java:184)
E/StrictMode(10629):    at java.util.zip.Inflater.<init>(Inflater.java:82)
E/StrictMode(10629):    at java.util.zip.ZipFile.getInputStream(ZipFile.java:331)
E/StrictMode(10629):    at java.util.jar.JarFile.getInputStream(JarFile.java:390)
E/StrictMode(10629):    at libcore.net.url.JarURLConnectionImpl.getInputStream(JarURLConnectionImpl.java:222)
E/StrictMode(10629):    at java.net.URL.openStream(URL.java:470)
E/StrictMode(10629):    at java.lang.ClassLoader.getResourceAsStream(ClassLoader.java:444)
E/StrictMode(10629):    at java.lang.Class.getResourceAsStream(Class.java:1334)
E/StrictMode(10629):    at com.pusher.client.PusherOptions.readVersionFromProperties(PusherOptions.java:187)
E/StrictMode(10629):    at com.pusher.client.PusherOptions.<clinit>(PusherOptions.java:11)
E/StrictMode(10629):    at ru.app.PusherService.createPusher(PusherService.java:402)
E/StrictMode(10629):    at ru.app.PusherService.pusherConnect(PusherService.java:423)
E/StrictMode(10629):    at ru.app.PusherService.onStartCommand(PusherService.java:268)
E/StrictMode(10629):    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2864)
E/StrictMode(10629):    at android.app.ActivityThread.access$2100(ActivityThread.java:144)
E/StrictMode(10629):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1376)
E/StrictMode(10629):    at android.os.Handler.dispatchMessage(Handler.java:102)
E/StrictMode(10629):    at android.os.Looper.loop(Looper.java:135)
E/StrictMode(10629):    at android.app.ActivityThread.main(ActivityThread.java:5221)
E/StrictMode(10629):    at java.lang.reflect.Method.invoke(Native Method)
E/StrictMode(10629):    at java.lang.reflect.Method.invoke(Method.java:372)
E/StrictMode(10629):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
E/StrictMode(10629):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

Pusher stops receiving events after a short period of time on a solid connection

I'm using the latest beta released and am finding that it is working, but after so many minutes of inactivity, the app quits firing onEvent(...) for the subscribed events.

I'm monitoring onConnectionStateChange to log when the connection state changes and reconnect if it disconnects (because of the phone losing connectivity, etc), but this event is never firing. I can turn off WIFI on the phone to make sure the event is working, and then it will fire an event stating that it goes from connected to disconnected ([PusherService]/onConnectionStateChange(22024): Connection state changed from [CONNECTED] to [DISCONNECTED])

Is anyone else seeing this problem?

Please let me know if there is any additional detail that I can provide to help reproduce this issue.

Thanks!

Unable to connect over WSS (SSL) on some devices

This issue is to keep track of reports of this problem. One person has reported that this is a problem and the solution is:

What you need to do is to make use of X509TrustManager and initiate SSLContext

If this can be confirmed as a fix it could be incorporated into the library.

Issue with SSL

When just trying to use some of the sample code, I was getting a strange exception:

Exception in thread "pusher-java-client eventQueue" java.lang.NoSuchMethodError: com.pusher.client.connection.websocket.WebSocketClientWrapper.setSocket(Ljava/net/Socket;)V
    at com.pusher.client.connection.websocket.WebSocketClientWrapper.(WebSocketClientWrapper.java:37)
    at com.pusher.client.util.Factory.newWebSocketClientWrapper(Factory.java:68)
    at com.pusher.client.connection.websocket.WebSocketConnection$1.run(WebSocketConnection.java:60)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)

And after seeing other issues related to SSL, on a whim I setEncryption(false) using the PusherOptions and that fixed the issue. I would however like to use SSL if thats possible.

I tried to track down the error, but am stumped because WebSocketClientWrapper extends WebSocketClient, which does have a setSocket(Socket) method, so I am not sure why it would be throwing a NoSuchMethodError only when SSL is enabled, unless there is some funky class stuff going on that I don't understand.

Using version 0.2.3 from maven central, jdk1.7.0_40.jdk on OSX.

Anyone else having this issue?

List of available channels

There should be a function such as get_channels() which returns a List of all available channels for the current application.

Maybe even with filtering by type (public, private, presence) or name.

This way real-time games with a lobby and single game rooms would become possible. Would be great!

Parsing presence channel authentication data fails when the user_id is numeric

Hi, there seems to be a value conversion issue in PresenceChannelImpl.java#L196.

When the private channel authorization data for channel_data.user_id is passed in json as a numeric value (decoded to double in Java ) the type casting to String fails with exception and the toSubscribeMessage channel subscription is interrupted.

The pusher docs do not explicitly state what the type of user_id should be, but in many cases it will simply be a primary key integer. The numeric value is also suggested in the example at http://pusher.com/docs/auth_signatures#presence.

Why embed Java-Websockets?

Just curious. It is causing a classpath issue for me to have both jars in use in the same Android project. Is it because they're not releasing a version with needed functionality?

Inefficient allocations after disconnect

I'm using pusher-java-client on Android, and every time after I call disconnect() I get lots of messages like this in logcat:

D/dalvikvm( 1850): GC_FOR_ALLOC freed 662K, 9% free 10842K/11788K, paused 20ms, total 20ms
D/dalvikvm( 1850): GC_FOR_ALLOC freed 662K, 9% free 10842K/11788K, paused 18ms, total 18ms
D/dalvikvm( 1850): GC_FOR_ALLOC freed 662K, 9% free 10842K/11788K, paused 18ms, total 18ms
D/dalvikvm( 1850): GC_FOR_ALLOC freed 662K, 9% free 10842K/11788K, paused 18ms, total 18ms
D/dalvikvm( 1850): GC_FOR_ALLOC freed 662K, 9% free 10842K/11788K, paused 18ms, total 18ms
D/dalvikvm( 1850): GC_FOR_ALLOC freed 662K, 9% free 10842K/11788K, paused 18ms, total 18ms
D/dalvikvm( 1850): GC_FOR_ALLOC freed 662K, 9% free 10842K/11788K, paused 19ms, total 19ms

This indicates that my app keeps allocating and then releasing objects. Looking in the Android allocation tracker, I can see hundreds if not thousands of javax.net.ssl.SSLEngineResult and java.nio.ByteBuffer[] objects being allocated in org.apache.harmony.xnet.provider.jsse.SSLEngineImpl#unwrap and respectively javax.net.ssl.SSLEngine#unwrap. The full stack traces for these are:

  at org.apache.harmony.xnet.provider.jsse.SSLEngineImpl.unwrap(SSLEngineImpl.java:411) 
  at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:383) 
  at org.java_websocket.SSLSocketChannel2.unwrap(SSLSocketChannel2.java:150)    
  at org.java_websocket.SSLSocketChannel2.readRemaining(SSLSocketChannel2.java:254) 
  at org.java_websocket.SSLSocketChannel2.readMore(SSLSocketChannel2.java:321)  
  at org.java_websocket.SocketChannelIOHelper.readMore(SocketChannelIOHelper.java:28)   
  at org.java_websocket.client.WebSocketClient.interruptableRun(WebSocketClient.java:238)   
  at org.java_websocket.client.WebSocketClient.run(WebSocketClient.java:188)    
  at java.lang.Thread.run(Thread.java:841)  

and

  at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:383) 
  at org.java_websocket.SSLSocketChannel2.unwrap(SSLSocketChannel2.java:150)    
  at org.java_websocket.SSLSocketChannel2.readRemaining(SSLSocketChannel2.java:254) 
  at org.java_websocket.SSLSocketChannel2.readMore(SSLSocketChannel2.java:321)  
  at org.java_websocket.SocketChannelIOHelper.readMore(SocketChannelIOHelper.java:28)   
  at org.java_websocket.client.WebSocketClient.interruptableRun(WebSocketClient.java:238)   
  at org.java_websocket.client.WebSocketClient.run(WebSocketClient.java:188)    
  at java.lang.Thread.run(Thread.java:841)  

Not sure if this is a java_websocket issue or an issue with how pusher-java-client uses it.

IllegalArgumentException in ConnectionStateChange

Hi, lately I've been seeing more and more of these and I don't see any way to stop them because they're inside your library. I already check the state and have put connect/disconnect calls inside try/catch.

Here's the complete stacktrace:
java.lang.IllegalArgumentException: Attempted to create an connection state update where both previous and current state are: CONNECTING at com.pusher.client.connection.ConnectionStateChange.<init>(ConnectionStateChange.java:20) at com.pusher.client.connection.websocket.WebSocketConnection.updateState(WebSocketConnection.java:131) at com.pusher.client.connection.websocket.WebSocketConnection.access$400(WebSocketConnection.java:26) at com.pusher.client.connection.websocket.WebSocketConnection$1.run(WebSocketConnection.java:63) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:841)

Looking at your code, in WebSocketConnection.java you have an unchecked call from handleConnectionMessage and I think that's the culprit.

Do you know how I could prevent these from happening? We already have 2 crashes a day for this.

Thanks,
Sasa

Re-connecting/Re-subscribing to a Channel after disconnection renders presenceChannelObject.trigger() inoperative.

As it is already difficult to verify the connection and subscription status, we are taking a forgiving approach to every event we trigger.

If we find that pusher is disconnected, or catch an IllegalStateException (which is not even advertised in the trigger method), we attempt to re-register the whole pusher process, holding the outgoing messages in a queue until the onSubscriptionSuccess event tells us they can be sent.

However, even though we can verify that we have the proper subscriptions, and the event trigger code is called the same way as it worked before the disconnection, no event registers on the pusher log, or anywhere. We have to restart the whole application to successfully trigger events again. It could have something to do with the eventQueue, but the factory method looks all right.

Anybody else have this issue?

AuthenticationFailure for private channel subscription

On subscribing to private channel I get this very error every time.
Authentication failure due to [{"auth":"f1cec20bd1a33b264fe5:06a34c74fc7550ce11f68a466a312c4e3f1239cdbf91db5b4a605136f3df1e25"}], exception was [com.pusher.client.AuthorizationFailureException: {"auth":"f1cec20bd1a33b264fe5:06a34c74fc7550ce11f68a466a312c4e3f1239cdbf91db5b4a605136f3df1e25"}]
Currently I am using pusher.0.3.3.jar version.Is android OS version has to do anything with pusher jar version as previously I was using pusher-java-client-0.0.1-SNAPSHOT-jar-with-dependencies.jar which was working fine upto android api level 19.

Gradle-ify the project

  • Update project to use Gradle (build, test etc.)
  • Create IDE project files
  • Simple deployment to package registry
  • Improve "Getting Started" README with gradle details
  • Improve "Library Development Environment" README details

Also see #53

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.