From fdf4259701a781e1a1c32daee87c04b7a6d8644d Mon Sep 17 00:00:00 2001 From: eoao Date: Sun, 10 May 2026 18:33:54 +0800 Subject: [PATCH] feat: convert attachment path to ArrayBuffer --- mail-worker/src/service/att-service.js | 39 ++++++++++++++--------- mail-worker/src/service/email-service.js | 8 ----- mail-worker/src/service/kv-obj-service.js | 11 +++++-- mail-worker/src/service/r2-service.js | 14 +++++++- mail-worker/src/service/s3-service.js | 19 ++++++++++- 5 files changed, 64 insertions(+), 27 deletions(-) diff --git a/mail-worker/src/service/att-service.js b/mail-worker/src/service/att-service.js index aa5f2d2..d33d8c6 100644 --- a/mail-worker/src/service/att-service.js +++ b/mail-worker/src/service/att-service.js @@ -91,13 +91,10 @@ const attService = { if (src.startsWith(domainUtils.toOssDomain(r2Domain))) { attData.key = src.replace(domainUtils.toOssDomain(r2Domain) + '/',''); - attData.path = src; } if (src.startsWith('attachments/')) { - const origin = new URL(c.req.url).origin; attData.key = src; - attData.path = origin + '/' + src; } attData.contentId = cid; @@ -117,22 +114,34 @@ const attService = { } //查询已有内嵌url图片信息 - const keys = [...new Set(imageDataList.filter(item => item.path).map(item => item.key))]; + const keys = [...new Set(imageDataList.filter(item => !item.content).map(item => item.key))]; const dbImageList = await this.selectOneByKeys(c, keys); //设置给当前附件 - imageDataList.forEach(image => { - dbImageList.forEach(dbImage => { - if (image.path && (image.key === dbImage.key)) { - image.size = dbImage.size; - image.filename = dbImage.filename; - image.mimeType = dbImage.mimeType; - image.contentType = dbImage.mimeType; - } - }) - }) + await Promise.all(imageDataList.map(async image => { + if (image.content) { + return; + } - imageDataList = imageDataList.filter(image => !image.path || image.size); + const dbImage = dbImageList.find(dbImage => image.key === dbImage.key); + if (!dbImage) { + return; + } + + image.size = dbImage.size; + image.filename = dbImage.filename; + image.mimeType = dbImage.mimeType; + image.contentType = dbImage.mimeType; + + const obj = await r2Service.getObj(c, image.key); + if (!obj) { + return; + } + + image.content = obj instanceof ArrayBuffer ? obj : await obj.arrayBuffer(); + })) + + imageDataList = imageDataList.filter(image => image.content); return { imageDataList, html: document.toString() }; }, diff --git a/mail-worker/src/service/email-service.js b/mail-worker/src/service/email-service.js index 8c5d54e..79e2942 100644 --- a/mail-worker/src/service/email-service.js +++ b/mail-worker/src/service/email-service.js @@ -472,14 +472,6 @@ const emailService = { async toAttachmentArrayBuffer(attachment) { let content = attachment.content; - if (!content && attachment.path) { - const response = await fetch(attachment.path); - if (!response.ok) { - throw new BizError(`Attachment fetch failed: ${attachment.filename}`); - } - return await response.arrayBuffer(); - } - if (!content) { return null; } diff --git a/mail-worker/src/service/kv-obj-service.js b/mail-worker/src/service/kv-obj-service.js index 965d2d5..b424e77 100644 --- a/mail-worker/src/service/kv-obj-service.js +++ b/mail-worker/src/service/kv-obj-service.js @@ -17,9 +17,11 @@ const kvObjService = { await Promise.all(keys.map( key => c.env.kv.delete(key))); }, - async toObjResp(c, key) { - + async getObj(c, key) { const obj = await c.env.kv.getWithMetadata(key, { type: "arrayBuffer"}); + if (!obj.value) { + return null; + } return new Response(obj.value, { headers: { @@ -28,6 +30,11 @@ const kvObjService = { 'Cache-Control': obj.metadata?.cacheControl || null } }); + }, + + async toObjResp(c, key) { + + return await this.getObj(c, key); } diff --git a/mail-worker/src/service/r2-service.js b/mail-worker/src/service/r2-service.js index 0a45392..9d83b7a 100644 --- a/mail-worker/src/service/r2-service.js +++ b/mail-worker/src/service/r2-service.js @@ -41,7 +41,19 @@ const r2Service = { }, async getObj(c, key) { - return await c.env.r2.get(key); + const storageType = await this.storageType(c); + + if (storageType === 'KV') { + return await kvObjService.getObj(c, key); + } + + if (storageType === 'R2') { + return await c.env.r2.get(key); + } + + if (storageType === 'S3') { + return await s3Service.getObj(c, key); + } }, async delete(c, key) { diff --git a/mail-worker/src/service/s3-service.js b/mail-worker/src/service/s3-service.js index 873ae73..d18385b 100644 --- a/mail-worker/src/service/s3-service.js +++ b/mail-worker/src/service/s3-service.js @@ -1,4 +1,4 @@ -import { S3Client, PutObjectCommand, DeleteObjectsCommand } from "@aws-sdk/client-s3"; +import { S3Client, PutObjectCommand, DeleteObjectsCommand, GetObjectCommand } from "@aws-sdk/client-s3"; import settingService from './setting-service'; import domainUtils from '../utils/domain-uitls'; import { settingConst } from '../const/entity-const'; @@ -75,6 +75,23 @@ const s3Service = { ); }, + async getObj(c, key) { + const client = await this.client(c); + const { bucket } = await settingService.query(c); + const result = await client.send(new GetObjectCommand({ + Bucket: bucket, + Key: key + })); + + return new Response(result.Body, { + headers: { + 'Content-Type': result.ContentType || 'application/octet-stream', + 'Content-Disposition': result.ContentDisposition || null, + 'Cache-Control': result.CacheControl || null + } + }); + }, + async client(c) { const { region, endpoint, s3AccessKey, s3SecretKey, forcePathStyle } = await settingService.query(c);