-
Notifications
You must be signed in to change notification settings - Fork 0
Add runtime metrics tracking and enhance info/rooms commands with centralized status #125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
b105d9b
309c6ff
e9ec7f3
254f88d
f6494b1
bbee3c9
2de2f08
53844e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,37 @@ | ||
| """ChatrixCD - Matrix bot for CI/CD automation with Semaphore UI.""" | ||
|
|
||
| import os | ||
| import subprocess | ||
|
|
||
| __version__ = "2025.11.15.5.2.0" | ||
|
|
||
| def _get_version_with_commit(): | ||
| """Get version with git commit if running from git repository. | ||
|
|
||
| Returns: | ||
| Version string with commit ID appended if running from git, | ||
| otherwise just the version string. | ||
| """ | ||
| try: | ||
| # Check if we're in a git repository | ||
| git_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), '.git') | ||
| if os.path.exists(git_dir): | ||
| # Get the short commit hash | ||
| result = subprocess.run( | ||
| ['git', 'rev-parse', '--short', 'HEAD'], | ||
| capture_output=True, | ||
| text=True, | ||
| timeout=1, | ||
| cwd=os.path.dirname(os.path.dirname(__file__)) | ||
| ) | ||
| if result.returncode == 0: | ||
| commit_id = result.stdout.strip() | ||
| return f"{__version__}-c{commit_id}" | ||
| except Exception: | ||
| # If anything fails, just return the base version | ||
| pass | ||
|
|
||
| return __version__ | ||
|
|
||
| # Get the full version (with commit if available) | ||
| __version_full__ = _get_version_with_commit() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -105,6 +105,14 @@ | |
| # Track whether we've done initial encryption setup after first sync | ||
| self._encryption_setup_done = False | ||
|
|
||
| # Runtime metrics tracking | ||
| self.metrics = { | ||
| 'messages_sent': 0, | ||
| 'requests_received': 0, | ||
| 'errors': 0, | ||
| 'emojis_used': 0 | ||
| } | ||
|
|
||
| # Setup event callbacks | ||
| self.client.add_event_callback(self.message_callback, RoomMessageText) | ||
| self.client.add_event_callback(self.invite_callback, InviteMemberEvent) | ||
|
|
@@ -543,6 +551,11 @@ | |
|
|
||
| logger.info(f"Message from {event.sender} in {room.display_name}: {event.body}") | ||
|
|
||
| # Track requests received (only if it's a command) | ||
| command_prefix = self.config.get_bot_config().get('command_prefix', '!cd') | ||
| if event.body.strip().startswith(command_prefix): | ||
| self.metrics['requests_received'] += 1 | ||
|
|
||
| # Check if message is a command | ||
| await self.command_handler.handle_message(room, event) | ||
|
|
||
|
|
@@ -802,6 +815,21 @@ | |
| ignore_unverified_devices=True | ||
| ) | ||
|
|
||
| # Track metrics | ||
| self.metrics['messages_sent'] += 1 | ||
| # Count emojis in the message (simple count of common emoji ranges) | ||
| import re | ||
| emoji_pattern = re.compile("[" | ||
| "\U0001F600-\U0001F64F" # emoticons | ||
|
||
| "\U0001F300-\U0001F5FF" # symbols & pictographs | ||
| "\U0001F680-\U0001F6FF" # transport & map symbols | ||
| "\U0001F1E0-\U0001F1FF" # flags (iOS) | ||
| "\U00002702-\U000027B0" # dingbats | ||
| "\U000024C2-\U0001F251" | ||
| "]+", flags=re.UNICODE) | ||
| emojis = emoji_pattern.findall(message) | ||
| self.metrics['emojis_used'] += len(emojis) | ||
|
||
|
|
||
| # Return the event_id for potential reactions | ||
| if hasattr(response, 'event_id'): | ||
| return response.event_id | ||
|
|
@@ -830,6 +858,9 @@ | |
| content=content, | ||
| ignore_unverified_devices=True | ||
| ) | ||
|
|
||
| # Track emoji usage | ||
| self.metrics['emojis_used'] += 1 | ||
| except Exception as e: | ||
| logger.debug(f"Failed to send reaction: {e}") | ||
|
|
||
|
|
@@ -879,6 +910,36 @@ | |
| except Exception as e: | ||
| logger.error(f"Failed to send shutdown message to room {room_id}: {e}") | ||
|
|
||
| def can_send_message_in_room(self, room_id: str) -> bool: | ||
| """Check if bot can send messages in a room. | ||
|
|
||
| Args: | ||
| room_id: Room ID to check | ||
|
|
||
| Returns: | ||
| True if bot can send messages, False otherwise | ||
| """ | ||
| room = self.client.rooms.get(room_id) | ||
| if not room: | ||
| return False | ||
|
|
||
| # Check if bot is a member of the room | ||
| if self.user_id not in room.users: | ||
| return False | ||
|
|
||
| # Check power levels | ||
| try: | ||
| # Get the bot's power level | ||
| bot_power_level = room.power_levels.get_user_level(self.user_id) | ||
| # Get the required power level to send messages | ||
| required_level = room.power_levels.get_event_level("m.room.message") | ||
|
|
||
| return bot_power_level >= required_level | ||
| except (AttributeError, KeyError): | ||
| # If we can't determine power levels, assume we can send | ||
| # (default behavior - will fail gracefully if not allowed) | ||
| return True | ||
|
|
||
| async def sync_callback(self, response: SyncResponse): | ||
| """Handle sync responses and manage encryption keys. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -7,12 +7,13 @@ | |||
| import platform | ||||
| import socket | ||||
| import psutil | ||||
| import sys | ||||
|
||||
| import sys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
remodule should be imported at the module level, not inside the method. This import is executed every timesend_message()is called, which is inefficient. Moveimport reto the top of the file with other imports.