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)