Coder Social home page Coder Social logo

centrifuge-java's Introduction

centrifuge-java

Websocket client for Centrifugo server and Centrifuge library.

There is no v1 release of this library yet – API still evolves. At the moment patch version updates only contain backwards compatible changes, minor version updates can have backwards incompatible API changes.

Check out client SDK API specification to learn how this SDK behaves. It's recommended to read that before starting to work with this SDK as the spec covers common SDK behavior - describes client and subscription state transitions, main options and methods. Also check out examples folder.

The features implemented by this SDK can be found in SDK feature matrix.

The latest centrifuge-java is compatible with Centrifugo server v5 and v4 and Centrifuge >= 0.25.0. For Centrifugo v2, Centrifugo v3 and Centrifuge < 0.25.0 you should use centrifuge-java v0.1.0.

Installation

Library available in Maven: https://search.maven.org/artifact/io.github.centrifugal/centrifuge-java

This library depends on streamsupport-minifuture. In case your project has a dependency to streamsupport-cfuture and you have a class name conflicts, you can exclude minifuture safely. Example for Gradle:

implementation('io.github.centrifugal:centrifuge-java:{version}') {
    exclude group: 'net.sourceforge.streamsupport', module: 'streamsupport-minifuture'
}

Javadoc online

http://www.javadoc.io/doc/io.github.centrifugal/centrifuge-java

Obfuscation with ProGuard

Centrifuge-java library uses Protobuf library (Lite version) for client protocol. This fact and the fact that Protobuf Lite uses reflection internally can cause connection errors when releasing your application with Android shrinking and obfuscation features enabled. See protocolbuffers/protobuf#6463 for details. To deal with this centrifuge-java comes with Proguard rules included in the jar.

More information about Android shrinking.

Basic usage

See example code in console Java example or in demo Android app

To use with Android don't forget to set INTERNET permission to AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />

Usage in background

When a mobile application goes to the background there are OS-specific limitations for established persistent connections - which can be silently closed shortly. Thus in most cases you need to disconnect from a server when app moves to the background and connect again when app goes to the foreground.

CI status

Build Status

License

Library is available under the MIT license. See LICENSE for details.

For Contributors

This section contains an information for library contributors. You don't need generating protobuf code if you just want to use centrifuge-java in your project.

Generate proto

The protobuf definitions are located in centrifuge/main/proto directory. Protocol class is generated automatically during project compilation by protobuf gradle plugin.

Check API signatures

We use metalava-gradle to ensure we are aware of breaking API changes in the library.

All PRs check API signatures for compatibility. If you see an error, it may indicate there is a breaking change. Regenerate API signature with the following command and include an updated api.txt in your PR:

./gradlew :centrifuge:metalavaGenerateSignature

Also indicate a breaking change in changelog.

To verify API compatibility locally, run the following command:

./gradlew :centrifuge:metalavaCheckCompatibility

For maintainer

Automatic publishing

  1. Bump version in publish-setup.gradle.
  2. Create new library tag.

The release GitHub Action should now publish the library.

Manual publishing

Do all steps from the automatic publishing. Create configuration file gradle.properties in GRADLE_USER_HOME:

signing.keyId=<LAST_8_SYMBOLS_OF_KEY_ID>
signing.password=<PASSWORD>
signing.secretKeyRingFile=/Path/to/.gnupg/secring.gpg

mavenCentralUsername=<USERNAME>
mavenCentralPassword=<PASSWORD>

Then run:

./gradlew publish --no-daemon --no-parallel
./gradlew closeAndReleaseRepository

The second command will promote staged release to production on MavenCentral.

You can do it manually by following the instructions:

https://central.sonatype.org/pages/releasing-the-deployment.html

I.e.

  1. Login here: https://oss.sonatype.org/
  2. Go to Staging repositories
  3. Find release, push Close button, wait
  4. Push Release button

Special thanks

centrifuge-java's People

Contributors

clmnin avatar fuliozor avatar fzambia avatar larryclean avatar ntoskrnl avatar oleg-smith avatar philipdukhov avatar vyndor 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

Watchers

 avatar  avatar  avatar  avatar

centrifuge-java's Issues

Error 3501 (Bad Request)

Hello!
I am trying to connect to Centrifugo-server to receive messages with donation-events.
The server owners provide a script for JS, which perectly works for JS:

 <script src="https://cdn.jsdelivr.net/gh/centrifugal/[email protected]/dist/centrifuge.min.js"></script>
    <script>
        async function start() {
            // Creating Centrifuge object
            window.centrifuge = new Centrifuge('wss://centrifugo.donatepay.ru:43002/connection/websocket', {
                subscribeEndpoint: 'https://donatepay.ru/api/v2/socket/token',
                subscribeParams:   {
                    access_token: 'od13l807htY4zXSDlWsV8n3BvpOExBIGoLTs9JXqWKzxf0ZrxVTZpcL87vL6'
                },
                disableWithCredentials: true
            });

            // Providing Centrifuge token
            centrifuge.setToken(await getToken())

            // Subscribing to user $public:USER_ID
            centrifuge.subscribe("$public:162386", function (message) {
                // Printing all new messages to console
                console.log('message', message);
            });

            centrifuge.on('error', (e) => {
                console.log('error', e)
            })

            centrifuge.on('subscribe', (e) => {
                console.log('subscribe', e)
            })

            centrifuge.on('connect', (e) => {
                console.log(e)
            })

            // Connecting to Centrifugo
            centrifuge.connect();
        }

So i tired to replicate it on Java. Here is my code:

        EventListener listener = new EventListener() {
            @Override
            public void onConnected(Client client,  ConnectedEvent event) {
                if (isItFirstSuccessfulConnection) {
                    logToConsole("Произведено успешное подключение к §b" + donationServiceToken.getDonationServiceType() + "§f!");
                    isItFirstSuccessfulConnection = false;
                } else {
                    logToConsole("Восстановлено соединение с §b" + donationServiceToken.getDonationServiceType() + "§f!");
                }
            }

            @Override
            public void onDisconnected(Client client, DisconnectedEvent event) {
                if (isActive) {
                    logToConsole("Потеряно соединение с §b" + donationServiceToken.getDonationServiceType() + "§f!");
                }
            }
        };

        Options options = new Options();
        options.setToken(centrifugeToken);
        
        centrifugoClient = new Client(SOCKET_SERVER, options, listener);
        
        centrifugoClient.connect();

        SubscriptionEventListener subListener = new SubscriptionEventListener() {
            @Override
            public void onJoin(Subscription sub, JoinEvent event) {
                logToConsole("Успешная подписка на канал " + sub.getChannel());
            }
            @Override
            public void onError(Subscription sub, SubscriptionErrorEvent event) {
                logToConsole("Ошибка подписки на канал " + sub.getChannel() + "! Причина: " + event.getError().getMessage());
            }
            @Override
            public void onPublication(Subscription sub, PublicationEvent event) {
                String data = new String(event.getData(), UTF_8);
                logToConsole("Получено сообщение: " + data);
            }
        };

        Subscription sub;
        try {
            sub = centrifugoClient.newSubscription("$public:"+userId, subListener);
        } catch (DuplicateSubscriptionException e) {
            e.printStackTrace();
            return;
        }
        sub.subscribe();

So when i try to launch the plugin (this code is a part of Minecraft plugin), i gets an error (3501, Bad Request) right after the "centrifugoClient.connect();" (it goes to DisconnectedListener and gives the error message i've mentioned above).

Server version is 3.2.0, my client version is 0.2.2

Could you give me any advice please? Thank you in advance.

Builder for Options

One more thing to improve is using builder pattern for options:

Code
package io.github.centrifugal.centrifuge;

import java.net.Proxy;
import java.util.Map;

/**
 * Configuration for a {@link Client} instance.
 */
public class Options {
    private final String token;
    private final ConnectionTokenGetter tokenGetter;
    private final String name;
    private final String version;
    private final byte[] data;
    private final Map<String, String> headers;
    private final int timeout;
    private final int minReconnectDelay;
    private final int maxReconnectDelay;
    private final int maxServerPingDelay;
    private final Proxy proxy;
    private final String proxyLogin;
    private final String proxyPassword;
    private final Dns dns;

    public String getToken() {
        return token;
    }

    public ConnectionTokenGetter getTokenGetter() {
        return tokenGetter;
    }

    public String getName() {
        return name;
    }

    public String getVersion() {
        return version;
    }

    public byte[] getData() {
        return data;
    }

    public Map<String, String> getHeaders() {
        return headers;
    }

    public int getTimeout() {
        return timeout;
    }

    public int getMinReconnectDelay() {
        return minReconnectDelay;
    }

    public int getMaxReconnectDelay() {
        return maxReconnectDelay;
    }

    public int getMaxServerPingDelay() {
        return maxServerPingDelay;
    }

    public Proxy getProxy() {
        return proxy;
    }

    public String getProxyLogin() {
        return proxyLogin;
    }

    public String getProxyPassword() {
        return proxyPassword;
    }

    public Dns getDns() {
        return this.dns;
    }

    private Options(Builder builder) {
        this.token = builder.token;
        this.tokenGetter = builder.tokenGetter;
        this.name = builder.name;
        this.version = builder.version;
        this.data = builder.data;
        this.headers = builder.headers;
        this.timeout = builder.timeout;
        this.minReconnectDelay = builder.minReconnectDelay;
        this.maxReconnectDelay = builder.maxReconnectDelay;
        this.maxServerPingDelay = builder.maxServerPingDelay;
        this.proxy = builder.proxy;
        this.proxyLogin = builder.proxyLogin;
        this.proxyPassword = builder.proxyPassword;
        this.dns = builder.dns;
    }

    public static class Builder {
        private String token = "";
        private ConnectionTokenGetter tokenGetter;
        private String name = "java";
        private String version = "";
        private byte[] data;
        private Map<String, String> headers;
        private int timeout = 5000;
        private int minReconnectDelay = 500;
        private int maxReconnectDelay = 20000;
        private int maxServerPingDelay = 10000;
        private Proxy proxy;
        private String proxyLogin;
        private String proxyPassword;
        private Dns dns;

        /**
         * Set connection token. This is a token you have to receive from your application backend.
         * If your tokens expire and you want SDK to automatically refresh tokens then set
         * ConnectionTokenGetter (see below).
         */
        public Builder setToken(String token) {
            this.token = token;
            return this;
        }

        /**
         * Set a method to extract new connection token upon expiration.
         */
        public Builder setTokenGetter(ConnectionTokenGetter tokenGetter) {
            this.tokenGetter = tokenGetter;
            return this;
        }

        /**
         * Set client name - name of this client. This should not be unique per client – it
         * identifies client application name actually, so name should have a limited
         * number of possible values. By default this client uses "java" as a name.
         */
        public Builder setName(String name) {
            this.name = name;
            return this;
        }

        /**
         * Set client version - version of application. This may be used for observability
         * on the server (for example in analytics).
         */
        public Builder setVersion(String version) {
            this.version = version;
            return this;
        }

        /**
         * Set custom connection data. This data will be delivered to server in Connect command.
         * For Centrifugo this may be useful in case of using connect proxy.
         */
        public Builder setData(byte[] data) {
            this.data = data;
            return this;
        }

        /**
         * Set custom headers for WebSocket Upgrade request.
         */
        public Builder setHeaders(Map<String, String> headers) {
            this.headers = headers;
            return this;
        }

        /**
         * Set custom timeout for requests in milliseconds. By default, 5000 is used.
         */
        public Builder setTimeout(int timeout) {
            this.timeout = timeout;
            return this;
        }

        /**
         * Set minimal time before reconnect attempt in milliseconds. By default, 500 is used.
         */
        public Builder setMinReconnectDelay(int minReconnectDelay) {
            this.minReconnectDelay = minReconnectDelay;
            return this;
        }

        /**
         * Set max time between reconnect attempts in milliseconds. By default, 20000 is used.
         */
        public Builder setMaxReconnectDelay(int maxReconnectDelay) {
            this.maxReconnectDelay = maxReconnectDelay;
            return this;
        }

        /**
         * Set max time of ping delay from server in milliseconds. By default, 10000 is used.
         */
        public Builder setMaxServerPingDelay(int maxServerPingDelay) {
            this.maxServerPingDelay = maxServerPingDelay;
            return this;
        }

        /**
         * Set proxy to use.
         */
        public Builder setProxy(Proxy proxy) {
            this.proxy = proxy;
            return this;
        }

        /**
         * Set proxy credentials.
         */
        public Builder setProxyCredentials(String login, String password) {
            this.proxyLogin = login;
            this.proxyPassword = password;
            return this;
        }

        /**
         * Set custom DNS resolver.
         */
        public Builder setDns(Dns dns) {
            this.dns = dns;
            return this;
        }

        public Options build() {
            return new Options(this);
        }
    }
}

Possibly we could have both current (for compatibility) and builder approach. Though the main benefit of Builder is immutability - combining both approaches makes the benefit less obvious (as we could just return this from current setters).

Calling subscribe on subscription causes "already subscribed" error

I'm using version 1.0.0 of this library, as my server is using Centrifugo v2.

According to documentation I should call subscription.subscribe() for each subscription.

But when I try doing this, looks like some auto-subscription method is being called, and after some delay(I suspect after auto-subscription succeeds) - when my subscribe call starts processing - SubscriptionEventListener.onSubscribeError is getting called with "already subscribed".

I could've remove subscription.subscribe() but auto-subscription system doesn't seems to be working with private channels - there I still have to call it. And I can't just ignore onSubscribeError, because client is closing with Closing : 1000 / log message.

My guess that that I need to call subscribe only for private channels - is that correct? Why documentation doesn't mention it?

  1. Is there a way to disable auto-subscription system, so I can call subscription.subscribe() on each subscription?
  2. Is there a way to prevent client from closing on this particular error?

TimeoutException on Subscription.publish

I'm trying to publish a message via onPublish callback, but I'm always getting :

/System.out: publish error: java.util.concurrent.TimeoutException

The code :

@Override
public void onPublish(Subscription sub, PublishEvent event) {
    String data = new String(event.getData(), UTF_8);
    Log.wtf("INCOMING", "message from " + sub.getChannel() + " " + data);

    try {
        JSONObject welcome = new JSONObject();
        welcome.put("input", "i'm old");
        byte[] msg = welcome.toString().getBytes("UTF-8");
        sub.publish(msg, new ReplyCallback<PublishResult>() {
            @Override
            public void onFailure(Throwable e) {
                System.out.println("publish error: " + e);
            }

            @Override
            public void onDone(ReplyError err, PublishResult reply) {
                if (err != null) {
                    System.out.println("error publish: " + err.getMessage());
                    return;
                }
                System.out.println("successfully published");
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }
}

but when sending a message via

client.publish("public", msg, new ReplyCallback<PublishResult>)

it's working fine

my centrifugo config :

{
    "anonymous":true,
    "publish":true,
    "subscribe_to_publish":true,
    "presence":true,
    "join_leave":true,
    "history_size":1500,
    "history_lifetime":300,
    "history_recover":true,
    "history_disable_for_client":false,
    "debug":true,
    "api_insecure":true,
    "log_level":"debug",
    "namespaces":[
        {
            "name":"public",
            "publish":true,
            "anonymous":true,
            "subscribe_to_publish":true,
            "history_size":10,
            "history_lifetime":300,
            "history_recover":true
        }
    ]
}

How can I subscribe to private channel?

Hi. I read that in Javascript client AJAX POST request is automatically sent to /centrifuge/subscribe endpoint on every private channel subscription attempt.
But In Java (Android) what is the manner to connect to private channels?

pinning

Hello, how can we implement certificate pinning if it is possible at all?

Uncloseable thread pools in Client class

There are 3 internal executors with thread pools in Client class:

  • executor
  • reconnectExecutor
  • scheduler
    every executor keeps own thread pool with single non-daemon thread, which prevents java app from regular termination.
    There are no method to stop these threads on exit and gracefully stop the application.
    I suggest to add shutdown() method similar as disconnect() but with shutdown of internal executors.

Automate new releases over CI

At moment it's pretty tedious to do new releases, automatic release workflow on new tag will let us evolve much faster.

Bad protocol happens when receiving messages and never reconnect to the server

Hi there,
I'm using the "centrifuge-java:0.2.5" in my Android project(backend side: V4.0.1),and endpoint is: wss://xxxx/connection/websocket?format=protobuf&cf_protocol_version=v2.
But when receiving messages, sometimes error happens like this:

  1. In EventListener() - onDisconnected() callback: DisconnectedEvent code = 2, reason = "bad protocol"
  2. In EventListener() - onError() callback: ErrorEvent reason = "java.net.SocketException: Socket closed"
    After that the SDK never trigger any reconnection and/or onConnected() event as a result we stop receiving new message from the server.

disconnected stale, reconnect false error on android

hi dear

i use your java library on android with kotlin implemention
but when i try to connect with JWT token, returns disconnected stale, reconnect false error
but on iOS(swift) and Web version every thing is ok

this is my code

`
val cfListener = object : EventListener() {
override fun onConnect(client: Client?, event: ConnectEvent?) {
Log.d("CENTRIFUGE", "connected")
}

        override fun onDisconnect(client: Client?, event: DisconnectEvent) {
            Log.d(
                "CENTRIFUGE",
                "disconnected %s, reconnect %s%n".format(event.reason, event.reconnect)
            )
        }

        override fun onError(client: Client?, event: ErrorEvent?) {
            super.onError(client, event)
            Log.d("CENTRIFUGE", event.toString())
        }
    }

    Log.d("CENTRIFUGE", Globals.CENTRIFUGE_TOKEN)

    val cfClient = Client(
        Constants.centrifugeBrokerUrl,
        Options(),
        cfListener
    )

    cfClient.setToken(Globals.CENTRIFUGE_TOKEN)
    cfClient.connect()

    val cfSubListener = object : SubscriptionEventListener() {
        override fun onSubscribeSuccess(sub: Subscription, event: SubscribeSuccessEvent?) {
            Log.d("CENTRIFUGE", "subscribed to " + sub.channel)
        }

        override fun onSubscribeError(sub: Subscription, event: SubscribeErrorEvent) {
            Log.d(
                "CENTRIFUGE",
                "subscribe error " + sub.channel.toString() + " " + event.message
            )
        }

        override fun onPublish(sub: Subscription, event: PublishEvent) {
            val data = String(event.data, UTF_8)
            Log.d("CENTRIFUGE", "message from " + sub.channel.toString() + " " + data)
        }
    }
    
    try {
        val subscription = cfClient.newSubscription("chat#${Globals.SHOP_ID}", cfSubListener)
        subscription.subscribe()
    }catch (e: DuplicateSubscriptionException){
        Log.d("CENTRIFUGE", e.message)
    }`

Unsupported class file major version 60

Hi there,

I am trying to integrate centrifuge-java into a Android Kotlin based project. I kept getting java.lang.IllegalArgumentException: Unsupported class file major version 60 compile error for version 0.0.6.

I am able to get a successful build with version 0.0.5.

What should be the other versions(gradle, gradle bin) for successful build for 0.0.6?

Stuck on connecting state after getting bad request during the first connect.

Steps to reproduce:

  1. (In my case) Get any malformed url, e.g.: wss://correcturl/ws?format=protobufABCDE. So this is almost correct url except the last part.
  2. Create Client with the url, set all listeners and callbacks properly.
  3. Call connect() method. See that only onDisconnected callback called with "bad request, reconnect = false"
  4. Call connect() again. Nothing happened.
    4.1) Call disconnect() / connect() in any order. The same result, no any callbacks called.

Debugging shows that in this case the second and others connect() methods don't make sense anymore because Client.connecting field is still true and will never change to false.

Can not see public classes after add library

Hello,
I added this line to gradle
implementation 'io.github.centrifugal:centrifuge-java:0.2.0'
library added successfully. Also I add this line of code manually at top of my class
import io.github.centrifugal.centrifuge.*
but I can not see the public classes like Client. EventListener or other public classes.

what should I do ?

Client disconnects abruptly with Centrifugo-server error

After subscribing to a channel, in a few mins the java-client disconnects from the centrifugo-server. During this disconnect the onLeave callback is called.

This is the error seen in the centrifugo-server log

error encoding subscribe error="json: error calling MarshalJSON for type protocol.Raw: invalid character 'W' looking for beginning of value"

This seem to be an error specific to the java client? I tried to run persistent golang clients and they did not disconnect abruptly or cause any issues.

options.setToken() seems not worked

Hello again
on the web :
the setToken() method works fine and generated token is worked. when we do not call setToken, received bad request Error on server side. when we call the method but send empty token, we received 'invalid token' error on server.
now on android:
I think setToken() method not worked properly because we always get this error on server side : bad request . and on android I received this error:

System.out: [socket]:check permission begin!
System: ClassLoader referenced unknown path: system/framework/mediatek-cta.jar
System.out: [socket] e:java.lang.ClassNotFoundException: com.mediatek.cta.CtaUtils
CentriFugo: error = Client error java.net.ProtocolException: Expected HTTP 101 response but was '403 Forbidden'

last line is my log on EventListener : override fun onError(client: Client?, event: ErrorEvent)

Use Result type for returning success result or error

Where we currently use void onDone​(@Nullable java.lang.Throwable e, @Nullable T result).

Similar to Result type we use in our Swift SDK. Or similar to kotlin.Result.

In Java it may be sth like this:

public class Result<T> {
    private T result;
    private Throwable error;

    private Result(T result, Throwable error) {
        this.result = result;
        this.error = error;
    }

    public static <T> Result<T> success(T result) {
        return new Result<>(result, null);
    }

    public static <T> Result<T> error(Throwable error) {
        return new Result<>(null, error);
    }

    public T getResult() {
        return result;
    }

    public Throwable getError() {
        return error;
    }

    public boolean isSuccess() {
        return error == null;
    }

    public boolean isError() {
        return error != null;
    }
}

For now opened to collect opinions, unfortunately this will break API.

Crash in my app

Here is the stack trace:

java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@651c9a5[Not completed] rejected from java.util.concurrent.ThreadPoolExecutor@6e1517a[Shutting down, pool size = 1, active threads = 1, queued tasks = 2, completed tasks = 1]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2072)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:834)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1364)
	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:118)
	at java.util.concurrent.Executors$DelegatedExecutorService.submit(Executors.java:671)
	at io.github.centrifugal.centrifuge.Client$1.onClosed(SourceFile:15)
	at okhttp3.internal.ws.RealWebSocket.writeOneFrame$okhttp(SourceFile:188)
	at okhttp3.internal.ws.RealWebSocket$WriterTask.runOnce(SourceFile:3)
	at okhttp3.internal.concurrent.TaskRunner.runTask(SourceFile:63)
	at okhttp3.internal.concurrent.TaskRunner.access$runTask(Unknown Source:0)
	at okhttp3.internal.concurrent.TaskRunner$runnable$1.run(SourceFile:55)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
	at java.lang.Thread.run(Thread.java:1012)

I have zero clue what happen. As you can see I can't even guard it with try/catch. I called unsubscribe() and then close(). Is that the problem? Should I put the close() in the onDestroy of the App? thanks.

How to make Centrifugo disconnect after 30 seconds of no Internet connection?

What I need is an onError callback after 30 seconds.
I see all these methods:

    /**
     * Set custom timeout for requests in milliseconds. By default, 5000 is used.
     */
    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }


    /**
     * Set minimal time before reconnect attempt in milliseconds. By default, 500 is used.
     */
    public void setMinReconnectDelay(int minReconnectDelay) {
        this.minReconnectDelay = minReconnectDelay;
    }

    
    /**
     * Set max time between reconnect attempts in milliseconds. By default, 20000 is used.
     */
    public void setMaxReconnectDelay(int maxReconnectDelay) {
        this.maxReconnectDelay = maxReconnectDelay;
    }

   
    /**
     * Set max time of ping delay from server in milliseconds. By default, 10000 is used.
     */
    public void setMaxServerPingDelay(int maxServerPingDelay) {
        this.maxServerPingDelay = maxServerPingDelay;
    }

But I still don't understand which should I use for this requirement?
Thanks.

Revisit using null safe modifiers

In #54 we made an attempt of introducing @Nullable and @Notnull modifiers. Unfortunately reverted the change since it introduced some warnings which need to be addressed somehow. Probably it's OK to go with them.
Screenshot 2023-02-14 at 23 44 57
Screenshot 2023-02-14 at 23 54 59

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.