aboutsummaryrefslogtreecommitdiff
path: root/http2irc.py
diff options
context:
space:
mode:
authorGravatar JustAnotherArchivist2021-04-28 05:29:06 +0000
committerGravatar JustAnotherArchivist2021-04-28 05:29:06 +0000
commit007c50fbc88fd4853b1dbe4f59f6a1989694413d (patch)
tree68b2993724b572ad69f097feeebdf066710b3cca /http2irc.py
parentFix crash if the data is split between CR and LF (cf. irclog commit 68c577bc) (diff)
signature
Add /status endpoint for monitoring (cf. irclog commit 5b809b1b)
Diffstat (limited to 'http2irc.py')
-rw-r--r--http2irc.py24
1 files changed, 21 insertions, 3 deletions
diff --git a/http2irc.py b/http2irc.py
index e8c8c4c..9225aa7 100644
--- a/http2irc.py
+++ b/http2irc.py
@@ -148,6 +148,8 @@ class Config(dict):
raise InvalidConfig(f'Invalid map {key!r} web path: not a string')
if not map_['webpath'].startswith('/'):
raise InvalidConfig(f'Invalid map {key!r} web path: does not start at the root')
+ if map_['webpath'] == '/status':
+ raise InvalidConfig(f'Invalid map {key!r} web path: cannot be "/status"')
if map_['webpath'] in seenWebPaths:
raise InvalidConfig(f'Invalid map {key!r} web path: collides with map {seenWebPaths[map_["webpath"]]!r}')
seenWebPaths[map_['webpath']] = key
@@ -312,6 +314,7 @@ class IRCClientProtocol(asyncio.Protocol):
self.connectionClosedEvent = connectionClosedEvent
self.loop = loop
self.config = config
+ self.lastRecvTime = None
self.buffer = b''
self.connected = False
self.channels = channels # Currently joined/supposed-to-be-joined channels; set(str)
@@ -495,6 +498,7 @@ class IRCClientProtocol(asyncio.Protocol):
def data_received(self, data):
self.logger.debug(f'Data received: {data!r}')
+ self.lastRecvTime = time.time()
# If there's any data left in the buffer, prepend it to the data. Split on CRLF.
# Then, process all messages except the last one (since data might not end on a CRLF) and keep the remainder in the buffer.
# If data does end with CRLF, all messages will have been processed and the buffer will be empty again.
@@ -647,24 +651,34 @@ class IRCClient:
await wait_cancel_pending({asyncio.create_task(connectionClosedEvent.wait()), asyncio.create_task(sigintEvent.wait())}, return_when = concurrent.futures.FIRST_COMPLETED)
finally:
self._transport.close() #TODO BaseTransport.close is asynchronous and then triggers the protocol's connection_lost callback; need to wait for connectionClosedEvent again perhaps to correctly handle ^C?
+ self._transport = None
+ self._protocol = None
except (ConnectionRefusedError, asyncio.TimeoutError) as e:
self.logger.error(str(e))
await wait_cancel_pending({asyncio.create_task(sigintEvent.wait())}, timeout = 5)
if sigintEvent.is_set():
break
+ @property
+ def lastRecvTime(self):
+ return self._protocol.lastRecvTime if self._protocol else None
+
class WebServer:
logger = logging.getLogger('http2irc.WebServer')
- def __init__(self, messageQueue, config):
+ def __init__(self, messageQueue, ircClient, config):
self.messageQueue = messageQueue
+ self.ircClient = ircClient
self.config = config
self._paths = {} # '/path' => ('#channel', auth, module, moduleargs) where auth is either False (no authentication) or the HTTP header value for basic auth
self._app = aiohttp.web.Application()
- self._app.add_routes([aiohttp.web.post('/{path:.+}', self.post)])
+ self._app.add_routes([
+ aiohttp.web.get('/status', self.get_status),
+ aiohttp.web.post('/{path:.+}', self.post)
+ ])
self.update_config(config)
self._configChanged = asyncio.Event()
@@ -688,6 +702,10 @@ class WebServer:
break
self._configChanged.clear()
+ async def get_status(self, request):
+ self.logger.info(f'Received request {id(request)} from {request.remote!r} for {request.path!r}')
+ return (aiohttp.web.Response if (self.ircClient.lastRecvTime or 0) > time.time() - 600 else aiohttp.web.HTTPInternalServerError)()
+
async def post(self, request):
self.logger.info(f'Received request {id(request)} from {request.remote!r} for {request.path!r} with body {(await request.read())!r}')
try:
@@ -761,7 +779,7 @@ async def main():
messageQueue = MessageQueue()
irc = IRCClient(messageQueue, config)
- webserver = WebServer(messageQueue, config)
+ webserver = WebServer(messageQueue, irc, config)
sigintEvent = asyncio.Event()
def sigint_callback():