2014-05-26 04:27:52 +04:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
2015-05-13 01:03:23 +03:00
|
|
|
wakatime.offlinequeue
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~
|
2014-05-26 04:27:52 +04:00
|
|
|
|
2015-05-13 01:03:23 +03:00
|
|
|
Queue for saving heartbeats while offline.
|
2014-05-26 04:27:52 +04:00
|
|
|
|
|
|
|
:copyright: (c) 2014 Alan Hamlett.
|
|
|
|
:license: BSD, see LICENSE for more details.
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import logging
|
|
|
|
import os
|
|
|
|
from time import sleep
|
2014-12-04 22:45:18 +03:00
|
|
|
|
2014-06-10 00:18:30 +04:00
|
|
|
try:
|
|
|
|
import sqlite3
|
|
|
|
HAS_SQL = True
|
2015-09-29 13:11:25 +03:00
|
|
|
except ImportError: # pragma: nocover
|
2014-06-10 00:18:30 +04:00
|
|
|
HAS_SQL = False
|
2014-05-26 04:27:52 +04:00
|
|
|
|
2015-08-25 10:42:37 +03:00
|
|
|
from .compat import u
|
|
|
|
|
2014-05-26 04:27:52 +04:00
|
|
|
|
2014-07-25 12:01:39 +04:00
|
|
|
log = logging.getLogger('WakaTime')
|
2014-05-26 04:27:52 +04:00
|
|
|
|
|
|
|
|
|
|
|
class Queue(object):
|
2017-10-29 21:32:03 +03:00
|
|
|
db_file = '.wakatime.db'
|
2015-09-29 13:11:25 +03:00
|
|
|
table_name = 'heartbeat_1'
|
|
|
|
|
|
|
|
def get_db_file(self):
|
2017-10-29 21:32:03 +03:00
|
|
|
home = '~'
|
|
|
|
if os.environ.get('WAKATIME_HOME'):
|
|
|
|
home = os.environ.get('WAKATIME_HOME')
|
|
|
|
return os.path.join(os.path.expanduser(home), '.wakatime.db')
|
2014-05-26 04:27:52 +04:00
|
|
|
|
|
|
|
def connect(self):
|
2017-02-21 03:18:38 +03:00
|
|
|
conn = sqlite3.connect(self.get_db_file(), isolation_level=None)
|
2014-05-26 04:27:52 +04:00
|
|
|
c = conn.cursor()
|
2015-09-29 13:11:25 +03:00
|
|
|
c.execute('''CREATE TABLE IF NOT EXISTS {0} (
|
|
|
|
entity text,
|
|
|
|
type text,
|
2014-05-26 04:27:52 +04:00
|
|
|
time real,
|
|
|
|
project text,
|
|
|
|
branch text,
|
|
|
|
is_write integer,
|
2014-12-22 10:01:09 +03:00
|
|
|
stats text,
|
|
|
|
misc text,
|
2014-05-26 04:27:52 +04:00
|
|
|
plugin text)
|
2015-09-29 13:11:25 +03:00
|
|
|
'''.format(self.table_name))
|
2014-05-26 04:27:52 +04:00
|
|
|
return (conn, c)
|
|
|
|
|
2014-12-22 10:01:09 +03:00
|
|
|
def push(self, data, stats, plugin, misc=None):
|
2015-09-29 13:11:25 +03:00
|
|
|
if not HAS_SQL: # pragma: nocover
|
2014-06-10 00:18:30 +04:00
|
|
|
return
|
2014-05-27 01:06:36 +04:00
|
|
|
try:
|
|
|
|
conn, c = self.connect()
|
2014-12-22 10:01:09 +03:00
|
|
|
heartbeat = {
|
2015-09-29 13:11:25 +03:00
|
|
|
'entity': u(data.get('entity')),
|
|
|
|
'type': u(data.get('type')),
|
2014-05-27 01:06:36 +04:00
|
|
|
'time': data.get('time'),
|
2015-08-25 10:42:37 +03:00
|
|
|
'project': u(data.get('project')),
|
|
|
|
'branch': u(data.get('branch')),
|
2014-05-27 01:06:36 +04:00
|
|
|
'is_write': 1 if data.get('is_write') else 0,
|
2015-08-25 10:42:37 +03:00
|
|
|
'stats': u(stats),
|
|
|
|
'misc': u(misc),
|
|
|
|
'plugin': u(plugin),
|
2014-05-27 01:06:36 +04:00
|
|
|
}
|
2015-09-29 13:11:25 +03:00
|
|
|
c.execute('INSERT INTO {0} VALUES (:entity,:type,:time,:project,:branch,:is_write,:stats,:misc,:plugin)'.format(self.table_name), heartbeat)
|
2014-05-27 01:06:36 +04:00
|
|
|
conn.commit()
|
|
|
|
conn.close()
|
2014-06-10 00:18:30 +04:00
|
|
|
except sqlite3.Error:
|
2016-06-17 11:17:29 +03:00
|
|
|
log.traceback()
|
2014-05-26 04:27:52 +04:00
|
|
|
|
|
|
|
def pop(self):
|
2015-09-29 13:11:25 +03:00
|
|
|
if not HAS_SQL: # pragma: nocover
|
2014-06-10 00:18:30 +04:00
|
|
|
return None
|
2014-05-26 04:27:52 +04:00
|
|
|
tries = 3
|
|
|
|
wait = 0.1
|
2014-12-22 10:01:09 +03:00
|
|
|
heartbeat = None
|
2014-05-27 01:06:36 +04:00
|
|
|
try:
|
|
|
|
conn, c = self.connect()
|
2014-06-10 00:18:30 +04:00
|
|
|
except sqlite3.Error:
|
2016-09-02 11:50:54 +03:00
|
|
|
log.traceback(logging.DEBUG)
|
2014-05-27 01:06:36 +04:00
|
|
|
return None
|
2014-05-26 04:27:52 +04:00
|
|
|
loop = True
|
|
|
|
while loop and tries > -1:
|
|
|
|
try:
|
|
|
|
c.execute('BEGIN IMMEDIATE')
|
2015-09-29 13:11:25 +03:00
|
|
|
c.execute('SELECT * FROM {0} LIMIT 1'.format(self.table_name))
|
2014-05-26 04:27:52 +04:00
|
|
|
row = c.fetchone()
|
|
|
|
if row is not None:
|
2014-05-27 02:01:32 +04:00
|
|
|
values = []
|
|
|
|
clauses = []
|
|
|
|
index = 0
|
2015-09-29 13:11:25 +03:00
|
|
|
for row_name in ['entity', 'type', 'time', 'project', 'branch', 'is_write']:
|
2014-05-27 02:01:32 +04:00
|
|
|
if row[index] is not None:
|
|
|
|
clauses.append('{0}=?'.format(row_name))
|
2015-08-25 21:20:12 +03:00
|
|
|
values.append(row[index])
|
2015-09-29 13:11:25 +03:00
|
|
|
else: # pragma: nocover
|
2014-05-27 02:01:32 +04:00
|
|
|
clauses.append('{0} IS NULL'.format(row_name))
|
|
|
|
index += 1
|
|
|
|
if len(values) > 0:
|
2015-09-29 13:11:25 +03:00
|
|
|
c.execute('DELETE FROM {0} WHERE {1}'.format(self.table_name, ' AND '.join(clauses)), values)
|
|
|
|
else: # pragma: nocover
|
|
|
|
c.execute('DELETE FROM {0} WHERE {1}'.format(self.table_name, ' AND '.join(clauses)))
|
2014-05-26 04:27:52 +04:00
|
|
|
conn.commit()
|
|
|
|
if row is not None:
|
2014-12-22 10:01:09 +03:00
|
|
|
heartbeat = {
|
2015-09-29 13:11:25 +03:00
|
|
|
'entity': row[0],
|
|
|
|
'type': row[1],
|
|
|
|
'time': row[2],
|
|
|
|
'project': row[3],
|
|
|
|
'branch': row[4],
|
|
|
|
'is_write': True if row[5] is 1 else False,
|
|
|
|
'stats': row[6],
|
|
|
|
'misc': row[7],
|
|
|
|
'plugin': row[8],
|
2014-05-26 04:27:52 +04:00
|
|
|
}
|
|
|
|
loop = False
|
2015-09-29 13:11:25 +03:00
|
|
|
except sqlite3.Error: # pragma: nocover
|
2016-09-02 11:50:54 +03:00
|
|
|
log.traceback(logging.DEBUG)
|
2014-05-26 04:27:52 +04:00
|
|
|
sleep(wait)
|
|
|
|
tries -= 1
|
2014-05-27 01:06:36 +04:00
|
|
|
try:
|
|
|
|
conn.close()
|
2015-09-29 13:11:25 +03:00
|
|
|
except sqlite3.Error: # pragma: nocover
|
2016-09-02 11:50:54 +03:00
|
|
|
log.traceback(logging.DEBUG)
|
2014-12-22 10:01:09 +03:00
|
|
|
return heartbeat
|