如何利用AWS监听存储桶并上传到tg bot

业务描述:

需要监听aws的存储中的最新消息,发送新的消息推送到指定tg的频道。

主要流程:

1.上传消息到s3存储桶(不做具体描述)

2.通过aws的lambda监听s3存储桶的最新消息(txt文件)

3.将txt文件内容处理后推送到tg频道中

具体流程:

一、准备工作

1.创建bot

2.在频道中添加bot作为管理员

3.获取bot的token和频道的channel id

二、监听s3消息并推送到指定的tg频道中

1.创建函数

2.上传代码到lambda中

注:建议使用zip上传
代码源中必须包含package和node_modules,需要项目的完整环境
注: 代码如下,可以根据自己的业务调整。我的业务tg频道的channel id是从txt中解析获取。
注: 需要注意parse_mode的选择
注: 在lambda中发送完消息之后是无法获取状态的,也就是代码中response是没法获取状态的,不管成功失败。这也就导致了会存在消息丢失的情况

javascript 复制代码
const TelegramBot = require('node-telegram-bot-api');
const AWS = require('aws-sdk');

const s3 = new AWS.S3();
const TELEGRAM_BOT_TOKEN = '你的tg bot token'; // Telegram Bot Token
const TARGET_BUCKET_NAME = '你需要监听的存储桶的名称'; // 监听的目标存储桶名称

// Initialize the Telegram bot
const bot = new TelegramBot(TELEGRAM_BOT_TOKEN);

// AWS Lambda Handler
exports.handler = async (event, context) => {
  const functionName = context.functionName; // 获取 Lambda 函数的名称
  // tg-bot-test:测试环境   tg-bot:生产
  const [TEXT_NAME, MEDIA_NAME] = functionName === 'tg-bot-test' ? ['text-output-test', 'media-test'] : ['text-output', 'media'];

  try {
    const currentTime = new Date();
    for (const record of event.Records) {
        const bucket = record.s3.bucket.name; // 存储桶名称
        const key = decodeURIComponent(record.s3.object.key.replace(/\+/g, ' ')); // 对象键
        const eventName = record.eventName;
        
        // 仅处理指定存储桶的事件(新增)
        if (bucket === TARGET_BUCKET_NAME && eventName.startsWith('ObjectCreated:Put')) {
            console.log(`New file uploaded: ${key} to bucket: ${bucket}`);

            // 获取对象的元数据
            const metadata = await getObjectMetadata(bucket, key);
            const creationTime = metadata.LastModified; // 获取创建时间
            const timeDiffInSeconds = (currentTime - creationTime) / 1000; // 计算时间差(秒)

            console.log(`File creation time: ${creationTime}, Time difference: ${timeDiffInSeconds} seconds`);

            // 若创建时间超过 60 秒,则不再继续执行
            if (timeDiffInSeconds > 60) {
                console.log(`File ${key} creation time exceeds 60 seconds, stopping execution...`);
                return; // 结束 Lambda 函数的执行
            }

            // 检查文件是否在指定的文件夹中
            if (key.startsWith(`${TEXT_NAME}/`)) {
                // 从 S3 获取文本文件内容
                const textContent = await getFileContentFromS3(bucket, key);
                console.log(`Updated file: ${key}`); // 打印更新文件的名称
                console.log(`textContent: ${textContent}`);
                
                // 获取第三行内容并转换为数字
                let numberValue = 0;
                const lines = textContent.split('\n');
                let captionContent = "";
                let channelId = "";
                if (lines.length >= 3) {
                    channelId = lines[0].trim();  // 获取发送到的频道的id
                    console.log("channelId:", channelId);
                    const thirdLine = lines[2].trim(); // 获取第三行并去除多余空格
                    numberValue = parseFloat(thirdLine); // 转换为数字
                    console.log(`Third line as number: ${numberValue}`); // 打印数字值
                    captionContent = lines.slice(3).join('\n').trim(); // 从第三行之后的所有内容
                } else {
                    console.error('The file does not contain enough lines.');
                    return;
                }

                // 提取文件名(去除文件夹和后缀)
                const fileName = key.split('/').pop().split('.').slice(0, -1).join('.');
                console.log(`File name without folder and extension: ${fileName}`); // 打印文件名

                // 生成所有图片的名称
                let allImage = [];
                for (let index = 0; index < numberValue; index++) {
                    allImage.push(`${fileName}.img${index}.jpg`);
                }
                console.log(`All images: ${allImage}`);

                // 收集图片的 URL
                const imageUrls = allImage.map(image => `https://${bucket}.s3.us-east-1.amazonaws.com/${MEDIA_NAME}/${image}`);

                // 发送所有图片作为一条消息
                await sendPhotosToTelegram(imageUrls, captionContent, channelId);
            }
        }
    }
  } catch (error) {
    console.error("error message:", error);
  }
};

const getObjectMetadata = async (bucket, key) => {
  const params = {
      Bucket: bucket,
      Key: key
  };
  const metadata = await s3.headObject(params).promise();
  return metadata; // 返回对象的元数据
};

const getFileContentFromS3 = async (bucket, key) => {
    const params = {
        Bucket: bucket,
        Key: key
    };
    const data = await s3.getObject(params).promise();
    return data.Body.toString('utf-8'); // 返回文件内容,假设是文本文件
};

const sendPhotosToTelegram = async (imageUrls, captionContent, channelId) => {
  const media = imageUrls.map((url) => ({
      type: 'photo',
      media: url,
  }));

  // 如果有需要,可以为第一张图片添加 caption
  if (captionContent) {
      media[0].caption = captionContent;
      media[0].parse_mode = 'Markdown'; 	//注意此处的选择,Markdown是支持多图和超链接文本的,但是MarkdownV2是不支持超链接文本的,而且也不支持特殊字符
  }
  
  try {
      console.log("request==================start");
      const response = await bot.sendMediaGroup(`@${channelId}`, media);
      console.log("request==================end");
      console.log('Response from Telegram:', response); // 打印 Telegram 的响应(lambda没有效果)
      return response;
  } catch (error) {
      console.error('Error sending photos to Telegram:', error.response ? error.response.data : error.message);
      throw error;
  }
};

其他

1.在没有解决消息丢失的情况下建议不要使用lambda推送重要消息

2.可以使用mq来完成消息的监听和发送,这样response也可以监听到状态,也不会存在消息丢失情况,即使丢失也可以通过状态控制。

相关推荐
DolphinScheduler社区2 天前
白鲸开源与亚马逊云科技携手推动AI-Ready数据架构创新
人工智能·科技·开源·aws·白鲸开源·whalestudio
AWS官方合作商5 天前
AWS S3企业级部署解决方案:从入门到高可用性实践
微服务·云计算·aws
亚林瓜子6 天前
AWS Elastic Beanstalk的部署Python Flask后端服务(Hello,World)
python·flask·aws·eb
weixin_307779136 天前
实现AWS Step Function安全地请求企业内部API返回数据
开发语言·python·云计算·aws
日月星辰Ace6 天前
基于 AWS DynamoDB 分布式锁
分布式·aws
日月星辰Ace6 天前
AWS EC2 Launch template
aws
AWS官方合作商6 天前
万物互联时代,AWS IoT Core如何构建企业级物联网中枢平台?
物联网·云计算·aws
lisw057 天前
云计算(Cloud Computing)概述——从AWS开始
云计算·aws
运维开发王义杰7 天前
解决 AWS RDS MySQL mysqldump 导入sql SET @@GLOBAL 权限不足问题
sql·mysql·aws
在云上(oncloudai)7 天前
DeepSeek-R3、GPT-4o 与 Claude-3.5-Sonnet 全面对比:性能、应用场景与技术解析
claude·aws·gpt-4o·deepseek-r3