# Fast.io SDK

This library provides javascript wrappers to access Fast.io API and toolkit for uploading large files.

- [Fast.io SDK](#fastio-sdk)
  - [Installation](#installation)
  - [API](#api)
  - [Multipart file uploader](#multipart-file-uploader)
  - [Uploader Item](#uploader-item)
    - [Properties:](#properties)
    - [Methods:](#methods)
    - [`chunkFile` process:](#chunkfile-process)
  - [Writing tests](#writing-tests)

## Installation

```sh
npm i fast-sdk
yarn add fast-sdk
```

`fast-sdk` exports [API](#api) object, `getAuthToken`, `setAuthToken` utils and [Uploader](#multipart-file-uploader) class.

## API

Before running the API methods you should authorize first, and the authorization is happening only by SSO.
For authorizing using SSO we have three options **Google SSO**, **Microsoft SSO**, and **Facebook SSO**. because all three ways are similar we explain the **Google SSO** only.

- **First**: you should request a `redirect URL` from the server:

 ```typescript
 const  googleRedirectUrl = await  api.auth.getGoogleRedirectURL()
 ```

 one of the results from this request is the `redirect_url` property which should be used in a new tab for going into the Google authorization process.

 ```typescript
 const  strWindowFeatures = 'toolbar=no, menubar=no, width=650, height=700';

 window.open(googleRedirectUrl.redirect_url, "Google Login", strWindowFeatures)
 ```

 This is an example of opening a new tab for beginning the authorization process. (The authorization process is handled by Google and after the user authorization, Google redirects the user to a `redirect URL` that we specified for it)

- **Second**: When the user reaches the page that we wrote for the after-authorizing by Google. (The page that we tell Google to redirect the users to it)
  - first, we should grab the search section in the URL and create an object. (the SDK has a function for that):

  ```typescript
  import { useLocation } from  'react-router'
  import { Utilities } from  'fast-sdk'

  const  location = useLocation()
  const  urlQueries = Utilities.URLToObject(location.search)
  ```

  - then we should send the result object to the server:

  ```typescript
  import { api, setAuthToken } from  'fast-sdk'
  
  api.auth.getGoogleSSOToken(urlQueries).then((res) => {
   if(res.result){
    const token = res.token
    setAuthToken(token)
   }
  })
  ```

- **Third**: SDK exposes  `getAuthToken`  and  `setAuthToken`  utils so you can set authorization token manually:

 ```typescript
 import { getAuthToken, setAuthToken } from  'fast-sdk'

 if (!getAuthToken())
  setAuthToken('your token')
 ```

You can do all of the above processes for the **Facebook SSO**, and the **Microsoft SSO** with relative methods.

As SDK is written in Typescript, your IDE should be able to suggest all existing API methods and show their parameters.

WebStorm:

![API Methods](img/ws-api-method.png)

VSCode:

![API Methods](img/vc-api-method.png)

Editor also will show signatures of parameters.

WebStorm:

![Parameter Signatures](img/ws-param-signature.png)

VSCode:

![Parameter Signatures](img/vc-param-signature.png)

## Multipart file uploader

Example For Uploader Class:

```jsx
import { Uploader } from  'fast-sdk'
const  uploader = new  Uploader({
  threads:  5,
  retry:  1,
})
```

Uploader options:

`threads`: (optional, 5 by default) - The number of chunks that can be uploaded in parallel.

`retry`: (optional, 1 by default) - The number of retries after failing API request.

---

## Uploader Item

The `Uploader` instance should be passed to the `UploaderItem` constructor along with the file input and an `Encryption Key`.
  
You can use the below example for uploading a file to the server:

```js
 const uploaderItem = new UploaderItem(uploader, file, "ENCRYPTION KEY")
 uploaderItem.iv = "IV"
// This is the IV (Initialization vector) for AES encryption

 let sessionId = ""
 if(uploaderItem.encryptedSize)
  sessionId = await uploaderItem.getSessionId(uploaderItem.encryptedSize)
 uploaderItem.session_id = sessionId;

await uploaderItem.chunkFile()
/* This method will chunk the file into pieces (based on the bucket-list algorithm with [100, 50, 25, 10, 3, 1] -in MegaBytes- as buckets) and stores them into the uploaderItem.chunks */

await uploaderItem.upload()

```

The process of uploading is as follows:

1. You should have an `Encryption Key` and the `IV` (Initialization vector) and give them to the `UploaderItem` as parameters.
2. The `encryptedSize` is needed for the `getSessionId` function. (This function returns the `session_id` that will be used in all the next steps)
3. You should update the `UploaderItem`'s `session_id`.
4. You can now call the `chunkFile` function in order to chunk the file.
5. Calling the `upload` method uploads all the chunks to the server.

### Properties:

1. `parallelTasksAmount`: The number of endpoints that we could send data to, at the same time.
2. `updateProgressFunc`(Optional): The callback function which has called every time the progress has been updated.
3. `chunks`: The chunks of the file. (calculated after The file has been put into the `UploaderItem` class)
4. `chunkSchema`: The Schema of the `UploaderItem` file chunks.
5. `iv`: The `IV` (Initialize Vector) for the encryption.
6. `session_id`: The session id for upload process.
7. `error`: All the errors that have occurred during the process of the upload.

### Methods:

1. `chunkFile`
2. `updateFile`: updates the `UploaderItem` file.
3. `syncWithIndexedDB`
4. `upload`
5. `getSessionId`

### `chunkFile` process:

- The file is chunked into smaller pieces.
- The chunks are stored in the `indexedDB` database.
- The chunks are encrypted with the `AES` algorithm with `CBC` mode and the `PKcs7` padding.
- The `hash` of the encrypted file (with the `SHA256` algorithm) is calculated.
- The `rollingHash` of the above hash is calculated.
- The above caclulated values (`encryptedFile` with `WordArray` type, `hash` and `rollingHash`) are stored to the relative `UploaderChunk` in the `indexedDB` database.

## Writing tests

Create account for testing and put it's email and password to .env file.
This account is used in most of tests, it should have at least one site created.
To create a site you need to connect a storage which were not connected to any other fast.io account yet.
I suggest to create a new dropbox user, they doesn't require email confirmation, so random email works.
Upload any image to the side header.
Add some files and folders to site root.
Put site name to .env as `SERVER_WITH_CONTENT_NAME`
