monitorify 1.0.1__tar.gz → 1.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. monitorify-1.0.2/PKG-INFO +62 -0
  2. monitorify-1.0.2/README.md +50 -0
  3. {monitorify-1.0.1 → monitorify-1.0.2}/pyproject.toml +1 -1
  4. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/__init__.py +1 -1
  5. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/collector/manager.py +2 -2
  6. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/collector/worker.py +14 -3
  7. monitorify-1.0.2/src/monitorify/config/__init__.py +29 -0
  8. monitorify-1.0.2/src/monitorify/config/configManager.py +47 -0
  9. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/config.py +3 -0
  10. monitorify-1.0.2/src/monitorify/config_manager.py +47 -0
  11. monitorify-1.0.2/src/monitorify/daemon.py +46 -0
  12. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/main.py +1 -2
  13. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/tui/components/menu.py +29 -2
  14. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/tui/tui.py +36 -5
  15. monitorify-1.0.2/src/monitorify.egg-info/PKG-INFO +62 -0
  16. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify.egg-info/SOURCES.txt +3 -0
  17. monitorify-1.0.1/PKG-INFO +0 -52
  18. monitorify-1.0.1/README.md +0 -40
  19. monitorify-1.0.1/src/monitorify/daemon.py +0 -32
  20. monitorify-1.0.1/src/monitorify.egg-info/PKG-INFO +0 -52
  21. {monitorify-1.0.1 → monitorify-1.0.2}/setup.cfg +0 -0
  22. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/__main__.py +0 -0
  23. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/collector/__init__.py +0 -0
  24. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/collector/schema.py +0 -0
  25. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/remote/__init__.py +0 -0
  26. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/remote/connector.py +0 -0
  27. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/stats/DiskStats.py +0 -0
  28. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/stats/__init__.py +0 -0
  29. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/stats/cpuStats.py +0 -0
  30. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/stats/networkStats.py +0 -0
  31. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/stats/programmList.py +0 -0
  32. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/stats/ramStats.py +0 -0
  33. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/storage/__init__.py +0 -0
  34. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/storage/db.py +0 -0
  35. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/__init__.py +0 -0
  36. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/tui/__init__.py +0 -0
  37. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/tui/components/widgetManager.py +0 -0
  38. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/tui/css/tui.css +0 -0
  39. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/tui/widgets/__init__.py +0 -0
  40. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/tui/widgets/brailleGraph.py +0 -0
  41. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/tui/widgets/cpuWidget.py +0 -0
  42. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/tui/widgets/diskWidget.py +0 -0
  43. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/tui/widgets/networkWidget.py +0 -0
  44. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/tui/widgets/procInfoWidget.py +0 -0
  45. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/tui/widgets/programmListWidget.py +0 -0
  46. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/tui/widgets/ramWidget.py +0 -0
  47. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify/ui/tui/widgets/statusWidget.py +0 -0
  48. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify.egg-info/dependency_links.txt +0 -0
  49. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify.egg-info/entry_points.txt +0 -0
  50. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify.egg-info/requires.txt +0 -0
  51. {monitorify-1.0.1 → monitorify-1.0.2}/src/monitorify.egg-info/top_level.txt +0 -0
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.4
2
+ Name: monitorify
3
+ Version: 1.0.2
4
+ Summary: A lightweight Linux terminal system monitor built with Textual
5
+ Author: Leon
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: textual>=0.80.0
10
+ Requires-Dist: platformdirs>=4.0.0
11
+ Requires-Dist: rich>=13.0.0
12
+
13
+ # Monitorify
14
+ ### A terminal montioring tool for linux
15
+
16
+ - Features
17
+ - CPU monitoring
18
+ - RAM monitoring
19
+ - Network monitoring
20
+ - Disk monitoring (I/O and storage capacity)
21
+ - Process monitoring
22
+ - Background daemon
23
+ - Customization menu (toggle widgets, set intervals, and change history window)
24
+ - Historical graphs
25
+ ## Installation
26
+ ### Using pipx
27
+ ```bash
28
+ pipx install git+https://github.com/leonst036/Monitorify.git
29
+ ```
30
+
31
+ ### Using pip
32
+ ```bash
33
+ pip install git+https://github.com/leonst036/Monitorify.git
34
+ ```
35
+
36
+ ### Using source
37
+ ```bash
38
+ git clone https://github.com/leonst036/Monitorify.git
39
+ cd Monitorify
40
+ pip install .
41
+ ```
42
+
43
+ ## Usage
44
+ ```bash
45
+ monitorify
46
+ ```
47
+
48
+ ## Tech Stack
49
+
50
+ * **Language & TUI:** Python, Textual
51
+ * **Database:** SQLite
52
+ * **Target OS:** Linux
53
+
54
+ ## Remote
55
+
56
+ To use Monitorify remotely over SSH on your server, you can set the following parameters:
57
+
58
+ - `--ip` – Set the target IP address.
59
+ - `--port` – Set the SSH port.
60
+ - `--username` – Set the username for the remote host.
61
+ - `--password` – Set the password for the SSH server.
62
+ - `--key_filename` – Set the path to an SSH key *(optional)*.
@@ -0,0 +1,50 @@
1
+ # Monitorify
2
+ ### A terminal montioring tool for linux
3
+
4
+ - Features
5
+ - CPU monitoring
6
+ - RAM monitoring
7
+ - Network monitoring
8
+ - Disk monitoring (I/O and storage capacity)
9
+ - Process monitoring
10
+ - Background daemon
11
+ - Customization menu (toggle widgets, set intervals, and change history window)
12
+ - Historical graphs
13
+ ## Installation
14
+ ### Using pipx
15
+ ```bash
16
+ pipx install git+https://github.com/leonst036/Monitorify.git
17
+ ```
18
+
19
+ ### Using pip
20
+ ```bash
21
+ pip install git+https://github.com/leonst036/Monitorify.git
22
+ ```
23
+
24
+ ### Using source
25
+ ```bash
26
+ git clone https://github.com/leonst036/Monitorify.git
27
+ cd Monitorify
28
+ pip install .
29
+ ```
30
+
31
+ ## Usage
32
+ ```bash
33
+ monitorify
34
+ ```
35
+
36
+ ## Tech Stack
37
+
38
+ * **Language & TUI:** Python, Textual
39
+ * **Database:** SQLite
40
+ * **Target OS:** Linux
41
+
42
+ ## Remote
43
+
44
+ To use Monitorify remotely over SSH on your server, you can set the following parameters:
45
+
46
+ - `--ip` – Set the target IP address.
47
+ - `--port` – Set the SSH port.
48
+ - `--username` – Set the username for the remote host.
49
+ - `--password` – Set the password for the SSH server.
50
+ - `--key_filename` – Set the path to an SSH key *(optional)*.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "monitorify"
7
- version = "1.0.1"
7
+ version = "1.0.2"
8
8
  description = "A lightweight Linux terminal system monitor built with Textual"
9
9
  readme = "README.md"
10
10
  authors = [
@@ -1,3 +1,3 @@
1
1
  """Monitorify - A lightweight Linux terminal system monitor."""
2
2
 
3
- __version__ = "1.0.1"
3
+ __version__ = "1.0.2"
@@ -1,9 +1,9 @@
1
- from typing import List, Optional, Any, Callable
1
+ from typing import List, Optional, Any, Callable, Union
2
2
  from monitorify.collector.worker import Worker
3
3
 
4
4
 
5
5
  class Manager:
6
- def __init__(self, db: Optional[Any] = None, interval: float = 1.0):
6
+ def __init__(self, db: Optional[Any] = None, interval: Union[float, Callable[[], float]] = 1.0):
7
7
  self._workers: List[Worker] = []
8
8
  self._interval = interval
9
9
  if db is None:
@@ -3,10 +3,10 @@ from threading import Thread
3
3
  from monitorify.stats import cpuStats, ramStats, networkStats, programmList, DiskStats
4
4
  from monitorify.collector.schema import MetricSnapshot
5
5
 
6
- from typing import Callable, Optional
6
+ from typing import Callable, Optional, Union
7
7
 
8
8
  class Worker:
9
- def __init__(self, interval: float = 1.0, on_data: Optional[Callable[[MetricSnapshot], None]] = None):
9
+ def __init__(self, interval: Union[float, Callable[[], float]] = 1.0, on_data: Optional[Callable[[MetricSnapshot], None]] = None):
10
10
  self._interval = interval
11
11
  self._on_data = on_data
12
12
  self._running = False
@@ -22,6 +22,17 @@ class Worker:
22
22
  if self._thread:
23
23
  self._thread.join()
24
24
 
25
+ def _get_interval(self) -> float:
26
+ if callable(self._interval):
27
+ try:
28
+ return float(self._interval())
29
+ except Exception:
30
+ return 1.0
31
+ try:
32
+ return float(self._interval)
33
+ except Exception:
34
+ return 1.0
35
+
25
36
  def _worker_loop(self):
26
37
  while self._running:
27
38
  snapshot = self.collect()
@@ -30,7 +41,7 @@ class Worker:
30
41
  self._on_data(snapshot)
31
42
  except Exception as e:
32
43
  print(f"Error handling metric snapshot: {e}")
33
- time.sleep(self._interval)
44
+ time.sleep(max(0.1, self._get_interval()))
34
45
 
35
46
  def collect(self) -> MetricSnapshot:
36
47
  return MetricSnapshot(
@@ -0,0 +1,29 @@
1
+ import os
2
+ from pathlib import Path
3
+ from platformdirs import user_data_dir, user_runtime_dir
4
+
5
+ # Data directory for database storage
6
+ DATA_DIR = Path(user_data_dir("monitorify", appauthor=False))
7
+ DATA_DIR.mkdir(parents=True, exist_ok=True)
8
+
9
+ # Runtime directory for PID files
10
+ try:
11
+ RUNTIME_DIR = Path(user_runtime_dir("monitorify", appauthor=False))
12
+ RUNTIME_DIR.mkdir(parents=True, exist_ok=True)
13
+ except Exception:
14
+ RUNTIME_DIR = DATA_DIR
15
+
16
+ # Database settings
17
+ DB_PATH = os.getenv("MONITORIFY_DB_PATH", str(DATA_DIR / "monitorify.db"))
18
+
19
+ # User configuration file path
20
+ CONFIG_PATH = Path(os.getenv("MONITORIFY_CONFIG_PATH", str(DATA_DIR / "config.json")))
21
+
22
+ # Daemon PID file path
23
+ DAEMON_PIDFILE = Path(os.getenv("MONITORIFY_PID_PATH", str(RUNTIME_DIR / "daemon.pid")))
24
+
25
+ # Collection settings (seconds)
26
+ DEFAULT_COLLECTION_INTERVAL = float(os.getenv("MONITORIFY_INTERVAL", "1.0"))
27
+
28
+ # Retention settings (default: 7 days in seconds)
29
+ RETENTION_SECONDS = float(os.getenv("MONITORIFY_RETENTION", str(7 * 24 * 3600)))
@@ -0,0 +1,47 @@
1
+ import json
2
+ from pathlib import Path
3
+
4
+
5
+ class configManager:
6
+ def __init__(self, config_path: str):
7
+ self.config_path = config_path
8
+ self.config_data = {}
9
+ self.load_config()
10
+
11
+ def load_config(self) -> dict:
12
+ path = Path(self.config_path)
13
+ if not path.exists():
14
+ self.config_data = {}
15
+ return self.config_data
16
+
17
+ try:
18
+ with path.open("r", encoding="utf-8") as file:
19
+ data = json.load(file)
20
+ if isinstance(data, dict):
21
+ self.config_data = data
22
+ else:
23
+ self.config_data = {}
24
+ except (json.JSONDecodeError, OSError):
25
+ self.config_data = {}
26
+
27
+ return self.config_data
28
+
29
+ def save_config(self, config_data: dict):
30
+ try:
31
+ path = Path(self.config_path)
32
+ path.parent.mkdir(parents=True, exist_ok=True)
33
+ with path.open("w", encoding="utf-8") as file:
34
+ json.dump(config_data, file, indent=4)
35
+ self.config_data = config_data
36
+ except Exception as e:
37
+ print(f"Error saving configuration: {e}")
38
+
39
+ def get(self, key: str, default=None):
40
+ return self.config_data.get(key, default)
41
+
42
+ def get_connfig(self, key: str):
43
+ return self.get(key, None)
44
+
45
+ def set(self, key: str, value):
46
+ self.config_data[key] = value
47
+ self.save_config(self.config_data)
@@ -16,6 +16,9 @@ except Exception:
16
16
  # Database settings
17
17
  DB_PATH = os.getenv("MONITORIFY_DB_PATH", str(DATA_DIR / "monitorify.db"))
18
18
 
19
+ # User configuration file path
20
+ CONFIG_PATH = Path(os.getenv("MONITORIFY_CONFIG_PATH", str(DATA_DIR / "config.json")))
21
+
19
22
  # Daemon PID file path
20
23
  DAEMON_PIDFILE = Path(os.getenv("MONITORIFY_PID_PATH", str(RUNTIME_DIR / "daemon.pid")))
21
24
 
@@ -0,0 +1,47 @@
1
+ import json
2
+ from pathlib import Path
3
+
4
+
5
+ class configManager:
6
+ def __init__(self, config_path: str):
7
+ self.config_path = config_path
8
+ self.config_data = {}
9
+ self.load_config()
10
+
11
+ def load_config(self) -> dict:
12
+ path = Path(self.config_path)
13
+ if not path.exists():
14
+ self.config_data = {}
15
+ return self.config_data
16
+
17
+ try:
18
+ with path.open("r", encoding="utf-8") as file:
19
+ data = json.load(file)
20
+ if isinstance(data, dict):
21
+ self.config_data = data
22
+ else:
23
+ self.config_data = {}
24
+ except (json.JSONDecodeError, OSError):
25
+ self.config_data = {}
26
+
27
+ return self.config_data
28
+
29
+ def save_config(self, config_data: dict):
30
+ try:
31
+ path = Path(self.config_path)
32
+ path.parent.mkdir(parents=True, exist_ok=True)
33
+ with path.open("w", encoding="utf-8") as file:
34
+ json.dump(config_data, file, indent=4)
35
+ self.config_data = config_data
36
+ except Exception as e:
37
+ print(f"Error saving configuration: {e}")
38
+
39
+ def get(self, key: str, default=None):
40
+ return self.config_data.get(key, default)
41
+
42
+ def get_connfig(self, key: str):
43
+ return self.get(key, None)
44
+
45
+ def set(self, key: str, value):
46
+ self.config_data[key] = value
47
+ self.save_config(self.config_data)
@@ -0,0 +1,46 @@
1
+ import time
2
+ import signal
3
+ import sys
4
+ from monitorify.collector import Manager
5
+ from monitorify.storage import Database
6
+ from monitorify import config
7
+ from monitorify.config.configManager import configManager
8
+
9
+
10
+ def get_collection_interval() -> float:
11
+ try:
12
+ cfg = configManager(str(config.CONFIG_PATH))
13
+ for key in ("update_interval", "collection_interval", "interval"):
14
+ val = cfg.get(key)
15
+ if val is not None:
16
+ return float(val)
17
+ except Exception:
18
+ pass
19
+ return config.DEFAULT_COLLECTION_INTERVAL
20
+
21
+
22
+ def main():
23
+ print("Starting Monitorify background metrics collector daemon...")
24
+ db = Database(config.DB_PATH)
25
+ interval = get_collection_interval()
26
+ manager = Manager(db=db, interval=get_collection_interval)
27
+
28
+ def signal_handler(sig, frame):
29
+ print("\nStopping Monitorify daemon...")
30
+ manager.stop()
31
+ sys.exit(0)
32
+
33
+ signal.signal(signal.SIGINT, signal_handler)
34
+ signal.signal(signal.SIGTERM, signal_handler)
35
+
36
+ manager.start()
37
+ print(
38
+ f"Metrics collector running (Interval: {interval}s, DB: {config.DB_PATH}). Press Ctrl+C to stop."
39
+ )
40
+
41
+ while True:
42
+ time.sleep(1)
43
+
44
+
45
+ if __name__ == "__main__":
46
+ main()
@@ -13,10 +13,9 @@ def parse_args():
13
13
  parser.add_argument("--username", type=str, default=None, help="Username for the remote machine")
14
14
  parser.add_argument("--password", type=str, default=None, help="Password for the remote machine")
15
15
  parser.add_argument("--key_filename", type=str, default=None, help="Path to the key file for the remote machine")
16
- parser.add_argument("--command", type=str, default=None, help="Command to run on the remote machine (default: monitorify)")
17
16
  args = parser.parse_args()
18
17
 
19
- if not args.ip and (args.port is not None or args.username or args.password or args.key_filename or args.command):
18
+ if not args.ip and (args.port is not None or args.username or args.password or args.key_filename):
20
19
  parser.error("--ip is required when specifying remote connection arguments")
21
20
 
22
21
  return args
@@ -41,6 +41,10 @@ def parse_duration(text: str) -> float | None:
41
41
 
42
42
  class Menu(Container):
43
43
 
44
+ def __init__(self, *args, **kwargs):
45
+ super().__init__(*args, **kwargs)
46
+ self._syncing_menu_state = False
47
+
44
48
  def compose(self):
45
49
  with Vertical(id="menu"):
46
50
  yield Static("[bold #61afef]M[/bold #61afef]enu", id="menu_title")
@@ -71,16 +75,25 @@ class Menu(Container):
71
75
 
72
76
  def populate_menu(self) -> None:
73
77
  """Populates selection list with widget options and updates interval select value."""
78
+ self._syncing_menu_state = True
74
79
  try:
75
80
  selection_list = self.query_one(SelectionList)
76
81
  selection_list.clear_options()
77
- for name, widget_id in self.get_available_widgets().items():
82
+ saved_visible = self.app.config_manager.get("visible_widgets")
83
+ widgets = self.get_available_widgets()
84
+ for name, widget_id in widgets.items():
78
85
  widget = self.app.query_one(f"#{widget_id}")
86
+ if saved_visible is not None:
87
+ initial_state = widget_id in saved_visible
88
+ else:
89
+ initial_state = widget.display
79
90
  selection_list.add_option(
80
- Selection(prompt=name, value=name, initial_state=widget.display)
91
+ Selection(prompt=name, value=name, initial_state=initial_state)
81
92
  )
82
93
  except Exception:
83
94
  pass
95
+ finally:
96
+ self._syncing_menu_state = False
84
97
 
85
98
  try:
86
99
  interval_select = self.query_one("#interval_select", Select)
@@ -90,6 +103,16 @@ class Menu(Container):
90
103
  except Exception:
91
104
  pass
92
105
 
106
+ try:
107
+ history_select = self.query_one("#history_select", Select)
108
+ current_history = getattr(self.app, "history_duration", 60.0)
109
+ if history_select.value != current_history:
110
+ history_select.value = current_history
111
+ custom_input = self.query_one("#custom_history_input", Input)
112
+ custom_input.display = history_select.value is None
113
+ except Exception:
114
+ pass
115
+
93
116
  def on_select_changed(self, event: Select.Changed) -> None:
94
117
  """Handles changes in the update interval and history duration selectors."""
95
118
  if event.select.id == "interval_select" and event.value is not Select.BLANK:
@@ -124,6 +147,8 @@ class Menu(Container):
124
147
 
125
148
  def on_selection_list_selected_changed(self, event: SelectionList.SelectedChanged) -> None:
126
149
  """Toggles widget visibility based on selection changes."""
150
+ if self._syncing_menu_state:
151
+ return
127
152
  selected_names = event.selection_list.selected
128
153
  for name, widget_id in self.get_available_widgets().items():
129
154
  try:
@@ -133,6 +158,8 @@ class Menu(Container):
133
158
  pass
134
159
  if hasattr(self.app, "update_layout"):
135
160
  self.app.update_layout()
161
+ if hasattr(self.app, "persist_config"):
162
+ self.app.persist_config()
136
163
 
137
164
  def get_available_widgets(self) -> dict[str, str]:
138
165
  """Returns a map of {widget_name: widget_id} from main_container."""
@@ -16,6 +16,7 @@ from monitorify.ui.tui.components.widgetManager import WidgetManager
16
16
  from monitorify.ui.tui.widgets.programmListWidget import ProgrammListWidget
17
17
  from monitorify.storage import Database
18
18
  from monitorify import config
19
+ from monitorify.config.configManager import configManager
19
20
 
20
21
 
21
22
  class MonitorifyApp(App):
@@ -30,13 +31,30 @@ class MonitorifyApp(App):
30
31
 
31
32
  def __init__(self, **kwargs):
32
33
  super().__init__(**kwargs)
34
+ self.config_manager = configManager(str(config.CONFIG_PATH))
33
35
  # Read-only DB connection
34
36
  self.db = Database(config.DB_PATH)
35
37
  self.db.connect()
36
- # Default history window: 1 minute
37
- self.history_duration: float = 60.0
38
+ # Load saved preferences from config
39
+ self.update_interval = float(self.config_manager.get("update_interval", 1.0))
40
+ self.history_duration: float = float(self.config_manager.get("history_duration", 60.0))
38
41
  self._last_graph_refresh: float = 0.0
39
42
 
43
+ def persist_config(self) -> None:
44
+ visible_widgets = []
45
+ for widget_id in ["cpu_widget", "ram_widget", "programmList_widget", "network_widget", "disk_widget"]:
46
+ try:
47
+ if self.query_one(f"#{widget_id}").display:
48
+ visible_widgets.append(widget_id)
49
+ except Exception:
50
+ pass
51
+
52
+ self.config_manager.save_config({
53
+ "update_interval": float(self.update_interval),
54
+ "history_duration": float(self.history_duration),
55
+ "visible_widgets": visible_widgets,
56
+ })
57
+
40
58
  def compose(self) -> ComposeResult:
41
59
  with Container(id="main_container"):
42
60
  yield CpuWidget(id="cpu_widget")
@@ -52,15 +70,25 @@ class MonitorifyApp(App):
52
70
  def on_mount(self) -> None:
53
71
  self.action_get_window_size()
54
72
  self.widget_manager = WidgetManager(self.query_one("#main_container"))
73
+ saved_visible = self.config_manager.get("visible_widgets")
74
+ if saved_visible is not None:
75
+ visible_widgets = set(saved_visible)
76
+ else:
77
+ visible_widgets = set()
78
+ for widget_id in ["cpu_widget", "ram_widget", "programmList_widget", "network_widget", "disk_widget"]:
79
+ try:
80
+ widget = self.query_one(f"#{widget_id}")
81
+ widget.display = widget_id in visible_widgets if saved_visible is not None else widget.display
82
+ except Exception:
83
+ pass
55
84
  self.update_layout()
56
- self.update_interval = 1.0
57
85
  # Load history from DB on startup
58
86
  self.call_after_refresh(self._load_initial_history)
59
87
  self.update_timer = self.set_interval(self.update_interval, self.update_display)
60
88
 
61
89
  def _load_initial_history(self) -> None:
62
90
  """Load history from DB after the first render so widgets have their sizes."""
63
- self.set_history_duration(self.history_duration)
91
+ self.set_history_duration(self.history_duration, persist=False)
64
92
 
65
93
  def set_update_interval(self, seconds: float) -> None:
66
94
  """Updates the graph refresh interval."""
@@ -68,10 +96,13 @@ class MonitorifyApp(App):
68
96
  if hasattr(self, "update_timer") and self.update_timer:
69
97
  self.update_timer.stop()
70
98
  self.update_timer = self.set_interval(self.update_interval, self.update_display)
99
+ self.persist_config()
71
100
 
72
- def set_history_duration(self, seconds: float) -> None:
101
+ def set_history_duration(self, seconds: float, persist: bool = True) -> None:
73
102
  """Load historical metrics from DB and push them into all graph widgets."""
74
103
  self.history_duration = seconds
104
+ if persist:
105
+ self.persist_config()
75
106
  start_time = time.time() - seconds
76
107
  snapshots = self.db.get_history(limit=10000, start_time=start_time)
77
108
 
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.4
2
+ Name: monitorify
3
+ Version: 1.0.2
4
+ Summary: A lightweight Linux terminal system monitor built with Textual
5
+ Author: Leon
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: textual>=0.80.0
10
+ Requires-Dist: platformdirs>=4.0.0
11
+ Requires-Dist: rich>=13.0.0
12
+
13
+ # Monitorify
14
+ ### A terminal montioring tool for linux
15
+
16
+ - Features
17
+ - CPU monitoring
18
+ - RAM monitoring
19
+ - Network monitoring
20
+ - Disk monitoring (I/O and storage capacity)
21
+ - Process monitoring
22
+ - Background daemon
23
+ - Customization menu (toggle widgets, set intervals, and change history window)
24
+ - Historical graphs
25
+ ## Installation
26
+ ### Using pipx
27
+ ```bash
28
+ pipx install git+https://github.com/leonst036/Monitorify.git
29
+ ```
30
+
31
+ ### Using pip
32
+ ```bash
33
+ pip install git+https://github.com/leonst036/Monitorify.git
34
+ ```
35
+
36
+ ### Using source
37
+ ```bash
38
+ git clone https://github.com/leonst036/Monitorify.git
39
+ cd Monitorify
40
+ pip install .
41
+ ```
42
+
43
+ ## Usage
44
+ ```bash
45
+ monitorify
46
+ ```
47
+
48
+ ## Tech Stack
49
+
50
+ * **Language & TUI:** Python, Textual
51
+ * **Database:** SQLite
52
+ * **Target OS:** Linux
53
+
54
+ ## Remote
55
+
56
+ To use Monitorify remotely over SSH on your server, you can set the following parameters:
57
+
58
+ - `--ip` – Set the target IP address.
59
+ - `--port` – Set the SSH port.
60
+ - `--username` – Set the username for the remote host.
61
+ - `--password` – Set the password for the SSH server.
62
+ - `--key_filename` – Set the path to an SSH key *(optional)*.
@@ -3,6 +3,7 @@ pyproject.toml
3
3
  src/monitorify/__init__.py
4
4
  src/monitorify/__main__.py
5
5
  src/monitorify/config.py
6
+ src/monitorify/config_manager.py
6
7
  src/monitorify/daemon.py
7
8
  src/monitorify/main.py
8
9
  src/monitorify.egg-info/PKG-INFO
@@ -15,6 +16,8 @@ src/monitorify/collector/__init__.py
15
16
  src/monitorify/collector/manager.py
16
17
  src/monitorify/collector/schema.py
17
18
  src/monitorify/collector/worker.py
19
+ src/monitorify/config/__init__.py
20
+ src/monitorify/config/configManager.py
18
21
  src/monitorify/remote/__init__.py
19
22
  src/monitorify/remote/connector.py
20
23
  src/monitorify/stats/DiskStats.py
monitorify-1.0.1/PKG-INFO DELETED
@@ -1,52 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: monitorify
3
- Version: 1.0.1
4
- Summary: A lightweight Linux terminal system monitor built with Textual
5
- Author: Leon
6
- License: MIT
7
- Requires-Python: >=3.10
8
- Description-Content-Type: text/markdown
9
- Requires-Dist: textual>=0.80.0
10
- Requires-Dist: platformdirs>=4.0.0
11
- Requires-Dist: rich>=13.0.0
12
-
13
- # Monitorify
14
- ### A terminal montioring tool for linux
15
-
16
- ## Features
17
- ### CPU monitoring
18
- ### RAM monitoring
19
- ### Network monitoring
20
- ### Disk monitoring (I/O and storage capacity)
21
- ### Process monitoring
22
- ### Background daemon
23
- ### Customization menu (toggle widgets, set intervals, and change history window)
24
- ### Historical graphs
25
-
26
- ## Installation
27
- ### Using pipx
28
- ```bash
29
- pipx install git+https://github.com/leonst036/Monitorify.git
30
- ```
31
-
32
- ### Using pip
33
- ```bash
34
- pip install git+https://github.com/leonst036/Monitorify.git
35
- ```
36
-
37
- ### Using source
38
- ```bash
39
- git clone https://github.com/leonst036/Monitorify.git
40
- cd Monitorify
41
- pip install .
42
- ```
43
-
44
- ## Usage
45
- ```bash
46
- monitorify
47
- ```
48
-
49
- ## Tech stack
50
- ### Python | Textual
51
- ### SQLite
52
- ### Linux
@@ -1,40 +0,0 @@
1
- # Monitorify
2
- ### A terminal montioring tool for linux
3
-
4
- ## Features
5
- ### CPU monitoring
6
- ### RAM monitoring
7
- ### Network monitoring
8
- ### Disk monitoring (I/O and storage capacity)
9
- ### Process monitoring
10
- ### Background daemon
11
- ### Customization menu (toggle widgets, set intervals, and change history window)
12
- ### Historical graphs
13
-
14
- ## Installation
15
- ### Using pipx
16
- ```bash
17
- pipx install git+https://github.com/leonst036/Monitorify.git
18
- ```
19
-
20
- ### Using pip
21
- ```bash
22
- pip install git+https://github.com/leonst036/Monitorify.git
23
- ```
24
-
25
- ### Using source
26
- ```bash
27
- git clone https://github.com/leonst036/Monitorify.git
28
- cd Monitorify
29
- pip install .
30
- ```
31
-
32
- ## Usage
33
- ```bash
34
- monitorify
35
- ```
36
-
37
- ## Tech stack
38
- ### Python | Textual
39
- ### SQLite
40
- ### Linux
@@ -1,32 +0,0 @@
1
- import time
2
- import signal
3
- import sys
4
- from monitorify.collector import Manager
5
- from monitorify.storage import Database
6
- from monitorify import config
7
-
8
-
9
- def main():
10
- print("Starting Monitorify background metrics collector daemon...")
11
- db = Database(config.DB_PATH)
12
- manager = Manager(db=db, interval=config.DEFAULT_COLLECTION_INTERVAL)
13
-
14
- def signal_handler(sig, frame):
15
- print("\nStopping Monitorify daemon...")
16
- manager.stop()
17
- sys.exit(0)
18
-
19
- signal.signal(signal.SIGINT, signal_handler)
20
- signal.signal(signal.SIGTERM, signal_handler)
21
-
22
- manager.start()
23
- print(
24
- f"Metrics collector running (Interval: {config.DEFAULT_COLLECTION_INTERVAL}s, DB: {config.DB_PATH}). Press Ctrl+C to stop."
25
- )
26
-
27
- while True:
28
- time.sleep(1)
29
-
30
-
31
- if __name__ == "__main__":
32
- main()
@@ -1,52 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: monitorify
3
- Version: 1.0.1
4
- Summary: A lightweight Linux terminal system monitor built with Textual
5
- Author: Leon
6
- License: MIT
7
- Requires-Python: >=3.10
8
- Description-Content-Type: text/markdown
9
- Requires-Dist: textual>=0.80.0
10
- Requires-Dist: platformdirs>=4.0.0
11
- Requires-Dist: rich>=13.0.0
12
-
13
- # Monitorify
14
- ### A terminal montioring tool for linux
15
-
16
- ## Features
17
- ### CPU monitoring
18
- ### RAM monitoring
19
- ### Network monitoring
20
- ### Disk monitoring (I/O and storage capacity)
21
- ### Process monitoring
22
- ### Background daemon
23
- ### Customization menu (toggle widgets, set intervals, and change history window)
24
- ### Historical graphs
25
-
26
- ## Installation
27
- ### Using pipx
28
- ```bash
29
- pipx install git+https://github.com/leonst036/Monitorify.git
30
- ```
31
-
32
- ### Using pip
33
- ```bash
34
- pip install git+https://github.com/leonst036/Monitorify.git
35
- ```
36
-
37
- ### Using source
38
- ```bash
39
- git clone https://github.com/leonst036/Monitorify.git
40
- cd Monitorify
41
- pip install .
42
- ```
43
-
44
- ## Usage
45
- ```bash
46
- monitorify
47
- ```
48
-
49
- ## Tech stack
50
- ### Python | Textual
51
- ### SQLite
52
- ### Linux
File without changes