replaced user endpoints, added TwitterException interface

This commit is contained in:
nuclearfog 2022-01-08 15:00:20 +01:00
parent 1c179b35b6
commit 969a12dc38
No known key found for this signature in database
GPG Key ID: AA0271FBE406DB98
12 changed files with 507 additions and 379 deletions

View File

@ -23,9 +23,9 @@ import androidx.appcompat.widget.Toolbar;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.Registration;
import org.nuclearfog.twidda.backend.api.Twitter;
import org.nuclearfog.twidda.backend.apiold.EngineException;
import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.ErrorHandler;
import org.nuclearfog.twidda.backend.utils.ErrorHandler.TwitterError;
import org.nuclearfog.twidda.database.GlobalSettings;
import static android.content.Intent.ACTION_VIEW;
@ -195,7 +195,7 @@ public class LoginActivity extends AppCompatActivity implements OnClickListener
*
* @param error Twitter exception
*/
public void onError(EngineException error) {
public void onError(TwitterError error) {
ErrorHandler.handleFailure(this, error);
}
}

View File

@ -15,7 +15,7 @@ import org.nuclearfog.twidda.activities.TweetActivity;
import org.nuclearfog.twidda.activities.TweetEditor;
import org.nuclearfog.twidda.activities.UserLists;
import org.nuclearfog.twidda.activities.UserProfile;
import org.nuclearfog.twidda.backend.apiold.TwitterEngine;
import org.nuclearfog.twidda.backend.api.Twitter;
import org.nuclearfog.twidda.model.User;
import java.lang.ref.WeakReference;
@ -42,12 +42,12 @@ public class LinkLoader extends AsyncTask<Uri, Integer, LinkLoader.DataHolder> {
private static final Pattern LIST_PATH = Pattern.compile("[\\w]+/lists");
private WeakReference<MainActivity> callback;
private TwitterEngine mTwitter;
private Twitter mTwitter;
public LinkLoader(MainActivity callback) {
public LinkLoader(MainActivity activity) {
super();
this.callback = new WeakReference<>(callback);
mTwitter = TwitterEngine.getInstance(callback);
this.callback = new WeakReference<>(activity);
mTwitter = Twitter.get(activity);
}
@Override
@ -105,7 +105,7 @@ public class LinkLoader extends AsyncTask<Uri, Integer, LinkLoader.DataHolder> {
int end = path.indexOf('/');
if (end > 0)
path = path.substring(0, end);
User user = mTwitter.getUser(path);
User user = mTwitter.showUser(path);
data.putSerializable(KEY_PROFILE_DATA, user);
data.putBoolean(KEY_PROFILE_DISABLE_RELOAD, true);
dataHolder = new DataHolder(data, UserProfile.class);

View File

@ -2,8 +2,11 @@ package org.nuclearfog.twidda.backend;
import android.os.AsyncTask;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.activities.LoginActivity;
import org.nuclearfog.twidda.backend.api.Twitter;
import org.nuclearfog.twidda.backend.api.TwitterException;
import org.nuclearfog.twidda.database.AccountDatabase;
import org.nuclearfog.twidda.database.AppDatabase;
import org.nuclearfog.twidda.database.GlobalSettings;
@ -19,6 +22,8 @@ import java.lang.ref.WeakReference;
*/
public class Registration extends AsyncTask<String, Void, String> {
@Nullable
private TwitterException exception;
private WeakReference<LoginActivity> callback;
private AccountDatabase accountDB;
private AppDatabase database;
@ -56,8 +61,8 @@ public class Registration extends AsyncTask<String, Void, String> {
User user = twitter.login(param[0], param[1]);
database.storeUser(user);
return "";
} catch (Exception err) {
err.printStackTrace();
} catch (TwitterException exception) {
this.exception = exception;
}
return null;
}
@ -65,12 +70,15 @@ public class Registration extends AsyncTask<String, Void, String> {
@Override
protected void onPostExecute(String redirectionURL) {
if (callback.get() != null) {
LoginActivity activity = callback.get();
if (activity != null) {
if (redirectionURL != null) {
if (!redirectionURL.isEmpty()) {
callback.get().connect(redirectionURL);
activity.connect(redirectionURL);
} else if (exception != null) {
activity.onError(exception);
} else {
callback.get().onSuccess();
activity.onSuccess();
}
}
}

View File

@ -3,6 +3,7 @@ package org.nuclearfog.twidda.backend;
import android.os.AsyncTask;
import org.nuclearfog.twidda.activities.UserProfile;
import org.nuclearfog.twidda.backend.api.Twitter;
import org.nuclearfog.twidda.backend.apiold.EngineException;
import org.nuclearfog.twidda.backend.apiold.TwitterEngine;
import org.nuclearfog.twidda.model.Relation;
@ -61,20 +62,22 @@ public class UserAction extends AsyncTask<UserAction.Action, User, Relation> {
private EngineException twException;
private WeakReference<UserProfile> callback;
private TwitterEngine mTwitter;
private Twitter twitter2;
private ExcludeDatabase exclDB;
private AppDatabase appDB;
private long userId;
/**
* @param callback Callback to return the result
* @param activity Callback to return the result
* @param userId ID of the twitter user
*/
public UserAction(UserProfile callback, long userId) {
public UserAction(UserProfile activity, long userId) {
super();
this.callback = new WeakReference<>(callback);
mTwitter = TwitterEngine.getInstance(callback);
exclDB = new ExcludeDatabase(callback);
appDB = new AppDatabase(callback);
this.callback = new WeakReference<>(activity);
mTwitter = TwitterEngine.getInstance(activity);
twitter2 = Twitter.get(activity);
exclDB = new ExcludeDatabase(activity);
appDB = new AppDatabase(activity);
this.userId = userId;
}
@ -95,7 +98,7 @@ public class UserAction extends AsyncTask<UserAction.Action, User, Relation> {
case PROFILE_lOAD:
// load user information from twitter
user = mTwitter.getUser(userId);
user = twitter2.showUser(userId);
publishProgress(user);
appDB.storeUser(user);
// load user relations from twitter

View File

@ -6,8 +6,6 @@ import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.api.Twitter;
import org.nuclearfog.twidda.backend.api.TwitterException;
import org.nuclearfog.twidda.backend.apiold.EngineException;
import org.nuclearfog.twidda.backend.apiold.TwitterEngine;
import org.nuclearfog.twidda.backend.lists.Users;
import org.nuclearfog.twidda.fragments.UserFragment;
@ -67,10 +65,9 @@ public class UserLoader extends AsyncTask<Long, Void, Users> {
}
@Nullable
private EngineException twException;
private TwitterException twException;
private final WeakReference<UserFragment> callback;
private final TwitterEngine mTwitter;
private Twitter mTwitter2;
private Twitter mTwitter;
private final Type type;
private final String search;
@ -80,8 +77,7 @@ public class UserLoader extends AsyncTask<Long, Void, Users> {
public UserLoader(UserFragment callback, Type type, long id, String search) {
super();
this.callback = new WeakReference<>(callback);
mTwitter = TwitterEngine.getInstance(callback.getContext());
mTwitter2 = Twitter.get(callback.getContext());
mTwitter = Twitter.get(callback.getContext());
this.type = type;
this.search = search;
this.id = id;
@ -100,16 +96,16 @@ public class UserLoader extends AsyncTask<Long, Void, Users> {
return mTwitter.getFollowing(id, cursor);
case RETWEET:
return mTwitter2.getRetweetingUsers(id);
return mTwitter.getRetweetingUsers(id);
case FAVORIT:
return mTwitter2.getLikingUsers(id);
return mTwitter.getLikingUsers(id);
case SEARCH:
return mTwitter.searchUsers(search, cursor);
case SUBSCRIBER:
return mTwitter.getListFollower(id, cursor);
return mTwitter.getListSubscriber(id, cursor);
case LISTMEMBER:
return mTwitter.getListMember(id, cursor);
@ -121,10 +117,8 @@ public class UserLoader extends AsyncTask<Long, Void, Users> {
return mTwitter.getMutedUsers(cursor);
}
} catch (EngineException twException) {
} catch (TwitterException twException) {
this.twException = twException;
} catch (TwitterException err) {
}
return null;
}

View File

@ -11,12 +11,14 @@ import org.nuclearfog.twidda.backend.lists.Users;
import org.nuclearfog.twidda.backend.utils.StringTools;
import org.nuclearfog.twidda.backend.utils.TLSSocketFactory;
import org.nuclearfog.twidda.backend.utils.Tokens;
import org.nuclearfog.twidda.database.ExcludeDatabase;
import org.nuclearfog.twidda.model.User;
import org.nuclearfog.twidda.database.GlobalSettings;
import java.io.IOException;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;
import javax.net.ssl.TrustManagerFactory;
@ -36,19 +38,31 @@ import okhttp3.Response;
public class Twitter {
private static final String OAUTH = "1.0";
public static final String SIGNATURE_ALG = "HMAC-SHA256";
private static final String API = "https://api.twitter.com/";
private static final String AUTHENTICATE = API + "oauth/authenticate";
private static final String REQUEST_TOKEN = API + "oauth/request_token";
private static final String OAUTH_VERIFIER = API + "oauth/access_token";
private static final String CREDENTIALS = API + "1.1/account/verify_credentials.json";
private static final String USER_LOOKUP = API + "1.1/users/show.json";
private static final String USER_FOLLOWING = API + "1.1/friends/list.json";
private static final String USER_FOLLOWER = API + "1.1/followers/list.json";
private static final String USER_SEARCH = API + "1.1/users/search.json";
private static final String USER_LIST_MEMBER = API + "1.1/lists/members.json";
private static final String USER_LIST_SUBSCRIBER = API + "1.1/lists/subscribers.json";
private static final String BLOCK_LIST = API + "1.1/blocks/list.json";
private static final String MUTES_LIST = API + "1.1/mutes/users/list.json";
public static final String REQUEST_URL = AUTHENTICATE + "?oauth_token=";
public static final String SIGNATURE_ALG = "HMAC-SHA256";
private static final String SKIP_STAT = "skip_status=true";
private static Twitter instance;
private OkHttpClient client;
private GlobalSettings settings;
private ExcludeDatabase filterList;
private Tokens tokens;
@ -65,8 +79,9 @@ public class Twitter {
} else {
client = new OkHttpClient().newBuilder().build();
}
settings = GlobalSettings.getInstance(context);
tokens = Tokens.getInstance(context);
settings = GlobalSettings.getInstance(context);
filterList = new ExcludeDatabase(context);
}
/**
@ -94,7 +109,7 @@ public class Twitter {
Uri uri = Uri.parse(AUTHENTICATE + "?" + res);
return uri.getQueryParameter("oauth_token");
} else {
throw new TwitterException(response.code());
throw new TwitterException(response);
}
} catch (IOException e) {
throw new TwitterException(e);
@ -108,8 +123,6 @@ public class Twitter {
*/
public User login(String oauth_token, String pin) throws TwitterException {
try {
if (oauth_token == null)
throw new TwitterException(TwitterException.TOKEN_NOT_SET);
String paramPin = "oauth_verifier=" + pin;
String paramToken = "oauth_token=" + oauth_token;
Response response = post(OAUTH_VERIFIER, paramPin, paramToken);
@ -123,37 +136,13 @@ public class Twitter {
settings.setogin(true);
return getCredentials();
} else {
throw new TwitterException(response.code());
throw new TwitterException(response);
}
} catch (IOException e) {
throw new TwitterException(e);
}
}
/**
* lookup single user
*
* @param id ID of the user
* @return user information
*/
public User showUser(long id) throws TwitterException {
try {
String param = "user_id=" + id;
String extra = "include_entities=true";
Response response = get(USER_LOOKUP, param, extra);
if (response.code() == 200 && response.body() != null) {
JSONObject json = new JSONObject(response.body().string());
return new UserV1(json, settings.getCurrentUserId());
} else {
throw new TwitterException(response.code());
}
} catch (IOException err) {
throw new TwitterException(err);
} catch (JSONException err) {
throw new TwitterException(err);
}
}
/**
* get credentials of the current user
*
@ -162,11 +151,15 @@ public class Twitter {
public User getCredentials() throws TwitterException {
try {
Response response = get(CREDENTIALS);
if (response.code() == 200 && response.body() != null) {
if (response.body() != null) {
JSONObject json = new JSONObject(response.body().string());
return new UserV1(json);
if (response.code() == 200) {
return new UserV1(json);
} else {
throw new TwitterException(json);
}
} else {
throw new TwitterException(response.code());
throw new TwitterException(response);
}
} catch (IOException err) {
throw new TwitterException(err);
@ -175,6 +168,108 @@ public class Twitter {
}
}
/**
* lookup user and return user information
*
* @param id ID of the user
* @return user information
*/
public User showUser(long id) throws TwitterException {
String param = "user_id=" + id;
String extra = "include_entities=true";
return showUser(param, extra);
}
/**
* lookup user and return user information
*
* @param name screen name of the user
* @return user information
*/
public User showUser(String name) throws TwitterException {
String param = "screen_name=" + name;
String extra = "include_entities=true";
return showUser(param, extra);
}
/**
* create a list of users a specified user is following
*
* @param userId ID of the user
* @param cursor cursor value used to parse the list
* @return list of users
*/
public Users getFollowing(long userId, long cursor) throws TwitterException {
String paramId = "user_id=" + userId;
String paramCsr = "cursor=" + cursor;
String paramCnt = "count=" + settings.getListSize();
return getUsers1(USER_FOLLOWING, paramId, paramCsr, paramCnt, SKIP_STAT);
}
/**
* create a list of users following a specified user
*
* @param userId ID of the user
* @param cursor cursor value used to parse the list
* @return list of users
*/
public Users getFollower(long userId, long cursor) throws TwitterException {
String paramId = "user_id=" + userId;
String paramCsr = "cursor=" + cursor;
String paramCnt = "count=" + settings.getListSize();
return getUsers1(USER_FOLLOWER, paramId, paramCsr, paramCnt, SKIP_STAT);
}
/**
* create a list of user list members
*
* @param listId ID of the list
* @param cursor cursor value used to parse the list
* @return list of users
*/
public Users getListMember(long listId, long cursor) throws TwitterException {
String paramId = "list_id=" + listId;
String paramCsr = "cursor=" + cursor;
String paramCnt = "count=" + settings.getListSize();
return getUsers1(USER_LIST_MEMBER, paramId, paramCsr, paramCnt, SKIP_STAT);
}
/**
* create a list of user list subscriber
*
* @param listId ID of the list
* @param cursor cursor value used to parse the list
* @return list of users
*/
public Users getListSubscriber(long listId, long cursor) throws TwitterException {
String paramId = "list_id=" + listId;
String paramCsr = "cursor=" + cursor;
String paramCnt = "count=" + settings.getListSize();
return getUsers1(USER_LIST_SUBSCRIBER, paramId, paramCsr, paramCnt, SKIP_STAT);
}
/**
* get block list of the current user
*
* @param cursor cursor value used to parse the list
* @return list of users
*/
public Users getBlockedUsers(long cursor) throws TwitterException {
String paramCsr = "cursor=" + cursor;
return getUsers1(BLOCK_LIST, paramCsr, SKIP_STAT);
}
/**
* get mute list of the current user
*
* @param cursor cursor value used to parse the list
* @return list of users
*/
public Users getMutedUsers(long cursor) throws TwitterException {
String paramCsr = "cursor=" + cursor;
return getUsers1(MUTES_LIST, paramCsr, SKIP_STAT);
}
/**
* get users retweeting a tweet
*
@ -183,7 +278,7 @@ public class Twitter {
*/
public Users getRetweetingUsers(long tweetId) throws TwitterException {
String endpoint = API + "2/tweets/" + tweetId + "/retweeted_by";
return getUsers(endpoint);
return getUsers2(endpoint);
}
/**
@ -194,29 +289,144 @@ public class Twitter {
*/
public Users getLikingUsers(long tweetId) throws TwitterException {
String endpoint = API + "2/tweets/" + tweetId + "/liking_users";
return getUsers(endpoint);
return getUsers2(endpoint);
}
/**
* get a list of twitter users
* search for users matching a search string
*
* @param search search string
* @param page page of the search results
* @return list of users
*/
public Users searchUsers(String search, long page) throws TwitterException {
// search endpoint only supports pages parameter
long currentPage = page > 0 ? page : 1;
long nextPage = currentPage + 1;
String paramQuery = "q=" + search;
String paramPage = "page=" + currentPage;
String paramCnt = "count=" + settings.getListSize();
try {
Response response = get(USER_SEARCH, paramQuery, paramPage, paramCnt);
if (response.body() != null) {
JSONArray array = new JSONArray(response.body().string());
if (response.code() == 200) {
if (array.length() < 20)
nextPage = 0;
Users users = new Users(currentPage - 1, nextPage);
long homeId = settings.getCurrentUserId();
// filter results if enabled
if (settings.filterResults()) {
Set<Long> exclude = filterList.getExcludeSet();
for (int i = 0; i < array.length(); i++) {
User user = new UserV1(array.getJSONObject(i), homeId);
if (!exclude.contains(user.getId())) {
users.add(user);
}
}
} else {
for (int i = 0; i < array.length(); i++) {
User user = new UserV1(array.getJSONObject(i), homeId);
users.add(user);
}
}
return users;
}
}
throw new TwitterException(response);
} catch (IOException err) {
throw new TwitterException(err);
} catch (JSONException err) {
throw new TwitterException(err);
}
}
/**
* lookup single user
*
* @param params additional parameter added to request
* @return user information
*/
public User showUser(String... params) throws TwitterException {
try {
Response response = get(USER_LOOKUP, params);
if (response.body() != null) {
JSONObject json = new JSONObject(response.body().string());
if (response.code() == 200) {
return new UserV1(json, settings.getCurrentUserId());
} else {
throw new TwitterException(json);
}
} else {
throw new TwitterException(response);
}
} catch (IOException err) {
throw new TwitterException(err);
} catch (JSONException err) {
throw new TwitterException(err);
}
}
/**
* create a list of users using API v 1.1
*
* @param endpoint endpoint url to get the user data from
* @param params additional parameters
* @return user list
*/
private Users getUsers1(String endpoint, String... params) throws TwitterException {
try {
Response response = get(endpoint, params);
if (response.body() != null) {
JSONObject json = new JSONObject(response.body().string());
if (response.code() == 200) {
JSONArray array = json.getJSONArray("users");
long prevCursor = json.getLong("previous_cursor");
long nextCursor = json.getLong("next_cursor");
Users users = new Users(prevCursor, nextCursor);
long homeId = settings.getCurrentUserId();
for (int i = 0; i < array.length(); i++) {
users.add(new UserV1(array.getJSONObject(i), homeId));
}
return users;
} else {
throw new TwitterException(json);
}
} else {
throw new TwitterException(response);
}
} catch (IOException err) {
throw new TwitterException(err);
} catch (JSONException err) {
throw new TwitterException(err);
}
}
/**
* create a list of users using API v 2
*
* @param endpoint endpoint url to get the user data from
* @return user list
*/
private Users getUsers(String endpoint) throws TwitterException {
private Users getUsers2(String endpoint) throws TwitterException {
try {
Response response = get(endpoint, UserV2.PARAMS);
if (response.code() == 200 && response.body() != null) {
if (response.body() != null) {
JSONObject json = new JSONObject(response.body().string());
JSONArray array = json.getJSONArray("data");
Users users = new Users();
long homeId = settings.getCurrentUserId();
for (int i = 0 ; i < array.length() ; i++) {
users.add(new UserV2(array.getJSONObject(i), homeId));
if (response.code() == 200) {
JSONArray array = json.getJSONArray("data");
Users users = new Users();
long homeId = settings.getCurrentUserId();
for (int i = 0; i < array.length(); i++) {
users.add(new UserV2(array.getJSONObject(i), homeId));
}
return users;
} else {
throw new TwitterException(json);
}
return users;
} else {
throw new TwitterException(response.code());
throw new TwitterException(response);
}
} catch (IOException err) {
throw new TwitterException(err);

View File

@ -1,24 +1,128 @@
package org.nuclearfog.twidda.backend.api;
import org.json.JSONArray;
import org.json.JSONObject;
import org.nuclearfog.twidda.backend.utils.ErrorHandler.TwitterError;
import java.io.IOException;
import okhttp3.Response;
public class TwitterException extends Exception {
/**
*
* @author nuclearfog
*/
public class TwitterException extends Exception implements TwitterError {
public static final int TOKEN_NOT_SET = 600;
private int httpCode = -1;
private int errorCode = -1;
private int retryAfter = -1;
private String message = "";
private int httpCode;
TwitterException(Exception e) {
super(e);
httpCode = -1;
}
TwitterException(int httpCode) {
this.httpCode = httpCode;
TwitterException(Response response) {
this.httpCode = response.code();
this.message = response.message();
}
public int getCode() {
return httpCode;
TwitterException(JSONObject json) {
JSONArray errors = json.optJSONArray("errors");
if (errors != null) {
JSONObject error = errors.optJSONObject(0);
if (error != null) {
message = error.optString("message");
errorCode = error.optInt("code");
retryAfter = error.optInt("x-rate-limit-remaining", -1);
}
}
}
@Override
public int getErrorType() {
switch (errorCode) {
case 88:
case 420: //
case 429: // Rate limit exceeded!
return RATE_LIMIT_EX;
case 17:
case 50: // USER not found
case 63: // USER suspended
case 108:
return USER_NOT_FOUND;
case 32:
return ACCESS_TOKEN_DEAD;
case 416:
return APP_SUSPENDED;
case 34: //
case 144: // TWEET not found
return RESOURCE_NOT_FOUND;
case 150:
return CANT_SEND_DM;
case 120:
return ACCOUNT_UPDATE_FAILED;
case 136:
case 179:
return NOT_AUTHORIZED;
case 186:
return TWEET_TOO_LONG;
case 187:
return DUPLICATE_TWEET;
case 349:
return NO_DM_TO_USER;
case 215: // Invalid API keys
case 261:
return ERROR_API_ACCESS_DENIED;
case 354:
return DM_TOO_LONG;
case 89:
return TOKEN_EXPIRED;
case 385: // replying tweet that is not visible or deleted
return TWEET_CANT_REPLY;
default:
if (httpCode == 401) {
return NOT_AUTHORIZED;
} else if (httpCode == 403) {
return REQUEST_FORBIDDEN;
} else if (httpCode == 408) {
return REQUEST_CANCELLED;
} else if (this.getCause() instanceof IOException) {
return NO_CONNECTION;
} else {
return ERROR_NOT_DEFINED;
}
}
}
@Override
public int getTimeToWait() {
return retryAfter;
}
@Override
public String getMessage() {
return message;
}
}

View File

@ -181,6 +181,12 @@ class UserV1 implements User {
return isCurrentUser;
}
@NonNull
@Override
public String toString() {
return username + " " + screenName;
}
/**
* set time of account creation
*

View File

@ -1,7 +1,6 @@
package org.nuclearfog.twidda.backend.apiold;
import static org.nuclearfog.twidda.backend.apiold.EngineException.ErrorType.RESOURCE_NOT_FOUND;
import static org.nuclearfog.twidda.backend.apiold.EngineException.ErrorType.USER_NOT_FOUND;
import org.nuclearfog.twidda.backend.utils.ErrorHandler.TwitterError;
import twitter4j.TwitterException;
@ -10,9 +9,9 @@ import twitter4j.TwitterException;
*
* @author nuclearfog
*/
public class EngineException extends Exception {
public class EngineException extends Exception implements TwitterError {
private final ErrorType errorType;
private int errorType;
private String msg;
private int retryAfter;
@ -30,7 +29,7 @@ public class EngineException extends Exception {
case 88:
case 420: //
case 429: // Rate limit exceeded!
errorType = ErrorType.RATE_LIMIT_EX;
errorType = RATE_LIMIT_EX;
retryAfter = error.getRetryAfter();
break;
@ -38,81 +37,81 @@ public class EngineException extends Exception {
case 50: // USER not found
case 63: // USER suspended
case 108:
errorType = ErrorType.USER_NOT_FOUND;
errorType = USER_NOT_FOUND;
break;
case 32:
errorType = ErrorType.ACCESS_TOKEN_DEAD;
errorType = ACCESS_TOKEN_DEAD;
break;
case 416:
errorType = ErrorType.APP_SUSPENDED;
errorType = APP_SUSPENDED;
break;
case 34: //
case 144: // TWEET not found
errorType = ErrorType.RESOURCE_NOT_FOUND;
errorType = RESOURCE_NOT_FOUND;
break;
case 150:
errorType = ErrorType.CANT_SEND_DM;
errorType = CANT_SEND_DM;
break;
case 120:
errorType = ErrorType.ACCOUNT_UPDATE_FAILED;
errorType = ACCOUNT_UPDATE_FAILED;
break;
case 136:
case 179:
errorType = ErrorType.NOT_AUTHORIZED;
errorType = NOT_AUTHORIZED;
break;
case 186:
errorType = ErrorType.TWEET_TOO_LONG;
errorType = TWEET_TOO_LONG;
break;
case 187:
errorType = ErrorType.DUPLICATE_TWEET;
errorType = DUPLICATE_TWEET;
break;
case 349:
errorType = ErrorType.NO_DM_TO_USER;
errorType = NO_DM_TO_USER;
break;
case 215: // Invalid API keys
case 261:
errorType = ErrorType.ERROR_API_ACCESS_DENIED;
errorType = ERROR_API_ACCESS_DENIED;
break;
case 354:
errorType = ErrorType.DM_TOO_LONG;
errorType = DM_TOO_LONG;
break;
case 89:
errorType = ErrorType.TOKEN_EXPIRED;
errorType = TOKEN_EXPIRED;
break;
case 385: // replying tweet that is not visible or deleted
errorType = ErrorType.TWEET_CANT_REPLY;
errorType = TWEET_CANT_REPLY;
break;
default:
if (error.getStatusCode() == 401) {
errorType = ErrorType.NOT_AUTHORIZED;
errorType = NOT_AUTHORIZED;
} else if (error.getStatusCode() == 403) {
errorType = ErrorType.REQUEST_FORBIDDEN;
errorType = REQUEST_FORBIDDEN;
} else if (error.getStatusCode() == 408) {
errorType = ErrorType.REQUEST_CANCELLED;
errorType = REQUEST_CANCELLED;
} else if (error.isCausedByNetworkIssue()) {
errorType = ErrorType.NO_CONNECTION;
errorType = NO_CONNECTION;
} else {
errorType = ErrorType.ERROR_NOT_DEFINED;
errorType = ERROR_NOT_DEFINED;
msg = error.getErrorMessage();
}
break;
}
} else {
errorType = ErrorType.ERROR_NOT_DEFINED;
errorType = ERROR_NOT_DEFINED;
msg = exception.getMessage();
}
}
@ -122,22 +121,22 @@ public class EngineException extends Exception {
*
* @param errorCode custom error code
*/
EngineException(InternalErrorType errorCode) {
EngineException(int errorCode) {
switch (errorCode) {
case FILENOTFOUND:
errorType = ErrorType.NO_MEDIA_FOUND;
errorType = NO_MEDIA_FOUND;
break;
case TOKENNOTSET:
errorType = ErrorType.NO_LINK_DEFINED;
errorType = NO_LINK_DEFINED;
break;
case BITMAP_FAILURE:
errorType = ErrorType.IMAGE_NOT_LOADED;
errorType = IMAGE_NOT_LOADED;
break;
default:
errorType = ErrorType.ERROR_NOT_DEFINED;
errorType = ERROR_NOT_DEFINED;
break;
}
}
@ -153,9 +152,9 @@ public class EngineException extends Exception {
/**
* get type of error defined by twitter API
*
* @return type of error {@link ErrorType}
* @return error code
*/
public ErrorType getErrorType() {
public int getErrorType() {
return errorType;
}
@ -176,41 +175,4 @@ public class EngineException extends Exception {
public int getTimeToWait() {
return retryAfter;
}
/**
* enum of error types used by this class
*/
public enum ErrorType {
RATE_LIMIT_EX,
USER_NOT_FOUND,
APP_SUSPENDED,
ACCESS_TOKEN_DEAD,
TWEET_CANT_REPLY,
RESOURCE_NOT_FOUND,
CANT_SEND_DM,
NOT_AUTHORIZED,
TWEET_TOO_LONG,
DUPLICATE_TWEET,
NO_DM_TO_USER,
DM_TOO_LONG,
TOKEN_EXPIRED,
NO_MEDIA_FOUND,
NO_LINK_DEFINED,
NO_CONNECTION,
IMAGE_NOT_LOADED,
REQUEST_CANCELLED,
REQUEST_FORBIDDEN,
ACCOUNT_UPDATE_FAILED,
ERROR_API_ACCESS_DENIED,
ERROR_NOT_DEFINED
}
/**
* error types only accessible by {@link TwitterEngine}
*/
enum InternalErrorType {
FILENOTFOUND,
TOKENNOTSET,
BITMAP_FAILURE
}
}

View File

@ -10,7 +10,6 @@ import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.holder.ListHolder;
import org.nuclearfog.twidda.backend.holder.TweetHolder;
import org.nuclearfog.twidda.backend.lists.Directmessages;
import org.nuclearfog.twidda.backend.lists.Users;
import org.nuclearfog.twidda.backend.lists.UserLists;
import org.nuclearfog.twidda.backend.utils.ProxySetup;
import org.nuclearfog.twidda.backend.utils.TLSSocketFactory;
@ -239,37 +238,6 @@ public class TwitterEngine {
}
}
/**
* Get User search result
*
* @param search Search String
* @return List of Users
* @throws EngineException if access is unavailable
*/
public Users searchUsers(String search, long cursor) throws EngineException {
try {
List<User> users;
int currentPage = 1;
if (cursor > 0)
currentPage = (int) cursor;
long prevPage = currentPage - 1;
long nextPage = currentPage + 1;
if (settings.filterResults()) {
users = convertUserListFiltered(twitter.searchUsers(search, currentPage));
} else {
users = convertUserList(twitter.searchUsers(search, currentPage));
}
if (users.size() < 20) {
nextPage = 0;
}
Users result = new Users(prevPage, nextPage);
result.addAll(users);
return result;
} catch (Exception err) {
throw new EngineException(err);
}
}
/**
* Get User Tweets
*
@ -357,21 +325,6 @@ public class TwitterEngine {
}
}
/**
* Get User
*
* @param username screen name of the user
* @return User Object
* @throws EngineException if Access is unavailable
*/
public User getUser(String username) throws EngineException {
try {
return new UserV1(twitter.showUser(username), twitter.getId());
} catch (Exception err) {
throw new EngineException(err);
}
}
/**
* Efficient Access of Connection Information
*
@ -517,70 +470,6 @@ public class TwitterEngine {
}
}
/**
* get Following User List
*
* @param userId User ID
* @return List of Following User with cursors
* @throws EngineException if Access is unavailable
*/
public Users getFollowing(long userId, long cursor) throws EngineException {
try {
PagableResponseList<twitter4j.User> list = twitter.getFriendsList(userId, cursor);
return createUserList(list, cursor);
} catch (Exception err) {
throw new EngineException(err);
}
}
/**
* get Follower
*
* @param userId User ID
* @return List of Follower with cursors attached
* @throws EngineException if Access is unavailable
*/
public Users getFollower(long userId, long cursor) throws EngineException {
try {
PagableResponseList<twitter4j.User> list = twitter.getFollowersList(userId, cursor);
return createUserList(list, cursor);
} catch (Exception err) {
throw new EngineException(err);
}
}
/**
* get a list of blocked users
*
* @param cursor list cursor
* @return user list
* @throws EngineException if twitter service is unavailable
*/
public Users getBlockedUsers(long cursor) throws EngineException {
try {
PagableResponseList<twitter4j.User> list = twitter.getBlocksList(cursor);
return createUserList(list, cursor);
} catch (Exception err) {
throw new EngineException(err);
}
}
/**
* get a list of muted users
*
* @param cursor list cursor
* @return user list
* @throws EngineException if twitter service is unavailable
*/
public Users getMutedUsers(long cursor) throws EngineException {
try {
PagableResponseList<twitter4j.User> list = twitter.getMutesList(cursor);
return createUserList(list, cursor);
} catch (Exception err) {
throw new EngineException(err);
}
}
/**
* get a list of blocked/muted user IDs
*
@ -991,38 +880,6 @@ public class TwitterEngine {
}
}
/**
* Get subscriber of a user list
*
* @param listId ID of the list
* @return list of users following the list
* @throws EngineException if access is unavailable
*/
public Users getListFollower(long listId, long cursor) throws EngineException {
try {
PagableResponseList<twitter4j.User> users = twitter.getUserListSubscribers(listId, cursor);
return createUserList(users, cursor);
} catch (Exception err) {
throw new EngineException(err);
}
}
/**
* Get member of a list
*
* @param listId ID of the list
* @return list of users
* @throws EngineException if access is unavailable
*/
public Users getListMember(long listId, long cursor) throws EngineException {
try {
PagableResponseList<twitter4j.User> users = twitter.getUserListMembers(listId, cursor);
return createUserList(users, cursor);
} catch (Exception err) {
throw new EngineException(err);
}
}
/**
* get tweets of a lists
*
@ -1055,7 +912,7 @@ public class TwitterEngine {
InputStream stream = url.openConnection().getInputStream();
return BitmapFactory.decodeStream(stream);
} catch (IOException err) {
throw new EngineException(EngineException.InternalErrorType.BITMAP_FAILURE);
throw new EngineException(EngineException.BITMAP_FAILURE);
}
}
@ -1071,7 +928,7 @@ public class TwitterEngine {
UploadedMedia media = twitter.uploadMedia("", new FileInputStream(path));
return media.getMediaId();
} catch (FileNotFoundException err) {
throw new EngineException(EngineException.InternalErrorType.FILENOTFOUND);
throw new EngineException(EngineException.FILENOTFOUND);
} catch (Exception err) {
throw new EngineException(err);
}
@ -1089,7 +946,7 @@ public class TwitterEngine {
UploadedMedia media = twitter.uploadMediaChunked("", new FileInputStream(path));
return media.getMediaId();
} catch (FileNotFoundException err) {
throw new EngineException(EngineException.InternalErrorType.FILENOTFOUND);
throw new EngineException(EngineException.FILENOTFOUND);
} catch (Exception err) {
throw new EngineException(err);
}
@ -1145,58 +1002,6 @@ public class TwitterEngine {
}
}
/**
* create user list from {@link PagableResponseList}
*
* @param list user list
* @param cursor prev cursor of the list
* @return user list
* @throws TwitterException if access is unavailable
*/
private Users createUserList(PagableResponseList<twitter4j.User> list, long cursor) throws TwitterException {
long prevCursor = cursor > 0 ? cursor : 0;
long nextCursor = list.getNextCursor();
Users result = new Users(prevCursor, nextCursor);
if (!list.isEmpty()) {
result.addAll(convertUserList(list));
}
return result;
}
/**
* convert {@link twitter4j.User} to User List
*
* @param users Twitter4J user List
* @return User
*/
private List<User> convertUserList(List<twitter4j.User> users) throws TwitterException {
long id = twitter.getId();
ArrayList<User> result = new ArrayList<>();
result.ensureCapacity(users.size());
for (twitter4j.User user : users) {
result.add(new UserV1(user, id));
}
return result;
}
/**
* convert {@link twitter4j.User} list to User List and filter excluded users
*
* @param users Twitter4J user List
* @return User
*/
private List<User> convertUserListFiltered(List<twitter4j.User> users) throws TwitterException {
long id = twitter.getId();
Set<Long> exclude = excludeDB.getExcludeSet();
List<User> result = new LinkedList<>();
for (twitter4j.User user : users) {
if (!exclude.contains(user.getId())) {
result.add(new UserV1(user, id));
}
}
return result;
}
/**
* create paging for tweets
*

View File

@ -27,7 +27,7 @@ public final class ErrorHandler {
* @param context current activity context
* @param error Error exception thrown by TwitterEngine
*/
public static void handleFailure(@NonNull Context context, @Nullable EngineException error) {
public static void handleFailure(@NonNull Context context, @Nullable TwitterError error) {
String message = getErrorMessage(context, error);
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
@ -39,10 +39,10 @@ public final class ErrorHandler {
* @param error Twitter error
* @return message string
*/
public static String getErrorMessage(Context context, @Nullable EngineException error) {
public static String getErrorMessage(Context context, @Nullable TwitterError error) {
if (error != null) {
switch (error.getErrorType()) {
case RATE_LIMIT_EX:
case TwitterError.RATE_LIMIT_EX:
if (error.getTimeToWait() > 0) {
String errMsg = context.getString(R.string.error_limit_exceeded);
if (error.getTimeToWait() >= 60)
@ -52,68 +52,68 @@ public final class ErrorHandler {
}
return context.getString(R.string.error_rate_limit);
case USER_NOT_FOUND:
case TwitterError.USER_NOT_FOUND:
return context.getString(R.string.error_user_not_found);
case RESOURCE_NOT_FOUND:
case TwitterError.RESOURCE_NOT_FOUND:
return context.getString(R.string.error_not_found);
case CANT_SEND_DM:
case TwitterError.CANT_SEND_DM:
return context.getString(R.string.error_send_dm_to_user);
case NOT_AUTHORIZED:
case TwitterError.NOT_AUTHORIZED:
return context.getString(R.string.error_not_authorized);
case TWEET_TOO_LONG:
case TwitterError.TWEET_TOO_LONG:
return context.getString(R.string.error_status_length);
case DUPLICATE_TWEET:
case TwitterError.DUPLICATE_TWEET:
return context.getString(R.string.error_duplicate_status);
case NO_DM_TO_USER:
case TwitterError.NO_DM_TO_USER:
return context.getString(R.string.error_dm_send);
case DM_TOO_LONG:
case TwitterError.DM_TOO_LONG:
return context.getString(R.string.error_dm_length);
case TOKEN_EXPIRED:
case TwitterError.TOKEN_EXPIRED:
return context.getString(R.string.error_accesstoken);
case NO_MEDIA_FOUND:
case TwitterError.NO_MEDIA_FOUND:
return context.getString(R.string.error_file_not_found);
case NO_LINK_DEFINED:
case TwitterError.NO_LINK_DEFINED:
return context.getString(R.string.error_token_not_set);
case NO_CONNECTION:
case TwitterError.NO_CONNECTION:
return context.getString(R.string.error_connection_failed);
case IMAGE_NOT_LOADED:
case TwitterError.IMAGE_NOT_LOADED:
return context.getString(R.string.error_image_loading);
case ACCESS_TOKEN_DEAD:
case TwitterError.ACCESS_TOKEN_DEAD:
return context.getString(R.string.error_corrupt_api_key);
case TWEET_CANT_REPLY:
case TwitterError.TWEET_CANT_REPLY:
return context.getString(R.string.error_cant_reply_to_tweet);
case ACCOUNT_UPDATE_FAILED:
case TwitterError.ACCOUNT_UPDATE_FAILED:
return context.getString(R.string.error_acc_update);
case REQUEST_CANCELLED:
case TwitterError.REQUEST_CANCELLED:
return context.getString(R.string.error_result_cancelled);
case REQUEST_FORBIDDEN:
case TwitterError.REQUEST_FORBIDDEN:
return context.getString(R.string.error_forbidden_api_access);
case APP_SUSPENDED:
case ERROR_API_ACCESS_DENIED:
case TwitterError.APP_SUSPENDED:
case TwitterError.ERROR_API_ACCESS_DENIED:
GlobalSettings settings = GlobalSettings.getInstance(context);
if (settings.isCustomApiSet())
return context.getString(R.string.error_api_access_denied);
return context.getString(R.string.error_api_key_expired);
case ERROR_NOT_DEFINED:
case TwitterError.ERROR_NOT_DEFINED:
return error.getMessage();
default:
@ -123,4 +123,39 @@ public final class ErrorHandler {
return context.getString(R.string.error_not_defined);
}
}
public interface TwitterError {
int ERROR_NOT_DEFINED = -1;
int RATE_LIMIT_EX = 0;
int USER_NOT_FOUND = 1;
int RESOURCE_NOT_FOUND = 2;
int CANT_SEND_DM = 3;
int NOT_AUTHORIZED = 4;
int TWEET_TOO_LONG = 5;
int DUPLICATE_TWEET = 6;
int NO_DM_TO_USER = 7;
int DM_TOO_LONG = 8;
int TOKEN_EXPIRED = 9;
int NO_MEDIA_FOUND = 10;
int NO_LINK_DEFINED = 11;
int NO_CONNECTION = 12;
int IMAGE_NOT_LOADED = 13;
int ACCESS_TOKEN_DEAD = 14;
int TWEET_CANT_REPLY = 15;
int ACCOUNT_UPDATE_FAILED = 16;
int REQUEST_CANCELLED = 17;
int REQUEST_FORBIDDEN = 18;
int APP_SUSPENDED = 19;
int ERROR_API_ACCESS_DENIED = 20;
int FILENOTFOUND = 23;
int TOKENNOTSET = 22;
int BITMAP_FAILURE = 21;
int getErrorType();
int getTimeToWait();
String getMessage();
}
}

View File

@ -22,6 +22,7 @@ import org.nuclearfog.twidda.backend.ListManager;
import org.nuclearfog.twidda.backend.ListManager.ListManagerCallback;
import org.nuclearfog.twidda.backend.UserLoader;
import org.nuclearfog.twidda.backend.UserLoader.Type;
import org.nuclearfog.twidda.backend.api.TwitterException;
import org.nuclearfog.twidda.backend.apiold.EngineException;
import org.nuclearfog.twidda.backend.lists.Users;
import org.nuclearfog.twidda.model.User;
@ -258,10 +259,10 @@ public class UserFragment extends ListFragment implements UserClickListener,
/**
* called when an error occurs
*
* @param error Engine exception
* @param exception Twitter exception
*/
public void onError(EngineException error) {
ErrorHandler.handleFailure(requireContext(), error);
public void onError(TwitterException exception) {
ErrorHandler.handleFailure(requireContext(), exception);
adapter.disableLoading();
setRefresh(false);
}