1# Copyright (C) 2018-2019 Garmin Ltd. 2# 3# SPDX-License-Identifier: GPL-2.0-only 4# 5 6import asyncio 7from contextlib import closing 8import re 9import itertools 10import json 11from collections import namedtuple 12from urllib.parse import urlparse 13 14UNIX_PREFIX = "unix://" 15WS_PREFIX = "ws://" 16WSS_PREFIX = "wss://" 17 18ADDR_TYPE_UNIX = 0 19ADDR_TYPE_TCP = 1 20ADDR_TYPE_WS = 2 21 22User = namedtuple("User", ("username", "permissions")) 23 24 25def parse_address(addr): 26 if addr.startswith(UNIX_PREFIX): 27 return (ADDR_TYPE_UNIX, (addr[len(UNIX_PREFIX) :],)) 28 elif addr.startswith(WS_PREFIX) or addr.startswith(WSS_PREFIX): 29 return (ADDR_TYPE_WS, (addr,)) 30 else: 31 m = re.match(r"\[(?P<host>[^\]]*)\]:(?P<port>\d+)$", addr) 32 if m is not None: 33 host = m.group("host") 34 port = m.group("port") 35 else: 36 host, port = addr.split(":") 37 38 return (ADDR_TYPE_TCP, (host, int(port))) 39 40 41def create_server( 42 addr, 43 dbname, 44 *, 45 sync=True, 46 upstream=None, 47 read_only=False, 48 db_username=None, 49 db_password=None, 50 anon_perms=None, 51 admin_username=None, 52 admin_password=None, 53): 54 def sqlite_engine(): 55 from .sqlite import DatabaseEngine 56 57 return DatabaseEngine(dbname, sync) 58 59 def sqlalchemy_engine(): 60 from .sqlalchemy import DatabaseEngine 61 62 return DatabaseEngine(dbname, db_username, db_password) 63 64 from . import server 65 66 if "://" in dbname: 67 db_engine = sqlalchemy_engine() 68 else: 69 db_engine = sqlite_engine() 70 71 if anon_perms is None: 72 anon_perms = server.DEFAULT_ANON_PERMS 73 74 s = server.Server( 75 db_engine, 76 upstream=upstream, 77 read_only=read_only, 78 anon_perms=anon_perms, 79 admin_username=admin_username, 80 admin_password=admin_password, 81 ) 82 83 (typ, a) = parse_address(addr) 84 if typ == ADDR_TYPE_UNIX: 85 s.start_unix_server(*a) 86 elif typ == ADDR_TYPE_WS: 87 url = urlparse(a[0]) 88 s.start_websocket_server(url.hostname, url.port) 89 else: 90 s.start_tcp_server(*a) 91 92 return s 93 94 95def create_client(addr, username=None, password=None): 96 from . import client 97 98 c = client.Client(username, password) 99 100 try: 101 (typ, a) = parse_address(addr) 102 if typ == ADDR_TYPE_UNIX: 103 c.connect_unix(*a) 104 elif typ == ADDR_TYPE_WS: 105 c.connect_websocket(*a) 106 else: 107 c.connect_tcp(*a) 108 return c 109 except Exception as e: 110 c.close() 111 raise e 112 113 114async def create_async_client(addr, username=None, password=None): 115 from . import client 116 117 c = client.AsyncClient(username, password) 118 119 try: 120 (typ, a) = parse_address(addr) 121 if typ == ADDR_TYPE_UNIX: 122 await c.connect_unix(*a) 123 elif typ == ADDR_TYPE_WS: 124 await c.connect_websocket(*a) 125 else: 126 await c.connect_tcp(*a) 127 128 return c 129 except Exception as e: 130 await c.close() 131 raise e 132