use of org.matrix.androidsdk.core.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 response the retrofit response
* @param exception the retrofit exception
*/
public void failure(Response<T> response, Exception exception) {
if (null != mEventDescription) {
String error = exception != null ? exception.getMessage() : (response != null ? response.message() : "unknown");
Log.d(LOG_TAG, "## failure(): [" + mEventDescription + "]" + " with error " + error);
}
boolean retry = true;
if (null != response) {
retry = (response.code() < 400) || (response.code() > 500);
}
// do not retry if the response format is not the expected one.
retry &= (null == exception.getCause()) || !(exception.getCause() instanceof MalformedJsonException || exception.getCause() instanceof JsonSyntaxException);
if (retry && (null != mUnsentEventsManager)) {
Log.d(LOG_TAG, "Add it to the UnsentEventsManager");
mUnsentEventsManager.onEventSendingFailed(mEventDescription, mIgnoreEventTimeLifeInOffline, response, exception, mApiCallback, mRequestRetryCallBack);
} else {
if (exception != null && exception instanceof IOException) {
try {
if (null != mApiCallback) {
try {
mApiCallback.onNetworkError(exception);
} catch (Exception e) {
Log.e(LOG_TAG, "## failure(): onNetworkError " + exception.getLocalizedMessage(), exception);
}
}
} catch (Exception e) {
// privacy
// Log.e(LOG_TAG, "Exception NetworkError " + e.getMessage() + " while managing " + error.getUrl());
Log.e(LOG_TAG, "## failure(): NetworkError " + e.getMessage(), e);
}
} else {
// Try to convert this into a Matrix error
MatrixError mxError;
try {
HttpError error = ((HttpException) exception).getHttpError();
ResponseBody errorBody = response.errorBody();
String bodyAsString = error.getErrorBody();
mxError = GsonProvider.provideGson().fromJson(bodyAsString, MatrixError.class);
mxError.mStatus = response.code();
mxError.mReason = response.message();
mxError.mErrorBodyAsString = bodyAsString;
} catch (Exception e) {
mxError = null;
}
if (mxError != null) {
if (MatrixError.LIMIT_EXCEEDED.equals(mxError.errcode) && (null != mUnsentEventsManager)) {
mUnsentEventsManager.onEventSendingFailed(mEventDescription, mIgnoreEventTimeLifeInOffline, response, exception, 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(), e);
}
}
} else {
try {
if (null != mApiCallback) {
mApiCallback.onUnexpectedError(exception);
}
} catch (Exception e) {
// privacy
// Log.e(LOG_TAG, "Exception UnexpectedError " + e.getMessage() + " while managing " + error.getUrl());
Log.e(LOG_TAG, "## failure(): UnexpectedError " + e.getMessage(), e);
}
}
}
}
}
use of org.matrix.androidsdk.core.model.MatrixError in project matrix-android-sdk by matrix-org.
the class UnsentEventsManager method onEventSendingFailed.
/**
* warns that an event failed to be sent.
*
* @param eventDescription the event description
* @param ignoreEventTimeLifeInOffline tell if the event timelife is ignored in offline mode
* @param response Retrofit response
* @param exception Retrofit Exception
* @param apiCallback the apiCallback.
* @param requestRetryCallBack requestRetryCallBack.
*/
public void onEventSendingFailed(final String eventDescription, final boolean ignoreEventTimeLifeInOffline, final Response response, final Exception exception, final ApiCallback apiCallback, final RestAdapterCallback.RequestRetryCallBack requestRetryCallBack) {
boolean isManaged = false;
if (null != eventDescription) {
Log.d(LOG_TAG, "Fail to send [" + eventDescription + "]");
}
if ((null != requestRetryCallBack) && (null != apiCallback)) {
synchronized (mUnsentEventsMap) {
UnsentEventSnapshot snapshot;
// Try to convert this into a Matrix error
MatrixError mxError = null;
if (null != response) {
try {
mxError = GsonProvider.provideGson().fromJson(response.errorBody().string(), MatrixError.class);
} catch (Exception e) {
mxError = null;
}
}
// trace the matrix error.
if ((null != eventDescription) && (null != mxError)) {
Log.d(LOG_TAG, "Matrix error " + mxError.errcode + " " + mxError.getMessage() + " [" + eventDescription + "]");
if (MatrixError.isConfigurationErrorCode(mxError.errcode)) {
Log.e(LOG_TAG, "## onEventSendingFailed() : invalid token detected");
mDataHandler.onConfigurationError(mxError.errcode);
triggerErrorCallback(mDataHandler, eventDescription, response, exception, apiCallback);
return;
}
}
int matrixRetryTimeout = -1;
if ((null != mxError) && MatrixError.LIMIT_EXCEEDED.equals(mxError.errcode) && (null != mxError.retry_after_ms)) {
matrixRetryTimeout = mxError.retry_after_ms + 200;
}
if (null != exception) {
UnrecognizedCertificateException unrecCertEx = CertUtil.getCertificateException(exception);
if (null != unrecCertEx) {
Log.e(LOG_TAG, "## onEventSendingFailed() : SSL issue detected");
mDataHandler.onSSLCertificateError(unrecCertEx);
triggerErrorCallback(mDataHandler, eventDescription, response, exception, apiCallback);
return;
}
}
// some matrix errors are not trapped.
if ((null == mxError) || !mxError.isSupportedErrorCode() || MatrixError.LIMIT_EXCEEDED.equals(mxError.errcode)) {
// is it the first time that the event has been sent ?
if (mUnsentEventsMap.containsKey(apiCallback)) {
snapshot = mUnsentEventsMap.get(apiCallback);
snapshot.mIsResending = false;
snapshot.stopTimer();
// assume that LIMIT_EXCEEDED error is not a default retry
if (matrixRetryTimeout < 0) {
snapshot.mRetryCount++;
}
// any event has a time life to avoid very old messages
long timeLife = 0;
// age < 0 means that the event time life is ignored
if (snapshot.mAge > 0) {
timeLife = System.currentTimeMillis() - snapshot.mAge;
}
if ((timeLife > MAX_MESSAGE_LIFETIME_MS) || (snapshot.mRetryCount > MAX_RETRIES)) {
snapshot.stopTimers();
mUnsentEventsMap.remove(apiCallback);
mUnsentEvents.remove(snapshot);
if (null != eventDescription) {
Log.d(LOG_TAG, "Cancel [" + eventDescription + "]");
}
isManaged = false;
} else {
isManaged = true;
}
} else {
snapshot = new UnsentEventSnapshot();
try {
snapshot.mAge = ignoreEventTimeLifeInOffline ? -1 : System.currentTimeMillis();
snapshot.mRequestRetryCallBack = requestRetryCallBack;
snapshot.mRetryCount = 1;
snapshot.mEventDescription = eventDescription;
mUnsentEventsMap.put(apiCallback, snapshot);
mUnsentEvents.add(snapshot);
if (mbIsConnected || !ignoreEventTimeLifeInOffline) {
// the event has a life time
final UnsentEventSnapshot fSnapshot = snapshot;
fSnapshot.mLifeTimeTimer = new Timer();
fSnapshot.mLifeTimeTimer.schedule(new TimerTask() {
@Override
public void run() {
try {
if (null != eventDescription) {
Log.d(LOG_TAG, "Cancel to send [" + eventDescription + "]");
}
fSnapshot.stopTimers();
synchronized (mUnsentEventsMap) {
mUnsentEventsMap.remove(apiCallback);
mUnsentEvents.remove(fSnapshot);
}
triggerErrorCallback(mDataHandler, eventDescription, response, exception, apiCallback);
} catch (Exception e) {
Log.e(LOG_TAG, "## onEventSendingFailed() : failure Msg=" + e.getMessage(), e);
}
}
}, MAX_MESSAGE_LIFETIME_MS);
} else if (ignoreEventTimeLifeInOffline) {
Log.d(LOG_TAG, "The request " + eventDescription + " will be sent when a network will be available");
}
} catch (Throwable throwable) {
Log.e(LOG_TAG, "## snapshot creation failed " + throwable.getMessage(), throwable);
if (null != snapshot.mLifeTimeTimer) {
snapshot.mLifeTimeTimer.cancel();
}
mUnsentEventsMap.remove(apiCallback);
mUnsentEvents.remove(snapshot);
try {
triggerErrorCallback(mDataHandler, eventDescription, response, exception, apiCallback);
} catch (Exception e) {
Log.e(LOG_TAG, "## onEventSendingFailed() : failure Msg=" + e.getMessage(), e);
}
}
isManaged = true;
}
// retry to send the message ?
if (isManaged) {
//
if (mbIsConnected) {
int jitterTime = ((int) Math.pow(2, snapshot.mRetryCount)) + (Math.abs(new Random(System.currentTimeMillis()).nextInt()) % RETRY_JITTER_MS);
isManaged = snapshot.resendEventAfter((matrixRetryTimeout > 0) ? matrixRetryTimeout : jitterTime);
}
}
}
}
}
if (!isManaged) {
Log.d(LOG_TAG, "Cannot resend it");
triggerErrorCallback(mDataHandler, eventDescription, response, exception, apiCallback);
}
}
use of org.matrix.androidsdk.core.model.MatrixError in project matrix-android-sdk by matrix-org.
the class CryptoTest method test07_testAliceAndBobInAEncryptedRoom.
@Test
public void test07_testAliceAndBobInAEncryptedRoom() throws Exception {
Log.e(LOG_TAG, "test07_testAliceAndBobInAEncryptedRoom");
Context context = InstrumentationRegistry.getContext();
final Map<String, Object> results = new HashMap<>();
CryptoTestData cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true);
final MXSession aliceSession = cryptoTestData.getFirstSession();
final String aliceRoomId = cryptoTestData.getRoomId();
final MXSession bobSession = cryptoTestData.getSecondSession();
final String messageFromAlice = "Hello I'm Alice!";
Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId);
Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId);
Assert.assertTrue(roomFromBobPOV.isEncrypted());
Assert.assertTrue(roomFromAlicePOV.isEncrypted());
CountDownLatch lock1 = new CountDownLatch(1);
roomFromAlicePOV.sendEvent(mCryptoTestHelper.buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new TestApiCallback<Void>(lock1, false) {
@Override
public void onMatrixError(MatrixError e) {
results.put("sendEventError", e);
super.onMatrixError(e);
}
});
mTestHelper.await(lock1);
Assert.assertTrue(results.containsKey("sendEventError"));
MXCryptoError error = (MXCryptoError) results.get("sendEventError");
Assert.assertEquals(MXCryptoError.UNKNOWN_DEVICES_CODE, error.errcode);
MXUsersDevicesMap<MXDeviceInfo> unknownDevices = (MXUsersDevicesMap<MXDeviceInfo>) error.mExceptionData;
List<String> deviceInfos = unknownDevices.getUserDeviceIds(bobSession.getMyUserId());
Assert.assertEquals(1, deviceInfos.size());
Assert.assertEquals(deviceInfos.get(0), bobSession.getCrypto().getMyDevice().deviceId);
CountDownLatch lock2 = new CountDownLatch(1);
aliceSession.getCrypto().setDevicesKnown(Arrays.asList(bobSession.getCrypto().getMyDevice()), new TestApiCallback<Void>(lock2) {
@Override
public void onSuccess(Void info) {
results.put("setDevicesKnown", "setDevicesKnown");
super.onSuccess(info);
}
});
mTestHelper.await(lock2);
Assert.assertTrue(results.containsKey("setDevicesKnown"));
final CountDownLatch lock3 = new CountDownLatch(3);
MXEventListener eventListener = new MXEventListener() {
@Override
public void onLiveEvent(Event event, RoomState roomState) {
if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) {
mCryptoTestHelper.checkEncryptedEvent(event, aliceRoomId, messageFromAlice, aliceSession);
results.put("onLiveEvent", "onLiveEvent");
lock3.countDown();
}
}
};
bobSession.getDataHandler().addListener(new MXEventListener() {
@Override
public void onToDeviceEvent(Event event) {
results.put("onToDeviceEvent", event);
lock3.countDown();
}
});
roomFromBobPOV.addEventListener(eventListener);
roomFromAlicePOV.sendEvent(mCryptoTestHelper.buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new TestApiCallback<Void>(lock3));
mTestHelper.await(lock3);
Assert.assertTrue(results.containsKey("onToDeviceEvent"));
Assert.assertTrue(results.containsKey("onLiveEvent"));
Assert.assertEquals(MXDeviceList.TRACKING_STATUS_UP_TO_DATE, bobSession.getCrypto().getDeviceTrackingStatus(bobSession.getMyUserId()));
Assert.assertEquals(MXDeviceList.TRACKING_STATUS_UP_TO_DATE, bobSession.getCrypto().getDeviceTrackingStatus(aliceSession.getMyUserId()));
Assert.assertEquals(MXDeviceList.TRACKING_STATUS_UP_TO_DATE, aliceSession.getCrypto().getDeviceTrackingStatus(bobSession.getMyUserId()));
Assert.assertEquals(MXDeviceList.TRACKING_STATUS_UP_TO_DATE, aliceSession.getCrypto().getDeviceTrackingStatus(aliceSession.getMyUserId()));
cryptoTestData.clear(context);
}
use of org.matrix.androidsdk.core.model.MatrixError in project matrix-android-sdk by matrix-org.
the class MXDataHandler method manageResponse.
/**
* Manage the sync response in a background thread.
*
* @param syncResponse the syncResponse to manage.
* @param fromToken the start sync token
* @param isCatchingUp true when there is a pending catch-up
*/
private void manageResponse(final SyncResponse syncResponse, final String fromToken, final boolean isCatchingUp) {
if (!isAlive()) {
Log.e(LOG_TAG, "manageResponse : ignored because the session has been closed");
return;
}
boolean isInitialSync = (null == fromToken);
boolean isEmptyResponse = true;
// sanity check
if (null != syncResponse) {
Log.d(LOG_TAG, "onSyncComplete");
// to ensure to decrypt them properly
if ((null != syncResponse.toDevice) && (null != syncResponse.toDevice.events) && (syncResponse.toDevice.events.size() > 0)) {
Log.d(LOG_TAG, "manageResponse : receives " + syncResponse.toDevice.events.size() + " toDevice events");
for (Event toDeviceEvent : syncResponse.toDevice.events) {
handleToDeviceEvent(toDeviceEvent);
}
}
// to be able to update direct chats dictionary during invites handling.
if (syncResponse.accountData != null && syncResponse.accountData.accountDataElements != null && !syncResponse.accountData.accountDataElements.isEmpty()) {
Log.d(LOG_TAG, "Received " + syncResponse.accountData.accountDataElements.size() + " accountData events");
manageAccountData(syncResponse.accountData.accountDataElements, isInitialSync);
// Global management, to be sure to handle any account data
getStore().storeAccountData(syncResponse.accountData);
for (AccountDataElement accountDataElement : syncResponse.accountData.accountDataElements) {
mMxEventDispatcher.dispatchOnAccountDataUpdate(accountDataElement);
}
}
// sanity check
if (null != syncResponse.rooms) {
// joined rooms events
if ((null != syncResponse.rooms.join) && (syncResponse.rooms.join.size() > 0)) {
Log.d(LOG_TAG, "Received " + syncResponse.rooms.join.size() + " joined rooms");
if (mMetricsListener != null) {
mMetricsListener.onRoomsLoaded(syncResponse.rooms.join.size());
}
Set<String> roomIds = syncResponse.rooms.join.keySet();
// Handle first joined rooms
for (String roomId : roomIds) {
try {
if (null != mLeftRoomsStore.getRoom(roomId)) {
Log.d(LOG_TAG, "the room " + roomId + " moves from left to the joined ones");
mLeftRoomsStore.deleteRoom(roomId);
}
getRoom(roomId).handleJoinedRoomSync(syncResponse.rooms.join.get(roomId), isInitialSync);
} catch (Exception e) {
Log.e(LOG_TAG, "## manageResponse() : handleJoinedRoomSync failed " + e.getMessage() + " for room " + roomId, e);
}
}
isEmptyResponse = false;
}
// invited room management
if ((null != syncResponse.rooms.invite) && (syncResponse.rooms.invite.size() > 0)) {
Log.d(LOG_TAG, "Received " + syncResponse.rooms.invite.size() + " invited rooms");
Set<String> roomIds = syncResponse.rooms.invite.keySet();
Map<String, List<String>> updatedDirectChatRoomsDict = null;
boolean hasChanged = false;
for (String roomId : roomIds) {
try {
Log.d(LOG_TAG, "## manageResponse() : the user has been invited to " + roomId);
if (null != mLeftRoomsStore.getRoom(roomId)) {
Log.d(LOG_TAG, "the room " + roomId + " moves from left to the invited ones");
mLeftRoomsStore.deleteRoom(roomId);
}
Room room = getRoom(roomId);
InvitedRoomSync invitedRoomSync = syncResponse.rooms.invite.get(roomId);
room.handleInvitedRoomSync(invitedRoomSync);
// Handle here the invites to a direct chat.
if (room.isDirectChatInvitation()) {
// Retrieve the inviter user id.
String participantUserId = null;
for (Event event : invitedRoomSync.inviteState.events) {
if (null != event.sender) {
participantUserId = event.sender;
break;
}
}
if (null != participantUserId) {
// Prepare the updated dictionary.
if (null == updatedDirectChatRoomsDict) {
if (null != getStore().getDirectChatRoomsDict()) {
// Consider the current dictionary.
updatedDirectChatRoomsDict = new HashMap<>(getStore().getDirectChatRoomsDict());
} else {
updatedDirectChatRoomsDict = new HashMap<>();
}
}
List<String> roomIdsList;
if (updatedDirectChatRoomsDict.containsKey(participantUserId)) {
roomIdsList = new ArrayList<>(updatedDirectChatRoomsDict.get(participantUserId));
} else {
roomIdsList = new ArrayList<>();
}
// Check whether the room was not yet seen as direct chat
if (roomIdsList.indexOf(roomId) < 0) {
Log.d(LOG_TAG, "## manageResponse() : add this new invite in direct chats");
// update room list with the new room
roomIdsList.add(roomId);
updatedDirectChatRoomsDict.put(participantUserId, roomIdsList);
hasChanged = true;
}
}
}
} catch (Exception e) {
Log.e(LOG_TAG, "## manageResponse() : handleInvitedRoomSync failed " + e.getMessage() + " for room " + roomId, e);
}
}
isEmptyResponse = false;
if (hasChanged) {
// Update account data to add new direct chat room(s)
mAccountDataRestClient.setAccountData(mCredentials.userId, AccountDataElement.ACCOUNT_DATA_TYPE_DIRECT_MESSAGES, updatedDirectChatRoomsDict, new ApiCallback<Void>() {
@Override
public void onSuccess(Void info) {
Log.d(LOG_TAG, "## manageResponse() : succeeds");
}
@Override
public void onNetworkError(Exception e) {
Log.e(LOG_TAG, "## manageResponse() : update account data failed " + e.getMessage(), e);
// TODO: we should try again.
}
@Override
public void onMatrixError(MatrixError e) {
Log.e(LOG_TAG, "## manageResponse() : update account data failed " + e.getMessage());
}
@Override
public void onUnexpectedError(Exception e) {
Log.e(LOG_TAG, "## manageResponse() : update account data failed " + e.getMessage(), e);
}
});
}
}
// when inviting after leaving a room, the room is defined in the both leave & invite rooms list.
if ((null != syncResponse.rooms.leave) && (syncResponse.rooms.leave.size() > 0)) {
Log.d(LOG_TAG, "Received " + syncResponse.rooms.leave.size() + " left rooms");
Set<String> roomIds = syncResponse.rooms.leave.keySet();
for (String roomId : roomIds) {
// RoomSync leftRoomSync = syncResponse.rooms.leave.get(roomId);
// Presently we remove the existing room from the rooms list.
// FIXME SYNC V2 Archive/Display the left rooms!
// For that create 'handleArchivedRoomSync' method
String membership = RoomMember.MEMBERSHIP_LEAVE;
Room room = getRoom(roomId);
// check if the room still exists.
if (null != room) {
// use 'handleJoinedRoomSync' to pass the last events to the room before leaving it.
// The room will then be able to notify its listeners.
room.handleJoinedRoomSync(syncResponse.rooms.leave.get(roomId), isInitialSync);
RoomMember member = room.getMember(getUserId());
if (null != member) {
membership = member.membership;
}
Log.d(LOG_TAG, "## manageResponse() : leave the room " + roomId);
}
if (!TextUtils.equals(membership, RoomMember.MEMBERSHIP_KICK) && !TextUtils.equals(membership, RoomMember.MEMBERSHIP_BAN)) {
// ensure that the room data are properly deleted
getStore().deleteRoom(roomId);
onLeaveRoom(roomId);
} else {
onRoomKick(roomId);
}
// don't add to the left rooms if the user has been kicked / banned
if ((mAreLeftRoomsSynced) && TextUtils.equals(membership, RoomMember.MEMBERSHIP_LEAVE)) {
Room leftRoom = getRoom(mLeftRoomsStore, roomId, true);
leftRoom.handleJoinedRoomSync(syncResponse.rooms.leave.get(roomId), isInitialSync);
}
}
isEmptyResponse = false;
}
}
// groups
if (null != syncResponse.groups) {
// Handle invited groups
if ((null != syncResponse.groups.invite) && !syncResponse.groups.invite.isEmpty()) {
// Handle invited groups
for (String groupId : syncResponse.groups.invite.keySet()) {
InvitedGroupSync invitedGroupSync = syncResponse.groups.invite.get(groupId);
mGroupsManager.onNewGroupInvitation(groupId, invitedGroupSync.profile, invitedGroupSync.inviter, !isInitialSync);
}
}
// Handle joined groups
if ((null != syncResponse.groups.join) && !syncResponse.groups.join.isEmpty()) {
for (String groupId : syncResponse.groups.join.keySet()) {
mGroupsManager.onJoinGroup(groupId, !isInitialSync);
}
}
// Handle left groups
if ((null != syncResponse.groups.leave) && !syncResponse.groups.leave.isEmpty()) {
// Handle joined groups
for (String groupId : syncResponse.groups.leave.keySet()) {
mGroupsManager.onLeaveGroup(groupId, !isInitialSync);
}
}
}
// Handle presence of other users
if ((null != syncResponse.presence) && (null != syncResponse.presence.events)) {
Log.d(LOG_TAG, "Received " + syncResponse.presence.events.size() + " presence events");
for (Event presenceEvent : syncResponse.presence.events) {
handlePresenceEvent(presenceEvent);
}
}
if (null != mCrypto) {
mCrypto.onSyncCompleted(syncResponse, fromToken, isCatchingUp);
}
IMXStore store = getStore();
if (!isEmptyResponse && (null != store)) {
store.setEventStreamToken(syncResponse.nextBatch);
store.commit();
}
}
if (isInitialSync) {
if (!isCatchingUp) {
startCrypto(true);
} else {
// the events thread sends a dummy initial sync event
// when the application is restarted.
mIsStartingCryptoWithInitialSync = !isEmptyResponse;
}
onInitialSyncComplete((null != syncResponse) ? syncResponse.nextBatch : null);
} else {
if (!isCatchingUp) {
startCrypto(mIsStartingCryptoWithInitialSync);
}
try {
onLiveEventsChunkProcessed(fromToken, (null != syncResponse) ? syncResponse.nextBatch : fromToken);
} catch (Exception e) {
Log.e(LOG_TAG, "onLiveEventsChunkProcessed failed " + e.getMessage(), e);
}
try {
// check if an incoming call has been received
mCallsManager.checkPendingIncomingCalls();
} catch (Exception e) {
Log.e(LOG_TAG, "checkPendingIncomingCalls failed " + e + " " + e.getMessage(), e);
}
}
}
use of org.matrix.androidsdk.core.model.MatrixError in project matrix-android-sdk by matrix-org.
the class MXCallsManager method refreshTurnServer.
/**
* Refresh the turn servers.
*/
private void refreshTurnServer() {
if (mSuspendTurnServerRefresh) {
return;
}
Log.d(LOG_TAG, "## refreshTurnServer () starts");
mUIThreadHandler.post(() -> mCallResClient.getTurnServer(new ApiCallback<JsonObject>() {
private void restartAfter(int msDelay) {
// "ttl" seems invalid
if (msDelay <= 0) {
Log.e(LOG_TAG, "## refreshTurnServer() : invalid delay " + msDelay);
} else {
if (null != mTurnServerTimer) {
mTurnServerTimer.cancel();
}
try {
mTurnServerTimer = new Timer();
mTurnServerTimer.schedule(new TimerTask() {
@Override
public void run() {
if (mTurnServerTimer != null) {
mTurnServerTimer.cancel();
mTurnServerTimer = null;
}
refreshTurnServer();
}
}, msDelay);
} catch (Throwable e) {
Log.e(LOG_TAG, "## refreshTurnServer() failed to start the timer", e);
if (null != mTurnServerTimer) {
mTurnServerTimer.cancel();
mTurnServerTimer = null;
}
refreshTurnServer();
}
}
}
@Override
public void onSuccess(JsonObject info) {
// privacy
Log.d(LOG_TAG, "## refreshTurnServer () : onSuccess");
if (null != info) {
if (info.has("uris")) {
synchronized (LOG_TAG) {
mTurnServer = info;
}
}
if (info.has("ttl")) {
int ttl = 60000;
try {
ttl = info.get("ttl").getAsInt();
// restart a 90 % before ttl expires
ttl = ttl * 9 / 10;
} catch (Exception e) {
Log.e(LOG_TAG, "Fail to retrieve ttl " + e.getMessage(), e);
}
Log.d(LOG_TAG, "## refreshTurnServer () : onSuccess : retry after " + ttl + " seconds");
restartAfter(ttl * 1000);
}
}
}
@Override
public void onNetworkError(Exception e) {
Log.e(LOG_TAG, "## refreshTurnServer () : onNetworkError", e);
restartAfter(60000);
}
@Override
public void onMatrixError(MatrixError e) {
Log.e(LOG_TAG, "## refreshTurnServer () : onMatrixError() : " + e.errcode);
if (TextUtils.equals(e.errcode, MatrixError.LIMIT_EXCEEDED) && (null != e.retry_after_ms)) {
Log.e(LOG_TAG, "## refreshTurnServer () : onMatrixError() : retry after " + e.retry_after_ms + " ms");
restartAfter(e.retry_after_ms);
}
}
@Override
public void onUnexpectedError(Exception e) {
// should never happen
Log.e(LOG_TAG, "## refreshTurnServer () : onUnexpectedError()", e);
}
}));
}
Aggregations