108902b01SBrad Bishop# Copyright (C) 2018-2019 Garmin Ltd. 219323693SBrad Bishop# 3c342db35SBrad Bishop# SPDX-License-Identifier: GPL-2.0-only 419323693SBrad Bishop# 519323693SBrad Bishop 66ce62a20SAndrew Geisslerimport asyncio 7a34c030eSBrad Bishopfrom contextlib import closing 8a34c030eSBrad Bishopimport re 9475cb72dSAndrew Geisslerimport itertools 10475cb72dSAndrew Geisslerimport json 11*ac13d5f3SPatrick Williamsfrom collections import namedtuple 12*ac13d5f3SPatrick Williamsfrom urllib.parse import urlparse 1319323693SBrad Bishop 14a34c030eSBrad BishopUNIX_PREFIX = "unix://" 15*ac13d5f3SPatrick WilliamsWS_PREFIX = "ws://" 16*ac13d5f3SPatrick WilliamsWSS_PREFIX = "wss://" 1719323693SBrad Bishop 18a34c030eSBrad BishopADDR_TYPE_UNIX = 0 19a34c030eSBrad BishopADDR_TYPE_TCP = 1 20*ac13d5f3SPatrick WilliamsADDR_TYPE_WS = 2 2119323693SBrad Bishop 22*ac13d5f3SPatrick WilliamsUser = namedtuple("User", ("username", "permissions")) 23a34c030eSBrad Bishop 24a34c030eSBrad Bishop 25a34c030eSBrad Bishopdef parse_address(addr): 26a34c030eSBrad Bishop if addr.startswith(UNIX_PREFIX): 27a34c030eSBrad Bishop return (ADDR_TYPE_UNIX, (addr[len(UNIX_PREFIX) :],)) 28*ac13d5f3SPatrick Williams elif addr.startswith(WS_PREFIX) or addr.startswith(WSS_PREFIX): 29*ac13d5f3SPatrick Williams return (ADDR_TYPE_WS, (addr,)) 30a34c030eSBrad Bishop else: 31*ac13d5f3SPatrick Williams m = re.match(r"\[(?P<host>[^\]]*)\]:(?P<port>\d+)$", addr) 32a34c030eSBrad Bishop if m is not None: 33*ac13d5f3SPatrick Williams host = m.group("host") 34*ac13d5f3SPatrick Williams port = m.group("port") 35a34c030eSBrad Bishop else: 36*ac13d5f3SPatrick Williams host, port = addr.split(":") 37a34c030eSBrad Bishop 38a34c030eSBrad Bishop return (ADDR_TYPE_TCP, (host, int(port))) 39a34c030eSBrad Bishop 40a34c030eSBrad Bishop 41*ac13d5f3SPatrick Williamsdef create_server( 42*ac13d5f3SPatrick Williams addr, 43*ac13d5f3SPatrick Williams dbname, 44*ac13d5f3SPatrick Williams *, 45*ac13d5f3SPatrick Williams sync=True, 46*ac13d5f3SPatrick Williams upstream=None, 47*ac13d5f3SPatrick Williams read_only=False, 48*ac13d5f3SPatrick Williams db_username=None, 49*ac13d5f3SPatrick Williams db_password=None, 50*ac13d5f3SPatrick Williams anon_perms=None, 51*ac13d5f3SPatrick Williams admin_username=None, 52*ac13d5f3SPatrick Williams admin_password=None, 53*ac13d5f3SPatrick Williams): 54*ac13d5f3SPatrick Williams def sqlite_engine(): 55*ac13d5f3SPatrick Williams from .sqlite import DatabaseEngine 56475cb72dSAndrew Geissler 57*ac13d5f3SPatrick Williams return DatabaseEngine(dbname, sync) 58475cb72dSAndrew Geissler 59*ac13d5f3SPatrick Williams def sqlalchemy_engine(): 60*ac13d5f3SPatrick Williams from .sqlalchemy import DatabaseEngine 61475cb72dSAndrew Geissler 62*ac13d5f3SPatrick Williams return DatabaseEngine(dbname, db_username, db_password) 63*ac13d5f3SPatrick Williams 64a34c030eSBrad Bishop from . import server 65*ac13d5f3SPatrick Williams 66*ac13d5f3SPatrick Williams if "://" in dbname: 67*ac13d5f3SPatrick Williams db_engine = sqlalchemy_engine() 68*ac13d5f3SPatrick Williams else: 69*ac13d5f3SPatrick Williams db_engine = sqlite_engine() 70*ac13d5f3SPatrick Williams 71*ac13d5f3SPatrick Williams if anon_perms is None: 72*ac13d5f3SPatrick Williams anon_perms = server.DEFAULT_ANON_PERMS 73*ac13d5f3SPatrick Williams 74*ac13d5f3SPatrick Williams s = server.Server( 75*ac13d5f3SPatrick Williams db_engine, 76*ac13d5f3SPatrick Williams upstream=upstream, 77*ac13d5f3SPatrick Williams read_only=read_only, 78*ac13d5f3SPatrick Williams anon_perms=anon_perms, 79*ac13d5f3SPatrick Williams admin_username=admin_username, 80*ac13d5f3SPatrick Williams admin_password=admin_password, 81*ac13d5f3SPatrick Williams ) 82a34c030eSBrad Bishop 83a34c030eSBrad Bishop (typ, a) = parse_address(addr) 84a34c030eSBrad Bishop if typ == ADDR_TYPE_UNIX: 85a34c030eSBrad Bishop s.start_unix_server(*a) 86*ac13d5f3SPatrick Williams elif typ == ADDR_TYPE_WS: 87*ac13d5f3SPatrick Williams url = urlparse(a[0]) 88*ac13d5f3SPatrick Williams s.start_websocket_server(url.hostname, url.port) 89a34c030eSBrad Bishop else: 90a34c030eSBrad Bishop s.start_tcp_server(*a) 91a34c030eSBrad Bishop 92a34c030eSBrad Bishop return s 93a34c030eSBrad Bishop 94a34c030eSBrad Bishop 95*ac13d5f3SPatrick Williamsdef create_client(addr, username=None, password=None): 96a34c030eSBrad Bishop from . import client 97a34c030eSBrad Bishop 98*ac13d5f3SPatrick Williams c = client.Client(username, password) 99*ac13d5f3SPatrick Williams 100*ac13d5f3SPatrick Williams try: 101a34c030eSBrad Bishop (typ, a) = parse_address(addr) 102a34c030eSBrad Bishop if typ == ADDR_TYPE_UNIX: 103a34c030eSBrad Bishop c.connect_unix(*a) 104*ac13d5f3SPatrick Williams elif typ == ADDR_TYPE_WS: 105*ac13d5f3SPatrick Williams c.connect_websocket(*a) 106a34c030eSBrad Bishop else: 107a34c030eSBrad Bishop c.connect_tcp(*a) 108a34c030eSBrad Bishop return c 109*ac13d5f3SPatrick Williams except Exception as e: 110*ac13d5f3SPatrick Williams c.close() 111*ac13d5f3SPatrick Williams raise e 1126ce62a20SAndrew Geissler 113*ac13d5f3SPatrick Williams 114*ac13d5f3SPatrick Williamsasync def create_async_client(addr, username=None, password=None): 1156ce62a20SAndrew Geissler from . import client 1166ce62a20SAndrew Geissler 117*ac13d5f3SPatrick Williams c = client.AsyncClient(username, password) 118*ac13d5f3SPatrick Williams 119*ac13d5f3SPatrick Williams try: 1206ce62a20SAndrew Geissler (typ, a) = parse_address(addr) 1216ce62a20SAndrew Geissler if typ == ADDR_TYPE_UNIX: 1226ce62a20SAndrew Geissler await c.connect_unix(*a) 123*ac13d5f3SPatrick Williams elif typ == ADDR_TYPE_WS: 124*ac13d5f3SPatrick Williams await c.connect_websocket(*a) 1256ce62a20SAndrew Geissler else: 1266ce62a20SAndrew Geissler await c.connect_tcp(*a) 1276ce62a20SAndrew Geissler 1286ce62a20SAndrew Geissler return c 129*ac13d5f3SPatrick Williams except Exception as e: 130*ac13d5f3SPatrick Williams await c.close() 131*ac13d5f3SPatrick Williams raise e 132