All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.avos.avoscloud.upload.QiniuSlicingUploader Maven / Gradle / Ivy

package com.avos.avoscloud.upload;

import com.avos.avoscloud.AVErrorUtils;
import com.avos.avoscloud.AVException;
import com.avos.avoscloud.AVFile;
import com.avos.avoscloud.AVOSCloud;
import com.avos.avoscloud.AVUtils;
import com.avos.avoscloud.LogUtil;
import com.avos.avoscloud.ProgressCallback;
import com.avos.avoscloud.SaveCallback;

import java.io.InputStream;

import java.util.List;
import java.util.ArrayList;

/**
 * Use one thread to upload file to qiniu, slicing with 4MB chunk.
 *
 * Created by fengjunwen on 2017/8/14.
 */

class QiniuSlicingUploader extends HttpClientUploader {
  private final String token;
  private final String fileKey;
  private FileUploader.ProgressCalculator progressCalculator;
  private int uploadChunkSize = QiniuAccessor.WIFI_CHUNK_SIZE;
  private QiniuAccessor qiniuAccessor;

  QiniuSlicingUploader(AVFile avFile, String token, String fileKey, SaveCallback saveCallback, ProgressCallback progressCallback) {
    super(avFile, saveCallback, progressCallback);
    this.token = token;
    this.fileKey = fileKey;
    this.qiniuAccessor = new QiniuAccessor(getOKHttpClient(), token, fileKey);
  }

  @Override
  public AVException doWork() {
    boolean isWifi = AVUtils.isWifi(AVOSCloud.applicationContext);
    if (!isWifi) {
      // 从七牛的接口来看block size为4M不可变,但是chunkSize是可以调整的
      uploadChunkSize = QiniuAccessor.NONWIFI_CHUNK_SIZE;
    }
    InputStream is = null;
    byte buf[] = new byte[uploadChunkSize];
    int fileSize = this.avFile.getSize();
    int blockCount = (fileSize / QiniuAccessor.BLOCK_SIZE) + (fileSize % QiniuAccessor.BLOCK_SIZE > 0 ? 1 : 0);
    List uploadFileCtxs = new ArrayList(blockCount);

    progressCalculator = new FileUploader.ProgressCalculator(blockCount, new FileUploader.FileUploadProgressCallback() {
      public void onProgress(int progress) {
        publishProgress(progress);
      }
    });

    try {
      is = this.avFile.getDataStream();
      // loop for read, upload block to qiniu.
      for (int i = 0; i< blockCount; i++) {
        int currentBlockSize = QiniuAccessor.BLOCK_SIZE;
        int currentBlockOffset = i * QiniuAccessor.BLOCK_SIZE;
        if (i == blockCount - 1) {
          // last block.
          currentBlockSize = fileSize - currentBlockOffset;
        }
        int chunkCount = currentBlockSize / uploadChunkSize + (currentBlockSize % uploadChunkSize > 0? 1 : 0);
        QiniuAccessor.QiniuBlockResponseData lastResponse = null;
        for (int j = 0; j < chunkCount; j++) {
          int currentChunkOffset = j * uploadChunkSize;
          int currentChunkSize = (j == chunkCount -1)? (currentBlockSize - currentChunkOffset): uploadChunkSize;

          // read BLOCK_SIZE content to buf until reach out block size or end-of-file.
          int totalReadCnt = 0;
          int curReadCnt = is.read(buf, totalReadCnt, currentChunkSize - totalReadCnt);
          totalReadCnt += curReadCnt;
          while (curReadCnt > 0 && totalReadCnt < currentChunkSize) {
            curReadCnt = is.read(buf, totalReadCnt, currentChunkSize - totalReadCnt);
            totalReadCnt += curReadCnt;
          }

          if (j == 0) {
            // 1.创建一个block,并且会上传第一个block的第一个chunk的数据
            lastResponse = this.qiniuAccessor.createBlockInQiniu(currentBlockSize, currentChunkSize, buf, DEFAULT_RETRY_TIMES);
          } else {
            // 2.分片上传
            lastResponse = this.qiniuAccessor.putFileBlocksToQiniu(lastResponse, currentBlockOffset, buf, currentChunkSize, DEFAULT_RETRY_TIMES);
          }
        }

        if (null != lastResponse){
          uploadFileCtxs.add(lastResponse.ctx);
          progressCalculator.publishProgress(i, 100);
        } else {
          // error.
          // FIXME: 2017/8/14 603 is hardcode.
          return new AVException(603, "failed to upload file to qiniu.");
        }
      }
      QiniuAccessor.QiniuMKFileResponseData finalResponse = this.qiniuAccessor.makeFile(fileSize, uploadFileCtxs, DEFAULT_RETRY_TIMES);
      if (finalResponse == null || !finalResponse.key.equals(fileKey)) {
        return AVErrorUtils.createException(AVException.OTHER_CAUSE, "upload file failure");
      }
    } catch (Exception ex) {
      return new AVException(ex);
    } finally {
      try {
        if (null != is) {
          is.close();
        }
      } catch (Exception e) {
        ;
      }
    }

    return null;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy