Refactor get_last_conversation_lines()
- use NATURAL JOIN in SQL query instead of multiple SELECT via _build_contact_where - make code more concise - update method documentation
This commit is contained in:
		
							parent
							
								
									5e63461e6d
								
							
						
					
					
						commit
						40ba449f47
					
				
					 2 changed files with 74 additions and 34 deletions
				
			
		|  | @ -1411,14 +1411,14 @@ class ChatControl(ChatControlBase): | |||
| 
 | ||||
|         # number of messages that are in queue and are already logged, we want | ||||
|         # to avoid duplication | ||||
|         pending_how_many = len(gajim.events.get_events(self.account, jid, | ||||
|         pending = len(gajim.events.get_events(self.account, jid, | ||||
|                 ['chat', 'pm'])) | ||||
|         if self.resource: | ||||
|             pending_how_many += len(gajim.events.get_events(self.account, | ||||
|             pending += len(gajim.events.get_events(self.account, | ||||
|                     self.contact.get_full_jid(), ['chat', 'pm'])) | ||||
| 
 | ||||
|         rows = gajim.logger.get_last_conversation_lines( | ||||
|             jid, pending_how_many, self.account) | ||||
|             self.account, jid, pending) | ||||
| 
 | ||||
|         local_old_kind = None | ||||
|         self.conv_textview.just_cleared = True | ||||
|  |  | |||
|  | @ -68,6 +68,9 @@ class KindConstant(IntEnum): | |||
|     CHAT_MSG_SENT = 6 | ||||
|     ERROR = 7 | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return str(self.value) | ||||
| 
 | ||||
| @unique | ||||
| class ShowConstant(IntEnum): | ||||
|     ONLINE = 0 | ||||
|  | @ -160,6 +163,10 @@ class Logger: | |||
|                 isolation_level='IMMEDIATE') | ||||
|         os.chdir(back) | ||||
|         self.con.row_factory = self.namedtuple_factory | ||||
| 
 | ||||
|         # DB functions | ||||
|         self.con.create_function("get_timeout", 0, self._get_timeout) | ||||
| 
 | ||||
|         self.cur = self.con.cursor() | ||||
|         self.set_synchronous(False) | ||||
| 
 | ||||
|  | @ -183,6 +190,18 @@ class Logger: | |||
|         self.open_db() | ||||
|         self.get_jids_already_in_db() | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def _get_timeout(): | ||||
|         """ | ||||
|         returns the timeout in epoch | ||||
|         """ | ||||
|         timeout = gajim.config.get('restore_timeout') | ||||
| 
 | ||||
|         now = int(time.time()) | ||||
|         if timeout > 0: | ||||
|             timeout = now - (timeout * 60) | ||||
|         return timeout | ||||
| 
 | ||||
|     def commit(self): | ||||
|         try: | ||||
|             self.con.commit() | ||||
|  | @ -249,6 +268,22 @@ class Logger: | |||
|                 return True | ||||
|             return False | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def _get_family_jids(account, jid): | ||||
|         """ | ||||
|         Get all jids of the metacontacts family | ||||
| 
 | ||||
|         :param account: The account | ||||
| 
 | ||||
|         :param jid:     The JID | ||||
| 
 | ||||
|         returns a list of JIDs' | ||||
|         """ | ||||
|         family = gajim.contacts.get_metacontacts_family(account, jid) | ||||
|         if family: | ||||
|             return [user['jid'] for user in family] | ||||
|         return [jid] | ||||
| 
 | ||||
|     def get_jid_id(self, jid, typestr=None): | ||||
|         """ | ||||
|         jids table has jid and jid_id logs table has log_id, jid_id, | ||||
|  | @ -593,44 +628,49 @@ class Logger: | |||
|                 exceptions.PysqliteOperationalError) as error: | ||||
|             self.dispatch('DB_ERROR', error) | ||||
| 
 | ||||
|     def get_last_conversation_lines(self, jid, pending_how_many, account): | ||||
|     def get_last_conversation_lines(self, account, jid, pending): | ||||
|         """ | ||||
|         Accept how many rows to restore and when to time them out (in minutes) | ||||
|         (mark them as too old) and number of messages that are in queue and are | ||||
|         already logged but pending to be viewed, returns a list of tuples | ||||
|         containg time, kind, message, subject list with empty tuple if nothing | ||||
|         found to meet our demands | ||||
|         Get recent messages | ||||
| 
 | ||||
|         Pending messages are already in queue to be printed when the | ||||
|         ChatControl is opened, so we dont want to request those messages. | ||||
|         How many messages are requested depends on the 'restore_lines' | ||||
|         config value. How far back in time messages are requested depends on | ||||
|         _get_timeout(). | ||||
| 
 | ||||
|         :param account: The account | ||||
| 
 | ||||
|         :param jid:     The jid from which we request the conversation lines | ||||
| 
 | ||||
|         :param pending: How many messages are currently pending so we dont | ||||
|                         request those messages | ||||
| 
 | ||||
|         returns a list of namedtuples | ||||
|         """ | ||||
|         try: | ||||
|             self.get_jid_id(jid) | ||||
|         except exceptions.PysqliteOperationalError: | ||||
|             # Error trying to create a new jid_id. This means there is no log | ||||
| 
 | ||||
|         restore = gajim.config.get('restore_lines') | ||||
|         if restore <= 0: | ||||
|             return [] | ||||
|         where_sql, jid_tuple = self._build_contact_where(account, jid) | ||||
| 
 | ||||
|         # How many lines to restore and when to time them out | ||||
|         restore_how_many = gajim.config.get('restore_lines') | ||||
|         if restore_how_many <= 0: | ||||
|             return [] | ||||
|         timeout = gajim.config.get('restore_timeout')  # in minutes | ||||
|         kinds = map(str, [KindConstant.SINGLE_MSG_RECV, | ||||
|                           KindConstant.SINGLE_MSG_SENT, | ||||
|                           KindConstant.CHAT_MSG_RECV, | ||||
|                           KindConstant.CHAT_MSG_SENT, | ||||
|                           KindConstant.ERROR]) | ||||
| 
 | ||||
|         now = int(float(time.time())) | ||||
|         if timeout > 0: | ||||
|             timeout = now - (timeout * 60) # before that they are too old | ||||
|         jids = self._get_family_jids(account, jid) | ||||
| 
 | ||||
|         sql = ''' | ||||
|             SELECT time, kind, message, subject, additional_data | ||||
|             FROM logs NATURAL JOIN jids WHERE jid IN ({jids}) AND | ||||
|             kind IN ({kinds}) AND time > get_timeout() | ||||
|             ORDER BY time DESC, log_line_id DESC LIMIT ? OFFSET ? | ||||
|             '''.format(jids=', '.join('?' * len(jids)), | ||||
|                        kinds=', '.join(kinds)) | ||||
| 
 | ||||
|         # so if we ask last 5 lines and we have 2 pending we get | ||||
|         # 3 - 8 (we avoid the last 2 lines but we still return 5 asked) | ||||
|         try: | ||||
|             self.cur.execute(''' | ||||
|                 SELECT time, kind, message, subject, additional_data FROM logs | ||||
|                 WHERE (%s) AND kind IN (%d, %d, %d, %d, %d) AND time > %d | ||||
|                 ORDER BY time DESC LIMIT %d OFFSET %d | ||||
|                 ''' % (where_sql, KindConstant.SINGLE_MSG_RECV, | ||||
|                 KindConstant.CHAT_MSG_RECV, KindConstant.SINGLE_MSG_SENT, | ||||
|                 KindConstant.CHAT_MSG_SENT, KindConstant.ERROR, timeout, | ||||
|                 restore_how_many, pending_how_many), jid_tuple) | ||||
| 
 | ||||
|             messages = self.cur.fetchall() | ||||
|             messages = self.con.execute( | ||||
|                 sql, (*jids, restore, pending)).fetchall() | ||||
|         except sqlite.DatabaseError: | ||||
|             self.dispatch('DB_ERROR', | ||||
|                           exceptions.DatabaseMalformed(LOG_DB_PATH)) | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue