From df78a6831c8299e8f1e10ba84afaa6cdbd4dc0a2 Mon Sep 17 00:00:00 2001
From: Diego Mello <diegolmello@gmail.com>
Date: Mon, 25 Feb 2019 13:23:17 -0300
Subject: [PATCH] [FIX] Handle database errors properly (#650)

---
 app/containers/MessageBox/index.js     |  6 ++-
 app/lib/methods/getCustomEmojis.js     | 17 ++++++--
 app/lib/methods/getSettings.js         | 12 +++++-
 app/lib/methods/loadMessagesForRoom.js |  6 ++-
 app/lib/methods/loadMissedMessages.js  | 22 +++++++---
 app/lib/methods/sendFileMessage.js     | 25 +++++++++--
 app/lib/methods/subscriptions/rooms.js | 58 ++++++++++++++++++--------
 app/lib/rocketchat.js                  | 18 +++++---
 8 files changed, 124 insertions(+), 40 deletions(-)

diff --git a/app/containers/MessageBox/index.js b/app/containers/MessageBox/index.js
index 1d8392fa1..9ecba3a00 100644
--- a/app/containers/MessageBox/index.js
+++ b/app/containers/MessageBox/index.js
@@ -353,7 +353,11 @@ export default class MessageBox extends Component {
 			if (results.users && results.users.length) {
 				database.write(() => {
 					results.users.forEach((user) => {
-						database.create('users', user, true);
+						try {
+							database.create('users', user, true);
+						} catch (e) {
+							log('create users', e);
+						}
 					});
 				});
 			}
diff --git a/app/lib/methods/getCustomEmojis.js b/app/lib/methods/getCustomEmojis.js
index 2fbbf46d9..adcb2e83c 100644
--- a/app/lib/methods/getCustomEmojis.js
+++ b/app/lib/methods/getCustomEmojis.js
@@ -18,10 +18,21 @@ export default async function() {
 		const result = await this.sdk.get('emoji-custom');
 		let { emojis } = result;
 		emojis = emojis.filter(emoji => !lastMessage || emoji._updatedAt > lastMessage);
+		if (emojis.length === 0) {
+			return;
+		}
 		emojis = this._prepareEmojis(emojis);
-		InteractionManager.runAfterInteractions(() => database.write(() => {
-			emojis.forEach(emoji => database.create('customEmojis', emoji, true));
-		}));
+		InteractionManager.runAfterInteractions(() => {
+			database.write(() => {
+				emojis.forEach((emoji) => {
+					try {
+						database.create('customEmojis', emoji, true);
+					} catch (e) {
+						log('create custom emojis', e);
+					}
+				});
+			});
+		});
 		reduxStore.dispatch(actions.setCustomEmojis(this.parseEmojis(emojis)));
 	} catch (e) {
 		log('getCustomEmojis', e);
diff --git a/app/lib/methods/getSettings.js b/app/lib/methods/getSettings.js
index 8a74271ed..2b0f5f2a1 100644
--- a/app/lib/methods/getSettings.js
+++ b/app/lib/methods/getSettings.js
@@ -8,7 +8,11 @@ import settings from '../../constants/settings';
 
 function updateServer(param) {
 	database.databases.serversDB.write(() => {
-		database.databases.serversDB.create('servers', { id: reduxStore.getState().server.server, ...param }, true);
+		try {
+			database.databases.serversDB.create('servers', { id: reduxStore.getState().server.server, ...param }, true);
+		} catch (e) {
+			log('updateServer', e);
+		}
 	});
 }
 
@@ -27,7 +31,11 @@ export default async function() {
 		InteractionManager.runAfterInteractions(
 			() => database.write(
 				() => filteredSettings.forEach((setting) => {
-					database.create('settings', { ...setting, _updatedAt: new Date() }, true);
+					try {
+						database.create('settings', { ...setting, _updatedAt: new Date() }, true);
+					} catch (e) {
+						log('create settings', e);
+					}
 
 					if (setting._id === 'Site_Name') {
 						updateServer.call(this, { name: setting.valueAsString });
diff --git a/app/lib/methods/loadMessagesForRoom.js b/app/lib/methods/loadMessagesForRoom.js
index 49d231746..f49ff8f64 100644
--- a/app/lib/methods/loadMessagesForRoom.js
+++ b/app/lib/methods/loadMessagesForRoom.js
@@ -39,7 +39,11 @@ export default function loadMessagesForRoom(...args) {
 			if (data && data.length) {
 				InteractionManager.runAfterInteractions(() => {
 					database.write(() => data.forEach((message) => {
-						database.create('messages', buildMessage(message), true);
+						try {
+							database.create('messages', buildMessage(message), true);
+						} catch (e) {
+							log('loadMessagesForRoom -> create messages', e);
+						}
 					}));
 					return resolve(data);
 				});
diff --git a/app/lib/methods/loadMissedMessages.js b/app/lib/methods/loadMissedMessages.js
index 0769f384c..806074815 100644
--- a/app/lib/methods/loadMissedMessages.js
+++ b/app/lib/methods/loadMissedMessages.js
@@ -33,19 +33,29 @@ export default function loadMissedMessages(...args) {
 					const { updated } = data;
 					updated.forEach(buildMessage);
 					InteractionManager.runAfterInteractions(() => {
-						database.write(() => updated.forEach(message => database.create('messages', message, true)));
+						database.write(() => updated.forEach((message) => {
+							try {
+								database.create('messages', message, true);
+							} catch (e) {
+								log('loadMissedMessages -> create messages', e);
+							}
+						}));
 						resolve(updated);
 					});
 				}
 				if (data.deleted && data.deleted.length) {
 					const { deleted } = data;
 					InteractionManager.runAfterInteractions(() => {
-						database.write(() => {
-							deleted.forEach((m) => {
-								const message = database.objects('messages').filtered('_id = $0', m._id);
-								database.delete(message);
+						try {
+							database.write(() => {
+								deleted.forEach((m) => {
+									const message = database.objects('messages').filtered('_id = $0', m._id);
+									database.delete(message);
+								});
 							});
-						});
+						} catch (e) {
+							log('loadMissedMessages -> delete message', e);
+						}
 					});
 				}
 			}
diff --git a/app/lib/methods/sendFileMessage.js b/app/lib/methods/sendFileMessage.js
index ecd0ced36..11621a6a4 100644
--- a/app/lib/methods/sendFileMessage.js
+++ b/app/lib/methods/sendFileMessage.js
@@ -2,6 +2,7 @@ import RNFetchBlob from 'rn-fetch-blob';
 
 import reduxStore from '../createStore';
 import database from '../realm';
+import log from '../../utils/log';
 
 const promises = {};
 
@@ -47,7 +48,11 @@ export async function sendFileMessage(rid, fileInfo) {
 		fileInfo.rid = rid;
 
 		database.write(() => {
-			database.create('uploads', fileInfo, true);
+			try {
+				database.create('uploads', fileInfo, true);
+			} catch (e) {
+				log('sendFileMessage -> create uploads 1', e);
+			}
 		});
 
 		const result = await _ufsCreate.call(this, fileInfo);
@@ -60,7 +65,11 @@ export async function sendFileMessage(rid, fileInfo) {
 			promises[fileInfo.path].uploadProgress((loaded, total) => {
 				database.write(() => {
 					fileInfo.progress = Math.floor((loaded / total) * 100);
-					database.create('uploads', fileInfo, true);
+					try {
+						database.create('uploads', fileInfo, true);
+					} catch (e) {
+						log('sendFileMessage -> create uploads 2', e);
+					}
 				});
 			});
 		});
@@ -79,12 +88,20 @@ export async function sendFileMessage(rid, fileInfo) {
 
 		database.write(() => {
 			const upload = database.objects('uploads').filtered('path = $0', fileInfo.path);
-			database.delete(upload);
+			try {
+				database.delete(upload);
+			} catch (e) {
+				log('sendFileMessage -> delete uploads', e);
+			}
 		});
 	} catch (e) {
 		database.write(() => {
 			fileInfo.error = true;
-			database.create('uploads', fileInfo, true);
+			try {
+				database.create('uploads', fileInfo, true);
+			} catch (err) {
+				log('sendFileMessage -> create uploads 3', err);
+			}
 		});
 	}
 }
diff --git a/app/lib/methods/subscriptions/rooms.js b/app/lib/methods/subscriptions/rooms.js
index f0abe7719..b02edbc41 100644
--- a/app/lib/methods/subscriptions/rooms.js
+++ b/app/lib/methods/subscriptions/rooms.js
@@ -53,30 +53,46 @@ export default async function subscribeRooms() {
 				if (subscription) {
 					messages = database.objects('messages').filtered('rid == $0', subscription.rid);
 				}
-				database.write(() => {
-					database.delete(messages);
-					database.delete(subscription);
-				});
+				try {
+					database.write(() => {
+						database.delete(messages);
+						database.delete(subscription);
+					});
+				} catch (e) {
+					log('handleStreamMessageReceived -> subscriptions removed', e);
+				}
 			} else {
 				const rooms = database.objects('rooms').filtered('_id == $0', data.rid);
 				const tpm = merge(data, rooms[0]);
-				database.write(() => {
-					database.create('subscriptions', tpm, true);
-					database.delete(rooms);
-				});
+				try {
+					database.write(() => {
+						database.create('subscriptions', tpm, true);
+						database.delete(rooms);
+					});
+				} catch (e) {
+					log('handleStreamMessageReceived -> subscriptions updated', e);
+				}
 			}
 		}
 		if (/rooms/.test(ev)) {
 			if (type === 'updated') {
 				const [sub] = database.objects('subscriptions').filtered('rid == $0', data._id);
-				database.write(() => {
-					const tmp = merge(sub, data);
-					database.create('subscriptions', tmp, true);
-				});
+				try {
+					database.write(() => {
+						const tmp = merge(sub, data);
+						database.create('subscriptions', tmp, true);
+					});
+				} catch (e) {
+					log('handleStreamMessageReceived -> rooms updated', e);
+				}
 			} else if (type === 'inserted') {
-				database.write(() => {
-					database.create('rooms', data, true);
-				});
+				try {
+					database.write(() => {
+						database.create('rooms', data, true);
+					});
+				} catch (e) {
+					log('handleStreamMessageReceived -> rooms inserted', e);
+				}
 			}
 		}
 		if (/message/.test(ev)) {
@@ -94,9 +110,15 @@ export default async function subscribeRooms() {
 					username: 'rocket.cat'
 				}
 			};
-			requestAnimationFrame(() => database.write(() => {
-				database.create('messages', message, true);
-			}));
+			requestAnimationFrame(() => {
+				try {
+					database.write(() => {
+						database.create('messages', message, true);
+					});
+				} catch (e) {
+					log('handleStreamMessageReceived -> message', e);
+				}
+			});
 		}
 	});
 
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index fbb73eafc..93e18f18c 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -246,7 +246,11 @@ const RocketChat = {
 
 				database.write(() => {
 					foreach(this.roles, (description, _id) => {
-						database.create('roles', { _id, description }, true);
+						try {
+							database.create('roles', { _id, description }, true);
+						} catch (e) {
+							log('create roles', e);
+						}
 					});
 				});
 
@@ -408,10 +412,14 @@ const RocketChat = {
 			});
 			await sendMessageCall.call(this, JSON.parse(JSON.stringify(message)));
 		} catch (error) {
-			database.write(() => {
-				message.status = messagesStatus.ERROR;
-				database.create('messages', message, true);
-			});
+			try {
+				database.write(() => {
+					message.status = messagesStatus.ERROR;
+					database.create('messages', message, true);
+				});
+			} catch (e) {
+				log('resendMessage error', e);
+			}
 		}
 	},
 
-- 
GitLab