Source code for django_growl.notifier

#!/usr/bin/env python3
# File: django_growl/notifier.py
# Author: Hadi Cahyadi <cumulus13@gmail.com>
# Date: 2025-12-03
# Description: 
# License: MIT

import gntp.notifier
from django.conf import settings
import logging
import os
from pathlib import Path

logger = logging.getLogger(__name__)


[docs] class GrowlNotifier:
[docs] def __init__(self): self.growl_hosts = getattr(settings, 'GROWL_HOSTS', []) # Setup default icon default_icon_path = Path(__file__).parent / 'icon.png' # Check the icon from settings or use the default custom_icon = getattr(settings, 'GROWL_ICON', None) if custom_icon and Path(custom_icon).is_file(): self.icon = Path(custom_icon).as_uri() elif default_icon_path.is_file(): self.icon = default_icon_path.as_uri() else: self.icon = None # No icon available self.app_name = getattr(settings, 'GROWL_APP_NAME', 'Django Server') self.enabled = getattr(settings, 'GROWL_ENABLED', True) self.notifiers = [] if not self.enabled: logger.info("Growl notifications are disabled") return if not self.growl_hosts: logger.warning("GROWL_HOSTS is not configured in settings.py") return # Initialize notifiers for each host for host_config in self.growl_hosts: try: if ':' in str(host_config): host, port = str(host_config).split(':') port = int(port) else: host = str(host_config) port = 23053 # default Growl port notifier = gntp.notifier.GrowlNotifier( applicationName=self.app_name, notifications=['Server Status', 'Error', 'Info'], defaultNotifications=['Server Status', 'Error', 'Info'], hostname=host, port=port ) # Register with Growl notifier.register() self.notifiers.append({ 'notifier': notifier, 'host': host, 'port': port }) logger.info(f"Growl notifier registered for {host}:{port}") except Exception as e: logger.error(f"Failed to register Growl notifier for {host_config}: {e}")
[docs] def notify(self, title, message, note_type='Info', sticky=False, icon=None): """Send notification to all Growl hosts""" if not self.enabled: return # Use the given or default icon of the instance notification_icon = icon or self.icon success_count = 0 for item in self.notifiers: try: kwargs = { 'noteType': note_type, 'title': title, 'description': message, 'sticky': sticky, } # Add icon if available if notification_icon: kwargs['icon'] = notification_icon item['notifier'].notify(**kwargs) success_count += 1 logger.debug(f"Notification sent to {item['host']}:{item['port']}") except Exception as e: logger.error(f"Failed to send notification to {item['host']}:{item['port']}: {e}") if success_count > 0: logger.info(f"Notification sent to {success_count}/{len(self.notifiers)} host(s)")
# Singleton instance _growl_notifier = None
[docs] def get_growl_notifier(): global _growl_notifier if _growl_notifier is None: _growl_notifier = GrowlNotifier() return _growl_notifier
[docs] def send_notification(title, message, note_type='Info', sticky=False, icon=None): '''Helper function to send notifications Args: title: Notification title message: Message content note_type: Notification type ('Info', 'Error', 'Server Status') sticky: Whether the notification stays visible (True/False) icon: Icon file path or URI (file://, http[s]://) ''' notifier = get_growl_notifier() # Cek icon priority: parameter > env > default if icon is None: # Cek dari environment variable env_icon = os.getenv('GROWL_ICON') if env_icon and Path(env_icon).is_file(): icon = Path(env_icon).as_uri() # Jika tidak ada, akan gunakan default dari notifier instance elif isinstance(icon, (str, Path)): # Convert ke URI jika belum icon_path = Path(icon) if icon_path.is_file(): icon = icon_path.as_uri() notifier.notify(title, message, note_type, sticky, icon=icon)