RocketChatService.java 4.5 KB
Newer Older
1 2 3 4 5 6 7
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;
Yusuke Iwaki's avatar
Yusuke Iwaki committed
8 9 10 11
import io.realm.RealmResults;

import java.util.HashMap;
import java.util.List;
12
import bolts.Task;
13
import chat.rocket.android.helper.LogcatIfError;
14
import chat.rocket.android.model.ServerConfig;
15 16 17
import chat.rocket.android.realm_helper.RealmHelper;
import chat.rocket.android.realm_helper.RealmListObserver;
import chat.rocket.android.realm_helper.RealmStore;
18

19 20 21
/**
 * Background service for Rocket.Chat.Application class.
 */
22 23
public class RocketChatService extends Service {

24
  private RealmHelper realmHelper;
Yusuke Iwaki's avatar
Yusuke Iwaki committed
25
  private HashMap<String, RocketChatWebSocketThread> webSocketThreads;
26
  private RealmListObserver<ServerConfig> connectionRequiredServerConfigObserver;
27

28 29 30 31 32 33
  /**
   * ensure RocketChatService alive.
   */
  public static void keepalive(Context context) {
    context.startService(new Intent(context, RocketChatService.class));
  }
34

Yusuke Iwaki's avatar
Yusuke Iwaki committed
35 36
  @Override
  public void onCreate() {
37
    super.onCreate();
Yusuke Iwaki's avatar
Yusuke Iwaki committed
38
    webSocketThreads = new HashMap<>();
39 40
    realmHelper = RealmStore.getDefault();
    connectionRequiredServerConfigObserver = realmHelper
Yusuke Iwaki's avatar
Yusuke Iwaki committed
41 42 43 44 45
        .createListObserver(realm -> realm.where(ServerConfig.class)
            .isNotNull("hostname")
            .equalTo("state", ServerConfig.STATE_READY)
            .findAll())
        .setOnUpdateListener(this::connectToServerWithServerConfig);
46

47 48 49 50 51
    refreshServerConfigState();
  }

  private void refreshServerConfigState() {
    realmHelper.executeTransaction(realm -> {
52 53 54
      RealmResults<ServerConfig> configs = realm.where(ServerConfig.class)
          .notEqualTo("state", ServerConfig.STATE_READY)
          .findAll();
Yusuke Iwaki's avatar
Yusuke Iwaki committed
55
      for (ServerConfig config : configs) {
56
        config.setState(ServerConfig.STATE_READY);
57 58
      }
      return null;
Yusuke Iwaki's avatar
Yusuke Iwaki committed
59 60
    }).continueWith(new LogcatIfError());
    ;
61
  }
62

Yusuke Iwaki's avatar
Yusuke Iwaki committed
63 64
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
Yusuke Iwaki's avatar
Yusuke Iwaki committed
65 66 67 68
    List<ServerConfig> configs = realmHelper.executeTransactionForReadResults(realm ->
        realm.where(ServerConfig.class)
            .equalTo("state", ServerConfig.STATE_CONNECTED)
            .findAll());
Yusuke Iwaki's avatar
Yusuke Iwaki committed
69
    for (ServerConfig config : configs) {
Yusuke Iwaki's avatar
Yusuke Iwaki committed
70 71 72 73 74 75 76 77 78
      String serverConfigId = config.getServerConfigId();
      if (webSocketThreads.containsKey(serverConfigId)) {
        RocketChatWebSocketThread thread = webSocketThreads.get(serverConfigId);
        if (thread != null) {
          thread.keepalive();
        }
      }
    }

79 80 81
    realmHelper.executeTransaction(realm -> {
      RealmResults<ServerConfig> targetConfigs = realm
          .where(ServerConfig.class)
Yusuke Iwaki's avatar
Yusuke Iwaki committed
82
          .beginGroup()
83
          .equalTo("state", ServerConfig.STATE_CONNECTION_ERROR)
Yusuke Iwaki's avatar
Yusuke Iwaki committed
84 85 86
          .or()
          .isNotNull("error")
          .endGroup()
87
          .isNotNull("session")
88 89
          .findAll();
      for (ServerConfig config : targetConfigs) {
90 91
        config.setState(ServerConfig.STATE_READY);
        config.setError(null);
92 93 94
      }
      return null;
    }).onSuccessTask(task -> {
95
      connectionRequiredServerConfigObserver.sub();
96 97
      return null;
    });
98 99
    return START_STICKY;
  }
100

Yusuke Iwaki's avatar
Yusuke Iwaki committed
101 102 103 104
  private void connectToServerWithServerConfig(List<ServerConfig> configList) {
    if (configList.isEmpty()) {
      return;
    }
105

Yusuke Iwaki's avatar
Yusuke Iwaki committed
106
    ServerConfig config = configList.get(0);
107 108 109 110 111 112 113 114 115 116
    final String serverConfigId = config.getServerConfigId();
    ServerConfig.updateState(serverConfigId, ServerConfig.STATE_CONNECTING)
        .onSuccessTask(task -> createWebSocketThread(config))
        .onSuccessTask(task -> {
          RocketChatWebSocketThread thread = task.getResult();
          if (thread != null) {
            thread.keepalive();
          }
          return ServerConfig.updateState(serverConfigId, ServerConfig.STATE_CONNECTED);
        }).continueWith(new LogcatIfError());
Yusuke Iwaki's avatar
Yusuke Iwaki committed
117
  }
118

Yusuke Iwaki's avatar
Yusuke Iwaki committed
119 120 121
  private Task<RocketChatWebSocketThread> createWebSocketThread(final ServerConfig config) {
    final String serverConfigId = config.getServerConfigId();
    webSocketThreads.put(serverConfigId, null);
122
    return RocketChatWebSocketThread.getStarted(getApplicationContext(), config)
Yusuke Iwaki's avatar
Yusuke Iwaki committed
123 124 125 126
        .onSuccessTask(task -> {
          webSocketThreads.put(serverConfigId, task.getResult());
          return task;
        });
127
  }
128

Yusuke Iwaki's avatar
Yusuke Iwaki committed
129 130
  @Override
  public void onDestroy() {
131 132 133 134 135 136
    if (connectionRequiredServerConfigObserver != null) {
      connectionRequiredServerConfigObserver.unsub();
    }
    super.onDestroy();
  }

Yusuke Iwaki's avatar
Yusuke Iwaki committed
137 138 139
  @Nullable
  @Override
  public IBinder onBind(Intent intent) {
140 141
    return null;
  }
142
}