Spaces:
Sleeping
Sleeping
File size: 7,311 Bytes
1f42647 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | 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"
@app.get("/health")
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)
}
@app.get("/")
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
@app.post("/")
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) |