Skip to content

Commit

Permalink
Merge pull request #2 from avast/hcp-rest
Browse files Browse the repository at this point in the history
HCP REST backend
  • Loading branch information
mi-char authored Aug 24, 2018
2 parents ab27fbb + 539e233 commit 6694934
Show file tree
Hide file tree
Showing 14 changed files with 565 additions and 20 deletions.
84 changes: 82 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,86 @@
# Scala storage client

Finally-tagless implementation of client for misc. storages represented by backends. Supports backends fallbacking.
Finally-tagless implementation of client for misc. storages represented by backends. Supports backends fallbacks.

Currently supported backends:
1. [Stor](https://github.com/avast/stor)
1. [Stor](stor/README.md)
1. [HCP](hcp/README.md)

## Dependency

Use dependency from README of selected backend:

```groovy
compile "com.avast.clients.storage:storage-client-BACKEND_2.12:x.x.x"
```

## Usage

The library has two levels:
1. Storage client which contains so called backend
1. Storage backend which is actual storage connector

The client has only single backend inside however backends are combinable to provide fallback support:

```scala
val backend1: StorageBackend[F] = ???
val backend2: StorageBackend[F] = ???

val merged: StorageBackend[F] = backend1 withFallbackTo backend2
```

### Retries etc.

Retries and similar functionality is not supported out-of-the-box by the library but you can easily implement them by your own by using some
`F[_]` which is capable of doing it and is familiar to you.

Example for `monix.eval.Task`:

```scala
import better.files.File
import com.avast.clients.storage.{GetResult, HeadResult, StorageBackend, StorageException}
import com.avast.scala.hashes.Sha256
import monix.eval.Task
val backend: StorageBackend[Task] = ???

val retried = new StorageBackend[Task] {
override def head(sha256: Sha256): Task[Either[StorageException, HeadResult]] = backend.head(sha256).onErrorRestart(3)

override def get(sha256: Sha256, dest: File): Task[Either[StorageException, GetResult]] = backend.get(sha256, dest).onErrorRestart(3)

override def close(): Unit = backend.close()
}
```

### Example

Example usage for `monix.eval.Task`:

```scala
import com.avast.clients.storage.{StorageBackend, StorageClient}
import monix.eval.Task
import monix.execution.Scheduler

implicit val scheduler: Scheduler = ???
val backend: StorageBackend[Task] = ???

val client = StorageClient(backend)
```

### Using strict types (Future etc.)

The library supports only `F[_]: Effect` by default which makes some common (strict) types like `scala.concurrent.Future` impossible to use.
There exists a workaround however:

```scala
import com.avast.clients.storage.{StorageBackend, StorageClient}
import monix.eval.Task
import monix.execution.Scheduler

implicit val scheduler: Scheduler = ???
implicit val taskToFuture: Task ~> Future = ???

val backend: StorageBackend[Task] = ???

val client: StorageClient[Future] = StorageClient[Task](backend).mapK[Future]
```
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ subprojects {
jcenter()
}

group = 'com.avast.clients.stor'
group = 'com.avast.clients.storage'
version = version == 'unspecified' ? 'DEVELOPER-SNAPSHOT' : version

jar {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.avast.clients.storage

case class ConfigurationException(desc: String, cause: Throwable = null) extends IllegalArgumentException(desc, cause)
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ class FileCopier {

private var finalHash: Option[Sha256] = None // scalastyle:ignore

def copy(is: InputStream, os: OutputStream): Int = lock.synchronized {
def copy(is: InputStream, os: OutputStream): Long = lock.synchronized {
val fis = new ProxyInputStream(is)(digest.update(_))

IOUtils.copy(fis, os)
IOUtils.copyLarge(fis, os)
}

def finalSha256: Sha256 = lock.synchronized {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ class DefaultStorageClient[F[_]: Effect](backend: StorageBackend[F]) extends Sto

override def close(): Unit = backend.close()
}

object StorageClient {
def apply[F[_]: Effect](backend: StorageBackend[F]): StorageClient[F] = new DefaultStorageClient[F](backend)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ object StorageException {
case class InvalidResponseException(status: Int, body: String, desc: String, cause: Throwable = null)
extends StorageException(s"Invalid response with status $status: $desc", cause)

case class InvalidDataException(status: Int, body: String, desc: String, cause: Throwable = null)
extends StorageException(s"Invalid response data [ with status $status ]: $desc", cause)

}
36 changes: 36 additions & 0 deletions hcp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# HCP REST backend

## Dependency

```groovy
compile "com.avast.clients.storage:storage-client-hcp_2.12:x.x.x"
```

## Usage

Configuration:

```hocon
namespace = "files"
tenant = "org"
repository = "hcp-repository-host.com"
```

Client init, example for `monix.eval.Task`:

```scala
import com.avast.clients.storage.hcp.HcpRestStorageBackend
import com.typesafe.config.Config
import monix.eval.Task
import monix.execution.Scheduler

implicit val scheduler: Scheduler = ???
val config: Config = ???

def initClient: Task[HcpRestStorageBackend[Task]] = {
HcpRestStorageBackend.fromConfig[Task](config) match {
case Right(cl) => cl
case Left(err) => Task.raiseError(err)
}
}
```
14 changes: 13 additions & 1 deletion hcp/build.gradle
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
archivesBaseName = "storage-client-hcp_2.12"
archivesBaseName = "storage-client-hcp_2.12"

dependencies {
compile project(":core")

compile "org.http4s:http4s-dsl_2.12:$http4sVersion"
compile "org.http4s:http4s-blaze-client_2.12:$http4sVersion"

compile "io.circe:circe-core_2.12:$circeVersion"
compile "io.circe:circe-parser_2.12:$circeVersion"
compile "io.circe:circe-generic_2.12:$circeVersion"
compile "io.circe:circe-generic-extras_2.12:$circeVersion"
}
12 changes: 12 additions & 0 deletions hcp/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
hcpRestBackendDefaults {
//namespace = "" // REQUIRED
//tenant = "" // REQUIRED
//repository = "" // REQUIRED
protocol = "http"

requestTimeout = 10 minutes
socketTimeout = 30 seconds
responseHeaderTimeout = 10 seconds

maxConnections = 10
}
Loading

0 comments on commit 6694934

Please sign in to comment.