Code Monkey home page Code Monkey logo

filestack-java's Introduction

Filestack Java SDK

Java SDK for Filestack. Includes wrappers for Core, Upload, Transformation, and Cloud APIs. Supports Amazon Drive, Box, Dropbox, Facebook, GitHub, Gmail, Google Drive, Google Photos, Instagram, and OneDrive.

Install

implementation 'com.filestack:filestack-java:0.9.0'

Upload

// Create a client
Config config = new Config("API_KEY");
Client client = new Client(config);

// Set options and metadata for upload
StorageOptions options = new StorageOptions.Builder()
    .mimeType("text/plain")
    .filename("hello.txt")
    .build();

// Perform a synchronous, blocking upload
FileLink file = client.upload("/path/to/file", false);

// Perform an asynchronous, non-blocking upload
Flowable<Progress<FileLink>> upload = client.uploadAsync("/path/to/file", false);
upload.doOnNext(new Consumer<Progress<FileLink>>() {
  @Override
  public void accept(Progress<FileLink> progress) throws Exception {
    System.out.printf("%f%% uploaded\n", progress.getPercent());
    if (progress.getData() != null) {
      FileLink file = progress.getData();
    }
  }
});

Asynchronous Functions

Every function that makes a network call has both a synchronous (blocking) and asynchronous (non-blocking) version. The asynchronous versions return RxJava classes (Observable, Single, Completable).

For example to delete a file both synchronously and asynchronously:

// Synchronous, blocking
fileLink.delete();

// Asynchronous, not blocking
fileLink.deleteAsync().doOnComplete(new Action() {
  @Override
  public void run() throws Exception {
    System.out.println("File deleted.");
  }
});

FileLink Operations

String handle = fileLink.getHandle(); // A handle is a file ID
fileLink.download("/path/to/save/file");
fileLink.delete();
fileLink.overwrite("/path/to/new/file");

Transformations

The transform functions generate URLs for backend transformations; No local processing occurs. With the exception of video transformations, front-end clients can directly use the generated URLS.

For example, to reduce image bandwidth usage, generate resize transform URLs based on display size:

ResizeTask task = new ResizeTask.Builder()
    .width(100)
    .fit("center")
    .build();
ImageTransform transform = fileLink.imageTransform().addTask(task);
String url = transform.url();

Cloud Transfers

// Check a user's auth status by first trying to list contents of drive
CloudResponse response = client.getCloudItems(Sources.GOOGLE_DRIVE, "/");
String authUrl = response.getAuthUrl();
// If auth URL isn't null, user needs to authenticate, open URL in browser
if (authUrl != null) {
    openBrowser(authUrl);
    return;
}

// Transfer the first file from the cloud provider to Filestack
CloudItem first = response.getItems()[0];
client.storeCloudItem(Sources.GOOGLE_DRIVE, first.getPath());

// Check for another page of results
String nextToken = response.getNextToken();
// If next token isn't null, there's more items to fetch
if (nextToken != null) {
  response = client.getCloudItems(Sources.GOOGLE_DRIVE, "/", nextToken);
}

// Save the session token
String sessionToken = client.getSessionToken();
saveSessionToken(sessionToken);

Cloud Auth States

There are 3 levels of state to note with cloud integrations: 1) the local state (stored by a session token) 2) the authorization state between the user's cloud account and Filestack (on the backend) and 3) (potentially) the login state within the browser where users complete the OAuth login.

A session token determines the auth state between an app and Filestack. Every response includes a refreshed token, and every request should send the last token received. Tokens do not just identify a session, they hold the session state. For example if a user logs out of a cloud, only the token returned by the logout response reflects that action; Using the old token would still allow listing the contents of the logged out cloud. To maintain state across client destruction, export and save the token.

The auth state in the local session does not connect to the authorization state between a cloud account and Filestack. For example a user can log out of an account in a local session, but still see Filestack as authorized in the cloud provider's settings. A user must revoke access to Filestack within a provider to truly disconnect Filestack.

Users complete the OAuth flow (aka login to their clouds) in a browser, and the browser state can cause confusion. For example if a user logs into a cloud they previously logged out of, the OAuth flow may work differently because they've already logged in within the browser, and have already authorized Filestack to that cloud.

Running Tests and Linting

To run tests:

./gradlew test

The project also has Checkstyle setup for code linting. The config is at config/checkstyle/checkstyle.xml. To run:

./gradlew check # Runs linter and unit tests

Proguard

If you are using Proguard, please include entries from this file in your Proguard configuration file.

Please note, that those rules will probably decrease in size as we proceed with getting rid of most of external dependencies.

Deployment

This is for Filestack devs. Deployments are made to Bintray. You must have an account that's been added to the Filestack organization to deploy. Also make sure to follow general Filestack release guidelines. "BINTRAY_USER" and "BINTRAY_API_KEY" environment variables are required. To run:

export BINTRAY_USER=''
export BINTRAY_API_KEY=''
./gradlew bintrayUpload

filestack-java's People

Contributors

marcinqualaroo avatar scana avatar shawnmaten avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

filestack-java's Issues

Still alive?

Is this project still alive? No commit during the past two years, no Release for 0.9.0. What is the supposed way to use filestack in a java app?

java.lang.RuntimeException: com.filestack.HttpException: {"error":"invalid params: size","timestamp":1640155298}

Getting error: java.lang.RuntimeException: com.filestack.HttpException: {"error":"invalid params: size","timestamp":1640155298} when File size is over 2 GB. (I am uploading File from Local storage).
Supporting of Uploading 2GB+ files is not supported.
Since in SdK We are using int as file size, When file size is over 2GB then size becomes negative since 2Gb+ hits the MAX.INT.
Please Add the 'long' variable type instead of 'int' if this fixes the issue.

The code used is similar to https://github.com/filestack/filestack-android.

It has crash sometimes when uploading files

Here is the log:
io.reactivex.exceptions.UndeliverableException: java.io.IOException
at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:349)
at io.reactivex.internal.operators.flowable.FlowableCreate$BaseEmitter.onError(FlowableCreate.java:271)
at io.reactivex.internal.operators.flowable.FlowableCreate.subscribeActual(FlowableCreate.java:75)
at io.reactivex.Flowable.subscribe(Flowable.java:13041)
at io.reactivex.Flowable.subscribe(Flowable.java:12987)
at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.run(FlowableSubscribeOn.java:82)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:61)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:52)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.io.IOException
at com.filestack.internal.Upload.reduceChunkSize(Upload.java:113)
at com.filestack.internal.UploadTransferFunc$2.onNetworkFail(UploadTransferFunc.java:108)
at com.filestack.internal.RetryNetworkFunc.run(RetryNetworkFunc.java:53)
at com.filestack.internal.RetryNetworkFunc.call(RetryNetworkFunc.java:36)
at com.filestack.internal.UploadTransferFunc.uploadToS3(UploadTransferFunc.java:124)
at com.filestack.internal.UploadTransferFunc.subscribe(UploadTransferFunc.java:41)
at io.reactivex.internal.operators.flowable.FlowableCreate.subscribeActual(FlowableCreate.java:72)
at io.reactivex.Flowable.subscribe(Flowable.java:13041)
at io.reactivex.Flowable.subscribe(Flowable.java:12987)
at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.run(FlowableSubscribeOn.java:82)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:61)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:52)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)

Unable to retrieve S3 Key String

I am using the upload method as mentioned here and successfully uploading an image to FileStack. As per the sample code here, I am able to retrieve the handle String. The problem is that we have things auto-configured so that the code will auto upload to the S3 bucket and I need to retrieve the S3 key from the response.

When our server uploads an image, they go through the pick and store flows and eventually retrieve back this response:

{
  "client": "computer",
  "container": "mycompany-products-development",
  "converted": true,
  "filename": "Image.png",
  "id": 1,
  "isWriteable": true,
  "key": "media_embeds/uploads/q12VsskeFtcxItJzYRm9_Image.png",
  "mimetype": "image/png",
  "size": 87970,
  "url": "https://www.filepicker.io/api/file/B2B3FFWWSvuopHofinML"
}

(Note that I changed the characters to mask our original image)

Which clearly has the handle at the suffix of the url, but it also includes a Key, which is what I need to obtain.

How do I go about obtaining this key with only the handle to work with? Can it be done by chaining different methods in the Java SDK? Or is there a way to convert it somehow into the key I need?

Missing 0.9.0 artifact?

Hello! Has the 0.9.0 jar file been taken down? My builds are failing due to a 403 Gradle encounters while attempting to find this SDK.

Could not GET 'https://s3-us-west-2.amazonaws.com/si-mobile-sdks/android/com/filestack/filestack-java/0.9.0/filestack-java-0.9.0.pom'. Received status code 403 from server: Forbidden

Support uploading of InputStreams

We need to be able to upload from InputStream objects so that we can properly support local uploads in Android. This will require refactoring the Upload* classes a bit. I think the main issue will just be rethinking how we divide the work between multiple workers. Right now we assign a (worker / thread / observable) a section of a file to read and upload. Instead we should have multiple workers that independently read and upload from a shared InputStream. That reading will have to be synchronized, but otherwise I don't think this will be too much of a problem. To keep support of uploading with a file system path, and not overcomplicate things, we should just convert file system paths to InputStreams.

Access to the response body from uploads

Is there a way to access the response body, or more ideally, the 'key' parameter returned in the response body, with this library?

Here's the response:

{ "url": "https://www.filestackapi.com/api/file/s7tdGfE5RRKFUxwsZoYv", "size": 8331, "type": "image/png", "filename": "watermark.png", "key": "a1RyBxiglW92bS2SRmqM_watermark.png" }

The 'key' in my case points at the filename in S3.

Refactor how requests to CloudRouter are made

The requests to CloudRouter (the internal service that handles file listing, transfers, etc for cloud storage) are currently made using Retrofit and involve POJO serialization. But the service isn't RESTful, it's really a JSON-RPC, and Retrofit doesn't integrate well with it. And because of its response formatting, it also doesn't work well with POJO serialization.

I think it would be less clunky if we either 1) found a better library to use for this or 2) did something more basic with OkHttp and Gson. I didn't really like this when I made it, but now there's cause to fix it because the awkwardness of trying to map everything to a Java object is partly what lead to an issue in the Android SDK. I mapped the S3 headers to an object, but it turns out I didn't know all the headers to expect.

More formally fixes the below:

Getting PolicySignatureException

Hello,
I have a problem getting image uploading to work. I tried replicating the following iOS code, which works fine:

    let filestack = Filestack(apiKey: signature.filepickerKey)
    let security = FSSecurity(policy: signature.policy, signature: signature.uploadSignature
    let storeOptions = FSStoreOptions()
    storeOptions.access = FSAccessPublic
    storeOptions.container = 'dev'
    storeOptions.security = security
    storeOptions.path = "/users/" + "\(userId)" + "/avatar"
    filestack.store(imageData, with: storeOptions, progress: { (progress) in },
    completionHandler: { (blob, error) in if (error == nil) {
    }

The code I'm trying to get to work on Android looks like this:

FilestackClient client = new FilestackClient(signature.filepickerKey(), Security.fromExisting(signature.policy(), signature.signature()));
        String path = "/users/" + userId + "/avatar";
        StorageOptions options = new StorageOptions.Builder()
                .access("public")
                .container("dev")
                .path(path)
                .build();
        client.uploadAsync(getRealPathFromURI(context, uri), "image/jpeg", options).subscribe(new SingleObserver<FileLink>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                Timber.d("onSubscribe()");
            }
            @Override
            public void onSuccess(@NonNull FileLink fileLink) {
                Timber.d("onSuccess()");
            }
            @Override
            public void onError(@NonNull Throwable e) {
                Timber.d("onError()");
            }
        });

The problem I have is receiving an exception: com.filestack.errors.PolicySignatureException
Don't know why could this be the case? The signatures provided from out endpoint work perfectly fine on iOS? Maybe I'm missing something?

Check for "location_url" during uploads

The request to "upload start" may return the field location_url. If this field is not empty, the value of it should be used as the host for all subsequent upload requests (upload, commit, complete) except the call to S3 directly, although I need to confirm that.

Send AWS S3 encryption header

I already pushed out a fix with 0.6.0-rc.1 and 2.0.0-alpha.3 (Android) for the user that was having a problem but it should be more formally fixed as part of #47.

Check for "location_region" during uploads

The request to "upload start" may return a field location_region If this field is not empty, the value of it should be sent as the header Filestack-Upload-Region for all "upload upload" requests.

NoClassDefFoundError in com.filestack.internal.Networking

This is in an Android app running in debug (i.e. no proguard/obfuscation). The client is unable to initialize. Here's the stacktrace:

java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread. at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:59) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764) Caused by: java.lang.NoClassDefFoundError: com.filestack.internal.Networking at com.filestack.internal.Networking.getCdnService(Networking.java:87) at com.filestack.Client.<init>(Client.java:48) at com.myapp.app.support.DatabaseArchiver$uploadArchive$1.call(DatabaseArchiver.kt:172) at com.myapp.app.support.DatabaseArchiver$uploadArchive$1.call(DatabaseArchiver.kt:47) at rx.internal.operators.OnSubscribeFromCallable.call(OnSubscribeFromCallable.java:48) at rx.internal.operators.OnSubscribeFromCallable.call(OnSubscribeFromCallable.java:33) at rx.Observable.unsafeSubscribe(Observable.java:10150) at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94) at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:228) at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764) Caused by: java.lang.ExceptionInInitializerError at com.filestack.internal.Networking.getCdnService(Networking.java:87) at com.filestack.Client.<init>(Client.java:48) at com.myapp.api.sync.SyncService$SyncAdapter.onPerformSync(SyncService.java:153) at android.content.AbstractThreadedSyncAdapter$SyncThread.run(AbstractThreadedSyncAdapter.java:321) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.InputStream java.lang.ClassLoader.getResourceAsStream(java.lang.String)' on a null object reference at com.filestack.internal.Util.getVersion(Util.java:30) at com.filestack.internal.HeaderInterceptor.<init>(HeaderInterceptor.java:22) at com.filestack.internal.Networking.buildOkHtttpClient(Networking.java:33) at com.filestack.internal.Networking.<clinit>(Networking.java:29) at com.filestack.internal.Networking.getCdnService(Networking.java:87) at com.filestack.Client.<init>(Client.java:48) at com.myapp.api.sync.SyncService$SyncAdapter.onPerformSync(SyncService.java:153) at android.content.AbstractThreadedSyncAdapter$SyncThread.run(AbstractThreadedSyncAdapter.java:321)

I'm using OKHTTP 3.11.0 currently - could this be why?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.