import IUploadTask from './IUploadTask'; import { ApplyUploadRequest, IMediaInfo } from '../BackendServerModel'; import { UploadProgress, ImageComplete, UploadResult } from '../Model'; import { Resolution, ImagePublishUsage } from '../UGCPublishTypeDef'; import S3, { PutObjectRequest } from 'aws-sdk/clients/s3'; import OSS from 'ali-oss'; import fs from 'fs'; import path from 'path'; import { TransformImage, GetGifInfo } from '../utils/ImageUtils'; import { StatusCheckpoint } from '../TaskStatus'; export default class ImageUploadTask implements IUploadTask { private _resolutions: Resolution[]; private _definiteResolutions: { w: number, h: number }[]; ffmpegPath?: string; objectKeyPrefix: string; // 默认前缀 images; 另外还有 headshot, figure constructor(resolutions: Resolution[], usage: ImagePublishUsage, definiteResolutions: { w: number, h: number }[]) { this._resolutions = resolutions; this._definiteResolutions = definiteResolutions; if(usage == ImagePublishUsage.Headshot) { this.objectKeyPrefix = 'headshot'; } else if (usage == ImagePublishUsage.Figure) { this.objectKeyPrefix = 'figure'; } else { this.objectKeyPrefix = 'images'; } } makeApplyUploadRequest(md5: string, objectKeyPartial: string, file: string, region: string, bucket: string, fileExt: string, serverType: number): ApplyUploadRequest { let fileSize = fs.statSync(file).size; let imageGroups = this._definiteResolutions.map((res, i) => { return { Name: this._resolutions[i].name, Resolution: { width: res.w, height: res.h } }; }); let mediaInfo: IMediaInfo = { FileExt: fileExt, ImageGroup: imageGroups }; let applyRequest: ApplyUploadRequest = { Md5: md5, CategoryId: 1, MediaType: 'image', FileName: objectKeyPartial, FileSize: fileSize, Region: region, BucketName: bucket, ServerType: serverType, MediaInfo: mediaInfo }; return applyRequest; } makeResult(mediaId: string, fileSize: number, mark: string, uploadRet: UploadResult[]): ImageComplete[] { let uploadResultLen = uploadRet.length; return this._resolutions.map((res, i) => { // uploadRet 返回数组可能只有一条数据 let uploadResultIndex = i <= uploadResultLen - 1 ? i : uploadResultLen - 1; let img: ImageComplete = { name: res.name, id: mediaId, url: uploadRet[uploadResultIndex].Url, mark: mark, width: this._definiteResolutions[i].w, height: this._definiteResolutions[i].h, filesize: fileSize // 不准确 }; return img; }); } async makeUploadTask(client: S3 | OSS, bucket: string, objectKeyPartial: string, mediaId: string, file: string, fileExt: string, md5: string, statusCp: StatusCheckpoint | undefined, listener: (progress: UploadProgress) => void): Promise { // 生成图片的buffer数组 let tikNow = new Date(); let bufArr = await TransformImage(this.ffmpegPath, file, this._resolutions); let tokNow = new Date(); let tiktokSec = tokNow.getSeconds() - tikNow.getSeconds(); let tiktokMs = tokNow.getMilliseconds() - tikNow.getMilliseconds(); //console.log(`TransformImage tiktok---${tiktokSec}:${tiktokMs}`); let totalSize: number = 0; let uploaded: Array = []; let imageKeys: Array = []; for (let i = 0; i < bufArr.length; i++) { let b = bufArr[i]; totalSize += b.fileSize;//fs.statSync(b.file).size; //let md5 = await GetMd5(b.file); uploaded[i] = 0; let extName = bufArr[i].name == 'Original' ? fileExt : '.jpg'; imageKeys[i] = `${objectKeyPartial}${mediaId}_${b.width}x${b.height}${extName}`; } let uploadRetArr = await Promise.all(bufArr.map((buf, index) => { let isGif = fileExt == '.gif'; return this.UploadImage(client, bucket, imageKeys[index], buf.fileSize, fs.createReadStream(buf.file), isGif, (progress) => { uploaded[index] += progress.Uploaded; let bytes = 0; uploaded.forEach(value => { bytes += value }); listener.call(listener, { Total: totalSize, Uploaded: bytes }); }) })); return uploadRetArr; } private async UploadImage(client: S3 | OSS, bucket: string, objectKey: string, fileSize: number, stream: fs.ReadStream, isGif: boolean, listener: (progress: UploadProgress) => void): Promise { if (client instanceof S3) { let request: PutObjectRequest = { Bucket: bucket, ContentLength: fileSize, ContentType: isGif ? 'image/gif' : 'image/jpg', Key: objectKey, Tagging: 'public=1', Body: stream }; let upload = client.upload(request); upload.on('httpUploadProgress', progress => { listener.call(listener, { Uploaded: progress.loaded, Total: progress.total }); }); let sendData = await upload.promise(); console.log(sendData); } else if (client instanceof OSS) { let sendData = await client.put(objectKey, stream); console.log(sendData); } else { throw 'makeUploadTask uploader object is wrong.'; } let url = `${IUploadTask.proxyUrl}/${objectKey}`; //let url = `https://${that._bucket}.s3-${that._region}.amazonaws.com/${objectKey}`; return { Url: url, Bucket: bucket, Key: objectKey }; } }