Browse Source

cli: Add support for Unix domain sockets

patch-4
yanmaani 3 years ago
parent
commit
b1005694ec
  1. 2
      electrum/commands.py
  2. 41
      electrum/daemon.py

2
electrum/commands.py

@ -1475,6 +1475,8 @@ def get_parser():
# daemon
parser_daemon = subparsers.add_parser('daemon', help="Run Daemon")
parser_daemon.add_argument("-d", "--detached", action="store_true", dest="detach", default=False, help="run daemon in detached mode")
parser_daemon.add_argument("--rpcsock", dest="rpcsock", default=None, help="what socket type to which to bind RPC daemon", choices=['unix', 'tcp', 'auto'])
parser_daemon.add_argument("--rpcsockpath", dest="rpcsockpath", help="where to place RPC file socket")
add_network_options(parser_daemon)
add_global_options(parser_daemon)
# commands

41
electrum/daemon.py

@ -61,10 +61,15 @@ _logger = get_logger(__name__)
class DaemonNotRunning(Exception):
pass
def get_rpcsock_defaultpath(config: SimpleConfig):
return os.path.join(config.path, 'daemon_rpc_socket')
def get_rpcsock_default_type(osname):
return 'tcp'
def get_lockfile(config: SimpleConfig):
return os.path.join(config.path, 'daemon')
def remove_lockfile(lockfile):
os.unlink(lockfile)
@ -96,7 +101,15 @@ def request(config: SimpleConfig, endpoint, args=(), timeout=60):
create_time = None
try:
with open(lockfile) as f:
(host, port), create_time = ast.literal_eval(f.read())
socktype, address, create_time = ast.literal_eval(f.read())
if socktype == 'unix':
path = address
(host, port) = "127.0.0.1", 0
# We still need a host and port for e.g. HTTP Host header
elif socktype == 'tcp':
(host, port) = address
else:
raise Exception(f"corrupt lockfile; socktype={socktype!r}")
except Exception:
raise DaemonNotRunning()
rpc_user, rpc_password = get_rpc_credentials(config)
@ -104,7 +117,13 @@ def request(config: SimpleConfig, endpoint, args=(), timeout=60):
auth = aiohttp.BasicAuth(login=rpc_user, password=rpc_password)
loop = asyncio.get_event_loop()
async def request_coroutine():
async with aiohttp.ClientSession(auth=auth) as session:
if socktype == 'unix':
connector = aiohttp.UnixConnector(path=path)
elif socktype == 'tcp':
connector = None # This will transform into TCP.
else:
raise Exception(f"impossible socktype ({socktype!r})")
async with aiohttp.ClientSession(auth=auth, connector=connector) as session:
c = util.JsonRPCClient(session, server_url)
return await c.request(endpoint, *args)
try:
@ -225,6 +244,9 @@ class CommandsServer(AuthenticatedServer):
self.daemon = daemon
self.fd = fd
self.config = daemon.config
sockettype = self.config.get('rpcsock', 'auto')
self.socktype = sockettype if sockettype != 'auto' else get_rpcsock_default_type(os.name)
self.sockpath = self.config.get('rpcsockpath', get_rpcsock_defaultpath(self.config))
self.host = self.config.get('rpchost', '127.0.0.1')
self.port = self.config.get('rpcport', 0)
self.app = web.Application()
@ -239,10 +261,21 @@ class CommandsServer(AuthenticatedServer):
async def run(self):
self.runner = web.AppRunner(self.app)
await self.runner.setup()
if self.socktype == 'unix':
site = web.UnixSite(self.runner, self.sockpath)
elif self.socktype == 'tcp':
site = web.TCPSite(self.runner, self.host, self.port)
else:
raise Exception(f"unknown socktype '{self.socktype!r}'")
await site.start()
socket = site._server.sockets[0]
os.write(self.fd, bytes(repr((socket.getsockname(), time.time())), 'utf8'))
if self.socktype == 'unix':
addr = self.sockpath
elif self.socktype == 'tcp':
addr = socket.getsockname()
else:
raise Exception(f"impossible socktype ({self.socktype!r})")
os.write(self.fd, bytes(repr((self.socktype, addr, time.time())), 'utf8'))
os.close(self.fd)
async def ping(self):

Loading…
Cancel
Save