当前位置 : 主页 > 网络编程 > JavaScript >

阿里云文件碎片上传oss

来源:互联网 收集:自由互联 发布时间:2021-06-28
gistfile1.txt /// /// /// /// 'use strict';/*** 这个是oss的管理类** 事件:StartCalculatorMd5、CalculatorMd5Progress、CalculatorMd5Finished* StartCalculatorMd5 event:{File:"上传的文件对象"}* CalculatorMd5Progress event:
gistfile1.txt
/// 
/// 
/// 
/// 



'use strict';
/**
* 这个是oss的管理类
*
* 事件:StartCalculatorMd5、CalculatorMd5Progress、CalculatorMd5Finished
* StartCalculatorMd5 event:{File:"上传的文件对象"}
* CalculatorMd5Progress event: {File: "上传的文件对象",Percent: "上传的百分比"}
* CalculatorMd5Finished event:{ File: "上传的文件对象",Md5: "计算出来的文件的md5码"}
* UploadProgress event:{}
* UploadSuccess event:{}
* UploadFail event:{}
*
* parms:
*   url:获取token的url地址
*   validtime:获取的token的有效时长
*   chunkSize:文件进行分片上传时的分片大小
*   bucket:文件上传的桶
*   multipartuploadmaxRetry:分片上传时最大的重试次数
*   keygeneratefunc:key的生成函数 参数:[OssUploadManager,进行上传的文件对象]
*   osshead_single_user:文件上传时用户自定义的head生成函数 参数:[ossmanager,预设的头信息, 上传文件对象]
*   osshead_single_user:文件上传时用户自定义的head生成函数 参数:[ossmanager,预设的头信息, 上传文件对象]
* */


//token url
//token有效时间
function OssUploadManager(parms) {
    if (typeof parms !== "object") {
        throw new Error("参数错误");
    }
    ClassEvent.call(this);//属性继承

    if (!parms.tokenurl || !parms.tokenvalidtime || !parms.bucket || !parms.endpoint) {
        throw new Error("参数错误");
    }
    this.ststoken = new ststokenmanager({
        requesturl: parms.tokenurl, //'http://sts.lichengsoft.com/GetSTS',
        tokenvalidtime: parms.tokenvalidtime // 30 * 1000
    });
    if (parms.tokenrequestsuccessfunc && typeof parms.tokenrequestsuccessfunc === "function") {
        this.ststoken.requestsuccessfunc = parms.tokenrequestsuccessfunc
    }

    this.chunkSize = parms.chunkSize || 1024 * 1024 * 4;//进行分片的大小
    this.bucket = parms.bucket;// "hz-pub";//上传的bucket
    this.multipartuploadmaxRetry = parms.multipartuploadmaxRetry || 3;//分片上传时失败的最大重试次数
    this.concurrency = parms.concurrency || 2;
    this.oss = new ALY.OSS({
        endpoint: parms.endpoint,
        apiVersion: '2013-10-15'
    });//aliyun oss对象
    this.FileArray = [];//文件上传数组
    this.keygeneratefunc = parms.keygeneratefunc || function (ossm, file) {
        return file.OssUploadControlParm.MD5; //ossm.bucket + "/" + file.OssUploadControlParm.MD5;
    }//key生成函数 用户实现


}


OssUploadManager.FileUploadState = {
    UnStart: 0,
    Uploading: 1,
    Success: 2,
    Fail: 3
}

OssUploadManager.prototype.Upload = function (file) {
    //file = file || {};
    if (this.FileArray.indexOf(file) != -1) {
        //文件已经添加到上传处理区
        if (file.OssUploadControlParm.RelativeFileIndex !== undefined) {
            var relfile = this.FileArray[file.OssUploadControlParm.RelativeFileIndex];
            if (relfile.OssUploadControlParm.OssUploadState === OssUploadManager.FileUploadState.Fail) {
                this.upload(relfile);
            }
        } else {
            if (file.OssUploadControlParm.OssUploadState === OssUploadManager.FileUploadState.Fail || file.OssUploadControlParm.OssUploadState === OssUploadManager.FileUploadState.UnStart) {
                this.upload(file);
            }
        }
        return;
    }
    file.OssUploadControlParm = {};
    file.OssUploadControlParm.OssUploadIndex = this.getfileindex();//为每一个进行上传的文件设置一个编号
    file.OssUploadControlParm.OssUploadState = OssUploadManager.FileUploadState.UnStart;//还为开始上传
    this.FileArray.push(file);//将文件添加到文件队列中
    this.calculatormd5(file);//计算文件的md5值
}



OssUploadManager.prototype.Cancel = function (file) {
    var fileindex = this.FileArray.indexOf(file)
    if (fileindex != -1) {
        if (file.OssUploadControlParm.OssUploadState === OssUploadManager.FileUploadState.Uploading) {
            file.OssUploadControlParm.UploadRequest.abort();
            delete file.OssUploadControlParm;
            this.FileArray.splice(fileindex, 1);
            this.ExcuteEvent("Cancel", this, { File: file });
        }
    }
}

OssUploadManager.prototype.getfileindex = function () {
    return this.FileArray.length;
}
OssUploadManager.prototype.calculatormd5 = function (file) {
    var self = this;
    self.ExcuteEvent("StartCalculatorMd5", self, { File: file });
    CalculatorFileMD5(file, function (calfile, block) {
        self.ExcuteEvent("CalculatorMd5Progress", self, {
            File: file,
            Percent: block.end / block.file_size
        })
    }, function (calfile, result) {
        self.ExcuteEvent("CalculatorMd5Finished", self, {
            File: file,
            Md5: result.md5
        });
        file.OssUploadControlParm.MD5 = result.md5;//设置文件的md5
        self.uploadfile(file);//上传文件
    });
}
OssUploadManager.prototype.uploadfile = function (file) {
    //判断是否有相同的文件已经上传或正在上传
    this.relativefile(file);
}
OssUploadManager.prototype.relativefile = function (file) {
    //关联文件 相同的文件进行关联
    var same = this.findallsamefile(file);//不包括自己
    if (same.length == 0) {
        //表示没有相同的文件已经上传 直接进行文件上传操作
        this.upload(file);
    } else {
        //表示有相同的文件,此时进行文件的关联操作
        if (same[0].OssUploadControlParm.RelativeFileIndex !== undefined) {
            file.OssUploadControlParm.RelativeFileIndex = same[0].OssUploadControlParm.RelativeFileIndex;
        } else {
            file.OssUploadControlParm.RelativeFileIndex = same[0].OssUploadControlParm.OssUploadIndex;
        }
        var refile = this.FileArray[file.OssUploadControlParm.OssUploadIndex];
        if (refile.OssUploadControlParm.OssUploadState === OssUploadManager.FileUploadState.Success) {
            //调文件上传完成函数
            this.filesuccess(file, {});
        } else if (refile.OssUploadControlParm.OssUploadState === OssUploadManager.FileUploadState.Fail) {
            //调文件上传失败函数 对失败的文件进行重新上传
            this.filefail(file, {});
        }
    }
}
OssUploadManager.prototype.findallsamefile = function (file) {
    var samefile = [];
    for (var i = 0; i < this.FileArray.lengt; i++) {
        if (file.OssUploadControlParm.MD5 && this.FileArray[i].OssUploadControlParm.MD5 && file.OssUploadControlParm.MD5 === this.FileArray[i].OssUploadControlParm.MD5 && file.OssUploadControlParm.OssUploadIndex !== this.FileArray[i].OssUploadControlParm.OssUploadIndex) {
            samefile.push(this.FileArray[i]);
        }
    }
    return samefile;
}

OssUploadManager.prototype.upload = function (file) {
    file.OssUploadControlParm.OssUploadState = OssUploadManager.FileUploadState.Uploading;
    var self = this;
    var self = this;
    this.ststoken.gettoken().done(function (data) {
        //this.oss set key start uploadfile
        file.OssUploadControlParm.Key = self.keygeneratefunc(self, file);
        self.oss.config.accessKeyId = data.Credentials.AccessKeyId;
        self.oss.config.secretAccessKey = data.Credentials.AccessKeySecret;
        self.oss.config.securityToken = data.Credentials.SecurityToken;

        //default 默认为进行文件是否已经存在的检测操作
        //if (true) {
        //    self.askisexists(file);
        //} else {
            self.ossupload(file);
        //}

    }).fail(function () {
        //文件上传状态改为失败 触发上传失败事件
        self.filefail(file, {});
    })
}

//向远程服务器询问文件是否已经进行了上传
OssUploadManager.prototype.askisexists = function (uploadfile) {
    var self = this;
    this.oss.headObject({
        Bucket: this.bucket,
        Key: uploadfile.OssUploadControlParm.Key,//需要一个key的实现函数
    }, function (error, data) {
        if (error) {
            //表示文件不存在
            self.ossupload(uploadfile);
        } else {
            //表示文件存在
            self.filesuccess(uploadfile);
        }
    })
}

OssUploadManager.prototype.ossupload = function (uploadfile) {//uploadfile:上传的文件
    var self = this;
    var file = uploadfile;

    var readFile = function (callback) {
        var result = {
            chunksHash: {},
            chunks: []
        };
        var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
        var chunkSize = self.chunkSize; //self._config.chunkSize;
        var chunksNum = Math.ceil(file.size / chunkSize);
        var currentChunk = 0;

        var frOnload = function (e) {
            result.chunks[currentChunk] = e.target.result;
            currentChunk++;
            if (currentChunk < chunksNum) {
                loadNext();
            }
            else {
                result.file_size = file.size;
                callback(null, result);
            }
        };
        var frOnerror = function () {
            self.filefail(uploadfile, { ErrReason: "读取文件失败" });
        };

        function loadNext() {
            var fileReader = new FileReader();
            fileReader.onload = frOnload;
            fileReader.onerror = frOnerror;

            var start = currentChunk * chunkSize,
                end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
            var blobPacket = blobSlice.call(file, start, end);
            fileReader.readAsArrayBuffer(blobPacket);
        }

        loadNext();
    };

    var uploadSingle = function (result, callback) {
        var params = self.osshead_single(uploadfile, result);
        if (typeof self.osshead_single_user === "function")
            self.osshead_single_user(self, params, uploadfile);

        var req = self.oss.putObject(params, callback);

        req.on('httpUploadProgress', function (p) {
            self.fileprocess(uploadfile, p);
        });
    };

    var uploadMultipart = function (result, callback) {
        var maxUploadTries = self.multipartuploadmaxRetry;
        var uploadId;
        var loadedNum = 0;
        var latestUploadNum = -1;
        var concurrency = 0;

        var multipartMap = {
            Parts: []
        };

        var init = function () {
            var params = self.osshead_multipart(uploadfile, result, callback);
            if (typeof self.osshead_multipart_user === "function") {
                self.osshead_multipart_user(self, params, uploadfile);
            }

            self.oss.createMultipartUpload(params,
                function (mpErr, res) {
                    if (mpErr) {
                        // console.log('Error!', mpErr);
                        callback(mpErr);
                        return;
                    }

                    // console.log("Got upload ID", res.UploadId);
                    uploadId = res.UploadId;

                    uploadPart(0);
                });
        };

        var uploadPart = function (partNum) {
            if (partNum >= result.chunks.length) {
                return;
            }

            concurrency++;
            if (latestUploadNum < partNum) {
                latestUploadNum = partNum;
            }
            if (concurrency < self.concurrency && (partNum < (result.chunks.length - 1))) {
                uploadPart(partNum + 1);
            }
            var partParams = {
                Body: result.chunks[partNum],
                Bucket: self.bucket, //self._config.bucket,
                Key: uploadfile.OssUploadControlParm.Key,//self.keygeneratefunc(this,uploadfile,result), // options.key,
                PartNumber: String(partNum + 1),
                UploadId: uploadId
            };

            var tryNum = 1;

            var doUpload = function () {

                multipartMap.Parts[partNum] = {
                    PartNumber: partNum + 1,
                    loaded: 0
                };

                var req = self.oss.uploadPart(partParams, function (multiErr, mData) {
                    if (multiErr) {
                        // console.log('multiErr, upload part error:', multiErr);
                        if (tryNum > maxUploadTries) {
                            console.log('上传分片失败: #', partParams.PartNumber);
                            callback(multiErr);
                        }
                        else {
                            console.log('重新上传分片: #', partParams.PartNumber);
                            multipartMap.Parts[partNum].loaded = 0;
                            tryNum++;
                            doUpload();
                        }
                        return;
                    }

                    multipartMap.Parts[partNum].ETag = mData.ETag;
                    multipartMap.Parts[partNum].loaded = partParams.Body.byteLength;

                    // console.log(mData);
                    concurrency--;

                    console.log("Completed part", partNum + 1);
                    //console.log('mData', mData);

                    loadedNum++;
                    if (loadedNum == result.chunks.length) {
                        complete();
                    }
                    else {
                        uploadPart(latestUploadNum + 1);
                    }
                });

                req.on('httpUploadProgress', function (p) {
                    multipartMap.Parts[partNum].loaded = p.loaded;

                    var loaded = 0;
                    for (var i in multipartMap.Parts) {
                        loaded += multipartMap.Parts[i].loaded;
                    }
                    self.fileprocess(uploadfile, { loaded: loaded, total: uploadfile.size });
                });
            };

            doUpload();

        };

        var complete = function () {
            // console.log("Completing upload...");

            for (var i in multipartMap.Parts) {
                delete multipartMap.Parts[i].loaded;
            }

            var doneParams = {
                Bucket: self.bucket, //self._config.bucket,
                Key: uploadfile.OssUploadControlParm.Key, //self.keygeneratefunc(self,uploadfile), //options.key,
                CompleteMultipartUpload: multipartMap,
                UploadId: uploadId
            };

            self.oss.listParts({//获取分片
                UploadId: uploadId,
                Bucket: self.bucket,
                Key: uploadfile.OssUploadControlParm.Key
            }, function (err, data) {
                var parts = data.Parts;
                multipartMap.Parts = [];
                var part = null;
                for (var i = 0; i < parts.length; i++) {
                    part = parts[i];
                    multipartMap.Parts.push({
                        PartNumber: part.PartNumber,
                        ETag: part.ETag
                    });
                }
                self.oss.completeMultipartUpload(doneParams, callback);
            });

        };

        init();
    };

    readFile(function (err, result) {
        var callback = function (err, res) {
            if (err) {
                self.filefail(uploadfile, err);//上传失败处理
                return;
            }
            self.filesuccess(uploadfile, res);
        };

        if (result.chunks.length == 1) {
            uploadSingle(result, callback)
        }
        else {
            uploadMultipart(result, callback);
        }
    });

};



//文件上传百分比处理函数
OssUploadManager.prototype.fileprocess = function (file, event) {
    var relative = this.findallrelativefile(file);
    relative.push(file);
    for (var i = 0; i < relative.length; i++) {
        this.ExcuteEvent("UploadProgress", this, { File: relative[i], Percent: event.loaded / event.total * 100 })
    }
}
//文件上传成功处理函数
OssUploadManager.prototype.filesuccess = function (file, event) {
    file.OssUploadControlParm.OssUploadState = OssUploadManager.FileUploadState.Success;
    var relative = this.findallrelativefile(file);
    relative.push(file);
    for (var i = 0; i < relative.length; i++) {
        this.ExcuteEvent("UploadSuccess", this, { File: relative[i] })
    }
}
//文件上传失败处理函数
OssUploadManager.prototype.filefail = function (file, event) {
    file.OssUploadControlParm.OssUploadState = OssUploadManager.FileUploadState.Fail;
    var relative = this.findallrelativefile(file);
    relative.push(file);
    for (var i = 0; i < relative.length; i++) {
        this.ExcuteEvent("UploadFail", this, { File: relative[i] })
    }
}

OssUploadManager.prototype.findallrelativefile = function (file) {//获取所有的关联在改文件上的文件
    var relative = [];
    for (var i = 0; i < this.FileArray.length; i++) {
        if (this.FileArray[i].OssUploadControlParm.RelativeFileIndex !== undefined && this.FileArray[i].OssUploadControlParm.RelativeFileIndex === file.OssUploadControlParm.OssUploadIndex) {
            relative.push(this.FileArray[i]);
        }
    }
    return relative;
}

OssUploadManager.prototype.osshead_single = function (uploadfile, result, callback) {
    var params = {
        Bucket: this.bucket,
        Key: uploadfile.OssUploadControlParm.Key,//需要一个key的实现函数
        Body: result.chunks[0],
        ContentType: uploadfile.type || ''
    };
    return params;
}
OssUploadManager.prototype.osshead_multipart = function (uploadfile, result, callback) {
    var params = {
        Bucket: this.bucket,
        Key: uploadfile.OssUploadControlParm.Key,
        ContentType: uploadfile.type || ''
    };
    return params;
}

OssUploadManager.prototype = Extend({}, ClassEvent.prototype, OssUploadManager.prototype)



//OssUploadManager.prototype.ExtendFile = function (file) {
//    [{ "FILENAME": "test0 - 副本 (4).pdf", "FILEPATHNAME": "C:/Usersenk/Desktop/testPDF/test0 - 副本 (4).pdf", "FILETYPE": "PDF", "MD5": "9e95ad55d9e4f0e83d72ab3630e6316e", "SIZE": 161770, "UUID": "77f160fa-467d-49c1-ae3a-2182cf8c123d" }]
//}
网友评论