-
Notifications
You must be signed in to change notification settings - Fork 2
/
database.py
72 lines (70 loc) · 3.35 KB
/
database.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import sqlite3
import os.path
from binascii import hexlify, unhexlify
from screen import ScreenSetup, Resolution, RelativeScreenPosition
class InvalidDBFile(Exception):
pass
class Database:
def __init__(self, dbfilename):
self._create = False
assert(os.path.isdir(os.path.dirname(dbfilename)))
if not os.path.isfile(dbfilename):
if os.path.lexists(dbfilename):
raise Exception("Database must be a file: '%s'" % dbfilename)
# database will be created on __enter__ because we need a dbconnection for it
self._create = True
self._dbfilename = dbfilename
self._connection = None
def __enter__(self):
self._connection = sqlite3.connect(self._dbfilename)
c = self._c()
if self._create:
c.execute("""CREATE TABLE meta (key text, value text, PRIMARY KEY(key))""")
c.execute("""INSERT INTO meta VALUES ('version', '1')""")
c.execute("""CREATE TABLE known_configs (edid blob, resinternal text, resexternal text, mode text, ext_is_primary integer, PRIMARY KEY(edid))""")
# edid in binary format
# resindernal, resexternal = "1024x768" or NULL if display is off
# mode: the enum text of screen.RelativeScreenPosition or NULL if one display is off
else: # check compatibility
dbversion = int(self._getMeta("version"))
if dbversion > 1:
raise InvalidDBFile("Database is too new: Version %d. Please update lilass." % dbversion)
return self
def _getMeta(self, key):
c = self._c()
c.execute("""SELECT value FROM meta WHERE key=?""", (key,))
got = c.fetchone()
if got is None: # to differentiate between the value being NULL and the row being not there
raise KeyError("""Key "%s" is not in the meta table.""" % key)
assert c.fetchone() is None # uniqueness
assert len(got) == 1
return got[0]
def putConfig(self, extconn_edid, conf):
c = self._c()
b_edid = unhexlify(extconn_edid)
intres = conf.intResolution.forDatabase() if conf.intResolution else None
extres = conf.extResolution.forDatabase() if conf.extResolution else None
mode = conf.relPosition.text if conf.relPosition else None
extprim = int(conf.extIsPrimary) # False => 0, True => 1
c.execute("""INSERT OR REPLACE INTO known_configs VALUES (?,?,?,?,?)""", (b_edid, intres, extres, mode, extprim))
def getConfig(self, extconn_edid):
c = self._c()
b_edid = unhexlify(extconn_edid)
c.execute("""SELECT * FROM known_configs WHERE edid=?""", (b_edid,))
result = c.fetchone()
if result is None:
return None
assert c.fetchone() is None # uniqueness
_, intres, extres, mode, extprim = result
intres = Resolution.fromDatabase(intres) # this method is safe for NULLs
extres = Resolution.fromDatabase(extres)
mode = RelativeScreenPosition(mode) if mode else None
extprim = bool(extprim) # 0 => False, 1 => True
return ScreenSetup(intres, extres, mode, extprim)
def __exit__(self, type, value, tb):
if self._connection:
self._connection.commit()
self._connection.close()
def _c(self):
assert(self._connection)
return self._connection.cursor()