|
1
|
1
|
# -*- coding:utf-8 -*-
|
|
2
|
|
-## src/common/logger.py
|
|
|
2
|
+## gajim/common/logger.py
|
|
3
|
3
|
##
|
|
4
|
4
|
## Copyright (C) 2003-2014 Yann Leboulanger <asterix AT lagaule.org>
|
|
5
|
5
|
## Copyright (C) 2004-2005 Vincent Hanquez <tab AT snarc.org>
|
| ... |
... |
@@ -8,6 +8,7 @@ |
|
8
|
8
|
## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
|
|
9
|
9
|
## Copyright (C) 2007 Tomasz Melcer <liori AT exroot.org>
|
|
10
|
10
|
## Julien Pivotto <roidelapluie AT gmail.com>
|
|
|
11
|
+## Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
|
|
11
|
12
|
##
|
|
12
|
13
|
## This file is part of Gajim.
|
|
13
|
14
|
##
|
| ... |
... |
@@ -34,11 +35,12 @@ import time |
|
34
|
35
|
import datetime
|
|
35
|
36
|
import calendar
|
|
36
|
37
|
import json
|
|
|
38
|
+import logging
|
|
|
39
|
+import sqlite3 as sqlite
|
|
37
|
40
|
from collections import namedtuple
|
|
38
|
41
|
from gzip import GzipFile
|
|
39
|
42
|
from io import BytesIO
|
|
40
|
43
|
from gi.repository import GLib
|
|
41
|
|
-from enum import IntEnum, unique
|
|
42
|
44
|
|
|
43
|
45
|
from gajim.common import exceptions
|
|
44
|
46
|
from gajim.common import app
|
| ... |
... |
@@ -47,152 +49,206 @@ from gajim.common.const import ( |
|
47
|
49
|
JIDConstant, KindConstant, ShowConstant, TypeConstant,
|
|
48
|
50
|
SubscriptionConstant)
|
|
49
|
51
|
|
|
50
|
|
-import sqlite3 as sqlite
|
|
51
|
|
-
|
|
52
|
52
|
LOG_DB_PATH = configpaths.get('LOG_DB')
|
|
53
|
53
|
LOG_DB_FOLDER, LOG_DB_FILE = os.path.split(LOG_DB_PATH)
|
|
54
|
54
|
CACHE_DB_PATH = configpaths.get('CACHE_DB')
|
|
55
|
55
|
|
|
56
|
|
-import logging
|
|
|
56
|
+LOGS_SQL_STATEMENT = '''
|
|
|
57
|
+ CREATE TABLE jids(
|
|
|
58
|
+ jid_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
|
59
|
+ jid TEXT UNIQUE,
|
|
|
60
|
+ type INTEGER
|
|
|
61
|
+ );
|
|
|
62
|
+ CREATE TABLE unread_messages(
|
|
|
63
|
+ message_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
|
64
|
+ jid_id INTEGER,
|
|
|
65
|
+ shown BOOLEAN default 0
|
|
|
66
|
+ );
|
|
|
67
|
+ CREATE INDEX idx_unread_messages_jid_id ON unread_messages (jid_id);
|
|
|
68
|
+ CREATE TABLE logs(
|
|
|
69
|
+ log_line_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
|
70
|
+ account_id INTEGER,
|
|
|
71
|
+ jid_id INTEGER,
|
|
|
72
|
+ contact_name TEXT,
|
|
|
73
|
+ time INTEGER,
|
|
|
74
|
+ kind INTEGER,
|
|
|
75
|
+ show INTEGER,
|
|
|
76
|
+ message TEXT,
|
|
|
77
|
+ subject TEXT,
|
|
|
78
|
+ additional_data TEXT,
|
|
|
79
|
+ stanza_id TEXT,
|
|
|
80
|
+ encryption TEXT,
|
|
|
81
|
+ encryption_state TEXT,
|
|
|
82
|
+ marker INTEGER
|
|
|
83
|
+ );
|
|
|
84
|
+ CREATE TABLE last_archive_message(
|
|
|
85
|
+ jid_id INTEGER PRIMARY KEY UNIQUE,
|
|
|
86
|
+ last_mam_id TEXT,
|
|
|
87
|
+ oldest_mam_timestamp TEXT,
|
|
|
88
|
+ last_muc_timestamp TEXT
|
|
|
89
|
+ );
|
|
|
90
|
+ CREATE INDEX idx_logs_jid_id_time ON logs (jid_id, time DESC);
|
|
|
91
|
+ CREATE INDEX idx_logs_stanza_id ON logs (stanza_id);
|
|
|
92
|
+ PRAGMA user_version=1;
|
|
|
93
|
+ '''
|
|
|
94
|
+
|
|
|
95
|
+CACHE_SQL_STATEMENT = '''
|
|
|
96
|
+ CREATE TABLE transports_cache (
|
|
|
97
|
+ transport TEXT UNIQUE,
|
|
|
98
|
+ type INTEGER
|
|
|
99
|
+ );
|
|
|
100
|
+ CREATE TABLE caps_cache (
|
|
|
101
|
+ hash_method TEXT,
|
|
|
102
|
+ hash TEXT,
|
|
|
103
|
+ data BLOB,
|
|
|
104
|
+ last_seen INTEGER);
|
|
|
105
|
+ CREATE TABLE rooms_last_message_time(
|
|
|
106
|
+ jid_id INTEGER PRIMARY KEY UNIQUE,
|
|
|
107
|
+ time INTEGER
|
|
|
108
|
+ );
|
|
|
109
|
+ CREATE TABLE roster_entry(
|
|
|
110
|
+ account_jid_id INTEGER,
|
|
|
111
|
+ jid_id INTEGER,
|
|
|
112
|
+ name TEXT,
|
|
|
113
|
+ subscription INTEGER,
|
|
|
114
|
+ ask BOOLEAN,
|
|
|
115
|
+ avatar_sha TEXT,
|
|
|
116
|
+ PRIMARY KEY (account_jid_id, jid_id)
|
|
|
117
|
+ );
|
|
|
118
|
+ CREATE TABLE roster_group(
|
|
|
119
|
+ account_jid_id INTEGER,
|
|
|
120
|
+ jid_id INTEGER,
|
|
|
121
|
+ group_name TEXT,
|
|
|
122
|
+ PRIMARY KEY (account_jid_id, jid_id, group_name)
|
|
|
123
|
+ );
|
|
|
124
|
+ PRAGMA user_version=1;
|
|
|
125
|
+ '''
|
|
|
126
|
+
|
|
57
|
127
|
log = logging.getLogger('gajim.c.logger')
|
|
58
|
128
|
|
|
59
|
129
|
|
|
60
|
130
|
class Logger:
|
|
61
|
131
|
def __init__(self):
|
|
62
|
132
|
self._jid_ids = {}
|
|
63
|
|
- self.con = None
|
|
64
|
|
- self.commit_timout_id = None
|
|
|
133
|
+ self._con = None
|
|
|
134
|
+ self._commit_timout_id = None
|
|
|
135
|
+
|
|
|
136
|
+ self._create_databases()
|
|
|
137
|
+ self._migrate_databases()
|
|
|
138
|
+ self._connect_databases()
|
|
|
139
|
+ self._get_jid_ids_from_db()
|
|
65
|
140
|
|
|
|
141
|
+ def _create_databases(self):
|
|
66
|
142
|
if os.path.isdir(LOG_DB_PATH):
|
|
67
|
|
- print(_('%s is a directory but should be a file') % LOG_DB_PATH)
|
|
68
|
|
- print(_('Gajim will now exit'))
|
|
|
143
|
+ log.error(_('%s is a directory but should be a file'),
|
|
|
144
|
+ LOG_DB_PATH)
|
|
69
|
145
|
sys.exit()
|
|
70
|
146
|
|
|
71
|
147
|
if os.path.isdir(CACHE_DB_PATH):
|
|
72
|
|
- print(_('%s or %s is a directory but should be a file') % CACHE_DB_PATH)
|
|
73
|
|
- print(_('Gajim will now exit'))
|
|
|
148
|
+ log.error(_('%s is a directory but should be a file'),
|
|
|
149
|
+ CACHE_DB_PATH)
|
|
74
|
150
|
sys.exit()
|
|
75
|
151
|
|
|
76
|
152
|
if not os.path.exists(LOG_DB_PATH):
|
|
77
|
153
|
if os.path.exists(CACHE_DB_PATH):
|
|
78
|
154
|
os.remove(CACHE_DB_PATH)
|
|
79
|
|
- self.create_log_db()
|
|
|
155
|
+ self._create(LOGS_SQL_STATEMENT, LOG_DB_PATH)
|
|
80
|
156
|
|
|
81
|
|
- self.init_vars()
|
|
82
|
157
|
if not os.path.exists(CACHE_DB_PATH):
|
|
83
|
|
- self.create_cache_db()
|
|
84
|
|
- self.attach_cache_database()
|
|
85
|
|
-
|
|
86
|
|
- def create_log_db(self):
|
|
87
|
|
- print(_('creating logs database'))
|
|
88
|
|
- con = sqlite.connect(LOG_DB_PATH)
|
|
89
|
|
- os.chmod(LOG_DB_PATH, 0o600) # rw only for us
|
|
90
|
|
- cur = con.cursor()
|
|
91
|
|
- # create the tables
|
|
92
|
|
- # kind can be
|
|
93
|
|
- # status, gcstatus, gc_msg, (we only recv for those 3),
|
|
94
|
|
- # single_msg_recv, chat_msg_recv, chat_msg_sent, single_msg_sent
|
|
95
|
|
- # to meet all our needs
|
|
96
|
|
- # logs.jid_id --> jids.jid_id but Sqlite doesn't do FK etc so it's done in python code
|
|
97
|
|
- # jids.jid text column will be JID if TC-related, room_jid if GC-related,
|
|
98
|
|
- # ROOM_JID/nick if pm-related.
|
|
99
|
|
- # also check optparser.py, which updates databases on gajim updates
|
|
100
|
|
- cur.executescript(
|
|
101
|
|
- '''
|
|
102
|
|
- CREATE TABLE jids(
|
|
103
|
|
- jid_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
104
|
|
- jid TEXT UNIQUE,
|
|
105
|
|
- type INTEGER
|
|
106
|
|
- );
|
|
107
|
|
-
|
|
108
|
|
- CREATE TABLE unread_messages(
|
|
109
|
|
- message_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
110
|
|
- jid_id INTEGER,
|
|
111
|
|
- shown BOOLEAN default 0
|
|
112
|
|
- );
|
|
113
|
|
-
|
|
114
|
|
- CREATE INDEX idx_unread_messages_jid_id ON unread_messages (jid_id);
|
|
115
|
|
-
|
|
116
|
|
- CREATE TABLE logs(
|
|
117
|
|
- log_line_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
118
|
|
- account_id INTEGER,
|
|
119
|
|
- jid_id INTEGER,
|
|
120
|
|
- contact_name TEXT,
|
|
121
|
|
- time INTEGER,
|
|
122
|
|
- kind INTEGER,
|
|
123
|
|
- show INTEGER,
|
|
124
|
|
- message TEXT,
|
|
125
|
|
- subject TEXT,
|
|
126
|
|
- additional_data TEXT,
|
|
127
|
|
- stanza_id TEXT,
|
|
128
|
|
- encryption TEXT,
|
|
129
|
|
- encryption_state TEXT,
|
|
130
|
|
- marker INTEGER
|
|
131
|
|
- );
|
|
132
|
|
-
|
|
133
|
|
- CREATE TABLE last_archive_message(
|
|
134
|
|
- jid_id INTEGER PRIMARY KEY UNIQUE,
|
|
135
|
|
- last_mam_id TEXT,
|
|
136
|
|
- oldest_mam_timestamp TEXT,
|
|
137
|
|
- last_muc_timestamp TEXT
|
|
138
|
|
- );
|
|
139
|
|
-
|
|
140
|
|
- CREATE INDEX idx_logs_jid_id_time ON logs (jid_id, time DESC);
|
|
141
|
|
-
|
|
142
|
|
- CREATE INDEX idx_logs_stanza_id ON logs (stanza_id);
|
|
143
|
|
-
|
|
144
|
|
- '''
|
|
145
|
|
- )
|
|
|
158
|
+ self._create(CACHE_SQL_STATEMENT, CACHE_DB_PATH)
|
|
146
|
159
|
|
|
147
|
|
- con.commit()
|
|
148
|
|
- con.close()
|
|
|
160
|
+ @staticmethod
|
|
|
161
|
+ def _create(statement, path):
|
|
|
162
|
+ log.info(_('Creating %s'), path)
|
|
|
163
|
+ con = sqlite.connect(path)
|
|
|
164
|
+ os.chmod(path, 0o600)
|
|
149
|
165
|
|
|
150
|
|
- def create_cache_db(self):
|
|
151
|
|
- print(_('creating cache database'))
|
|
152
|
|
- con = sqlite.connect(CACHE_DB_PATH)
|
|
153
|
|
- os.chmod(CACHE_DB_PATH, 0o600) # rw only for us
|
|
154
|
|
- cur = con.cursor()
|
|
155
|
|
- cur.executescript(
|
|
156
|
|
- '''
|
|
157
|
|
- CREATE TABLE transports_cache (
|
|
158
|
|
- transport TEXT UNIQUE,
|
|
159
|
|
- type INTEGER
|
|
160
|
|
- );
|
|
161
|
|
-
|
|
162
|
|
- CREATE TABLE caps_cache (
|
|
163
|
|
- hash_method TEXT,
|
|
164
|
|
- hash TEXT,
|
|
165
|
|
- data BLOB,
|
|
166
|
|
- last_seen INTEGER);
|
|
167
|
|
-
|
|
168
|
|
- CREATE TABLE rooms_last_message_time(
|
|
169
|
|
- jid_id INTEGER PRIMARY KEY UNIQUE,
|
|
170
|
|
- time INTEGER
|
|
171
|
|
- );
|
|
172
|
|
-
|
|
173
|
|
- CREATE TABLE IF NOT EXISTS roster_entry(
|
|
174
|
|
- account_jid_id INTEGER,
|
|
175
|
|
- jid_id INTEGER,
|
|
176
|
|
- name TEXT,
|
|
177
|
|
- subscription INTEGER,
|
|
178
|
|
- ask BOOLEAN,
|
|
179
|
|
- avatar_sha TEXT,
|
|
180
|
|
- PRIMARY KEY (account_jid_id, jid_id)
|
|
181
|
|
- );
|
|
182
|
|
-
|
|
183
|
|
- CREATE TABLE IF NOT EXISTS roster_group(
|
|
184
|
|
- account_jid_id INTEGER,
|
|
185
|
|
- jid_id INTEGER,
|
|
186
|
|
- group_name TEXT,
|
|
187
|
|
- PRIMARY KEY (account_jid_id, jid_id, group_name)
|
|
188
|
|
- );
|
|
189
|
|
- '''
|
|
190
|
|
- )
|
|
|
166
|
+ try:
|
|
|
167
|
+ con.executescript(statement)
|
|
|
168
|
+ except Exception as error:
|
|
|
169
|
+ log.exception('Error')
|
|
|
170
|
+ con.close()
|
|
|
171
|
+ os.remove(path)
|
|
|
172
|
+ sys.exit()
|
|
191
|
173
|
|
|
192
|
174
|
con.commit()
|
|
193
|
175
|
con.close()
|
|
194
|
176
|
|
|
195
|
177
|
@staticmethod
|
|
|
178
|
+ def _get_user_version(con) -> int:
|
|
|
179
|
+ """ Return the value of PRAGMA user_version. """
|
|
|
180
|
+ return con.execute('PRAGMA user_version').fetchone()[0]
|
|
|
181
|
+
|
|
|
182
|
+ def _migrate_databases(self):
|
|
|
183
|
+ try:
|
|
|
184
|
+ con = sqlite.connect(LOG_DB_PATH)
|
|
|
185
|
+ self._migrate_logs(con)
|
|
|
186
|
+ con.close()
|
|
|
187
|
+
|
|
|
188
|
+ con = sqlite.connect(CACHE_DB_PATH)
|
|
|
189
|
+ self._migrate_cache(con)
|
|
|
190
|
+ con.close()
|
|
|
191
|
+ except Exception:
|
|
|
192
|
+ log.exception('Error')
|
|
|
193
|
+ sys.exit()
|
|
|
194
|
+
|
|
|
195
|
+ def _migrate_logs(self, con):
|
|
|
196
|
+ if self._get_user_version(con) == 0:
|
|
|
197
|
+ # All migrations from 0.16.9 until 1.0.0
|
|
|
198
|
+ statements = [
|
|
|
199
|
+ 'ALTER TABLE logs ADD COLUMN "account_id" INTEGER',
|
|
|
200
|
+ 'ALTER TABLE logs ADD COLUMN "stanza_id" TEXT',
|
|
|
201
|
+ 'ALTER TABLE logs ADD COLUMN "encryption" TEXT',
|
|
|
202
|
+ 'ALTER TABLE logs ADD COLUMN "encryption_state" TEXT',
|
|
|
203
|
+ 'ALTER TABLE logs ADD COLUMN "marker" INTEGER',
|
|
|
204
|
+ 'ALTER TABLE logs ADD COLUMN "additional_data" TEXT',
|
|
|
205
|
+ '''CREATE TABLE IF NOT EXISTS last_archive_message(
|
|
|
206
|
+ jid_id INTEGER PRIMARY KEY UNIQUE,
|
|
|
207
|
+ last_mam_id TEXT,
|
|
|
208
|
+ oldest_mam_timestamp TEXT,
|
|
|
209
|
+ last_muc_timestamp TEXT
|
|
|
210
|
+ )''',
|
|
|
211
|
+
|
|
|
212
|
+ '''CREATE INDEX IF NOT EXISTS idx_logs_stanza_id
|
|
|
213
|
+ ON logs(stanza_id)''',
|
|
|
214
|
+ 'PRAGMA user_version=1'
|
|
|
215
|
+ ]
|
|
|
216
|
+
|
|
|
217
|
+ self._execute_multiple(con, statements)
|
|
|
218
|
+
|
|
|
219
|
+ if self._get_user_version(con) < 2:
|
|
|
220
|
+ pass
|
|
|
221
|
+
|
|
|
222
|
+ def _migrate_cache(self, con):
|
|
|
223
|
+ if self._get_user_version(con) == 0:
|
|
|
224
|
+ # All migrations from 0.16.9 until 1.0.0
|
|
|
225
|
+ statements = [
|
|
|
226
|
+ 'ALTER TABLE roster_entry ADD COLUMN "avatar_sha" TEXT',
|
|
|
227
|
+ 'PRAGMA user_version=1'
|
|
|
228
|
+ ]
|
|
|
229
|
+ self._execute_multiple(con, statements)
|
|
|
230
|
+
|
|
|
231
|
+ if self._get_user_version(con) < 2:
|
|
|
232
|
+ pass
|
|
|
233
|
+
|
|
|
234
|
+ @staticmethod
|
|
|
235
|
+ def _execute_multiple(con, statements):
|
|
|
236
|
+ """
|
|
|
237
|
+ Execute mutliple statements with the option to fail on duplicates
|
|
|
238
|
+ but still continue
|
|
|
239
|
+ """
|
|
|
240
|
+ for sql in statements:
|
|
|
241
|
+ try:
|
|
|
242
|
+ con.execute(sql)
|
|
|
243
|
+ con.commit()
|
|
|
244
|
+ except sqlite.OperationalError as error:
|
|
|
245
|
+ if str(error).startswith('duplicate column name:'):
|
|
|
246
|
+ log.info(error)
|
|
|
247
|
+ else:
|
|
|
248
|
+ log.exception('Error')
|
|
|
249
|
+ sys.exit()
|
|
|
250
|
+
|
|
|
251
|
+ @staticmethod
|
|
196
|
252
|
def namedtuple_factory(cursor, row):
|
|
197
|
253
|
"""
|
|
198
|
254
|
Usage:
|
| ... |
... |
@@ -209,55 +265,33 @@ class Logger: |
|
209
|
265
|
def dispatch(self, event, error):
|
|
210
|
266
|
app.ged.raise_event(event, None, str(error))
|
|
211
|
267
|
|
|
212
|
|
- def close_db(self):
|
|
213
|
|
- if self.con:
|
|
214
|
|
- self.con.close()
|
|
215
|
|
- self.con = None
|
|
216
|
|
- self.cur = None
|
|
217
|
|
-
|
|
218
|
|
- def open_db(self):
|
|
219
|
|
- self.close_db()
|
|
|
268
|
+ def _connect_databases(self):
|
|
|
269
|
+ self._con = sqlite.connect(
|
|
|
270
|
+ LOG_DB_PATH, timeout=20.0, isolation_level='IMMEDIATE')
|
|
220
|
271
|
|
|
221
|
|
- # FIXME: sqlite3_open wants UTF8 strings. So a path with
|
|
222
|
|
- # non-ascii chars doesn't work. See #2812 and
|
|
223
|
|
- # http://lists.initd.org/pipermail/pysqlite/2005-August/000134.html
|
|
224
|
|
- back = os.getcwd()
|
|
225
|
|
- os.chdir(LOG_DB_FOLDER)
|
|
226
|
|
-
|
|
227
|
|
- # if locked, wait up to 20 sec to unlock
|
|
228
|
|
- # before raise (hopefully should be enough)
|
|
229
|
|
-
|
|
230
|
|
- self.con = sqlite.connect(LOG_DB_FILE, timeout=20.0,
|
|
231
|
|
- isolation_level='IMMEDIATE')
|
|
232
|
|
- os.chdir(back)
|
|
233
|
|
- self.con.row_factory = self.namedtuple_factory
|
|
|
272
|
+ self._con.row_factory = self.namedtuple_factory
|
|
234
|
273
|
|
|
235
|
274
|
# DB functions
|
|
236
|
|
- self.con.create_function("like", 1, self._like)
|
|
237
|
|
- self.con.create_function("get_timeout", 0, self._get_timeout)
|
|
|
275
|
+ self._con.create_function("like", 1, self._like)
|
|
|
276
|
+ self._con.create_function("get_timeout", 0, self._get_timeout)
|
|
238
|
277
|
|
|
239
|
|
- self.cur = self.con.cursor()
|
|
240
|
|
- self.set_synchronous(False)
|
|
241
|
|
-
|
|
242
|
|
- def attach_cache_database(self):
|
|
|
278
|
+ self._set_synchronous(False)
|
|
243
|
279
|
try:
|
|
244
|
|
- self.cur.execute("ATTACH DATABASE '%s' AS cache" % \
|
|
245
|
|
- CACHE_DB_PATH.replace("'", "''"))
|
|
246
|
|
- except sqlite.Error as e:
|
|
247
|
|
- log.debug("Failed to attach cache database: %s" % str(e))
|
|
|
280
|
+ self._con.execute("ATTACH DATABASE '%s' AS cache" %
|
|
|
281
|
+ CACHE_DB_PATH.replace("'", "''"))
|
|
|
282
|
+ except Exception as error:
|
|
|
283
|
+ log.exception('Error')
|
|
|
284
|
+ self._con.close()
|
|
|
285
|
+ sys.exit()
|
|
248
|
286
|
|
|
249
|
|
- def set_synchronous(self, sync):
|
|
|
287
|
+ def _set_synchronous(self, sync):
|
|
250
|
288
|
try:
|
|
251
|
289
|
if sync:
|
|
252
|
|
- self.cur.execute("PRAGMA synchronous = NORMAL")
|
|
|
290
|
+ self._con.execute("PRAGMA synchronous = NORMAL")
|
|
253
|
291
|
else:
|
|
254
|
|
- self.cur.execute("PRAGMA synchronous = OFF")
|
|
|
292
|
+ self._con.execute("PRAGMA synchronous = OFF")
|
|
255
|
293
|
except sqlite.Error as e:
|
|
256
|
|
- log.debug("Failed to set_synchronous(%s): %s" % (sync, str(e)))
|
|
257
|
|
-
|
|
258
|
|
- def init_vars(self):
|
|
259
|
|
- self.open_db()
|
|
260
|
|
- self.get_jid_ids_from_db()
|
|
|
294
|
+ log.exception('Error')
|
|
261
|
295
|
|
|
262
|
296
|
@staticmethod
|
|
263
|
297
|
def _get_timeout():
|
| ... |
... |
@@ -277,29 +311,29 @@ class Logger: |
|
277
|
311
|
|
|
278
|
312
|
def commit(self):
|
|
279
|
313
|
try:
|
|
280
|
|
- self.con.commit()
|
|
|
314
|
+ self._con.commit()
|
|
281
|
315
|
except sqlite.OperationalError as e:
|
|
282
|
316
|
print(str(e), file=sys.stderr)
|
|
283
|
|
- self.commit_timout_id = None
|
|
|
317
|
+ self._commit_timout_id = None
|
|
284
|
318
|
return False
|
|
285
|
319
|
|
|
286
|
320
|
def _timeout_commit(self):
|
|
287
|
|
- if self.commit_timout_id:
|
|
|
321
|
+ if self._commit_timout_id:
|
|
288
|
322
|
return
|
|
289
|
|
- self.commit_timout_id = GLib.timeout_add(500, self.commit)
|
|
|
323
|
+ self._commit_timout_id = GLib.timeout_add(500, self.commit)
|
|
290
|
324
|
|
|
291
|
325
|
def simple_commit(self, sql_to_commit):
|
|
292
|
326
|
"""
|
|
293
|
327
|
Helper to commit
|
|
294
|
328
|
"""
|
|
295
|
|
- self.cur.execute(sql_to_commit)
|
|
|
329
|
+ self._con.execute(sql_to_commit)
|
|
296
|
330
|
self._timeout_commit()
|
|
297
|
331
|
|
|
298
|
|
- def get_jid_ids_from_db(self):
|
|
|
332
|
+ def _get_jid_ids_from_db(self):
|
|
299
|
333
|
"""
|
|
300
|
334
|
Load all jid/jid_id tuples into a dict for faster access
|
|
301
|
335
|
"""
|
|
302
|
|
- rows = self.con.execute(
|
|
|
336
|
+ rows = self._con.execute(
|
|
303
|
337
|
'SELECT jid_id, jid, type FROM jids').fetchall()
|
|
304
|
338
|
for row in rows:
|
|
305
|
339
|
self._jid_ids[row.jid] = row
|
| ... |
... |
@@ -327,8 +361,8 @@ class Logger: |
|
327
|
361
|
"""
|
|
328
|
362
|
Return True if it's a room jid, False if it's not, None if we don't know
|
|
329
|
363
|
"""
|
|
330
|
|
- self.cur.execute('SELECT type FROM jids WHERE jid=?', (jid,))
|
|
331
|
|
- row = self.cur.fetchone()
|
|
|
364
|
+ row = self._con.execute(
|
|
|
365
|
+ 'SELECT type FROM jids WHERE jid=?', (jid,)).fetchone()
|
|
332
|
366
|
if row is None:
|
|
333
|
367
|
return None
|
|
334
|
368
|
else:
|
| ... |
... |
@@ -380,7 +414,7 @@ class Logger: |
|
380
|
414
|
return result.jid_id
|
|
381
|
415
|
|
|
382
|
416
|
sql = 'SELECT jid_id, jid, type FROM jids WHERE jid = ?'
|
|
383
|
|
- row = self.con.execute(sql, [jid]).fetchone()
|
|
|
417
|
+ row = self._con.execute(sql, [jid]).fetchone()
|
|
384
|
418
|
if row is not None:
|
|
385
|
419
|
self._jid_ids[jid] = row
|
|
386
|
420
|
return row.jid_id
|
| ... |
... |
@@ -390,7 +424,7 @@ class Logger: |
|
390
|
424
|
'Unable to insert new JID because type is missing')
|
|
391
|
425
|
|
|
392
|
426
|
sql = 'INSERT INTO jids (jid, type) VALUES (?, ?)'
|
|
393
|
|
- lastrowid = self.con.execute(sql, (jid, type_)).lastrowid
|
|
|
427
|
+ lastrowid = self._con.execute(sql, (jid, type_)).lastrowid
|
|
394
|
428
|
Row = namedtuple('Row', 'jid_id jid type')
|
|
395
|
429
|
self._jid_ids[jid] = Row(lastrowid, jid, type_)
|
|
396
|
430
|
self._timeout_commit()
|
| ... |
... |
@@ -576,9 +610,8 @@ class Logger: |
|
576
|
610
|
"""
|
|
577
|
611
|
all_messages = []
|
|
578
|
612
|
try:
|
|
579
|
|
- self.cur.execute(
|
|
580
|
|
- 'SELECT message_id, shown from unread_messages')
|
|
581
|
|
- unread_results = self.cur.fetchall()
|
|
|
613
|
+ unread_results = self._con.execute(
|
|
|
614
|
+ 'SELECT message_id, shown from unread_messages').fetchall()
|
|
582
|
615
|
except Exception:
|
|
583
|
616
|
unread_results = []
|
|
584
|
617
|
for message in unread_results:
|
| ... |
... |
@@ -587,20 +620,19 @@ class Logger: |
|
587
|
620
|
# here we get infos for that message, and related jid from jids table
|
|
588
|
621
|
# do NOT change order of SELECTed things, unless you change function(s)
|
|
589
|
622
|
# that called this function
|
|
590
|
|
- self.cur.execute('''
|
|
|
623
|
+ result = self._con.execute('''
|
|
591
|
624
|
SELECT logs.log_line_id, logs.message, logs.time, logs.subject,
|
|
592
|
625
|
jids.jid, logs.additional_data
|
|
593
|
626
|
FROM logs, jids
|
|
594
|
627
|
WHERE logs.log_line_id = %d AND logs.jid_id = jids.jid_id
|
|
595
|
628
|
''' % msg_log_id
|
|
596
|
|
- )
|
|
597
|
|
- results = self.cur.fetchone()
|
|
598
|
|
- if results is None:
|
|
|
629
|
+ ).fetchone()
|
|
|
630
|
+ if result is None:
|
|
599
|
631
|
# Log line is no more in logs table. remove it from unread_messages
|
|
600
|
632
|
self.set_read_messages([msg_log_id])
|
|
601
|
633
|
continue
|
|
602
|
634
|
|
|
603
|
|
- all_messages.append((results, shown))
|
|
|
635
|
+ all_messages.append((result, shown))
|
|
604
|
636
|
return all_messages
|
|
605
|
637
|
|
|
606
|
638
|
def get_last_conversation_lines(self, account, jid, pending):
|
| ... |
... |
@@ -644,7 +676,7 @@ class Logger: |
|
644
|
676
|
kinds=', '.join(kinds))
|
|
645
|
677
|
|
|
646
|
678
|
try:
|
|
647
|
|
- messages = self.con.execute(
|
|
|
679
|
+ messages = self._con.execute(
|
|
648
|
680
|
sql, tuple(jids) + (restore, pending)).fetchall()
|
|
649
|
681
|
except sqlite.DatabaseError:
|
|
650
|
682
|
self.dispatch('DB_ERROR',
|
| ... |
... |
@@ -691,7 +723,7 @@ class Logger: |
|
691
|
723
|
ORDER BY time, log_line_id
|
|
692
|
724
|
'''.format(jids=', '.join('?' * len(jids)))
|
|
693
|
725
|
|
|
694
|
|
- return self.con.execute(sql, tuple(jids) +
|
|
|
726
|
+ return self._con.execute(sql, tuple(jids) +
|
|
695
|
727
|
(date.timestamp(),
|
|
696
|
728
|
(date + delta).timestamp())).fetchall()
|
|
697
|
729
|
|
| ... |
... |
@@ -734,7 +766,7 @@ class Logger: |
|
734
|
766
|
'''.format(jids=', '.join('?' * len(jids)),
|
|
735
|
767
|
date_search=between if date else '')
|
|
736
|
768
|
|
|
737
|
|
- return self.con.execute(sql, tuple(jids) + (query,)).fetchall()
|
|
|
769
|
+ return self._con.execute(sql, tuple(jids) + (query,)).fetchall()
|
|
738
|
770
|
|
|
739
|
771
|
def get_days_with_logs(self, account, jid, year, month):
|
|
740
|
772
|
"""
|
| ... |
... |
@@ -772,7 +804,7 @@ class Logger: |
|
772
|
804
|
""".format(jids=', '.join('?' * len(jids)),
|
|
773
|
805
|
kinds=', '.join(kinds))
|
|
774
|
806
|
|
|
775
|
|
- return self.con.execute(sql, tuple(jids) +
|
|
|
807
|
+ return self._con.execute(sql, tuple(jids) +
|
|
776
|
808
|
(date.timestamp(),
|
|
777
|
809
|
(date + delta).timestamp())).fetchall()
|
|
778
|
810
|
|
| ... |
... |
@@ -800,7 +832,7 @@ class Logger: |
|
800
|
832
|
|
|
801
|
833
|
# fetchone() returns always at least one Row with all
|
|
802
|
834
|
# attributes set to None because of the MAX() function
|
|
803
|
|
- return self.con.execute(sql, tuple(jids)).fetchone().time
|
|
|
835
|
+ return self._con.execute(sql, tuple(jids)).fetchone().time
|
|
804
|
836
|
|
|
805
|
837
|
def get_first_date_that_has_logs(self, account, jid):
|
|
806
|
838
|
"""
|
| ... |
... |
@@ -826,7 +858,7 @@ class Logger: |
|
826
|
858
|
|
|
827
|
859
|
# fetchone() returns always at least one Row with all
|
|
828
|
860
|
# attributes set to None because of the MIN() function
|
|
829
|
|
- return self.con.execute(sql, tuple(jids)).fetchone().time
|
|
|
861
|
+ return self._con.execute(sql, tuple(jids)).fetchone().time
|
|
830
|
862
|
|
|
831
|
863
|
def get_date_has_logs(self, account, jid, date):
|
|
832
|
864
|
"""
|
| ... |
... |
@@ -856,7 +888,7 @@ class Logger: |
|
856
|
888
|
AND time BETWEEN ? AND ?
|
|
857
|
889
|
'''.format(jids=', '.join('?' * len(jids)))
|
|
858
|
890
|
|
|
859
|
|
- return self.con.execute(sql, tuple(jids) +
|
|
|
891
|
+ return self._con.execute(sql, tuple(jids) +
|
|
860
|
892
|
(date.timestamp(),
|
|
861
|
893
|
(date + delta).timestamp())).fetchone()
|
|
862
|
894
|
|
| ... |
... |
@@ -875,7 +907,7 @@ class Logger: |
|
875
|
907
|
NATURAL JOIN jids WHERE jid = ?
|
|
876
|
908
|
'''
|
|
877
|
909
|
|
|
878
|
|
- row = self.con.execute(sql, (jid,)).fetchone()
|
|
|
910
|
+ row = self._con.execute(sql, (jid,)).fetchone()
|
|
879
|
911
|
if not row:
|
|
880
|
912
|
return self.get_last_date_that_has_logs(account, jid)
|
|
881
|
913
|
return row.time
|
| ... |
... |
@@ -896,7 +928,7 @@ class Logger: |
|
896
|
928
|
(SELECT time FROM rooms_last_message_time
|
|
897
|
929
|
WHERE jid_id = :jid_id AND time >= :time), :time))'''
|
|
898
|
930
|
|
|
899
|
|
- self.con.execute(sql, {"jid_id": jid_id, "time": timestamp})
|
|
|
931
|
+ self._con.execute(sql, {"jid_id": jid_id, "time": timestamp})
|
|
900
|
932
|
self._timeout_commit()
|
|
901
|
933
|
|
|
902
|
934
|
def save_transport_type(self, jid, type_):
|
| ... |
... |
@@ -907,11 +939,10 @@ class Logger: |
|
907
|
939
|
if not type_id:
|
|
908
|
940
|
# unknown type
|
|
909
|
941
|
return
|
|
910
|
|
- self.cur.execute(
|
|
911
|
|
- 'SELECT type from transports_cache WHERE transport = "%s"' % jid)
|
|
912
|
|
- results = self.cur.fetchone()
|
|
913
|
|
- if results:
|
|
914
|
|
- if results.type == type_id:
|
|
|
942
|
+ result = self._con.execute(
|
|
|
943
|
+ 'SELECT type from transports_cache WHERE transport = "%s"' % jid).fetchone()
|
|
|
944
|
+ if result:
|
|
|
945
|
+ if result.type == type_id:
|
|
915
|
946
|
return
|
|
916
|
947
|
sql = 'UPDATE transports_cache SET type = %d WHERE transport = "%s"' %\
|
|
917
|
948
|
(type_id, jid)
|
| ... |
... |
@@ -924,9 +955,7 @@ class Logger: |
|
924
|
955
|
"""
|
|
925
|
956
|
Return all the type of the transports in DB
|
|
926
|
957
|
"""
|
|
927
|
|
- self.cur.execute(
|
|
928
|
|
- 'SELECT * from transports_cache')
|
|
929
|
|
- results = self.cur.fetchall()
|
|
|
958
|
+ results = self._con.execute('SELECT * from transports_cache').fetchall()
|
|
930
|
959
|
if not results:
|
|
931
|
960
|
return {}
|
|
932
|
961
|
answer = {}
|
| ... |
... |
@@ -954,7 +983,7 @@ class Logger: |
|
954
|
983
|
# the data field contains binary object (gzipped data), this is a hack
|
|
955
|
984
|
# to get that data without trying to convert it to unicode
|
|
956
|
985
|
try:
|
|
957
|
|
- self.cur.execute('SELECT hash_method, hash, data FROM caps_cache;')
|
|
|
986
|
+ rows = self._con.execute('SELECT hash_method, hash, data FROM caps_cache;')
|
|
958
|
987
|
except sqlite.OperationalError:
|
|
959
|
988
|
# might happen when there's no caps_cache table yet
|
|
960
|
989
|
# -- there's no data to read anyway then
|
| ... |
... |
@@ -962,7 +991,7 @@ class Logger: |
|
962
|
991
|
|
|
963
|
992
|
# list of corrupted entries that will be removed
|
|
964
|
993
|
to_be_removed = []
|
|
965
|
|
- for row in self.cur:
|
|
|
994
|
+ for row in rows:
|
|
966
|
995
|
# for each row: unpack the data field
|
|
967
|
996
|
# (format: (category, type, name, category, type, name, ...
|
|
968
|
997
|
# ..., 'FEAT', feature1, feature2, ...).join(' '))
|
| ... |
... |
@@ -1013,7 +1042,7 @@ class Logger: |
|
1013
|
1042
|
gzip.write(data.encode('utf-8'))
|
|
1014
|
1043
|
gzip.close()
|
|
1015
|
1044
|
data = string.getvalue()
|
|
1016
|
|
- self.cur.execute('''
|
|
|
1045
|
+ self._con.execute('''
|
|
1017
|
1046
|
INSERT INTO caps_cache ( hash_method, hash, data, last_seen )
|
|
1018
|
1047
|
VALUES (?, ?, ?, ?);
|
|
1019
|
1048
|
''', (hash_method, hash_, memoryview(data), int(time.time())))
|
| ... |
... |
@@ -1076,10 +1105,10 @@ class Logger: |
|
1076
|
1105
|
jid_id = self.get_jid_id(jid)
|
|
1077
|
1106
|
except exceptions.PysqliteOperationalError as e:
|
|
1078
|
1107
|
raise exceptions.PysqliteOperationalError(str(e))
|
|
1079
|
|
- self.cur.execute(
|
|
|
1108
|
+ self._con.execute(
|
|
1080
|
1109
|
'DELETE FROM roster_group WHERE account_jid_id=? AND jid_id=?',
|
|
1081
|
1110
|
(account_jid_id, jid_id))
|
|
1082
|
|
- self.cur.execute(
|
|
|
1111
|
+ self._con.execute(
|
|
1083
|
1112
|
'DELETE FROM roster_entry WHERE account_jid_id=? AND jid_id=?',
|
|
1084
|
1113
|
(account_jid_id, jid_id))
|
|
1085
|
1114
|
self._timeout_commit()
|
| ... |
... |
@@ -1101,18 +1130,18 @@ class Logger: |
|
1101
|
1130
|
|
|
1102
|
1131
|
# Update groups information
|
|
1103
|
1132
|
# First we delete all previous groups information
|
|
1104
|
|
- self.cur.execute(
|
|
|
1133
|
+ self._con.execute(
|
|
1105
|
1134
|
'DELETE FROM roster_group WHERE account_jid_id=? AND jid_id=?',
|
|
1106
|
1135
|
(account_jid_id, jid_id))
|
|
1107
|
1136
|
# Then we add all new groups information
|
|
1108
|
1137
|
for group in groups:
|
|
1109
|
|
- self.cur.execute('INSERT INTO roster_group VALUES(?, ?, ?)',
|
|
|
1138
|
+ self._con.execute('INSERT INTO roster_group VALUES(?, ?, ?)',
|
|
1110
|
1139
|
(account_jid_id, jid_id, group))
|
|
1111
|
1140
|
|
|
1112
|
1141
|
if name is None:
|
|
1113
|
1142
|
name = ''
|
|
1114
|
1143
|
|
|
1115
|
|
- self.cur.execute('''
|
|
|
1144
|
+ self._con.execute('''
|
|
1116
|
1145
|
REPLACE INTO roster_entry
|
|
1117
|
1146
|
(account_jid_id, jid_id, name, subscription, ask)
|
|
1118
|
1147
|
VALUES(?, ?, ?, ?, ?)''', (
|
| ... |
... |
@@ -1130,11 +1159,11 @@ class Logger: |
|
1130
|
1159
|
account_jid_id = self.get_jid_id(account_jid, type_=JIDConstant.NORMAL_TYPE)
|
|
1131
|
1160
|
|
|
1132
|
1161
|
# First we fill data with roster_entry informations
|
|
1133
|
|
- self.cur.execute('''
|
|
|
1162
|
+ rows = self._con.execute('''
|
|
1134
|
1163
|
SELECT j.jid, re.jid_id, re.name, re.subscription, re.ask, re.avatar_sha
|
|
1135
|
1164
|
FROM roster_entry re, jids j
|
|
1136
|
1165
|
WHERE re.account_jid_id=? AND j.jid_id=re.jid_id''', (account_jid_id,))
|
|
1137
|
|
- for row in self.cur:
|
|
|
1166
|
+ for row in rows:
|
|
1138
|
1167
|
#jid, jid_id, name, subscription, ask
|
|
1139
|
1168
|
jid = row.jid
|
|
1140
|
1169
|
name = row.name
|
| ... |
... |
@@ -1157,11 +1186,11 @@ class Logger: |
|
1157
|
1186
|
|
|
1158
|
1187
|
# Then we add group for roster entries
|
|
1159
|
1188
|
for jid in data:
|
|
1160
|
|
- self.cur.execute('''
|
|
|
1189
|
+ rows = self._con.execute('''
|
|
1161
|
1190
|
SELECT group_name FROM roster_group
|
|
1162
|
1191
|
WHERE account_jid_id=? AND jid_id=?''',
|
|
1163
|
1192
|
(account_jid_id, data[jid]['id']))
|
|
1164
|
|
- for row in self.cur:
|
|
|
1193
|
+ for row in rows:
|
|
1165
|
1194
|
group_name = row.group_name
|
|
1166
|
1195
|
data[jid]['groups'].append(group_name)
|
|
1167
|
1196
|
del data[jid]['id']
|
| ... |
... |
@@ -1186,7 +1215,7 @@ class Logger: |
|
1186
|
1215
|
DELETE FROM roster_group WHERE account_jid_id = {jid_id};
|
|
1187
|
1216
|
'''.format(jid_id=jid_id)
|
|
1188
|
1217
|
|
|
1189
|
|
- self.con.executescript(sql)
|
|
|
1218
|
+ self._con.executescript(sql)
|
|
1190
|
1219
|
self._timeout_commit()
|
|
1191
|
1220
|
|
|
1192
|
1221
|
def search_for_duplicate(self, account, jid, timestamp, msg):
|
| ... |
... |
@@ -1216,7 +1245,7 @@ class Logger: |
|
1216
|
1245
|
AND time BETWEEN ? AND ?
|
|
1217
|
1246
|
'''
|
|
1218
|
1247
|
|
|
1219
|
|
- result = self.con.execute(
|
|
|
1248
|
+ result = self._con.execute(
|
|
1220
|
1249
|
sql, (jid, msg, account_id, start_time, end_time)).fetchone()
|
|
1221
|
1250
|
|
|
1222
|
1251
|
if result is not None:
|
| ... |
... |
@@ -1263,14 +1292,14 @@ class Logger: |
|
1263
|
1292
|
WHERE stanza_id IN ({values})
|
|
1264
|
1293
|
AND jid_id = ? AND account_id = ? LIMIT 1
|
|
1265
|
1294
|
'''.format(values=', '.join('?' * len(ids)))
|
|
1266
|
|
- result = self.con.execute(
|
|
|
1295
|
+ result = self._con.execute(
|
|
1267
|
1296
|
sql, tuple(ids) + (archive_id, account_id)).fetchone()
|
|
1268
|
1297
|
else:
|
|
1269
|
1298
|
sql = '''
|
|
1270
|
1299
|
SELECT stanza_id FROM logs
|
|
1271
|
1300
|
WHERE stanza_id IN ({values}) AND account_id = ? AND kind != ? LIMIT 1
|
|
1272
|
1301
|
'''.format(values=', '.join('?' * len(ids)))
|
|
1273
|
|
- result = self.con.execute(
|
|
|
1302
|
+ result = self._con.execute(
|
|
1274
|
1303
|
sql, tuple(ids) + (account_id, KindConstant.GC_MSG)).fetchone()
|
|
1275
|
1304
|
|
|
1276
|
1305
|
if result is not None:
|
| ... |
... |
@@ -1324,7 +1353,7 @@ class Logger: |
|
1324
|
1353
|
'''.format(columns=', '.join(kwargs.keys()),
|
|
1325
|
1354
|
values=', '.join('?' * len(kwargs)))
|
|
1326
|
1355
|
|
|
1327
|
|
- lastrowid = self.con.execute(
|
|
|
1356
|
+ lastrowid = self._con.execute(
|
|
1328
|
1357
|
sql, (account_id, jid_id, time_, kind) + tuple(kwargs.values())).lastrowid
|
|
1329
|
1358
|
|
|
1330
|
1359
|
log.info('Insert into DB: jid: %s, time: %s, kind: %s, stanza_id: %s',
|
| ... |
... |
@@ -1333,7 +1362,7 @@ class Logger: |
|
1333
|
1362
|
if unread and kind == KindConstant.CHAT_MSG_RECV:
|
|
1334
|
1363
|
sql = '''INSERT INTO unread_messages (message_id, jid_id)
|
|
1335
|
1364
|
VALUES (?, (SELECT jid_id FROM jids WHERE jid = ?))'''
|
|
1336
|
|
- self.con.execute(sql, (lastrowid, jid))
|
|
|
1365
|
+ self._con.execute(sql, (lastrowid, jid))
|
|
1337
|
1366
|
|
|
1338
|
1367
|
self._timeout_commit()
|
|
1339
|
1368
|
|
| ... |
... |
@@ -1358,7 +1387,7 @@ class Logger: |
|
1358
|
1387
|
UPDATE roster_entry SET avatar_sha = ?
|
|
1359
|
1388
|
WHERE account_jid_id = ? AND jid_id = ?
|
|
1360
|
1389
|
'''
|
|
1361
|
|
- self.con.execute(sql, (sha, account_jid_id, jid_id))
|
|
|
1390
|
+ self._con.execute(sql, (sha, account_jid_id, jid_id))
|
|
1362
|
1391
|
self._timeout_commit()
|
|
1363
|
1392
|
|
|
1364
|
1393
|
def get_archive_timestamp(self, jid, type_=None):
|
| ... |
... |
@@ -1370,7 +1399,7 @@ class Logger: |
|
1370
|
1399
|
"""
|
|
1371
|
1400
|
jid_id = self.get_jid_id(jid, type_=type_)
|
|
1372
|
1401
|
sql = '''SELECT * FROM last_archive_message WHERE jid_id = ?'''
|
|
1373
|
|
- return self.con.execute(sql, (jid_id,)).fetchone()
|
|
|
1402
|
+ return self._con.execute(sql, (jid_id,)).fetchone()
|
|
1374
|
1403
|
|
|
1375
|
1404
|
def set_archive_timestamp(self, jid, **kwargs):
|
|
1376
|
1405
|
"""
|
| ... |
... |
@@ -1391,7 +1420,7 @@ class Logger: |
|
1391
|
1420
|
exists = self.get_archive_timestamp(jid)
|
|
1392
|
1421
|
if not exists:
|
|
1393
|
1422
|
sql = '''INSERT INTO last_archive_message VALUES (?, ?, ?, ?)'''
|
|
1394
|
|
- self.con.execute(sql, (jid_id,
|
|
|
1423
|
+ self._con.execute(sql, (jid_id,
|
|
1395
|
1424
|
kwargs.get('last_mam_id', None),
|
|
1396
|
1425
|
kwargs.get('oldest_mam_timestamp', None),
|
|
1397
|
1426
|
kwargs.get('last_muc_timestamp', None)))
|
| ... |
... |
@@ -1399,6 +1428,6 @@ class Logger: |
|
1399
|
1428
|
args = ' = ?, '.join(kwargs.keys()) + ' = ?'
|
|
1400
|
1429
|
sql = '''UPDATE last_archive_message SET {}
|
|
1401
|
1430
|
WHERE jid_id = ?'''.format(args)
|
|
1402
|
|
- self.con.execute(sql, tuple(kwargs.values()) + (jid_id,))
|
|
|
1431
|
+ self._con.execute(sql, tuple(kwargs.values()) + (jid_id,))
|
|
1403
|
1432
|
log.info('Save archive timestamps: %s', kwargs)
|
|
1404
|
1433
|
self._timeout_commit()
|