108902b01SBrad Bishop# Copyright (C) 2018-2019 Garmin Ltd.
219323693SBrad Bishop#
3c342db35SBrad Bishop# SPDX-License-Identifier: GPL-2.0-only
419323693SBrad Bishop#
519323693SBrad Bishop
6*a34c030eSBrad Bishopfrom contextlib import closing
7*a34c030eSBrad Bishopimport re
819323693SBrad Bishopimport sqlite3
919323693SBrad Bishop
10*a34c030eSBrad BishopUNIX_PREFIX = "unix://"
1119323693SBrad Bishop
12*a34c030eSBrad BishopADDR_TYPE_UNIX = 0
13*a34c030eSBrad BishopADDR_TYPE_TCP = 1
1419323693SBrad Bishop
1508902b01SBrad Bishop
16*a34c030eSBrad Bishopdef setup_database(database, sync=True):
17*a34c030eSBrad Bishop    db = sqlite3.connect(database)
1819323693SBrad Bishop    db.row_factory = sqlite3.Row
1919323693SBrad Bishop
20*a34c030eSBrad Bishop    with closing(db.cursor()) as cursor:
2119323693SBrad Bishop        cursor.execute('''
2208902b01SBrad Bishop            CREATE TABLE IF NOT EXISTS tasks_v2 (
2319323693SBrad Bishop                id INTEGER PRIMARY KEY AUTOINCREMENT,
2419323693SBrad Bishop                method TEXT NOT NULL,
2519323693SBrad Bishop                outhash TEXT NOT NULL,
2619323693SBrad Bishop                taskhash TEXT NOT NULL,
2719323693SBrad Bishop                unihash TEXT NOT NULL,
2819323693SBrad Bishop                created DATETIME,
2919323693SBrad Bishop
3019323693SBrad Bishop                -- Optional fields
3119323693SBrad Bishop                owner TEXT,
3219323693SBrad Bishop                PN TEXT,
3319323693SBrad Bishop                PV TEXT,
3419323693SBrad Bishop                PR TEXT,
3519323693SBrad Bishop                task TEXT,
3608902b01SBrad Bishop                outhash_siginfo TEXT,
3708902b01SBrad Bishop
3808902b01SBrad Bishop                UNIQUE(method, outhash, taskhash)
3919323693SBrad Bishop                )
4019323693SBrad Bishop            ''')
41*a34c030eSBrad Bishop        cursor.execute('PRAGMA journal_mode = WAL')
42*a34c030eSBrad Bishop        cursor.execute('PRAGMA synchronous = %s' % ('NORMAL' if sync else 'OFF'))
4319323693SBrad Bishop
44*a34c030eSBrad Bishop        # Drop old indexes
45*a34c030eSBrad Bishop        cursor.execute('DROP INDEX IF EXISTS taskhash_lookup')
46*a34c030eSBrad Bishop        cursor.execute('DROP INDEX IF EXISTS outhash_lookup')
4708902b01SBrad Bishop
48*a34c030eSBrad Bishop        # Create new indexes
49*a34c030eSBrad Bishop        cursor.execute('CREATE INDEX IF NOT EXISTS taskhash_lookup_v2 ON tasks_v2 (method, taskhash, created)')
50*a34c030eSBrad Bishop        cursor.execute('CREATE INDEX IF NOT EXISTS outhash_lookup_v2 ON tasks_v2 (method, outhash)')
5108902b01SBrad Bishop
52*a34c030eSBrad Bishop    return db
53*a34c030eSBrad Bishop
54*a34c030eSBrad Bishop
55*a34c030eSBrad Bishopdef parse_address(addr):
56*a34c030eSBrad Bishop    if addr.startswith(UNIX_PREFIX):
57*a34c030eSBrad Bishop        return (ADDR_TYPE_UNIX, (addr[len(UNIX_PREFIX):],))
58*a34c030eSBrad Bishop    else:
59*a34c030eSBrad Bishop        m = re.match(r'\[(?P<host>[^\]]*)\]:(?P<port>\d+)$', addr)
60*a34c030eSBrad Bishop        if m is not None:
61*a34c030eSBrad Bishop            host = m.group('host')
62*a34c030eSBrad Bishop            port = m.group('port')
63*a34c030eSBrad Bishop        else:
64*a34c030eSBrad Bishop            host, port = addr.split(':')
65*a34c030eSBrad Bishop
66*a34c030eSBrad Bishop        return (ADDR_TYPE_TCP, (host, int(port)))
67*a34c030eSBrad Bishop
68*a34c030eSBrad Bishop
69*a34c030eSBrad Bishopdef create_server(addr, dbname, *, sync=True):
70*a34c030eSBrad Bishop    from . import server
71*a34c030eSBrad Bishop    db = setup_database(dbname, sync=sync)
72*a34c030eSBrad Bishop    s = server.Server(db)
73*a34c030eSBrad Bishop
74*a34c030eSBrad Bishop    (typ, a) = parse_address(addr)
75*a34c030eSBrad Bishop    if typ == ADDR_TYPE_UNIX:
76*a34c030eSBrad Bishop        s.start_unix_server(*a)
77*a34c030eSBrad Bishop    else:
78*a34c030eSBrad Bishop        s.start_tcp_server(*a)
79*a34c030eSBrad Bishop
80*a34c030eSBrad Bishop    return s
81*a34c030eSBrad Bishop
82*a34c030eSBrad Bishop
83*a34c030eSBrad Bishopdef create_client(addr):
84*a34c030eSBrad Bishop    from . import client
85*a34c030eSBrad Bishop    c = client.Client()
86*a34c030eSBrad Bishop
87*a34c030eSBrad Bishop    (typ, a) = parse_address(addr)
88*a34c030eSBrad Bishop    if typ == ADDR_TYPE_UNIX:
89*a34c030eSBrad Bishop        c.connect_unix(*a)
90*a34c030eSBrad Bishop    else:
91*a34c030eSBrad Bishop        c.connect_tcp(*a)
92*a34c030eSBrad Bishop
93*a34c030eSBrad Bishop    return c
94