ChannelDiscoveryService.java

  1package eu.siacs.conversations.services;
  2
  3import android.support.annotation.NonNull;
  4import android.util.Log;
  5
  6import com.google.common.cache.Cache;
  7import com.google.common.cache.CacheBuilder;
  8
  9import java.io.IOException;
 10import java.util.Collections;
 11import java.util.List;
 12import java.util.concurrent.Executors;
 13import java.util.concurrent.TimeUnit;
 14
 15import eu.siacs.conversations.Config;
 16import eu.siacs.conversations.http.HttpConnectionManager;
 17import eu.siacs.conversations.http.services.MuclumbusService;
 18import okhttp3.OkHttpClient;
 19import okhttp3.ResponseBody;
 20import retrofit2.Call;
 21import retrofit2.Callback;
 22import retrofit2.Response;
 23import retrofit2.Retrofit;
 24import retrofit2.converter.gson.GsonConverterFactory;
 25
 26public class ChannelDiscoveryService {
 27
 28    private final XmppConnectionService service;
 29
 30
 31    private MuclumbusService muclumbusService;
 32
 33    private final Cache<String, List<MuclumbusService.Room>> cache;
 34
 35    ChannelDiscoveryService(XmppConnectionService service) {
 36        this.service = service;
 37        this.cache = CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build();
 38    }
 39
 40    void initializeMuclumbusService() {
 41        OkHttpClient.Builder builder = new OkHttpClient.Builder();
 42        if (service.useTorToConnect()) {
 43            try {
 44                builder.proxy(HttpConnectionManager.getProxy());
 45            } catch (IOException e) {
 46                throw new RuntimeException("Unable to use Tor proxy", e);
 47            }
 48        }
 49        Retrofit retrofit = new Retrofit.Builder()
 50                .client(builder.build())
 51                .baseUrl(Config.CHANNEL_DISCOVERY)
 52                .addConverterFactory(GsonConverterFactory.create())
 53                .callbackExecutor(Executors.newSingleThreadExecutor())
 54                .build();
 55        this.muclumbusService = retrofit.create(MuclumbusService.class);
 56    }
 57
 58    void discover(String query, OnChannelSearchResultsFound onChannelSearchResultsFound) {
 59        final boolean all = query == null || query.trim().isEmpty();
 60        Log.d(Config.LOGTAG, "discover channels. query=" + query);
 61        List<MuclumbusService.Room> result = cache.getIfPresent(all ? "" : query);
 62        if (result != null) {
 63            onChannelSearchResultsFound.onChannelSearchResultsFound(result);
 64            return;
 65        }
 66        if (all) {
 67            discoverChannels(onChannelSearchResultsFound);
 68        } else {
 69            discoverChannels(query, onChannelSearchResultsFound);
 70        }
 71    }
 72
 73    private void discoverChannels(OnChannelSearchResultsFound listener) {
 74        Call<MuclumbusService.Rooms> call = muclumbusService.getRooms(1);
 75        try {
 76            call.enqueue(new Callback<MuclumbusService.Rooms>() {
 77                @Override
 78                public void onResponse(@NonNull Call<MuclumbusService.Rooms> call, @NonNull Response<MuclumbusService.Rooms> response) {
 79                    final MuclumbusService.Rooms body = response.body();
 80                    if (body == null) {
 81                        listener.onChannelSearchResultsFound(Collections.emptyList());
 82                        logError(response);
 83                        return;
 84                    }
 85                    cache.put("", body.items);
 86                    listener.onChannelSearchResultsFound(body.items);
 87                }
 88
 89                @Override
 90                public void onFailure(@NonNull Call<MuclumbusService.Rooms> call, @NonNull Throwable throwable) {
 91                    Log.d(Config.LOGTAG, "Unable to query muclumbus on " + Config.CHANNEL_DISCOVERY, throwable);
 92                    listener.onChannelSearchResultsFound(Collections.emptyList());
 93                }
 94            });
 95        } catch (Exception e) {
 96            e.printStackTrace();
 97        }
 98    }
 99
100    private void discoverChannels(final String query, OnChannelSearchResultsFound listener) {
101        Call<MuclumbusService.SearchResult> searchResultCall = muclumbusService.search(new MuclumbusService.SearchRequest(query));
102
103        searchResultCall.enqueue(new Callback<MuclumbusService.SearchResult>() {
104            @Override
105            public void onResponse(@NonNull Call<MuclumbusService.SearchResult> call, @NonNull Response<MuclumbusService.SearchResult> response) {
106                final MuclumbusService.SearchResult body = response.body();
107                if (body == null) {
108                    listener.onChannelSearchResultsFound(Collections.emptyList());
109                    logError(response);
110                    return;
111                }
112                cache.put(query, body.result.items);
113                listener.onChannelSearchResultsFound(body.result.items);
114            }
115
116            @Override
117            public void onFailure(@NonNull Call<MuclumbusService.SearchResult> call, @NonNull Throwable throwable) {
118                Log.d(Config.LOGTAG, "Unable to query muclumbus on " + Config.CHANNEL_DISCOVERY, throwable);
119                listener.onChannelSearchResultsFound(Collections.emptyList());
120            }
121        });
122    }
123
124    private static void logError(final Response response) {
125        final ResponseBody errorBody = response.errorBody();
126        Log.d(Config.LOGTAG, "code from muclumbus=" + response.code());
127        if (errorBody == null) {
128            return;
129        }
130        try {
131            Log.d(Config.LOGTAG,"error body="+errorBody.string());
132        } catch (IOException e) {
133            //ignored
134        }
135    }
136
137    public interface OnChannelSearchResultsFound {
138        void onChannelSearchResultsFound(List<MuclumbusService.Room> results);
139    }
140}