aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/pixart/messenger/services/ChannelDiscoveryService.java
diff options
context:
space:
mode:
authorChristian Schneppe <christian.schneppe@pix-art.de>2019-11-03 19:41:16 +0100
committerChristian Schneppe <christian.schneppe@pix-art.de>2019-11-03 19:41:16 +0100
commitad75ab3f683391c26c2a99242210747c0bf881c2 (patch)
tree03cb3f2d2eb80e5a19a72315e09da0619f322316 /src/main/java/de/pixart/messenger/services/ChannelDiscoveryService.java
parent6a672b4aacfd62fcbbbe3ea031bf53c0daace132 (diff)
optionally search local muc rooms instead of jabber.network
Diffstat (limited to 'src/main/java/de/pixart/messenger/services/ChannelDiscoveryService.java')
-rw-r--r--src/main/java/de/pixart/messenger/services/ChannelDiscoveryService.java172
1 files changed, 134 insertions, 38 deletions
diff --git a/src/main/java/de/pixart/messenger/services/ChannelDiscoveryService.java b/src/main/java/de/pixart/messenger/services/ChannelDiscoveryService.java
index bd92c886d..81668cb92 100644
--- a/src/main/java/de/pixart/messenger/services/ChannelDiscoveryService.java
+++ b/src/main/java/de/pixart/messenger/services/ChannelDiscoveryService.java
@@ -1,39 +1,48 @@
package de.pixart.messenger.services;
-import androidx.annotation.NonNull;
import android.util.Log;
+import androidx.annotation.NonNull;
+
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
-import org.jetbrains.annotations.NotNull;
-
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import de.pixart.messenger.Config;
+import de.pixart.messenger.entities.Account;
+import de.pixart.messenger.entities.Room;
import de.pixart.messenger.http.HttpConnectionManager;
import de.pixart.messenger.http.services.MuclumbusService;
-import okhttp3.Interceptor;
+import de.pixart.messenger.parser.IqParser;
+import de.pixart.messenger.xmpp.OnIqPacketReceived;
+import de.pixart.messenger.xmpp.XmppConnection;
+import de.pixart.messenger.xmpp.stanzas.IqPacket;
import okhttp3.OkHttpClient;
-import okhttp3.Request;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
+import rocks.xmpp.addr.Jid;
public class ChannelDiscoveryService {
private final XmppConnectionService service;
+
private MuclumbusService muclumbusService;
- private final Cache<String, List<MuclumbusService.Room>> cache;
+ private final Cache<String, List<Room>> cache;
ChannelDiscoveryService(XmppConnectionService service) {
this.service = service;
@@ -42,6 +51,7 @@ public class ChannelDiscoveryService {
void initializeMuclumbusService() {
final OkHttpClient.Builder builder = new OkHttpClient.Builder();
+
if (service.useTorToConnect()) {
try {
builder.proxy(HttpConnectionManager.getProxy());
@@ -49,11 +59,6 @@ public class ChannelDiscoveryService {
throw new RuntimeException("Unable to use Tor proxy", e);
}
}
- try {
- builder.networkInterceptors().add(new UserAgentInterceptor(service.getIqGenerator().getUserAgent()));
- } catch (Exception e) {
- e.printStackTrace();
- }
Retrofit retrofit = new Retrofit.Builder()
.client(builder.build())
.baseUrl(Config.CHANNEL_DISCOVERY)
@@ -63,21 +68,28 @@ public class ChannelDiscoveryService {
this.muclumbusService = retrofit.create(MuclumbusService.class);
}
- void discover(String query, OnChannelSearchResultsFound onChannelSearchResultsFound) {
- final boolean all = query == null || query.trim().isEmpty();
- List<MuclumbusService.Room> result = cache.getIfPresent(all ? "" : query);
+ void cleanCache() {
+ cache.invalidateAll();
+ }
+
+ void discover(@NonNull final String query, Method method, OnChannelSearchResultsFound onChannelSearchResultsFound) {
+ List<Room> result = cache.getIfPresent(key(method, query));
if (result != null) {
onChannelSearchResultsFound.onChannelSearchResultsFound(result);
return;
}
- if (all) {
- discoverChannels(onChannelSearchResultsFound);
+ if (method == Method.LOCAL_SERVER) {
+ discoverChannelsLocalServers(query, onChannelSearchResultsFound);
} else {
- discoverChannels(query, onChannelSearchResultsFound);
+ if (query.isEmpty()) {
+ discoverChannelsJabberNetwork(onChannelSearchResultsFound);
+ } else {
+ discoverChannelsJabberNetwork(query, onChannelSearchResultsFound);
+ }
}
}
- private void discoverChannels(OnChannelSearchResultsFound listener) {
+ private void discoverChannelsJabberNetwork(OnChannelSearchResultsFound listener) {
Call<MuclumbusService.Rooms> call = muclumbusService.getRooms(1);
try {
call.enqueue(new Callback<MuclumbusService.Rooms>() {
@@ -89,7 +101,7 @@ public class ChannelDiscoveryService {
logError(response);
return;
}
- cache.put("", body.items);
+ cache.put(key(Method.JABBER_NETWORK, ""), body.items);
listener.onChannelSearchResultsFound(body.items);
}
@@ -104,9 +116,10 @@ public class ChannelDiscoveryService {
}
}
- private void discoverChannels(final String query, OnChannelSearchResultsFound listener) {
+ private void discoverChannelsJabberNetwork(final String query, OnChannelSearchResultsFound listener) {
MuclumbusService.SearchRequest searchRequest = new MuclumbusService.SearchRequest(query);
Call<MuclumbusService.SearchResult> searchResultCall = muclumbusService.search(searchRequest);
+
searchResultCall.enqueue(new Callback<MuclumbusService.SearchResult>() {
@Override
public void onResponse(@NonNull Call<MuclumbusService.SearchResult> call, @NonNull Response<MuclumbusService.SearchResult> response) {
@@ -116,7 +129,7 @@ public class ChannelDiscoveryService {
logError(response);
return;
}
- cache.put(query, body.result.items);
+ cache.put(key(Method.JABBER_NETWORK, query), body.result.items);
listener.onChannelSearchResultsFound(body.result.items);
}
@@ -128,6 +141,102 @@ public class ChannelDiscoveryService {
});
}
+ private void discoverChannelsLocalServers(final String query, final OnChannelSearchResultsFound listener) {
+ final Map<Jid, Account> localMucService = getLocalMucServices();
+ Log.d(Config.LOGTAG, "checking with " + localMucService.size() + " muc services");
+ if (localMucService.size() == 0) {
+ listener.onChannelSearchResultsFound(Collections.emptyList());
+ return;
+ }
+ if (!query.isEmpty()) {
+ final List<Room> cached = cache.getIfPresent(key(Method.LOCAL_SERVER, ""));
+ if (cached != null) {
+ final List<Room> results = copyMatching(cached, query);
+ cache.put(key(Method.LOCAL_SERVER, query), results);
+ listener.onChannelSearchResultsFound(results);
+ }
+ }
+ final AtomicInteger queriesInFlight = new AtomicInteger();
+ final List<Room> rooms = new ArrayList<>();
+ for (Map.Entry<Jid, Account> entry : localMucService.entrySet()) {
+ IqPacket itemsRequest = service.getIqGenerator().queryDiscoItems(entry.getKey());
+ queriesInFlight.incrementAndGet();
+ service.sendIqPacket(entry.getValue(), itemsRequest, (account, itemsResponse) -> {
+ if (itemsResponse.getType() == IqPacket.TYPE.RESULT) {
+ final List<Jid> items = IqParser.items(itemsResponse);
+ for (Jid item : items) {
+ IqPacket infoRequest = service.getIqGenerator().queryDiscoInfo(item);
+ queriesInFlight.incrementAndGet();
+ service.sendIqPacket(account, infoRequest, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket infoResponse) {
+ if (infoResponse.getType() == IqPacket.TYPE.RESULT) {
+ final Room room = IqParser.parseRoom(infoResponse);
+ if (room != null) {
+ rooms.add(room);
+ }
+ if (queriesInFlight.decrementAndGet() <= 0) {
+ finishDiscoSearch(rooms, query, listener);
+ }
+ } else {
+ queriesInFlight.decrementAndGet();
+ }
+ }
+ });
+ }
+ }
+ if (queriesInFlight.decrementAndGet() <= 0) {
+ finishDiscoSearch(rooms, query, listener);
+ }
+ });
+ }
+ }
+
+ private void finishDiscoSearch(List<Room> rooms, String query, OnChannelSearchResultsFound listener) {
+ Collections.sort(rooms);
+ cache.put(key(Method.LOCAL_SERVER, ""), rooms);
+ if (query.isEmpty()) {
+ listener.onChannelSearchResultsFound(rooms);
+ } else {
+ List<Room> results = copyMatching(rooms, query);
+ cache.put(key(Method.LOCAL_SERVER, query), results);
+ listener.onChannelSearchResultsFound(rooms);
+ }
+ }
+
+ private static List<Room> copyMatching(List<Room> haystack, String needle) {
+ ArrayList<Room> result = new ArrayList<>();
+ for (Room room : haystack) {
+ if (room.contains(needle)) {
+ result.add(room);
+ }
+ }
+ return result;
+ }
+
+ private Map<Jid, Account> getLocalMucServices() {
+ final HashMap<Jid, Account> localMucServices = new HashMap<>();
+ for (Account account : service.getAccounts()) {
+ if (account.isEnabled()) {
+ final XmppConnection xmppConnection = account.getXmppConnection();
+ if (xmppConnection == null) {
+ continue;
+ }
+ for (final String mucService : xmppConnection.getMucServers()) {
+ Jid jid = Jid.of(mucService);
+ if (!localMucServices.containsKey(jid)) {
+ localMucServices.put(jid, account);
+ }
+ }
+ }
+ }
+ return localMucServices;
+ }
+
+ private static String key(Method method, String query) {
+ return String.format("%s\00%s", method, query);
+ }
+
private static void logError(final Response response) {
final ResponseBody errorBody = response.errorBody();
Log.d(Config.LOGTAG, "code from muclumbus=" + response.code());
@@ -142,24 +251,11 @@ public class ChannelDiscoveryService {
}
public interface OnChannelSearchResultsFound {
- void onChannelSearchResultsFound(List<MuclumbusService.Room> results);
+ void onChannelSearchResultsFound(List<Room> results);
}
- private class UserAgentInterceptor implements Interceptor {
- private final String userAgent;
-
- UserAgentInterceptor(String userAgent) {
- this.userAgent = userAgent;
- }
-
- @NotNull
- @Override
- public okhttp3.Response intercept(Chain chain) throws IOException {
- Request originalRequest = chain.request();
- Request requestWithUserAgent = originalRequest.newBuilder()
- .header("User-Agent", userAgent)
- .build();
- return chain.proceed(requestWithUserAgent);
- }
+ public enum Method {
+ JABBER_NETWORK,
+ LOCAL_SERVER
}
} \ No newline at end of file