Commit bed51e93 authored by Tiago Cunha's avatar Tiago Cunha

Trying some Rx spice

parent 8dc3027d
...@@ -8,13 +8,12 @@ import java.io.IOException; ...@@ -8,13 +8,12 @@ import java.io.IOException;
import okhttp3.Call; import okhttp3.Call;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody; import okhttp3.ResponseBody;
import rx.Emitter;
import rx.Observable;
public class DefaultServerPolicyApi implements ServerPolicyApi { public class DefaultServerPolicyApi implements ServerPolicyApi {
private static final String SECURE_PROTOCOL = "https://";
private static final String INSECURE_PROTOCOL = "http://";
private static final String API_INFO_PATH = "/api/info"; private static final String API_INFO_PATH = "/api/info";
private final OkHttpClient client; private final OkHttpClient client;
...@@ -26,13 +25,23 @@ public class DefaultServerPolicyApi implements ServerPolicyApi { ...@@ -26,13 +25,23 @@ public class DefaultServerPolicyApi implements ServerPolicyApi {
} }
@Override @Override
public void getApiInfoSecurely(@NonNull Callback callback) { public Observable<Response<JSONObject>> getApiInfoSecurely() {
client.newCall(createRequest(SECURE_PROTOCOL)).enqueue(getOkHttpCallback(callback)); return getApiInfo(SECURE_PROTOCOL);
} }
@Override @Override
public void getApiInfoInsecurely(@NonNull Callback callback) { public Observable<Response<JSONObject>> getApiInfoInsecurely() {
client.newCall(createRequest(INSECURE_PROTOCOL)).enqueue(getOkHttpCallback(callback)); return getApiInfo(INSECURE_PROTOCOL);
}
private Observable<Response<JSONObject>> getApiInfo(@NonNull String protocol) {
return Observable.fromEmitter(responseEmitter -> {
final Call call = client.newCall(createRequest(protocol));
call.enqueue(getOkHttpCallback(responseEmitter, protocol));
responseEmitter.setCancellation(call::cancel);
}, Emitter.BackpressureMode.LATEST);
} }
private Request createRequest(@NonNull String protocol) { private Request createRequest(@NonNull String protocol) {
...@@ -42,31 +51,36 @@ public class DefaultServerPolicyApi implements ServerPolicyApi { ...@@ -42,31 +51,36 @@ public class DefaultServerPolicyApi implements ServerPolicyApi {
.build(); .build();
} }
private okhttp3.Callback getOkHttpCallback(@NonNull Callback callback) { private okhttp3.Callback getOkHttpCallback(@NonNull Emitter<Response<JSONObject>> emitter,
@NonNull String protocol) {
return new okhttp3.Callback() { return new okhttp3.Callback() {
@Override @Override
public void onFailure(Call call, IOException ioException) { public void onFailure(Call call, IOException ioException) {
callback.onNetworkError(); emitter.onError(ioException);
} }
@Override @Override
public void onResponse(Call call, Response response) throws IOException { public void onResponse(Call call, okhttp3.Response response) throws IOException {
if (!response.isSuccessful()) { if (!response.isSuccessful()) {
callback.onResponseError(); emitter.onNext(new Response<>(false, protocol, null));
emitter.onCompleted();
return; return;
} }
final ResponseBody body = response.body(); final ResponseBody body = response.body();
if (body == null || body.contentLength() == 0) { if (body == null || body.contentLength() == 0) {
callback.onResponseError(); emitter.onNext(new Response<>(false, protocol, null));
emitter.onCompleted();
return; return;
} }
try { try {
callback.onSuccess(new JSONObject(body.string())); emitter.onNext(new Response<>(true, protocol, new JSONObject(body.string())));
} catch (Exception e) { } catch (Exception e) {
callback.onResponseError(); emitter.onNext(new Response<>(false, protocol, null));
} }
emitter.onCompleted();
} }
}; };
} }
......
package chat.rocket.android.api.rest;
public class Response<T> {
private final boolean successful;
private final String protocol;
private final T data;
public Response(boolean successful, String protocol, T data) {
this.successful = successful;
this.protocol = protocol;
this.data = data;
}
public boolean isSuccessful() {
return successful;
}
public String getProtocol() {
return protocol;
}
public T getData() {
return data;
}
}
package chat.rocket.android.api.rest; package chat.rocket.android.api.rest;
import android.support.annotation.NonNull;
import org.json.JSONObject; import org.json.JSONObject;
public interface ServerPolicyApi { import rx.Observable;
void getApiInfoSecurely(@NonNull Callback callback);
void getApiInfoInsecurely(@NonNull Callback callback); public interface ServerPolicyApi {
interface Callback { String SECURE_PROTOCOL = "https://";
void onSuccess(JSONObject jsonObject); String INSECURE_PROTOCOL = "http://";
void onResponseError(); Observable<Response<JSONObject>> getApiInfoSecurely();
void onNetworkError(); Observable<Response<JSONObject>> getApiInfoInsecurely();
}
} }
...@@ -11,11 +11,14 @@ import chat.rocket.android.api.rest.DefaultServerPolicyApi; ...@@ -11,11 +11,14 @@ import chat.rocket.android.api.rest.DefaultServerPolicyApi;
import chat.rocket.android.api.rest.ServerPolicyApi; import chat.rocket.android.api.rest.ServerPolicyApi;
import chat.rocket.android.helper.LogcatIfError; import chat.rocket.android.helper.LogcatIfError;
import chat.rocket.android.helper.OkHttpHelper; import chat.rocket.android.helper.OkHttpHelper;
import chat.rocket.android.helper.ServerPolicyApiValidationHelper;
import chat.rocket.android.helper.ServerPolicyHelper; import chat.rocket.android.helper.ServerPolicyHelper;
import chat.rocket.android.helper.TextUtils; import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.model.ServerConfig; import chat.rocket.android.model.ServerConfig;
import chat.rocket.android.realm_helper.RealmObjectObserver; import chat.rocket.android.realm_helper.RealmObjectObserver;
import chat.rocket.android.realm_helper.RealmStore; import chat.rocket.android.realm_helper.RealmStore;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/** /**
* Input server host. * Input server host.
...@@ -51,27 +54,25 @@ public class InputHostnameFragment extends AbstractServerConfigFragment { ...@@ -51,27 +54,25 @@ public class InputHostnameFragment extends AbstractServerConfigFragment {
private void handleConnect() { private void handleConnect() {
final String hostname = ServerPolicyHelper.enforceHostname(getHostname()); final String hostname = ServerPolicyHelper.enforceHostname(getHostname());
ServerPolicyApi serverPolicyApi = final ServerPolicyApi serverPolicyApi =
new DefaultServerPolicyApi(OkHttpHelper.getClientForUploadFile(), hostname); new DefaultServerPolicyApi(OkHttpHelper.getClientForUploadFile(), hostname);
ServerPolicyHelper.isApiVersionValid(serverPolicyApi, final ServerPolicyApiValidationHelper validationHelper =
new ServerPolicyHelper.Callback() { new ServerPolicyApiValidationHelper(serverPolicyApi);
@Override
public void isValid(boolean usesSecureConnection) { ServerPolicyHelper.isApiVersionValid(validationHelper)
getActivity().runOnUiThread(() -> onServerValid(hostname, usesSecureConnection)); .subscribeOn(Schedulers.io())
} .observeOn(AndroidSchedulers.mainThread())
.subscribe(
@Override serverValidation -> {
public void isNotValid() { if (serverValidation.isValid()) {
getActivity().runOnUiThread(() -> onServerValid(hostname, serverValidation.usesSecureConnection());
showError(getString(R.string.input_hostname_invalid_server_message))); } else {
} showError(getString(R.string.input_hostname_invalid_server_message));
}
@Override },
public void onNetworkError() { throwable -> {
getActivity().runOnUiThread(() -> showError(getString(R.string.connection_error_try_later));
showError(getString(R.string.connection_error_try_later)));
}
}); });
} }
......
...@@ -2,67 +2,23 @@ package chat.rocket.android.helper; ...@@ -2,67 +2,23 @@ package chat.rocket.android.helper;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import org.json.JSONObject;
import chat.rocket.android.api.rest.ServerPolicyApi; import chat.rocket.android.api.rest.ServerPolicyApi;
import rx.Observable;
public class ServerPolicyApiValidationHelper { public class ServerPolicyApiValidationHelper {
public static void getApiVersion(@NonNull ServerPolicyApi serverPolicyApi, private final ServerPolicyApi serverPolicyApi;
@NonNull Callback callback) {
trySecurely(serverPolicyApi, new Callback() {
@Override
public void onSuccess(boolean usesSecureConnection, JSONObject apiInfo) {
callback.onSuccess(usesSecureConnection, apiInfo);
}
@Override
public void onResponseError() {
callback.onResponseError();
}
@Override
public void onNetworkError() {
tryInsecurely(serverPolicyApi, callback);
}
});
}
private static void trySecurely(@NonNull ServerPolicyApi serverPolicyApi,
@NonNull Callback callback) {
serverPolicyApi.getApiInfoSecurely(getServerPolicyApiCallback(true, callback));
}
private static void tryInsecurely(@NonNull ServerPolicyApi serverPolicyApi,
@NonNull Callback callback) {
serverPolicyApi.getApiInfoInsecurely(getServerPolicyApiCallback(false, callback));
}
private static ServerPolicyApi.Callback getServerPolicyApiCallback(boolean isSecureConnection, public ServerPolicyApiValidationHelper(@NonNull ServerPolicyApi serverPolicyApi) {
@NonNull Callback callback) { this.serverPolicyApi = serverPolicyApi;
return new ServerPolicyApi.Callback() {
@Override
public void onSuccess(JSONObject jsonObject) {
callback.onSuccess(isSecureConnection, jsonObject);
} }
@Override public Observable<ServerPolicyHelper.ServerInfo> getApiVersion() {
public void onResponseError() { return serverPolicyApi.getApiInfoSecurely()
callback.onResponseError(); .onErrorResumeNext(serverPolicyApi.getApiInfoInsecurely())
} .map(response -> new ServerPolicyHelper.ServerInfo(
response.getProtocol().equals(ServerPolicyApi.SECURE_PROTOCOL),
@Override response.getData()
public void onNetworkError() { ));
callback.onNetworkError();
}
};
}
interface Callback {
void onSuccess(boolean usesSecureConnection, JSONObject apiInfo);
void onResponseError();
void onNetworkError();
} }
} }
...@@ -4,7 +4,7 @@ import android.support.annotation.NonNull; ...@@ -4,7 +4,7 @@ import android.support.annotation.NonNull;
import org.json.JSONObject; import org.json.JSONObject;
import chat.rocket.android.api.rest.ServerPolicyApi; import rx.Observable;
public class ServerPolicyHelper { public class ServerPolicyHelper {
...@@ -19,29 +19,12 @@ public class ServerPolicyHelper { ...@@ -19,29 +19,12 @@ public class ServerPolicyHelper {
return removeTrailingSlash(removeProtocol(enforceDefaultHost(hostname))); return removeTrailingSlash(removeProtocol(enforceDefaultHost(hostname)));
} }
public static void isApiVersionValid(@NonNull ServerPolicyApi serverPolicyApi, public static Observable<ServerValidation> isApiVersionValid(
@NonNull Callback callback) { @NonNull ServerPolicyApiValidationHelper serverPolicyApiValidationHelper) {
ServerPolicyApiValidationHelper.getApiVersion(serverPolicyApi, return serverPolicyApiValidationHelper.getApiVersion()
new ServerPolicyApiValidationHelper.Callback() { .map(serverInfo ->
@Override new ServerValidation(isValid(serverInfo.getApiInfo()),
public void onSuccess(boolean usesSecureConnection, JSONObject apiInfo) { serverInfo.usesSecureConnection()));
if (isValid(apiInfo)) {
callback.isValid(usesSecureConnection);
return;
}
callback.isNotValid();
}
@Override
public void onResponseError() {
callback.isNotValid();
}
@Override
public void onNetworkError() {
callback.onNetworkError();
}
});
} }
@NonNull @NonNull
...@@ -89,11 +72,39 @@ public class ServerPolicyHelper { ...@@ -89,11 +72,39 @@ public class ServerPolicyHelper {
return versionParts.length >= 3 && Integer.parseInt(versionParts[1]) >= 49; return versionParts.length >= 3 && Integer.parseInt(versionParts[1]) >= 49;
} }
public interface Callback { public static class ServerInfo {
void isValid(boolean usesSecureConnection); private final boolean secureConnection;
private final JSONObject apiInfo;
public ServerInfo(boolean secureConnection, JSONObject apiInfo) {
this.secureConnection = secureConnection;
this.apiInfo = apiInfo;
}
public boolean usesSecureConnection() {
return secureConnection;
}
void isNotValid(); public JSONObject getApiInfo() {
return apiInfo;
}
}
void onNetworkError(); public static class ServerValidation {
private final boolean valid;
private final boolean secureConnection;
public ServerValidation(boolean valid, boolean secureConnection) {
this.valid = valid;
this.secureConnection = secureConnection;
}
public boolean isValid() {
return valid;
}
public boolean usesSecureConnection() {
return secureConnection;
}
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment