from ... import util import datetime import os import select from threading import Thread, RLock class TokenControl(util.Loggable): def __init__(self, token_path, fifo_path, control): super().__init__("door") self._token_path = token_path self._fifo_path = fifo_path self._control = control self._open_fifo() self.refresh_tokens() pipes = os.pipe() self._mutex = RLock() self._stop_pipe_write = pipes[1] self._stop_pipe_read = pipes[0] self._thread = None def _open_fifo(self): self._fifo = open(self._fifo_path, "r") def refresh_tokens(self): """Refreshes all tokens from config.valid_tokens""" valid = {} try: self._logger().info("Loading tokens") lines =[ s.strip() for s in open(self._token_path, "r").readlines() ] for i, line in enumerate(lines): l = line.split('|') if len(l) == 5: if not l[0].strip().startswith('#'): token, name, organization, email, valid_thru = l try: if len(valid_thru.strip()) > 0: valid_thru = datetime.date.fromisoformat(valid_thru) else: valid_thru = None except Exception: self._logger().error(f"Could not parse valid thru date for token {token} in line {i}") valid_thru = None self._logger().debug(f"Got token {token} associated with {name} <{email}> of {organization}, valid thru {valid_thru}") if token in valid: self._logger().warning(f"Overwriting token {token}") valid[token] = { 'name': name, 'organization': organization, 'email': email, 'valid_thru': valid_thru } else: self._logger().warning(f"Skipping line {i} ({line}) since it does not contain exactly 5 data field") except Exception as e: valid = {} self._logger().error(f"Error reading token file. Exception: {e}") with self._mutex: self._tokens = valid def start(self): with self._mutex: if self._thread != None: return self._thread = Thread(target = self.run, daemon=True) self._thread.start() def stop(self): with self._mutex: if self._thread == None: return self._stop_pipe_write.write('c') self._thread.join() self._thread = None def run(self): while True: readable = select.select([self._fifo, self._stop_pipe_read], [], [], 0.5)[0] if self._stop_pipe_read in readable: self._stop_pipe_read.read(1) return if self._fifo in readable: line = self._fifo.readline() if line == None: self._open_fifo() continue