Skip to content

Commit

Permalink
BREAKING CHANGE: Removed Stor client implementation
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Upgrade to the latest version of Cats, Htt4s, Pureconfig, ...
BREAKING CHANGE: HCP backend requires authenticated access
BREAKING CHANGE: Removed build-in Future support
feat: HCP backend is balancing load by random IP address selection
feat: Removed Monix dependency
  • Loading branch information
Michal Charvát committed Mar 13, 2020
1 parent b5da556 commit be1fe02
Show file tree
Hide file tree
Showing 27 changed files with 266 additions and 733 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ language: java
scala:
- 2.12.4
jdk:
- oraclejdk8
- oraclejdk9
cache:
directories:
- $HOME/.gradle/wrapper/
Expand Down
19 changes: 0 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
Finally-tagless implementation of client for misc. storages represented by backends. Supports backends fallbacks.

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

## Dependency
Expand Down Expand Up @@ -66,21 +65,3 @@ 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]
```
19 changes: 11 additions & 8 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ buildscript {
dependencies {
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
classpath 'com.github.maiflai:gradle-scalatest:0.19'
classpath "com.github.ben-manes:gradle-versions-plugin:0.27.0"
}
}

ext {
circeVersion = "0.9.3"
metricsVersion = "2.4.4"
http4sVersion = "0.18.15"
monixVersion = "3.0.0-RC1"
circeVersion = "0.13.0"
metricsVersion = "2.6.6"
http4sVersion = "0.21.1"
monixVersion = "3.1.0" // Used only in tests.
}

subprojects {
Expand All @@ -24,6 +25,8 @@ subprojects {
apply plugin: 'maven'
apply plugin: 'maven-publish'
apply plugin: 'com.github.maiflai.scalatest'
apply plugin: "com.github.ben-manes.versions"


sourceCompatibility = '1.8'
targetCompatibility = '1.8'
Expand All @@ -45,14 +48,14 @@ subprojects {
dependencies {
compile 'org.slf4j:jul-to-slf4j:1.7.23'
compile 'org.slf4j:jcl-over-slf4j:1.7.23'
compile 'com.typesafe.scala-logging:scala-logging_2.12:3.9.0'
compile 'com.typesafe.scala-logging:scala-logging_2.12:3.9.2'

testCompile "org.http4s:http4s-blaze-server_2.12:$http4sVersion"

testCompile "ch.qos.logback:logback-classic:1.1.8"
testCompile 'junit:junit:4.12'
testCompile "ch.qos.logback:logback-classic:1.2.3"
testCompile 'junit:junit:4.13'
testCompile "org.scalatest:scalatest_2.12:3.0.5"
testCompile 'org.mockito:mockito-core:2.21.0'
testCompile 'org.mockito:mockito-core:3.3.1'
testCompile "org.pegdown:pegdown:1.6.0"
}

Expand Down
19 changes: 8 additions & 11 deletions core/build.gradle
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
archivesBaseName = "storage-client-core_2.12"

dependencies {
compile 'com.avast.hashes:scala-hashes_2.12:1.0.1'
compile 'com.avast.hashes:scala-hashes_2.12:1.1.1'

compile 'com.github.pathikrit:better-files_2.12:3.4.0'
compile 'com.github.pathikrit:better-files_2.12:3.8.0'

compile "io.monix:monix_2.12:$monixVersion"
compile "org.typelevel:cats-core_2.12:1.2.0"
compile "com.kailuowang:mainecoon-core_2.12:0.6.2"
compile "org.typelevel:cats-core_2.12:2.1.1"

compile 'commons-codec:commons-codec:1.11'
compile 'commons-io:commons-io:2.6'

compile 'com.typesafe:config:1.3.1'
compile "com.github.pureconfig:pureconfig_2.12:0.9.1"
compile "com.github.pureconfig:pureconfig-http4s_2.12:0.9.1"
compile 'com.typesafe:config:1.4.0'
compile "com.github.pureconfig:pureconfig_2.12:0.12.3"
compile "com.github.pureconfig:pureconfig-http4s_2.12:0.12.3"

compile "com.avast.metrics:metrics-scala_2.12:$metricsVersion"

testCompile "io.monix:monix_2.12:$monixVersion"
}
71 changes: 0 additions & 71 deletions core/src/main/scala/com/avast/clients/storage/FileCopier.scala

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ trait StorageBackend[F[_]] extends AutoCloseable {
def head(sha256: Sha256): F[Either[StorageException, HeadResult]]

def get(sha256: Sha256, dest: File = File.newTemporaryFile(prefix = "stor")): F[Either[StorageException, GetResult]]

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ package com.avast.clients.storage
sealed abstract class StorageException(msg: String, cause: Throwable = null) extends Exception(msg, cause)

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)

}
4 changes: 0 additions & 4 deletions core/src/main/scala/com/avast/clients/storage/results.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,15 @@ import better.files.File
sealed trait HeadResult

object HeadResult {

case class Exists(length: Long) extends HeadResult

case object NotFound extends HeadResult

}

sealed trait GetResult

object GetResult {

case class Downloaded(file: File, fileSize: Long) extends GetResult

case object NotFound extends GetResult

}
57 changes: 13 additions & 44 deletions core/src/main/scala/com/avast/clients/storage/storage.scala
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
package com.avast.clients

import better.files.File
import cats.Monad
import cats.data.EitherT
import cats.{~>, Monad}
import com.avast.scala.hashes.Sha256
import mainecoon.FunctorK

import scala.language.higherKinds

package object storage {

implicit class StorageClientOps[F[_]](val client: StorageClient[F]) extends AnyVal {
def mapK[G[_]](implicit fToG: F ~> G): StorageClient[G] = {
storageClientFunctorK.mapK(client)(fToG)
}
}

implicit class StorageBackendOps[F[_]: Monad](val backend: StorageBackend[F]) {
def withFallbackIfError(fallback: StorageBackend[F]): StorageBackend[F] = new StorageBackend[F] {
override def head(sha256: Sha256): F[Either[StorageException, HeadResult]] = {
Expand All @@ -38,17 +31,21 @@ package object storage {

def withFallbackIfNotFound(fallback: StorageBackend[F]): StorageBackend[F] = new StorageBackend[F] {
override def head(sha256: Sha256): F[Either[StorageException, HeadResult]] = {
EitherT(backend.head(sha256)).flatMap[StorageException, HeadResult] {
case r: HeadResult.Exists => EitherT.rightT(r)
case HeadResult.NotFound => EitherT(fallback.head(sha256))
}.value
EitherT(backend.head(sha256))
.flatMap[StorageException, HeadResult] {
case r: HeadResult.Exists => EitherT.rightT(r)
case HeadResult.NotFound => EitherT(fallback.head(sha256))
}
.value
}

override def get(sha256: Sha256, dest: File): F[Either[StorageException, GetResult]] = {
EitherT(backend.get(sha256, dest)).flatMap[StorageException, GetResult] {
case r: GetResult.Downloaded => EitherT.rightT(r)
case GetResult.NotFound => EitherT(fallback.get(sha256, dest))
}.value
EitherT(backend.get(sha256, dest))
.flatMap[StorageException, GetResult] {
case r: GetResult.Downloaded => EitherT.rightT(r)
case GetResult.NotFound => EitherT(fallback.get(sha256, dest))
}
.value
}

override def close(): Unit = {
Expand All @@ -57,32 +54,4 @@ package object storage {
}
}
}

implicit val storageBackendFunctorK: FunctorK[StorageBackend] = new FunctorK[StorageBackend] {
override def mapK[F[_], G[_]](backend: StorageBackend[F])(fToG: F ~> G): StorageBackend[G] = new StorageBackend[G] {
override def head(sha256: Sha256): G[Either[StorageException, HeadResult]] = fToG {
backend.head(sha256)
}

override def get(sha256: Sha256, dest: File): G[Either[StorageException, GetResult]] = fToG {
backend.get(sha256, dest)
}

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

implicit val storageClientFunctorK: FunctorK[StorageClient] = new FunctorK[StorageClient] {
override def mapK[F[_], G[_]](client: StorageClient[F])(fToG: F ~> G): StorageClient[G] = new StorageClient[G] {
override def head(sha256: Sha256): G[Either[StorageException, HeadResult]] = fToG {
client.head(sha256)
}

override def get(sha256: Sha256, dest: File): G[Either[StorageException, GetResult]] = fToG {
client.get(sha256, dest)
}

override def close(): Unit = client.close()
}
}
}
31 changes: 0 additions & 31 deletions core/src/test/scala/com/avast/clients/storage/FileCopierTest.scala

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ class StorageBackendOpsTest extends FunSuite with ScalaFutures {

val merged = first.withFallbackIfError(second)

assertResult(Right(HeadResult.Exists(42)))(merged.head(randomSha).runAsync.futureValue)
assertResult(Right(HeadResult.Exists(42)))(merged.head(randomSha).runToFuture.futureValue)
val dest = File.newTemporaryFile()
assertResult(Right(GetResult.Downloaded(dest, 42)))(merged.get(randomSha, dest).runAsync.futureValue)
assertResult(Right(GetResult.Downloaded(dest, 42)))(merged.get(randomSha, dest).runToFuture.futureValue)
}

test("withFallbackIfError - fallback used") {
Expand All @@ -56,8 +56,8 @@ class StorageBackendOpsTest extends FunSuite with ScalaFutures {

val merged = first.withFallbackIfError(second)

assertResult(Right(HeadResult.Exists(42)))(merged.head(randomSha).runAsync.futureValue)
assertResult(Right(HeadResult.Exists(42)))(merged.head(randomSha).runToFuture.futureValue)
val dest = File.newTemporaryFile()
assertResult(Right(GetResult.Downloaded(dest, 42)))(merged.get(randomSha, dest).runAsync.futureValue)
assertResult(Right(GetResult.Downloaded(dest, 42)))(merged.get(randomSha, dest).runToFuture.futureValue)
}
}
Loading

0 comments on commit be1fe02

Please sign in to comment.