Search in sources :

Example 71 with MatrixError

use of org.matrix.androidsdk.rest.model.MatrixError in project matrix-android-sdk by matrix-org.

the class RestAdapterCallback method failure.

/**
 * Default failure implementation that calls the right error handler
 *
 * @param error the retrofit error
 */
@Override
public void failure(RetrofitError error) {
    if (null != mEventDescription) {
        Log.d(LOG_TAG, "## failure(): [" + mEventDescription + "]" + " with error " + error.getMessage());
    }
    boolean retry = true;
    if (null != error.getResponse()) {
        retry = (error.getResponse().getStatus() < 400) || (error.getResponse().getStatus() > 500);
    }
    // do not retry if the response format is not the expected one.
    retry &= (null == error.getCause()) || !(error.getCause() instanceof ConversionException);
    if (retry && (null != mUnsentEventsManager)) {
        Log.d(LOG_TAG, "Add it to the UnsentEventsManager");
        mUnsentEventsManager.onEventSendingFailed(mEventDescription, mIgnoreEventTimeLifeInOffline, error, mApiCallback, mRequestRetryCallBack);
    } else {
        if (error.isNetworkError()) {
            try {
                if (null != mApiCallback) {
                    try {
                        mApiCallback.onNetworkError(error);
                    } catch (Exception e) {
                        Log.e(LOG_TAG, "## failure(): onNetworkError " + error.getMessage());
                    }
                }
            } catch (Exception e) {
                // privacy
                // Log.e(LOG_TAG, "Exception NetworkError " + e.getMessage() + " while managing " + error.getUrl());
                Log.e(LOG_TAG, "## failure():  NetworkError " + e.getMessage());
            }
        } else {
            // Try to convert this into a Matrix error
            MatrixError mxError;
            try {
                mxError = (MatrixError) error.getBodyAs(MatrixError.class);
                mxError.mStatus = error.getResponse().getStatus();
                mxError.mReason = error.getResponse().getReason();
                TypedInput body = error.getResponse().getBody();
                if (null != body) {
                    mxError.mErrorBodyMimeType = body.mimeType();
                    mxError.mErrorBody = body;
                    try {
                        if (body instanceof TypedByteArray) {
                            mxError.mErrorBodyAsString = new String(((TypedByteArray) body).getBytes());
                        } else {
                            mxError.mErrorBodyAsString = (String) error.getBodyAs(String.class);
                        }
                    } catch (Exception castException) {
                        Log.e(LOG_TAG, "## failure(): MatrixError cannot cast the response body" + castException.getMessage());
                    }
                }
            } catch (Exception e) {
                mxError = null;
            }
            if (mxError != null) {
                if (MatrixError.LIMIT_EXCEEDED.equals(mxError.errcode) && (null != mUnsentEventsManager)) {
                    mUnsentEventsManager.onEventSendingFailed(mEventDescription, mIgnoreEventTimeLifeInOffline, error, mApiCallback, mRequestRetryCallBack);
                } else if (MatrixError.isConfigurationErrorCode(mxError.errcode) && (null != mUnsentEventsManager)) {
                    mUnsentEventsManager.onConfigurationErrorCode(mxError.errcode, mEventDescription);
                } else {
                    try {
                        if (null != mApiCallback) {
                            mApiCallback.onMatrixError(mxError);
                        }
                    } catch (Exception e) {
                        // privacy
                        // Log.e(LOG_TAG, "Exception MatrixError " + e.getMessage() + " while managing " + error.getUrl());
                        Log.e(LOG_TAG, "## failure():  MatrixError " + e.getMessage());
                    }
                }
            } else {
                try {
                    if (null != mApiCallback) {
                        mApiCallback.onUnexpectedError(error);
                    }
                } catch (Exception e) {
                    // privacy
                    // Log.e(LOG_TAG, "Exception UnexpectedError " + e.getMessage() + " while managing " + error.getUrl());
                    Log.e(LOG_TAG, "## failure():  UnexpectedError " + e.getMessage());
                }
            }
        }
    }
}
Also used : ConversionException(retrofit.converter.ConversionException) TypedInput(retrofit.mime.TypedInput) TypedByteArray(retrofit.mime.TypedByteArray) MatrixError(org.matrix.androidsdk.rest.model.MatrixError) ConversionException(retrofit.converter.ConversionException)

Example 72 with MatrixError

use of org.matrix.androidsdk.rest.model.MatrixError in project matrix-android-sdk by matrix-org.

the class EventsThread method startSync.

/**
 * Start the events sync
 */
@SuppressLint("NewApi")
private void startSync() {
    if (null != mCurrentToken) {
        Log.d(LOG_TAG, "Resuming initial sync from " + mCurrentToken);
    } else {
        Log.d(LOG_TAG, "Requesting initial sync...");
    }
    int serverTimeout;
    mPaused = false;
    // 
    mInitialSyncDone = null != mCurrentToken;
    if (mInitialSyncDone) {
        // get the latest events asap
        serverTimeout = 0;
        // dummy initial sync
        // to hide the splash screen
        SyncResponse dummySyncResponse = new SyncResponse();
        dummySyncResponse.nextBatch = mCurrentToken;
        mListener.onSyncResponse(dummySyncResponse, null, true);
    } else {
        // Start with initial sync
        while (!mInitialSyncDone) {
            final CountDownLatch latch = new CountDownLatch(1);
            mEventsRestClient.syncFromToken(null, 0, DEFAULT_CLIENT_TIMEOUT_MS, mIsOnline ? null : "offline", DATA_SAVE_MODE_FILTER, new SimpleApiCallback<SyncResponse>(mFailureCallback) {

                @Override
                public void onSuccess(SyncResponse syncResponse) {
                    Log.d(LOG_TAG, "Received initial sync response.");
                    mNextServerTimeoutms = hasDevicesChanged(syncResponse) ? 0 : mDefaultServerTimeoutms;
                    mListener.onSyncResponse(syncResponse, null, (0 == mNextServerTimeoutms));
                    mCurrentToken = syncResponse.nextBatch;
                    mInitialSyncDone = true;
                    // unblock the events thread
                    latch.countDown();
                }

                private void sleepAndUnblock() {
                    Log.i(LOG_TAG, "Waiting a bit before retrying");
                    new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {

                        public void run() {
                            latch.countDown();
                        }
                    }, RETRY_WAIT_TIME_MS);
                }

                @Override
                public void onNetworkError(Exception e) {
                    if (null != mCurrentToken) {
                        onSuccess(null);
                    } else {
                        Log.e(LOG_TAG, "Sync V2 onNetworkError " + e.getMessage());
                        super.onNetworkError(e);
                        sleepAndUnblock();
                    }
                }

                @Override
                public void onMatrixError(MatrixError e) {
                    super.onMatrixError(e);
                    if (MatrixError.isConfigurationErrorCode(e.errcode)) {
                        mListener.onConfigurationError(e.errcode);
                    } else {
                        sleepAndUnblock();
                    }
                }

                @Override
                public void onUnexpectedError(Exception e) {
                    super.onUnexpectedError(e);
                    Log.e(LOG_TAG, "Sync V2 onUnexpectedError " + e.getMessage());
                    sleepAndUnblock();
                }
            });
            // block until the initial sync callback is invoked.
            try {
                latch.await();
            } catch (InterruptedException e) {
                Log.e(LOG_TAG, "Interrupted whilst performing initial sync.");
            } catch (Exception e) {
                Log.e(LOG_TAG, "## startSync() failed " + e.getMessage());
            }
        }
        serverTimeout = mNextServerTimeoutms;
    }
    Log.d(LOG_TAG, "Starting event stream from token " + mCurrentToken);
    // sanity check
    if (null != mNetworkConnectivityReceiver) {
        mNetworkConnectivityReceiver.addEventListener(mNetworkListener);
        // 
        mbIsConnected = mNetworkConnectivityReceiver.isConnected();
        mIsNetworkSuspended = !mbIsConnected;
    }
    // Then repeatedly long-poll for events
    while (!mKilling) {
        // test if a delay between two syncs
        if ((!mPaused && !mIsNetworkSuspended) && (0 != mRequestDelayMs)) {
            Log.d(LOG_TAG, "startSync : start a delay timer ");
            Intent intent = new Intent(mContext, SyncDelayReceiver.class);
            intent.putExtra(SyncDelayReceiver.EXTRA_INSTANCE_ID, this.toString());
            mPendingDelayedIntent = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            long futureInMillis = SystemClock.elapsedRealtime() + mRequestDelayMs;
            if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) && mPowerManager.isIgnoringBatteryOptimizations(mContext.getPackageName())) {
                mAlarmManager.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, futureInMillis, mPendingDelayedIntent);
            } else {
                mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, futureInMillis, mPendingDelayedIntent);
            }
        }
        if (mPaused || mIsNetworkSuspended || (null != mPendingDelayedIntent)) {
            if (null != mPendingDelayedIntent) {
                Log.d(LOG_TAG, "Event stream is paused because there is a timer delay.");
            } else if (mIsNetworkSuspended) {
                Log.d(LOG_TAG, "Event stream is paused because there is no available network.");
            } else {
                Log.d(LOG_TAG, "Event stream is paused. Waiting.");
            }
            try {
                Log.d(LOG_TAG, "startSync : wait ...");
                synchronized (mSyncObject) {
                    mSyncObject.wait();
                }
                if (null != mPendingDelayedIntent) {
                    Log.d(LOG_TAG, "startSync : cancel mSyncDelayTimer");
                    mAlarmManager.cancel(mPendingDelayedIntent);
                    mPendingDelayedIntent.cancel();
                    mPendingDelayedIntent = null;
                }
                Log.d(LOG_TAG, "Event stream woken from pause.");
                // perform a catchup asap
                serverTimeout = 0;
            } catch (InterruptedException e) {
                Log.e(LOG_TAG, "Unexpected interruption while paused: " + e.getMessage());
            }
        }
        // the service could have been killed while being paused.
        if (!mKilling) {
            // "{\"room\":{\"timeline\":{\"limit\":250}}}";
            String inlineFilter = mIsInDataSaveMode ? DATA_SAVE_MODE_FILTER : null;
            final CountDownLatch latch = new CountDownLatch(1);
            if (mIsInDataSaveMode) {
                Log.d(LOG_TAG, "[Data save mode] Get events from token " + mCurrentToken);
            } else {
                Log.d(LOG_TAG, "Get events from token " + mCurrentToken);
            }
            final int fServerTimeout = serverTimeout;
            mNextServerTimeoutms = mDefaultServerTimeoutms;
            mEventsRestClient.syncFromToken(mCurrentToken, serverTimeout, DEFAULT_CLIENT_TIMEOUT_MS, mIsOnline ? null : "offline", inlineFilter, new SimpleApiCallback<SyncResponse>(mFailureCallback) {

                @Override
                public void onSuccess(SyncResponse syncResponse) {
                    if (!mKilling) {
                        // we get no to_device messages back.
                        if (0 == fServerTimeout) {
                            if (hasDevicesChanged(syncResponse)) {
                                if (mIsCatchingUp) {
                                    Log.d(LOG_TAG, "Some devices have changed but do not set mNextServerTimeoutms to 0 to avoid infinite loops");
                                } else {
                                    Log.d(LOG_TAG, "mNextServerTimeoutms is set to 0 because of hasDevicesChanged " + syncResponse.deviceLists.changed);
                                    mNextServerTimeoutms = 0;
                                }
                            }
                        }
                        // to loop again
                        if (mIsCatchingUp && (0 != mNextServerTimeoutms)) {
                            // the catchup triggers sync requests until there are some useful events
                            int eventCounts = 0;
                            if (null != syncResponse.rooms) {
                                RoomsSyncResponse roomsSyncResponse = syncResponse.rooms;
                                if (null != roomsSyncResponse.join) {
                                    eventCounts += roomsSyncResponse.join.size();
                                }
                                if (null != roomsSyncResponse.invite) {
                                    eventCounts += roomsSyncResponse.invite.size();
                                }
                            }
                            // stop any catch up
                            mIsCatchingUp = false;
                            mPaused = (0 == mRequestDelayMs);
                            Log.d(LOG_TAG, "Got " + eventCounts + " useful events while catching up : mPaused is set to " + mPaused);
                        }
                        Log.d(LOG_TAG, "Got event response");
                        mListener.onSyncResponse(syncResponse, mCurrentToken, (0 == mNextServerTimeoutms));
                        mCurrentToken = syncResponse.nextBatch;
                        Log.d(LOG_TAG, "mCurrentToken is now set to " + mCurrentToken);
                    }
                    // unblock the events thread
                    latch.countDown();
                }

                private void onError(String description) {
                    boolean isConnected;
                    Log.d(LOG_TAG, "Got an error while polling events " + description);
                    synchronized (mSyncObject) {
                        isConnected = mbIsConnected;
                    }
                    // detected if the device is connected before trying again
                    if (isConnected) {
                        new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {

                            public void run() {
                                latch.countDown();
                            }
                        }, RETRY_WAIT_TIME_MS);
                    } else {
                        // no network -> wait that a network connection comes back.
                        mIsNetworkSuspended = true;
                        latch.countDown();
                    }
                }

                @Override
                public void onNetworkError(Exception e) {
                    onError(e.getLocalizedMessage());
                }

                @Override
                public void onMatrixError(MatrixError e) {
                    if (MatrixError.isConfigurationErrorCode(e.errcode)) {
                        mListener.onConfigurationError(e.errcode);
                    } else {
                        onError(e.getLocalizedMessage());
                    }
                }

                @Override
                public void onUnexpectedError(Exception e) {
                    onError(e.getLocalizedMessage());
                }
            });
            // block until the sync callback is invoked.
            try {
                latch.await();
            } catch (InterruptedException e) {
                Log.e(LOG_TAG, "Interrupted whilst polling message");
            } catch (Exception e) {
                // reported by GA
                // The thread might have been killed.
                Log.e(LOG_TAG, "latch.await() failed " + e.getMessage());
            }
        }
        serverTimeout = mNextServerTimeoutms;
    }
    if (null != mNetworkConnectivityReceiver) {
        mNetworkConnectivityReceiver.removeEventListener(mNetworkListener);
    }
    Log.d(LOG_TAG, "Event stream terminating.");
}
Also used : Handler(android.os.Handler) Intent(android.content.Intent) PendingIntent(android.app.PendingIntent) RoomsSyncResponse(org.matrix.androidsdk.rest.model.sync.RoomsSyncResponse) CountDownLatch(java.util.concurrent.CountDownLatch) SuppressLint(android.annotation.SuppressLint) RoomsSyncResponse(org.matrix.androidsdk.rest.model.sync.RoomsSyncResponse) SyncResponse(org.matrix.androidsdk.rest.model.sync.SyncResponse) MatrixError(org.matrix.androidsdk.rest.model.MatrixError) SuppressLint(android.annotation.SuppressLint)

Example 73 with MatrixError

use of org.matrix.androidsdk.rest.model.MatrixError in project matrix-android-sdk by matrix-org.

the class TestsHelper method createAccountAndSync.

/**
 * Create an account and a dedicated session
 * @param context the context
 * @param userName the account username
 * @param password the password
 * @param startSession true to perform an initial sync
 * @param callback the callback
 * @throws Exception an exception if the account cannot be created
 */
public static void createAccountAndSync(Context context, String userName, String password, boolean startSession, ApiCallback<MXSession> callback) throws Exception {
    RestClient.mUseMXExececutor = true;
    Uri uri = Uri.parse(TESTS_HOME_SERVER_URL);
    HomeServerConnectionConfig hs = new HomeServerConnectionConfig(uri);
    LoginRestClient loginRestClient = new LoginRestClient(hs);
    final HashMap<String, Object> params = new HashMap<>();
    RegistrationParams registrationParams = new RegistrationParams();
    mLock = new CountDownLatch(1);
    // get the registration session id
    loginRestClient.register(registrationParams, new ApiCallback<Credentials>() {

        @Override
        public void onSuccess(Credentials credentials) {
            mLock.countDown();
        }

        @Override
        public void onNetworkError(Exception e) {
            mLock.countDown();
        }

        @Override
        public void onMatrixError(MatrixError e) {
            // detect if a parameter is expected
            RegistrationFlowResponse registrationFlowResponse = null;
            // when a response is not completed the server returns an error message
            if ((null != e.mStatus) && (e.mStatus == 401)) {
                try {
                    registrationFlowResponse = JsonUtils.toRegistrationFlowResponse(e.mErrorBodyAsString);
                } catch (Exception castExcept) {
                }
            }
            // check if the server response can be casted
            if (null != registrationFlowResponse) {
                params.put("session", registrationFlowResponse.session);
            }
            mLock.countDown();
        }

        @Override
        public void onUnexpectedError(Exception e) {
            mLock.countDown();
        }
    });
    mLock.await(1000, TimeUnit.MILLISECONDS);
    String session = (String) params.get("session");
    if (null == session) {
        callback.onUnexpectedError(null);
    }
    registrationParams.username = userName;
    registrationParams.password = password;
    HashMap<String, Object> authParams = new HashMap<>();
    authParams.put("session", session);
    authParams.put("type", LoginRestClient.LOGIN_FLOW_TYPE_DUMMY);
    registrationParams.auth = authParams;
    mLock = new CountDownLatch(1);
    loginRestClient.register(registrationParams, new ApiCallback<Credentials>() {

        @Override
        public void onSuccess(Credentials credentials) {
            params.put("credentials", credentials);
            mLock.countDown();
        }

        @Override
        public void onNetworkError(Exception e) {
            mLock.countDown();
        }

        @Override
        public void onMatrixError(MatrixError e) {
            mLock.countDown();
        }

        @Override
        public void onUnexpectedError(Exception e) {
            mLock.countDown();
        }
    });
    mLock.await(1000, TimeUnit.MILLISECONDS);
    Credentials credentials = (Credentials) params.get("credentials");
    if (null == credentials) {
        callback.onMatrixError(null);
        return;
    }
    hs.setCredentials(credentials);
    IMXStore store = new MXFileStore(hs, context);
    MXSession mxSession = new MXSession(hs, new MXDataHandler(store, credentials), context);
    if (!startSession) {
        callback.onSuccess(mxSession);
        return;
    }
    mxSession.getDataHandler().getStore().open();
    mxSession.startEventStream(null);
    mLock = new CountDownLatch(1);
    mxSession.getDataHandler().addListener(new MXEventListener() {

        @Override
        public void onInitialSyncComplete(String toToken) {
            params.put("isInit", true);
            mLock.countDown();
        }
    });
    mLock.await(10000, TimeUnit.MILLISECONDS);
    if (params.containsKey("isInit")) {
        callback.onSuccess(mxSession);
    } else {
        callback.onMatrixError(null);
    }
}
Also used : HashMap(java.util.HashMap) RegistrationFlowResponse(org.matrix.androidsdk.rest.model.login.RegistrationFlowResponse) IMXStore(org.matrix.androidsdk.data.store.IMXStore) MXFileStore(org.matrix.androidsdk.data.store.MXFileStore) CountDownLatch(java.util.concurrent.CountDownLatch) Uri(android.net.Uri) MXEventListener(org.matrix.androidsdk.listeners.MXEventListener) RegistrationParams(org.matrix.androidsdk.rest.model.login.RegistrationParams) LoginRestClient(org.matrix.androidsdk.rest.client.LoginRestClient) MatrixError(org.matrix.androidsdk.rest.model.MatrixError) Credentials(org.matrix.androidsdk.rest.model.login.Credentials)

Aggregations

MatrixError (org.matrix.androidsdk.rest.model.MatrixError)73 HashMap (java.util.HashMap)41 CountDownLatch (java.util.concurrent.CountDownLatch)39 Room (org.matrix.androidsdk.data.Room)33 JsonObject (com.google.gson.JsonObject)31 Test (org.junit.Test)30 Event (org.matrix.androidsdk.rest.model.Event)27 MXEventListener (org.matrix.androidsdk.listeners.MXEventListener)25 ArrayList (java.util.ArrayList)24 Context (android.content.Context)23 RoomState (org.matrix.androidsdk.data.RoomState)20 MXDeviceInfo (org.matrix.androidsdk.crypto.data.MXDeviceInfo)17 ApiCallback (org.matrix.androidsdk.rest.callback.ApiCallback)15 MXUsersDevicesMap (org.matrix.androidsdk.crypto.data.MXUsersDevicesMap)13 IMXStore (org.matrix.androidsdk.data.store.IMXStore)12 Credentials (org.matrix.androidsdk.rest.model.login.Credentials)12 Uri (android.net.Uri)10 MXFileStore (org.matrix.androidsdk.data.store.MXFileStore)10 EventTimeline (org.matrix.androidsdk.data.EventTimeline)9 SimpleApiCallback (org.matrix.androidsdk.rest.callback.SimpleApiCallback)7