agent-claw: automated task changes
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import json
|
||||
import os
|
||||
import threading
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
import boto3
|
||||
|
||||
# Cache bot token (fetched once at Lambda init)
|
||||
_bot_token: str | None = None
|
||||
_token_lock = threading.Lock()
|
||||
|
||||
|
||||
def get_bot_token() -> str:
|
||||
global _bot_token
|
||||
if _bot_token is None:
|
||||
with _token_lock:
|
||||
if _bot_token is None:
|
||||
sm = boto3.client('secretsmanager')
|
||||
_bot_token = sm.get_secret_value(
|
||||
SecretId=os.environ['TELEGRAM_BOT_TOKEN_SECRET_ARN']
|
||||
)['SecretString']
|
||||
return _bot_token
|
||||
|
||||
|
||||
def send_typing(chat_id: str) -> None:
|
||||
"""Fire-and-forget typing action (does not raise on failure)."""
|
||||
try:
|
||||
token = get_bot_token()
|
||||
data = json.dumps({'chat_id': chat_id, 'action': 'typing'}).encode()
|
||||
req = urllib.request.Request(
|
||||
f'https://api.telegram.org/bot{token}/sendChatAction',
|
||||
data=data,
|
||||
headers={'Content-Type': 'application/json'},
|
||||
)
|
||||
urllib.request.urlopen(req, timeout=3)
|
||||
except Exception:
|
||||
pass # typing is best-effort
|
||||
|
||||
|
||||
def handler(event, context):
|
||||
# ── Validate Telegram webhook secret ──────────────────────────────────
|
||||
expected_secret = os.environ.get('TELEGRAM_WEBHOOK_SECRET', '')
|
||||
if expected_secret:
|
||||
headers = event.get('headers') or {}
|
||||
received = headers.get('x-telegram-bot-api-secret-token', '')
|
||||
if received != expected_secret:
|
||||
return {'statusCode': 403, 'body': 'Forbidden'}
|
||||
|
||||
# ── Parse Telegram Update ─────────────────────────────────────────────
|
||||
try:
|
||||
body = json.loads(event.get('body', '{}'))
|
||||
except json.JSONDecodeError:
|
||||
return {'statusCode': 400, 'body': 'Bad Request'}
|
||||
|
||||
update_id = body.get('update_id')
|
||||
|
||||
# Support regular messages and edited messages
|
||||
message = body.get('message') or body.get('edited_message')
|
||||
if not message:
|
||||
# Not a message update (could be channel_post, callback_query, etc.)
|
||||
return {'statusCode': 200, 'body': 'ok'}
|
||||
|
||||
chat_id = str(message.get('chat', {}).get('id', ''))
|
||||
text = message.get('text', '')
|
||||
from_user = message.get('from', {})
|
||||
timestamp = message.get('date', 0)
|
||||
|
||||
if not chat_id or not text:
|
||||
return {'statusCode': 200, 'body': 'ok'}
|
||||
|
||||
# ── Send typing action (non-blocking, background thread) ──────────────
|
||||
t = threading.Thread(target=send_typing, args=(chat_id,))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
# ── Enqueue to SQS FIFO ───────────────────────────────────────────────
|
||||
sqs = boto3.client('sqs')
|
||||
sqs.send_message(
|
||||
QueueUrl=os.environ['MESSAGE_QUEUE_URL'],
|
||||
MessageGroupId=chat_id,
|
||||
MessageDeduplicationId=str(update_id),
|
||||
MessageBody=json.dumps({
|
||||
'channel': 'telegram',
|
||||
'chat_id': chat_id,
|
||||
'messages': [{
|
||||
'text': text,
|
||||
'from_id': str(from_user.get('id', '')),
|
||||
'from_username': from_user.get('username', ''),
|
||||
'from_name': f"{from_user.get('first_name', '')} {from_user.get('last_name', '')}".strip(),
|
||||
}],
|
||||
'update_id': update_id,
|
||||
'timestamp': timestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return {'statusCode': 200, 'body': 'ok'}
|
||||
@@ -0,0 +1 @@
|
||||
boto3>=1.34.0
|
||||
Reference in New Issue
Block a user