webhooks: Close clients that become unresponsive

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2022-05-23 22:04:18 -04:00
parent 7b9583391e
commit a283e0f7d4
1 changed files with 15 additions and 0 deletions

View File

@ -162,6 +162,16 @@ class ServerSocket:
def pop_client(self, client_id): def pop_client(self, client_id):
self.clients.pop(client_id, None) self.clients.pop(client_id, None)
def stats(self, eventtime):
# Called once per second - check for idle clients
for client in list(self.clients.values()):
if client.is_blocking:
client.blocking_count -= 1
if client.blocking_count < 0:
logging.info("Closing unresponsive client %s", client.uid)
client.close()
return False, ""
class ClientConnection: class ClientConnection:
def __init__(self, server, sock): def __init__(self, server, sock):
self.printer = server.printer self.printer = server.printer
@ -174,6 +184,7 @@ class ClientConnection:
self.sock.fileno(), self.process_received, self._do_send) self.sock.fileno(), self.process_received, self._do_send)
self.partial_data = self.send_buffer = b"" self.partial_data = self.send_buffer = b""
self.is_blocking = False self.is_blocking = False
self.blocking_count = 0
self.set_client_info("?", "New connection") self.set_client_info("?", "New connection")
self.request_log = collections.deque([], REQUEST_LOG_SIZE) self.request_log = collections.deque([], REQUEST_LOG_SIZE)
@ -277,6 +288,7 @@ class ClientConnection:
if not self.is_blocking: if not self.is_blocking:
self.reactor.set_fd_wake(self.fd_handle, False, True) self.reactor.set_fd_wake(self.fd_handle, False, True)
self.is_blocking = True self.is_blocking = True
self.blocking_count = 5
elif self.is_blocking: elif self.is_blocking:
self.reactor.set_fd_wake(self.fd_handle, True, False) self.reactor.set_fd_wake(self.fd_handle, True, False)
self.is_blocking = False self.is_blocking = False
@ -370,6 +382,9 @@ class WebHooks:
state_message, state = self.printer.get_state_message() state_message, state = self.printer.get_state_message()
return {'state': state, 'state_message': state_message} return {'state': state, 'state_message': state_message}
def stats(self, eventtime):
return self.sconn.stats(eventtime)
def call_remote_method(self, method, **kwargs): def call_remote_method(self, method, **kwargs):
if method not in self._remote_methods: if method not in self._remote_methods:
raise self.printer.command_error( raise self.printer.command_error(