mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 16:42:42 +01:00
bpd: track and log client session details
Keep track of a list of currently-connected clients. Use `socket.getpeername()` to get an identifier for each connection and include this in each log message. This function is documented as not being available on all systems, but it's unclear which systems this involves. Also log a message on client connect and disconnect events. If the disconnection reason is because the client sent a blank line, match MPD by returning a protocol error then hanging up. Escape curly braces.
This commit is contained in:
parent
5b0a02eb31
commit
ee0c31ba6a
2 changed files with 38 additions and 6 deletions
|
|
@ -187,9 +187,22 @@ class BaseServer(object):
|
|||
self.paused = False
|
||||
self.error = None
|
||||
|
||||
# Current connections
|
||||
self.connections = set()
|
||||
|
||||
# Object for random numbers generation
|
||||
self.random_obj = random.Random()
|
||||
|
||||
def connect(self, conn):
|
||||
"""A new client has connected.
|
||||
"""
|
||||
self.connections.add(conn)
|
||||
|
||||
def disconnect(self, conn):
|
||||
"""Client has disconnected; clean up residual state.
|
||||
"""
|
||||
self.connections.remove(conn)
|
||||
|
||||
def run(self):
|
||||
"""Block and start listening for connections from clients. An
|
||||
interrupt (^C) closes the server.
|
||||
|
|
@ -643,6 +656,7 @@ class Connection(object):
|
|||
self.server = server
|
||||
self.sock = sock
|
||||
self.authenticated = False
|
||||
self.address = u'{}:{}'.format(*sock.sock.getpeername())
|
||||
|
||||
def send(self, lines):
|
||||
"""Send lines, which which is either a single string or an
|
||||
|
|
@ -653,9 +667,9 @@ class Connection(object):
|
|||
if isinstance(lines, six.string_types):
|
||||
lines = [lines]
|
||||
out = NEWLINE.join(lines) + NEWLINE
|
||||
# Don't log trailing newline:
|
||||
message = out[:-1].replace(u'\n', u'\n' + u' ' * 13)
|
||||
self.server._log.debug('server: {}', message)
|
||||
session = u'>[{}]: '.format(self.address)
|
||||
for l in out.split(NEWLINE)[:-1]:
|
||||
self.server._log.debug('{}', session + l)
|
||||
if isinstance(out, six.text_type):
|
||||
out = out.encode('utf-8')
|
||||
return self.sock.sendall(out)
|
||||
|
|
@ -672,24 +686,36 @@ class Connection(object):
|
|||
# Send success code.
|
||||
yield self.send(RESP_OK)
|
||||
|
||||
def disconnect(self):
|
||||
"""The connection has closed for any reason.
|
||||
"""
|
||||
self.server.disconnect(self)
|
||||
self.server._log.debug(u'*[{}]: disconnected', self.address)
|
||||
|
||||
def run(self):
|
||||
"""Send a greeting to the client and begin processing commands
|
||||
as they arrive.
|
||||
"""
|
||||
self.server._log.debug('New client connected')
|
||||
self.server._log.debug(u'*[{}]: connected', self.address)
|
||||
self.server.connect(self)
|
||||
yield self.send(HELLO)
|
||||
|
||||
session = u'<[{}]: '.format(self.address)
|
||||
clist = None # Initially, no command list is being constructed.
|
||||
while True:
|
||||
line = yield self.sock.readline()
|
||||
if not line:
|
||||
self.disconnect() # Client disappeared.
|
||||
break
|
||||
line = line.strip()
|
||||
if not line:
|
||||
err = BPDError(ERROR_UNKNOWN, u'No command given')
|
||||
yield self.send(err.response())
|
||||
self.disconnect() # Client sent a blank line.
|
||||
break
|
||||
line = line.decode('utf8') # MPD protocol uses UTF-8.
|
||||
message = line.replace(u'\n', u'\n' + u' ' * 13)
|
||||
self.server._log.debug(u'client: {}', message)
|
||||
for l in line.split(NEWLINE):
|
||||
self.server._log.debug('{}', session + l)
|
||||
|
||||
if clist is not None:
|
||||
# Command list already opened.
|
||||
|
|
@ -710,6 +736,7 @@ class Connection(object):
|
|||
except BPDClose:
|
||||
# Command indicates that the conn should close.
|
||||
self.sock.close()
|
||||
self.disconnect() # Client explicitly closed.
|
||||
return
|
||||
|
||||
@classmethod
|
||||
|
|
|
|||
|
|
@ -367,6 +367,11 @@ class BPDTest(BPDTestHelper):
|
|||
response = client.send_command('crash_TypeError')
|
||||
self._assert_failed(response, bpd.ERROR_SYSTEM)
|
||||
|
||||
def test_empty_request(self):
|
||||
with self.run_bpd() as client:
|
||||
response = client.send_command('')
|
||||
self._assert_failed(response, bpd.ERROR_UNKNOWN)
|
||||
|
||||
|
||||
class BPDQueryTest(BPDTestHelper):
|
||||
test_implements_query = implements({
|
||||
|
|
|
|||
Loading…
Reference in a new issue