package com.cheikh.lazywaimai.network; import com.google.gson.JsonParseException; import com.orhanobut.logger.Logger; import org.apache.http.conn.ConnectTimeoutException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.net.ConnectException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.util.HashMap; import java.util.Map; import retrofit2.adapter.rxjava.HttpException; import rx.Observable; import rx.functions.Action1; import rx.functions.Func1; import com.cheikh.lazywaimai.BuildConfig; import com.cheikh.lazywaimai.R; import com.cheikh.lazywaimai.context.AppConfig; import com.cheikh.lazywaimai.context.AppCookie; import com.cheikh.lazywaimai.model.bean.ResponseError; import com.cheikh.lazywaimai.model.bean.Token; import com.cheikh.lazywaimai.util.StringFetcher; import static com.cheikh.lazywaimai.util.Constants.HttpCode.HTTP_NETWORK_ERROR; import static com.cheikh.lazywaimai.util.Constants.HttpCode.HTTP_SERVER_ERROR; import static com.cheikh.lazywaimai.util.Constants.HttpCode.HTTP_UNAUTHORIZED; import static com.cheikh.lazywaimai.util.Constants.HttpCode.HTTP_UNKNOWN_ERROR; import static com.cheikh.lazywaimai.util.Constants.Key.PARAM_CLIENT_ID; import static com.cheikh.lazywaimai.util.Constants.Key.PARAM_CLIENT_SECRET; import static com.cheikh.lazywaimai.util.Constants.Key.PARAM_GRANT_TYPE; import static com.cheikh.lazywaimai.util.Constants.Key.PARAM_REFRESH_TOKEN; public class ResponseErrorProxy implements InvocationHandler { public static final String TAG = ResponseErrorProxy.class.getSimpleName(); private Object mProxyObject; private RestApiClient mRestApiClient; public ResponseErrorProxy(Object proxyObject, RestApiClient restApiClient) { mProxyObject = proxyObject; mRestApiClient = restApiClient; } @Override public Object invoke(Object proxy, final Method method, final Object[] args) { return Observable.just(null) .flatMap(new Func1<Object, Observable<?>>() { @Override public Observable<?> call(Object o) { try { return (Observable<?>) method.invoke(mProxyObject, args); } catch (Exception e) { e.printStackTrace(); } return null; } }) .retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() { @Override public Observable<?> call(Observable<? extends Throwable> observable) { return observable.flatMap(new Func1<Throwable, Observable<?>>() { @Override public Observable<?> call(Throwable throwable) { ResponseError error = null; if (throwable instanceof ConnectTimeoutException || throwable instanceof SocketTimeoutException || throwable instanceof UnknownHostException || throwable instanceof ConnectException) { error = new ResponseError(HTTP_NETWORK_ERROR, StringFetcher.getString(R.string.toast_error_network)); } else if (throwable instanceof HttpException) { HttpException exception = (HttpException) throwable; try { error = GsonHelper.builderGson().fromJson( exception.response().errorBody().string(), ResponseError.class); } catch (Exception e) { if (e instanceof JsonParseException) { error = new ResponseError(HTTP_SERVER_ERROR, StringFetcher.getString(R.string.toast_error_server)); } else { error = new ResponseError(HTTP_UNKNOWN_ERROR, StringFetcher.getString(R.string.toast_error_unknown)); } } } else if (throwable instanceof JsonParseException) { error = new ResponseError(HTTP_SERVER_ERROR, StringFetcher.getString(R.string.toast_error_server)); } else { error = new ResponseError(HTTP_UNKNOWN_ERROR, StringFetcher.getString(R.string.toast_error_unknown)); } if (BuildConfig.DEBUG) { Logger.e("网络请求出现错误: " + error.toString()); } if (error.getStatus() == HTTP_UNAUTHORIZED) { return refreshTokenWhenTokenInvalid(); } else { return Observable.error(error); } } }); } }); } private Observable<?> refreshTokenWhenTokenInvalid() { synchronized (ResponseErrorProxy.class) { Map<String, String> params = new HashMap<>(); params.put(PARAM_CLIENT_ID, AppConfig.APP_KEY); params.put(PARAM_CLIENT_SECRET, AppConfig.APP_SECRET); params.put(PARAM_GRANT_TYPE, "refresh_token"); params.put(PARAM_REFRESH_TOKEN, AppCookie.getRefreshToken()); return mRestApiClient.tokenService() .refreshToken(params) .doOnNext(new Action1<Token>() { @Override public void call(Token token) { AppCookie.saveAccessToken(token.getAccessToken()); AppCookie.saveRefreshToken(token.getRefreshToken()); mRestApiClient.setToken(token.getAccessToken()); } }); } } }