| Total Complexity | 45 |
| Total Lines | 244 |
| Duplicated Lines | 0 % |
Complex classes like glances.outputs.GlancesCursesBrowser often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | # -*- coding: utf-8 -*- |
||
| 30 | class GlancesCursesBrowser(_GlancesCurses): |
||
| 31 | |||
| 32 | """Class for the Glances curse client browser.""" |
||
| 33 | |||
| 34 | def __init__(self, args=None): |
||
| 35 | # Init the father class |
||
| 36 | super(GlancesCursesBrowser, self).__init__(args=args) |
||
| 37 | |||
| 38 | _colors_list = { |
||
| 39 | 'UNKNOWN': self.no_color, |
||
| 40 | 'SNMP': self.default_color2, |
||
| 41 | 'ONLINE': self.default_color2, |
||
| 42 | 'OFFLINE': self.ifCRITICAL_color2, |
||
| 43 | 'PROTECTED': self.ifWARNING_color2, |
||
| 44 | } |
||
| 45 | self.colors_list.update(_colors_list) |
||
| 46 | |||
| 47 | # First time scan tag |
||
| 48 | # Used to display a specific message when the browser is started |
||
| 49 | self.first_scan = True |
||
| 50 | |||
| 51 | # Init refresh time |
||
| 52 | self.__refresh_time = args.time |
||
| 53 | |||
| 54 | # Init the cursor position for the client browser |
||
| 55 | self.cursor_position = 0 |
||
| 56 | |||
| 57 | # Active Glances server number |
||
| 58 | self._active_server = None |
||
| 59 | |||
| 60 | @property |
||
| 61 | def active_server(self): |
||
| 62 | """Return the active server or None if it's the browser list.""" |
||
| 63 | return self._active_server |
||
| 64 | |||
| 65 | @active_server.setter |
||
| 66 | def active_server(self, index): |
||
| 67 | """Set the active server or None if no server selected.""" |
||
| 68 | self._active_server = index |
||
| 69 | |||
| 70 | @property |
||
| 71 | def cursor(self): |
||
| 72 | """Get the cursor position.""" |
||
| 73 | return self.cursor_position |
||
| 74 | |||
| 75 | @cursor.setter |
||
| 76 | def cursor(self, position): |
||
| 77 | """Set the cursor position.""" |
||
| 78 | self.cursor_position = position |
||
| 79 | |||
| 80 | def cursor_up(self, servers_list): |
||
| 81 | """Set the cursor to position N-1 in the list.""" |
||
| 82 | if self.cursor_position > 0: |
||
| 83 | self.cursor_position -= 1 |
||
| 84 | else: |
||
| 85 | self.cursor_position = len(servers_list) - 1 |
||
| 86 | |||
| 87 | def cursor_down(self, servers_list): |
||
| 88 | """Set the cursor to position N-1 in the list.""" |
||
| 89 | if self.cursor_position < len(servers_list) - 1: |
||
| 90 | self.cursor_position += 1 |
||
| 91 | else: |
||
| 92 | self.cursor_position = 0 |
||
| 93 | |||
| 94 | def __catch_key(self, servers_list): |
||
| 95 | # Catch the browser pressed key |
||
| 96 | self.pressedkey = self.get_key(self.term_window) |
||
| 97 | |||
| 98 | if self.pressedkey != -1: |
||
| 99 | logger.debug("Key pressed. Code=%s" % self.pressedkey) |
||
| 100 | |||
| 101 | # Actions... |
||
| 102 | if self.pressedkey == ord('\x1b') or self.pressedkey == ord('q'): |
||
| 103 | # 'ESC'|'q' > Quit |
||
| 104 | self.end() |
||
| 105 | logger.info("Stop Glances client browser") |
||
| 106 | sys.exit(0) |
||
| 107 | elif self.pressedkey == 10: |
||
| 108 | # 'ENTER' > Run Glances on the selected server |
||
| 109 | logger.debug("Server number {0} selected".format(self.cursor + 1)) |
||
| 110 | self.active_server = self.cursor |
||
| 111 | elif self.pressedkey == 65: |
||
| 112 | # 'UP' > Up in the server list |
||
| 113 | self.cursor_up(servers_list) |
||
| 114 | elif self.pressedkey == 66: |
||
| 115 | # 'DOWN' > Down in the server list |
||
| 116 | self.cursor_down(servers_list) |
||
| 117 | |||
| 118 | # Return the key code |
||
| 119 | return self.pressedkey |
||
| 120 | |||
| 121 | def update(self, servers_list): |
||
| 122 | """Update the servers' list screen. |
||
| 123 | |||
| 124 | Wait for __refresh_time sec / catch key every 100 ms. |
||
| 125 | |||
| 126 | servers_list: Dict of dict with servers stats |
||
| 127 | """ |
||
| 128 | # Flush display |
||
| 129 | logger.debug('Servers list: {0}'.format(servers_list)) |
||
| 130 | self.flush(servers_list) |
||
| 131 | |||
| 132 | # Wait |
||
| 133 | exitkey = False |
||
| 134 | countdown = Timer(self.__refresh_time) |
||
| 135 | while not countdown.finished() and not exitkey: |
||
| 136 | # Getkey |
||
| 137 | pressedkey = self.__catch_key(servers_list) |
||
| 138 | # Is it an exit or select server key ? |
||
| 139 | exitkey = ( |
||
| 140 | pressedkey == ord('\x1b') or pressedkey == ord('q') or pressedkey == 10) |
||
| 141 | if not exitkey and pressedkey > -1: |
||
| 142 | # Redraw display |
||
| 143 | self.flush(servers_list) |
||
| 144 | # Wait 100ms... |
||
| 145 | self.wait() |
||
| 146 | |||
| 147 | return self.active_server |
||
| 148 | |||
| 149 | def flush(self, servers_list): |
||
| 150 | """Update the servers' list screen. |
||
| 151 | |||
| 152 | servers_list: List of dict with servers stats |
||
| 153 | """ |
||
| 154 | self.erase() |
||
| 155 | self.display(servers_list) |
||
| 156 | |||
| 157 | def display(self, servers_list): |
||
| 158 | """Display the servers list. |
||
| 159 | |||
| 160 | Return: |
||
| 161 | True if the stats have been displayed |
||
| 162 | False if the stats have not been displayed (no server available) |
||
| 163 | """ |
||
| 164 | # Init the internal line/column for Glances Curses |
||
| 165 | self.init_line_column() |
||
| 166 | |||
| 167 | # Get the current screen size |
||
| 168 | screen_x = self.screen.getmaxyx()[1] |
||
| 169 | screen_y = self.screen.getmaxyx()[0] |
||
| 170 | |||
| 171 | # Init position |
||
| 172 | x = 0 |
||
| 173 | y = 0 |
||
| 174 | |||
| 175 | # Display top header |
||
| 176 | if len(servers_list) == 0: |
||
| 177 | if self.first_scan and not self.args.disable_autodiscover: |
||
| 178 | msg = 'Glances is scanning your network. Please wait...' |
||
| 179 | self.first_scan = False |
||
| 180 | else: |
||
| 181 | msg = 'No Glances server available' |
||
| 182 | elif len(servers_list) == 1: |
||
| 183 | msg = 'One Glances server available' |
||
| 184 | else: |
||
| 185 | msg = '{0} Glances servers available'.format(len(servers_list)) |
||
| 186 | if self.args.disable_autodiscover: |
||
| 187 | msg += ' ' + '(auto discover is disabled)' |
||
| 188 | self.term_window.addnstr(y, x, |
||
| 189 | msg, |
||
| 190 | screen_x - x, |
||
| 191 | self.colors_list['TITLE']) |
||
| 192 | |||
| 193 | if len(servers_list) == 0: |
||
| 194 | return False |
||
| 195 | |||
| 196 | # Display the Glances server list |
||
| 197 | # ================================ |
||
| 198 | |||
| 199 | # Table of table |
||
| 200 | # Item description: [stats_id, column name, column size] |
||
| 201 | column_def = [ |
||
| 202 | ['name', 'Name', 16], |
||
| 203 | ['alias', None, None], |
||
| 204 | ['load_min5', 'LOAD', 6], |
||
| 205 | ['cpu_percent', 'CPU%', 5], |
||
| 206 | ['mem_percent', 'MEM%', 5], |
||
| 207 | ['status', 'STATUS', 9], |
||
| 208 | ['ip', 'IP', 15], |
||
| 209 | # ['port', 'PORT', 5], |
||
| 210 | ['hr_name', 'OS', 16], |
||
| 211 | ] |
||
| 212 | y = 2 |
||
| 213 | |||
| 214 | # Display table header |
||
| 215 | xc = x + 2 |
||
| 216 | for cpt, c in enumerate(column_def): |
||
| 217 | if xc < screen_x and y < screen_y and c[1] is not None: |
||
| 218 | self.term_window.addnstr(y, xc, |
||
| 219 | c[1], |
||
| 220 | screen_x - x, |
||
| 221 | self.colors_list['BOLD']) |
||
| 222 | xc += c[2] + self.space_between_column |
||
| 223 | y += 1 |
||
| 224 | |||
| 225 | # If a servers has been deleted from the list... |
||
| 226 | # ... and if the cursor is in the latest position |
||
| 227 | if self.cursor > len(servers_list) - 1: |
||
| 228 | # Set the cursor position to the latest item |
||
| 229 | self.cursor = len(servers_list) - 1 |
||
| 230 | |||
| 231 | # Display table |
||
| 232 | line = 0 |
||
| 233 | for v in servers_list: |
||
| 234 | # Get server stats |
||
| 235 | server_stat = {} |
||
| 236 | for c in column_def: |
||
| 237 | try: |
||
| 238 | server_stat[c[0]] = v[c[0]] |
||
| 239 | except KeyError as e: |
||
| 240 | logger.debug( |
||
| 241 | "Cannot grab stats {0} from server (KeyError: {1})".format(c[0], e)) |
||
| 242 | server_stat[c[0]] = '?' |
||
| 243 | # Display alias instead of name |
||
| 244 | try: |
||
| 245 | if c[0] == 'alias' and v[c[0]] is not None: |
||
| 246 | server_stat['name'] = v[c[0]] |
||
| 247 | except KeyError: |
||
| 248 | pass |
||
| 249 | |||
| 250 | # Display line for server stats |
||
| 251 | cpt = 0 |
||
| 252 | xc = x |
||
| 253 | |||
| 254 | # Is the line selected ? |
||
| 255 | if line == self.cursor: |
||
| 256 | # Display cursor |
||
| 257 | self.term_window.addnstr( |
||
| 258 | y, xc, ">", screen_x - xc, self.colors_list['BOLD']) |
||
| 259 | |||
| 260 | # Display the line |
||
| 261 | xc += 2 |
||
| 262 | for c in column_def: |
||
| 263 | if xc < screen_x and y < screen_y and c[1] is not None: |
||
| 264 | # Display server stats |
||
| 265 | self.term_window.addnstr( |
||
| 266 | y, xc, format(server_stat[c[0]]), c[2], self.colors_list[v['status']]) |
||
| 267 | xc += c[2] + self.space_between_column |
||
| 268 | cpt += 1 |
||
| 269 | # Next line, next server... |
||
| 270 | y += 1 |
||
| 271 | line += 1 |
||
| 272 | |||
| 273 | return True |
||
| 274 |