From d406d269da371e8d0c80a1185d34bddc1ccc34ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Mon, 15 Jul 2019 19:14:03 +0300 Subject: [PATCH] Implement offline timeouts --- ethermess.py | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/ethermess.py b/ethermess.py index 9126e29..808b9c5 100644 --- a/ethermess.py +++ b/ethermess.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 libexec_dir = __LIBEXECDIR__ +offline_timeout = 5 * 60 + import enum import select import subprocess @@ -143,8 +145,6 @@ def handle_status(mac, status, nick): peers[mac] = Peer(nick = None, status = None, lastseen = None) - peers[mac].lastseen = time.monotonic() - if peers[mac].nick is not None and peers[mac].status != statuses.offline and nick != peers[mac].nick: print('=== ~%s -> ~%s [%s]' % (peers[mac].nick, nick, format_mac(mac))) @@ -193,6 +193,8 @@ def handle_message(mac, message): print('<%s> %s' % (nick, line)) def eventloop(proc): + global peers + # Create unbuffered version of stdin and close the old one as we # won't need it anymore unbuf_stdin = open(sys.stdin.buffer.fileno(), 'rb', buffering = 0) @@ -207,7 +209,30 @@ def eventloop(proc): running = True while running: - for fd, event in poll.poll(): + # Handle offline timeouts + now = time.monotonic() + for mac, peer in peers.items(): + if peer.lastseen + offline_timeout < now: + peer.status = statuses.offline + print('<<< (timeout) ~%s [%s]' % (peer.nick, format_mac(mac))) + + # Figure out how long to wait in poll() + wait = None + for peer in peers.values(): + if peer.status != statuses.offline: + if wait is None or wait >= peer.lastseen + offline_timeout - now: + wait = peer.lastseen + offline_timeout - now + + # Clamp at 0 + if wait is not None and wait < 0: + wait = 0 + + # Convert s to ms + if wait is not None: + wait = wait * 1000 + + # Process events + for fd, event in poll.poll(wait): if fd == proc.stdout.fileno() and event & select.POLLIN: event_type = readall(proc.stdout, 1) if event_type == b's': @@ -219,6 +244,8 @@ def eventloop(proc): handle_status(source_mac, statuses(status), nick.decode('utf-8')) + peers[source_mac].lastseen = time.monotonic() + elif event_type == b'i': # Msgid for message msgid = readall_u16(proc.stdout) @@ -234,6 +261,8 @@ def eventloop(proc): msgid = readall_u16(proc.stdout) print('(ack: %s %i)' % (format_mac(source_mac), msgid)) #debg + peers[source_mac].lastseen = time.monotonic() + elif event_type == b'A': # ACK not received (and message send failed) print('(ack failed)') #debg @@ -246,6 +275,8 @@ def eventloop(proc): handle_message(source_mac, message.decode('utf-8')) + peers[source_mac].lastseen = time.monotonic() + else: raise ValueError('Unknown event type from backend: %s' % repr(event_type)) @@ -272,6 +303,7 @@ def eventloop(proc): else: raise Exception('Unreachable') + def main(): global own_nick, own_status