def init_windows(self): self.stdscr = curses.initscr() self.stdscr.clear() self.stdscr.nodelay(True) curses.start_color() self.main_window = MainWindow(self.stdscr) self.warning_windows = []
class Monitor: def __init__(self, args): self.controls = {} self.init_windows() self.godname = args.god_name self.dump_file = args.state self.state = {} self.notification_command = args.notification_command self.quiet = args.quiet self.browser = args.browser if args.browser else "x-www-browser" self.refresh_command = args.refresh_command self.autorefresh = args.autorefresh self.open_browser_on_start = args.open_browser_on_start self.token = args.token self.rules = [] self.prev_state = None self.error = None curses.noecho() try: curses.cbreak() except curses.error: logging.error('curses error: cbreak returned ERR, probably invalid terminal. Try screen or tmux.') pass self.init_colors() self.init_keys() self.init_status_checkers() def finalize(self): curses.echo() try: curses.nocbreak() except curses.error: logging.error('curses error: cbreak returned ERR, probably invalid terminal. Try screen or tmux.') pass curses.endwin() def init_keys(self): self.controls['q'] = self.quit self.controls['f'] = self.open_browser self.controls['F'] = self.refresh_session self.controls[' '] = self.remove_warning def init_windows(self): self.stdscr = curses.initscr() self.stdscr.clear() self.stdscr.nodelay(True) curses.start_color() self.main_window = MainWindow(self.stdscr) self.warning_windows = [] def init_colors(self): curses.use_default_colors() COLOR_TRANSPARENT = -1 curses.init_pair(Colors.STANDART, curses.COLOR_WHITE, COLOR_TRANSPARENT) curses.init_pair(Colors.HEALTH_POINTS, curses.COLOR_RED, COLOR_TRANSPARENT) curses.init_pair(Colors.POWER_POINTS, curses.COLOR_BLUE, COLOR_TRANSPARENT) curses.init_pair(Colors.ATTENTION, curses.COLOR_WHITE, curses.COLOR_RED) curses.init_pair(Colors.MONEY, curses.COLOR_YELLOW, COLOR_TRANSPARENT) curses.init_pair(Colors.HEALING, curses.COLOR_GREEN, COLOR_TRANSPARENT) def post_warning(self, warning_message): if self.quiet: return if self.notification_command: os.system(self.notification_command.format(warning_message)) # FIXME: Highly insecure! self.warning_windows.append(WarningWindow(self.stdscr, warning_message)) def remove_warning(self): if len(self.warning_windows) != 0: del self.warning_windows[-1] self.main_window.update(self.state) def handle_expired_session(self): if self.autorefresh: if self.expired_on_start: self.expired_on_start = False if self.open_browser_on_start: self.open_browser() else: self.refresh_session() else: self.refresh_session() else: self.post_warning(tr('Session is expired. Please reconnect.')) def init_status_checkers(self): self.rules.append(Rule( lambda info: 'expired' in info and info['expired'], self.handle_expired_session )) for custom_rule in CUSTOM_RULES: action = custom_rule(None) if isinstance(action, str) or isinstance(action, unicode): # Trick to bind message text at the creation time, not call time. action = lambda action=action: self.post_warning(action) self.rules.append(Rule(custom_rule, action)) def read_state(self): logging.debug('%s: reading state', self.read_state.__name__) state = None try: if self.dump_file != None: state = self.read_dump(self.dump_file) else: state = load_hero_state(self.godname, self.token) self.error = None except urllib.error.URLError as e: logging.error('%s: reading state error \n %s', self.read_state.__name__, str(e)) self.post_warning(tr('Connection error: {0}').format(e)) if self.prev_state is None: print(tr('Error occured, please see the pygod.log')) sys.exit(1) state = self.prev_state self.error = str(e) except Exception as e: logging.error('%s: reading state error \n %s %s %s', self.read_state.__name__, str(type(e)), repr(e), str(e)) print(tr('Error occured, please see the pygod.log')) sys.exit(1) if 'token_expired' in state: self.post_warning(tr('Token is expired.\n' 'Visit user profile page to generate a new one:\n' 'https://godville.net/user/profile' )) self.prev_state = state return state def read_dump(self, dumpfile): state = None try: state = load_hero_state(self.godname, filename=dumpfile) except IOError: logging.error('%s: Error reading file %s', self.read_dump.__name__, dumpfile) return state def handle_key(self): try: key = self.stdscr.getkey() if key in self.controls: self.controls[key]() except curses.error as e: if not 'no input' in e.args: raise def quit(self): sys.exit(0) def open_browser(self): subprocess.Popen("{0} http://godville.net/superhero".format(self.browser), shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # FIXME also unsafe! def refresh_session(self): if self.refresh_command: subprocess.Popen(self.refresh_command, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # FIXME also unsafe! def check_status(self, state): for rule in self.rules: rule.check(state) def main_loop(self): UPDATE_INTERVAL = 61 last_update_time = time.time() self.state = self.read_state() if self.error: self.state['error'] = self.error self.expired_on_start = 'expired' in self.state and self.state['expired'] self.check_status(self.state) self.main_window.update(self.state) while(True): if last_update_time + UPDATE_INTERVAL < time.time(): last_update_time = time.time() self.state = self.read_state() self.check_status(self.state) self.main_window.update(self.state) if len(self.warning_windows) != 0: self.warning_windows[-1].update({}) self.handle_key() time.sleep(0.1)