package chat.rocket.android.service; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.support.annotation.Nullable; import bolts.Task; import chat.rocket.android.helper.LogcatIfError; import chat.rocket.android.model.ServerConfig; import chat.rocket.android.realm_helper.RealmHelper; import chat.rocket.android.realm_helper.RealmListObserver; import chat.rocket.android.realm_helper.RealmStore; import io.realm.RealmResults; import java.util.HashMap; import java.util.List; /** * Background service for Rocket.Chat.Application class. */ public class RocketChatService extends Service { private RealmHelper realmHelper; private HashMap<String, RocketChatWebSocketThread> webSocketThreads; private RealmListObserver<ServerConfig> connectionRequiredServerConfigObserver; /** * ensure RocketChatService alive. */ public static void keepalive(Context context) { context.startService(new Intent(context, RocketChatService.class)); } @Override public void onCreate() { super.onCreate(); webSocketThreads = new HashMap<>(); realmHelper = RealmStore.getDefault(); connectionRequiredServerConfigObserver = realmHelper .createListObserver(realm -> realm.where(ServerConfig.class) .isNotNull("hostname") .equalTo("state", ServerConfig.STATE_READY) .findAll()) .setOnUpdateListener(this::connectToServerWithServerConfig); refreshServerConfigState(); } private void refreshServerConfigState() { realmHelper.executeTransaction(realm -> { RealmResults<ServerConfig> configs = realm.where(ServerConfig.class).findAll(); for (ServerConfig config: configs) { if (config.getState() != ServerConfig.STATE_READY) { config.setState(ServerConfig.STATE_READY); } } return null; }).continueWith(new LogcatIfError());; } @Override public int onStartCommand(Intent intent, int flags, int startId) { List<ServerConfig> configs = realmHelper.executeTransactionForReadResults(realm -> realm.where(ServerConfig.class) .equalTo("state", ServerConfig.STATE_CONNECTED) .findAll()); for (ServerConfig config: configs) { String serverConfigId = config.getServerConfigId(); if (webSocketThreads.containsKey(serverConfigId)) { RocketChatWebSocketThread thread = webSocketThreads.get(serverConfigId); if (thread != null) { thread.keepalive(); } } } realmHelper.executeTransaction(realm -> { RealmResults<ServerConfig> targetConfigs = realm .where(ServerConfig.class) .beginGroup() .equalTo("state", ServerConfig.STATE_CONNECTION_ERROR) .or() .isNotNull("error") .endGroup() .isNotNull("session") .findAll(); for (ServerConfig config : targetConfigs) { config.setState(ServerConfig.STATE_READY); config.setError(null); } return null; }).onSuccessTask(task -> { connectionRequiredServerConfigObserver.keepalive(); return null; }); return START_STICKY; } private void connectToServerWithServerConfig(List<ServerConfig> configList) { if (configList.isEmpty()) { return; } ServerConfig config = configList.get(0); createWebSocketThread(config).onSuccess(task -> { RocketChatWebSocketThread thread = task.getResult(); if (thread != null) { thread.keepalive(); } return null; }); } private Task<RocketChatWebSocketThread> createWebSocketThread(final ServerConfig config) { final String serverConfigId = config.getServerConfigId(); webSocketThreads.put(serverConfigId, null); return ServerConfig.updateState(serverConfigId, ServerConfig.STATE_CONNECTING) .onSuccessTask(_task -> RocketChatWebSocketThread.getStarted(getApplicationContext(), config)) .onSuccessTask(task -> ServerConfig.updateState(serverConfigId, ServerConfig.STATE_CONNECTED) .onSuccessTask(_task -> task)) .onSuccessTask(task -> { webSocketThreads.put(serverConfigId, task.getResult()); return task; }); } private Task<RocketChatWebSocketThread> findOrCreateWebSocketThread(final ServerConfig config) { final String serverConfigId = config.getServerConfigId(); if (webSocketThreads.containsKey(serverConfigId)) { return Task.forResult(webSocketThreads.get(serverConfigId)); } else { return createWebSocketThread(config); } } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }