tus / tus-android-client

The tus client for Android.
https://tus.io/
161 stars 46 forks source link

Upload don't resume instead restart from 0, when uploading to vimeo #40

Closed HarishJangra closed 4 years ago

HarishJangra commented 4 years ago

I am having problem resuming upload when uploading to vimeo here is the code i am using

  private Map<String, TusRunnable> executorsMap;
  private ExecutorService pool;

  public RNTusClientModule(ReactApplicationContext reactContext) {
    super(reactContext);
    this.reactContext = reactContext;
    this.executorsMap = new HashMap<String, TusRunnable>();
    pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
  }

  @Override
  public String getName() {
    return "RNTusClient";
  }

  @ReactMethod
  public void createUpload(String fileUrl, ReadableMap options, Callback callback) {
    String endpoint = options.getString("endpoint");
    Map<String, Object> rawHeaders = options.getMap("headers").toHashMap();
    Map<String, Object> rawMetadata = options.getMap("metadata").toHashMap();

    Map<String, String> metadata = new HashMap<>();
    for (String key : rawMetadata.keySet()) {
      metadata.put(key, String.valueOf(rawMetadata.get(key)));
    }
    Map<String, String> headers = new HashMap<>();
    for (String key : rawHeaders.keySet()) {
      headers.put(key, String.valueOf(rawHeaders.get(key)));
    }

    try {
      String uploadId = UUID.randomUUID().toString();
      TusRunnable executor = new TusRunnable(fileUrl, uploadId, endpoint, metadata, headers);
      this.executorsMap.put(uploadId, executor);
      Log.d(TAG, "CREATE UPLOAD " + uploadId);

      callback.invoke(uploadId);
    } catch (FileNotFoundException | MalformedURLException e) {
      callback.invoke((Object) null, e.getMessage());
    }
  }
  @ReactMethod
  public void resume(String uploadId, Callback callback) {
    TusRunnable executor = this.executorsMap.get(uploadId);
    if (executor != null) {
      Log.d(TAG, "on resume upload");

      pool.submit(executor);
      callback.invoke(true);
    } else {
      callback.invoke(false);
    }
  }

  class TusRunnable extends TusExecutor implements Runnable {
    private TusAndroidUpload upload;
    private TusUploader uploader;
    private String uploadId;
    private String uploadEndPoint;
    private TusClient client;
    private boolean shouldFinish;
    private boolean isRunning;

    public TusRunnable(String fileUrl, String uploadId, String endpoint, Map<String, String> metadata,
        Map<String, String> headers) throws FileNotFoundException, MalformedURLException {
      this.uploadId = uploadId;
      this.uploadEndPoint = endpoint;

      client = new TusClient();
      // client.setUploadCreationURL(new URL(endpoint));

      SharedPreferences pref = reactContext.getSharedPreferences("tus", 0);

      client.enableResuming(new TusPreferencesURLStore(pref));
      client.setHeaders(headers);

      upload = new TusAndroidUpload(Uri.parse(fileUrl), reactContext);
      upload.setMetadata(metadata);

      Log.d(TAG, "executor created");

      shouldFinish = false;
      isRunning = false;
    }

    protected void makeAttempt() throws ProtocolException, IOException {
      // uploader = client.resumeOrCreateUpload(upload);
      uploader = client.beginOrResumeUploadFromURL(upload, new URL(uploadEndPoint));

      uploader.setChunkSize(1024);
      uploader.setRequestPayloadSize(10 * 1024 * 1024);
      Log.d(TAG, "attempt upload " + uploader.getChunkSize());

      // do {
      // long totalBytes = upload.getSize();
      // long bytesUploaded = uploader.getOffset();
      // sendProgressEvent(totalBytes, bytesUploaded);
      // Log.d(TAG, "on uploadchunk");

      // } while (uploader.uploadChunk() > -1 && !shouldFinish);

      Timer progressTicker = new Timer();

      progressTicker.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
          sendProgressEvent(upload.getSize(), uploader.getOffset());
        }
      }, 0, 500);

      do {
      } while (uploader.uploadChunk() > -1 && !shouldFinish);

      sendProgressEvent(upload.getSize(), upload.getSize());

      progressTicker.cancel();
      uploader.finish();
    }

    private void sendProgressEvent(long bytesTotal, long bytesUploaded) {
      WritableMap params = Arguments.createMap();

      params.putString("uploadId", uploadId);
      params.putDouble("bytesWritten", bytesUploaded);
      params.putDouble("bytesTotal", bytesTotal);

      reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(ON_PROGRESS, params);
    }

    public void finish() throws ProtocolException, IOException {
      if (isRunning) {
        shouldFinish = true;
      } else {
        if (uploader != null) {
          uploader.finish();
        }
      }
    }

    @Override
    public void run() {
      isRunning = true;
      try {
        makeAttempts();
        String uploadUrl = uploader.getUploadURL().toString();
        executorsMap.remove(this.uploadId);
        WritableMap params = Arguments.createMap();
        params.putString("uploadId", uploadId);
        params.putString("uploadUrl", uploadUrl);
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(ON_SUCCESS, params);
      } catch (ProtocolException | IOException e) {
        WritableMap params = Arguments.createMap();
        params.putString("uploadId", uploadId);
        params.putString("error", e.toString());
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(ON_ERROR, params);
      }
      isRunning = false;
    }
  }
HarishJangra commented 4 years ago

I did it. i need to pass the headers for offset manually when resume.