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        final OkHttpClient.Builder builder = new OkHttpClient.Builder();
 42
 43        if (service.useTorToConnect()) {
 44            try {
 45                builder.proxy(HttpConnectionManager.getProxy());
 46            } catch (IOException e) {
 47                throw new RuntimeException("Unable to use Tor proxy", e);
 48            }
 49        }
 50        Retrofit retrofit = new Retrofit.Builder()
 51                .client(builder.build())
 52                .baseUrl(Config.CHANNEL_DISCOVERY)
 53                .addConverterFactory(GsonConverterFactory.create())
 54                .callbackExecutor(Executors.newSingleThreadExecutor())
 55                .build();
 56        this.muclumbusService = retrofit.create(MuclumbusService.class);
 57    }
 58
 59    void discover(String query, OnChannelSearchResultsFound onChannelSearchResultsFound) {
 60        final boolean all = query == null || query.trim().isEmpty();
 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        MuclumbusService.SearchRequest searchRequest = new MuclumbusService.SearchRequest(query);
102        Call<MuclumbusService.SearchResult> searchResultCall = muclumbusService.search(searchRequest);
103
104        searchResultCall.enqueue(new Callback<MuclumbusService.SearchResult>() {
105            @Override
106            public void onResponse(@NonNull Call<MuclumbusService.SearchResult> call, @NonNull Response<MuclumbusService.SearchResult> response) {
107                final MuclumbusService.SearchResult body = response.body();
108                if (body == null) {
109                    listener.onChannelSearchResultsFound(Collections.emptyList());
110                    logError(response);
111                    return;
112                }
113                cache.put(query, body.result.items);
114                listener.onChannelSearchResultsFound(body.result.items);
115            }
116
117            @Override
118            public void onFailure(@NonNull Call<MuclumbusService.SearchResult> call, @NonNull Throwable throwable) {
119                Log.d(Config.LOGTAG, "Unable to query muclumbus on " + Config.CHANNEL_DISCOVERY, throwable);
120                listener.onChannelSearchResultsFound(Collections.emptyList());
121            }
122        });
123    }
124
125    private static void logError(final Response response) {
126        final ResponseBody errorBody = response.errorBody();
127        Log.d(Config.LOGTAG, "code from muclumbus=" + response.code());
128        if (errorBody == null) {
129            return;
130        }
131        try {
132            Log.d(Config.LOGTAG,"error body="+errorBody.string());
133        } catch (IOException e) {
134            //ignored
135        }
136    }
137
138    public interface OnChannelSearchResultsFound {
139        void onChannelSearchResultsFound(List<MuclumbusService.Room> results);
140    }
141}