real time notifications over websocket (#1000)

* real time notifications over websocket
* automatically re-establish websocket connections
This commit is contained in:
Akinwale Ariwodola 2020-09-09 14:16:22 +01:00 committed by GitHub
parent 86dbfd54d1
commit ed50e1300a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 0 deletions

View file

@ -117,6 +117,8 @@ dependencies {
implementation 'com.arthenica:mobile-ffmpeg-full-gpl:4.3.1.LTS' implementation 'com.arthenica:mobile-ffmpeg-full-gpl:4.3.1.LTS'
implementation 'org.java-websocket:Java-WebSocket:1.5.1'
compileOnly 'org.projectlombok:lombok:1.18.10' compileOnly 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'org.projectlombok:lombok:1.18.10' annotationProcessor 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'

View file

@ -98,6 +98,8 @@ import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -107,6 +109,7 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.URI;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -199,6 +202,7 @@ import io.lbry.lbrysdk.ServiceHelper;
import io.lbry.lbrysdk.Utils; import io.lbry.lbrysdk.Utils;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.SneakyThrows;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
public class MainActivity extends AppCompatActivity implements SdkStatusListener { public class MainActivity extends AppCompatActivity implements SdkStatusListener {
@ -208,6 +212,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
private static final int REMOTE_NOTIFICATION_REFRESH_TTL = 300000; // 5 minutes private static final int REMOTE_NOTIFICATION_REFRESH_TTL = 300000; // 5 minutes
public static final String SKU_SKIP = "lbryskip"; public static final String SKU_SKIP = "lbryskip";
private boolean shuttingDown;
private Date remoteNotifcationsLastLoaded; private Date remoteNotifcationsLastLoaded;
private Map<String, Class> specialRouteFragmentClassMap; private Map<String, Class> specialRouteFragmentClassMap;
@Getter @Getter
@ -240,6 +245,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
@Setter @Setter
private BackPressInterceptor backPressInterceptor; private BackPressInterceptor backPressInterceptor;
private WebSocketClient webSocketClient;
@Getter @Getter
private String firebaseMessagingToken; private String firebaseMessagingToken;
@ -1020,11 +1026,15 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
@Override @Override
protected void onDestroy() { protected void onDestroy() {
shuttingDown = true;
unregisterReceivers(); unregisterReceivers();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
if (receivedStopService || !isServiceRunning(this, LbrynetService.class)) { if (receivedStopService || !isServiceRunning(this, LbrynetService.class)) {
notificationManager.cancelAll(); notificationManager.cancelAll();
} }
if (webSocketClient != null) {
webSocketClient.close();
}
if (dbHelper != null) { if (dbHelper != null) {
dbHelper.close(); dbHelper.close();
} }
@ -1090,10 +1100,40 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
@SneakyThrows
private void checkWebSocketClient() {
if ((webSocketClient == null || webSocketClient.isClosed()) && !Helper.isNullOrEmpty(Lbryio.AUTH_TOKEN)) {
webSocketClient = new WebSocketClient(new URI(String.format("%s%s", Lbryio.WS_CONNECTION_BASE_URL, Lbryio.AUTH_TOKEN))) {
@Override
public void onOpen(ServerHandshake handshakedata) { }
@Override
public void onMessage(String message) {
loadRemoteNotifications(false);
}
@Override
public void onClose(int code, String reason, boolean remote) {
if (!shuttingDown) {
// attempt to re-establish the connection if the app isn't being closed
checkWebSocketClient();
}
}
@Override
public void onError(Exception ex) { }
};
webSocketClient.connect();
}
}
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
checkPurchases(); checkPurchases();
checkWebSocketClient();
enteringPIPMode = false; enteringPIPMode = false;
applyNavbarSigninPadding(); applyNavbarSigninPadding();
@ -2672,6 +2712,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
loadRemoteNotifications(false); loadRemoteNotifications(false);
checkUrlIntent(getIntent()); checkUrlIntent(getIntent());
checkWebSocketClient();
LbryAnalytics.logEvent(LbryAnalytics.EVENT_APP_LAUNCH); LbryAnalytics.logEvent(LbryAnalytics.EVENT_APP_LAUNCH);
appStarted = true; appStarted = true;
} }

View file

@ -57,6 +57,7 @@ public final class Lbryio {
public static final String TAG = "Lbryio"; public static final String TAG = "Lbryio";
public static final String CONNECTION_STRING = "https://api.lbry.com"; public static final String CONNECTION_STRING = "https://api.lbry.com";
public static final String WS_CONNECTION_BASE_URL = "wss://api.lbry.com/subscribe?auth_token=";
public static final String AUTH_TOKEN_PARAM = "auth_token"; public static final String AUTH_TOKEN_PARAM = "auth_token";
public static List<Subscription> subscriptions = new ArrayList<>(); public static List<Subscription> subscriptions = new ArrayList<>();
public static List<Claim> cacheResolvedSubscriptions = new ArrayList<>(); public static List<Claim> cacheResolvedSubscriptions = new ArrayList<>();