Spaces:
Sleeping
Sleeping
| import os | |
| import logging | |
| import socket | |
| import requests | |
| import dns.resolver | |
| from heyoo import WhatsApp | |
| from dotenv import load_dotenv | |
| from flask import Flask, request, make_response | |
| # Initialize Flask App | |
| app = Flask(__name__) | |
| # Configure logging | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" | |
| ) | |
| logger = logging.getLogger(__name__) | |
| # Load .env file | |
| load_dotenv() | |
| # Configure DNS resolver with environment variables from Spaces | |
| nameserver1 = os.getenv('nameserver1', '8.8.8.8') | |
| nameserver2 = os.getenv('nameserver2', '8.8.4.4') | |
| # Configure global DNS resolution | |
| def setup_dns(): | |
| """Configure DNS resolution globally""" | |
| resolver = dns.resolver.Resolver() | |
| resolver.nameservers = [nameserver1, nameserver2] | |
| # Create a custom getaddrinfo function | |
| _orig_getaddrinfo = socket.getaddrinfo | |
| def new_getaddrinfo(*args, **kwargs): | |
| try: | |
| # If the host is graph.facebook.com, use our custom resolver | |
| if args and args[0] == 'graph.facebook.com': | |
| answers = resolver.resolve('graph.facebook.com', 'A') | |
| ip = str(answers[0]) | |
| return _orig_getaddrinfo(ip, *args[1:], **kwargs) | |
| except Exception as e: | |
| logger.error(f"DNS resolution failed: {e}") | |
| return _orig_getaddrinfo(*args, **kwargs) | |
| # Replace the global getaddrinfo function | |
| socket.getaddrinfo = new_getaddrinfo | |
| # Setup DNS resolution | |
| setup_dns() | |
| # Initialize WhatsApp | |
| try: | |
| messenger = WhatsApp( | |
| os.getenv("whatsapp_token"), | |
| phone_number_id=os.getenv("phone_number_id") | |
| ) | |
| if not os.getenv("whatsapp_token") or not os.getenv("phone_number_id"): | |
| raise ValueError("Missing required environment variables") | |
| except Exception as e: | |
| logger.error(f"Failed to initialize WhatsApp messenger: {str(e)}") | |
| raise | |
| VERIFY_TOKEN = "30cca545-3838-48b2-80a7-9e43b1ae8ce4" | |
| def health_check(): | |
| """Health check endpoint to verify DNS resolution""" | |
| try: | |
| resolver = dns.resolver.Resolver() | |
| resolver.nameservers = [nameserver1, nameserver2] | |
| ip = resolver.resolve('graph.facebook.com', 'A')[0] | |
| return { | |
| "status": "healthy", | |
| "dns_resolution": str(ip), | |
| "nameserver1": nameserver1, | |
| "nameserver2": nameserver2 | |
| } | |
| except Exception as e: | |
| return { | |
| "status": "unhealthy", | |
| "error": str(e) | |
| } | |
| def verify_token(): | |
| """Webhook verification endpoint""" | |
| try: | |
| if request.args.get("hub.verify_token") == VERIFY_TOKEN: | |
| logger.info("Verified webhook") | |
| response = make_response(request.args.get("hub.challenge"), 200) | |
| response.mimetype = "text/plain" | |
| return response | |
| logger.error("Webhook Verification failed") | |
| return "Invalid verification token" | |
| except Exception as e: | |
| logger.error(f"Error in verify_token: {str(e)}") | |
| return "Internal server error", 500 | |
| def hook(): | |
| """Main webhook handler""" | |
| try: | |
| data = request.get_json() | |
| logger.info("Received webhook data: %s", data) | |
| changed_field = messenger.changed_field(data) | |
| if changed_field != "messages": | |
| return "OK", 200 | |
| if not messenger.is_message(data): | |
| delivery = messenger.get_delivery(data) | |
| if delivery: | |
| logger.info(f"Message delivery status: {delivery}") | |
| return "OK", 200 | |
| # Extract message details | |
| mobile = messenger.get_mobile(data) | |
| name = messenger.get_name(data) | |
| message_type = messenger.get_message_type(data) | |
| logger.info(f"New Message; sender:{mobile} name:{name} type:{message_type}") | |
| # Handle different message types | |
| try: | |
| if message_type == "text": | |
| message = messenger.get_message(data) | |
| logger.info("Message: %s", message) | |
| messenger.send_message(f"Hi {name}, nice to connect with you", mobile) | |
| elif message_type == "interactive": | |
| message_response = messenger.get_interactive_response(data) | |
| interactive_type = message_response.get("type") | |
| message_id = message_response[interactive_type]["id"] | |
| message_text = message_response[interactive_type]["title"] | |
| logger.info(f"Interactive Message; {message_id}: {message_text}") | |
| elif message_type == "location": | |
| message_location = messenger.get_location(data) | |
| message_latitude = message_location["latitude"] | |
| message_longitude = message_location["longitude"] | |
| logger.info("Location: %s, %s", message_latitude, message_longitude) | |
| elif message_type in ["image", "video", "audio", "document"]: | |
| handle_media_message(messenger, data, message_type, mobile) | |
| else: | |
| logger.info(f"{mobile} sent unsupported message type: {message_type}") | |
| logger.debug(f"Full message data: {data}") | |
| except Exception as e: | |
| logger.error(f"Error processing message type {message_type}: {str(e)}") | |
| return "Internal server error", 500 | |
| return "OK", 200 | |
| except Exception as e: | |
| logger.error(f"Error in webhook handler: {str(e)}") | |
| return "Internal server error", 500 | |
| def handle_media_message(messenger, data, message_type, mobile): | |
| """Handle different types of media messages""" | |
| try: | |
| media_methods = { | |
| "image": messenger.get_image, | |
| "video": messenger.get_video, | |
| "audio": messenger.get_audio, | |
| "document": messenger.get_document | |
| } | |
| media = media_methods[message_type](data) | |
| media_id, mime_type = media["id"], media["mime_type"] | |
| try: | |
| media_url = messenger.query_media_url(media_id) | |
| media_filename = messenger.download_media(media_url, mime_type) | |
| logger.info(f"{mobile} sent {message_type} {media_filename}") | |
| except requests.exceptions.ConnectionError as ce: | |
| logger.error(f"Connection error while downloading {message_type}: {str(ce)}") | |
| except Exception as e: | |
| logger.error(f"Error downloading {message_type}: {str(e)}") | |
| except Exception as e: | |
| logger.error(f"Error processing {message_type} message: {str(e)}") | |
| raise | |
| def test_connection(): | |
| """Test DNS resolution and connection to Graph API""" | |
| try: | |
| resolver = dns.resolver.Resolver() | |
| resolver.nameservers = [nameserver1, nameserver2] | |
| ip = resolver.resolve('graph.facebook.com', 'A')[0] | |
| logger.info(f"DNS Resolution successful: {ip}") | |
| response = requests.get('https://graph.facebook.com') | |
| logger.info(f"HTTPS Connection successful: {response.status_code}") | |
| except Exception as e: | |
| logger.error(f"Connection test failed: {e}") | |
| if __name__ == "__main__": | |
| # Test connection before starting | |
| test_connection() | |
| # Start Flask app | |
| app.run(debug=True, host="0.0.0.0", port=7860) |