Setup client-side for integration with the wryk/tusky-api prototype.

This commit is contained in:
Vavassor 2017-05-19 21:28:12 -04:00
parent 73a5144741
commit e282f13fdc
4 changed files with 115 additions and 31 deletions

View File

@ -35,6 +35,8 @@ import com.keylesspalace.tusky.json.SpannedTypeAdapter;
import com.keylesspalace.tusky.json.StringWithEmoji;
import com.keylesspalace.tusky.json.StringWithEmojiTypeAdapter;
import com.keylesspalace.tusky.network.MastodonAPI;
import com.keylesspalace.tusky.network.TuskyApi;
import com.keylesspalace.tusky.util.Log;
import com.keylesspalace.tusky.util.OkHttpUtils;
import com.keylesspalace.tusky.util.PushNotificationClient;
@ -45,11 +47,17 @@ import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class BaseActivity extends AppCompatActivity {
private static final String TAG = "BaseActivity"; // logging tag
public MastodonAPI mastodonAPI;
public TuskyApi tuskyApi;
protected PushNotificationClient pushNotificationClient;
protected Dispatcher mastodonApiDispatcher;
@ -59,7 +67,8 @@ public class BaseActivity extends AppCompatActivity {
redirectIfNotLoggedIn();
createMastodonAPI();
createTuskyAPI();
createTuskyApi();
createPushNotificationClient();
/* There isn't presently a way to globally change the theme of a whole application at
* runtime, just individual activities. So, each activity has to set its theme before any
@ -151,9 +160,19 @@ public class BaseActivity extends AppCompatActivity {
mastodonAPI = retrofit.create(MastodonAPI.class);
}
protected void createTuskyAPI() {
protected void createTuskyApi() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://" + getString(R.string.tusky_api_domain))
.client(OkHttpUtils.getCompatibleClient())
.build();
tuskyApi = retrofit.create(TuskyApi.class);
}
protected void createPushNotificationClient() {
// TODO: Switch to ssl:// when TLS support is added.
pushNotificationClient = new PushNotificationClient(getApplicationContext(),
getString(R.string.tusky_api_url));
"tcp://" + getString(R.string.tusky_api_domain));
}
protected void redirectIfNotLoggedIn() {
@ -187,10 +206,57 @@ public class BaseActivity extends AppCompatActivity {
}
protected void enablePushNotifications() {
pushNotificationClient.subscribeToTopic();
Callback<ResponseBody> callback = new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call,
retrofit2.Response<ResponseBody> response) {
if (response.isSuccessful()) {
pushNotificationClient.subscribeToTopic(getPushNotificationTopic());
} else {
onEnablePushNotificationsFailure();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
onEnablePushNotificationsFailure();
}
};
tuskyApi.register(getBaseUrl(), getAccessToken(), pushNotificationClient.getDeviceToken())
.enqueue(callback);
}
private void onEnablePushNotificationsFailure() {
Log.e(TAG, "Enabling push notifications failed.");
}
protected void disablePushNotifications() {
pushNotificationClient.unsubscribeToTopic();
Callback<ResponseBody> callback = new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call,
retrofit2.Response<ResponseBody> response) {
if (response.isSuccessful()) {
pushNotificationClient.unsubscribeToTopic(getPushNotificationTopic());
} else {
onDisablePushNotificationsFailure();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
onDisablePushNotificationsFailure();
}
};
tuskyApi.unregister(getBaseUrl(), getAccessToken(), pushNotificationClient.getDeviceToken())
.enqueue(callback);
}
private void onDisablePushNotificationsFailure() {
Log.e(TAG, "Disabling push notifications failed.");
}
private String getPushNotificationTopic() {
return String.format("%s/%s/%s", getBaseUrl(), getAccessToken(),
pushNotificationClient.getDeviceToken());
}
}

View File

@ -17,15 +17,14 @@ package com.keylesspalace.tusky.network;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
public interface TuskyAPI {
public interface TuskyApi {
@FormUrlEncoded
@POST("/register")
Call<ResponseBody> register(@Field("instance_url") String instanceUrl, @Field("access_token") String accessToken, @Field("device_token") String deviceToken);
Call<ResponseBody> register(String instanceUrl, String accessToken, String deviceToken);
@FormUrlEncoded
@POST("/unregister")
Call<ResponseBody> unregister(@Field("instance_url") String instanceUrl, @Field("access_token") String accessToken);
Call<ResponseBody> unregister(String instanceUrl, String accessToken, String deviceToken);
}

View File

@ -29,6 +29,7 @@ import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayDeque;
import java.util.ArrayList;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
@ -43,23 +44,37 @@ import static android.content.Context.NOTIFICATION_SERVICE;
public class PushNotificationClient {
private static final String TAG = "PushNotificationClient";
private static final String TOPIC = "tusky/notification";
private static final int NOTIFY_ID = 666;
private enum QueuedAction {
SUBSCRIBE,
UNSUBSCRIBE,
DISCONNECT,
private static class QueuedAction {
enum Type {
SUBSCRIBE,
UNSUBSCRIBE,
DISCONNECT,
}
Type type;
String topic;
QueuedAction(Type type) {
this.type = type;
}
QueuedAction(Type type, String topic) {
this.type = type;
this.topic = topic;
}
}
private MqttAndroidClient mqttAndroidClient;
private MastodonAPI mastodonApi;
private ArrayDeque<QueuedAction> queuedActions;
private boolean subscribed;
private ArrayList<String> subscribedTopics;
public PushNotificationClient(final @NonNull Context applicationContext,
@NonNull String serverUri) {
queuedActions = new ArrayDeque<>();
subscribedTopics = new ArrayList<>();
// Create the MQTT client.
String clientId = MqttClient.generateClientId();
@ -69,8 +84,8 @@ public class PushNotificationClient {
public void connectComplete(boolean reconnect, String serverURI) {
if (reconnect) {
flushQueuedActions();
if (subscribed) {
subscribeToTopic();
for (String topic : subscribedTopics) {
subscribeToTopic(topic);
}
}
}
@ -133,10 +148,10 @@ public class PushNotificationClient {
private void flushQueuedActions() {
while (!queuedActions.isEmpty()) {
QueuedAction action = queuedActions.pop();
switch (action) {
case SUBSCRIBE: subscribeToTopic(); break;
case UNSUBSCRIBE: unsubscribeToTopic(); break;
case DISCONNECT: disconnect(); break;
switch (action.type) {
case SUBSCRIBE: subscribeToTopic(action.topic); break;
case UNSUBSCRIBE: unsubscribeToTopic(action.topic); break;
case DISCONNECT: disconnect(); break;
}
}
}
@ -144,7 +159,7 @@ public class PushNotificationClient {
/** Disconnect from the MQTT broker. */
public void disconnect() {
if (!mqttAndroidClient.isConnected()) {
queuedActions.add(QueuedAction.DISCONNECT);
queuedActions.add(new QueuedAction(QueuedAction.Type.DISCONNECT));
return;
}
try {
@ -160,16 +175,16 @@ public class PushNotificationClient {
}
/** Subscribe to the push notification topic. */
public void subscribeToTopic() {
public void subscribeToTopic(final String topic) {
if (!mqttAndroidClient.isConnected()) {
queuedActions.add(QueuedAction.SUBSCRIBE);
queuedActions.add(new QueuedAction(QueuedAction.Type.SUBSCRIBE, topic));
return;
}
try {
mqttAndroidClient.subscribe(TOPIC, 0, null, new IMqttActionListener() {
mqttAndroidClient.subscribe(topic, 0, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
subscribed = true;
subscribedTopics.add(topic);
onConnectionSuccess();
}
@ -186,14 +201,14 @@ public class PushNotificationClient {
}
/** Unsubscribe from the push notification topic. */
public void unsubscribeToTopic() {
public void unsubscribeToTopic(String topic) {
if (!mqttAndroidClient.isConnected()) {
queuedActions.add(QueuedAction.UNSUBSCRIBE);
queuedActions.add(new QueuedAction(QueuedAction.Type.UNSUBSCRIBE, topic));
return;
}
try {
mqttAndroidClient.unsubscribe(TOPIC);
subscribed = false;
mqttAndroidClient.unsubscribe(topic);
subscribedTopics.remove(topic);
} catch (MqttException e) {
Log.e(TAG, "An exception occurred while unsubscribing." + e.getMessage());
onConnectionFailure();
@ -271,4 +286,8 @@ public class PushNotificationClient {
public void clearNotifications(Context context) {
((NotificationManager) (context.getSystemService(NOTIFICATION_SERVICE))).cancel(NOTIFY_ID);
}
public String getDeviceToken() {
return mqttAndroidClient.getClientId();
}
}

View File

@ -2,7 +2,7 @@
<resources>
<string name="app_name" translatable="false">Tusky</string>
<string name="app_website" translatable="false">https://tusky.keylesspalace.com</string>
<string name="tusky_api_url" translatable="false">tcp://tuskyapi.keylesspalace.com</string>
<string name="tusky_api_domain" translatable="false">tuskyapi.keylesspalace.com</string>
<string name="tusky_api_keystore_password" translatable="false">your_password_here</string>
<string name="oauth_scheme" translatable="false">oauth2redirect</string>