aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/xyz')
-rw-r--r--src/main/scala/xyz/driver/core/Refresh.scala20
-rw-r--r--src/main/scala/xyz/driver/core/app/init.scala1
-rw-r--r--src/main/scala/xyz/driver/core/cache.scala4
-rw-r--r--src/main/scala/xyz/driver/core/core.scala7
-rw-r--r--src/main/scala/xyz/driver/core/database/Repository.scala1
-rw-r--r--src/main/scala/xyz/driver/core/file/S3Storage.scala32
-rw-r--r--src/main/scala/xyz/driver/core/messaging/Bus.scala1
-rw-r--r--src/main/scala/xyz/driver/core/rest/package.scala25
-rw-r--r--src/main/scala/xyz/driver/core/swagger.scala37
-rw-r--r--src/main/scala/xyz/driver/core/time.scala1
10 files changed, 79 insertions, 50 deletions
diff --git a/src/main/scala/xyz/driver/core/Refresh.scala b/src/main/scala/xyz/driver/core/Refresh.scala
index ca28da7..e66b22f 100644
--- a/src/main/scala/xyz/driver/core/Refresh.scala
+++ b/src/main/scala/xyz/driver/core/Refresh.scala
@@ -8,8 +8,8 @@ import scala.concurrent.duration.Duration
/** A single-value asynchronous cache with TTL.
*
- * Slightly adapted from Twitter's "util" library
- * https://github.com/twitter/util/blob/ae0ab09134414438af9dfaa88a4613cecbff4741/util-cache/src/main/scala/com/twitter/cache/Refresh.scala
+ * Slightly adapted from
+ * [[https://github.com/twitter/util/blob/ae0ab09134414438af9dfaa88a4613cecbff4741/util-cache/src/main/scala/com/twitter/cache/Refresh.scala Twitter's "util" library]]
*
* Released under the Apache License 2.0.
*/
@@ -17,15 +17,27 @@ object Refresh {
/** Creates a function that will provide a cached value for a given time-to-live (TTL).
*
+ * It avoids the "thundering herd" problem if multiple requests arrive
+ * simultanously and the cached value has expired or is unset.
+ *
+ * Usage example:
* {{{
* def freshToken(): Future[String] = // expensive network call to get an access token
- * val getToken: Future[String] = Refresh.every(1.hour)(freshToken())
+ * val getToken: () => Future[String] = Refresh.every(1.hour)(freshToken())
*
* getToken() // new token is issued
* getToken() // subsequent calls use the cached token
* // wait 1 hour
* getToken() // new token is issued
- * }}} */
+ * }}}
+ *
+ * @param ttl Time-To-Live duration to cache a computed value.
+ * @param compute Call-by-name operation that eventually computes a value to
+ * be cached. Note that if the computation (i.e. the future) fails, the value
+ * is not cached.
+ * @param ec The execution context in which valeu computations will be run.
+ * @return A zero-arg function that returns the cached value.
+ */
def every[A](ttl: Duration)(compute: => Future[A])(implicit ec: ExecutionContext): () => Future[A] = {
val ref = new AtomicReference[(Future[A], Instant)](
(Future.failed(new NoSuchElementException("Cached value was never computed")), Instant.MIN)
diff --git a/src/main/scala/xyz/driver/core/app/init.scala b/src/main/scala/xyz/driver/core/app/init.scala
index f1e80b9..b638fd3 100644
--- a/src/main/scala/xyz/driver/core/app/init.scala
+++ b/src/main/scala/xyz/driver/core/app/init.scala
@@ -15,6 +15,7 @@ import xyz.driver.tracing.{GoogleTracer, NoTracer, Tracer}
import scala.concurrent.ExecutionContext
import scala.util.Try
+import scala.language.reflectiveCalls
object init {
diff --git a/src/main/scala/xyz/driver/core/cache.scala b/src/main/scala/xyz/driver/core/cache.scala
index 3500a2a..9897c16 100644
--- a/src/main/scala/xyz/driver/core/cache.scala
+++ b/src/main/scala/xyz/driver/core/cache.scala
@@ -89,8 +89,8 @@ object cache {
object AsyncCache {
val DEFAULT_CAPACITY: Long = 10000L
- val DEFAULT_READ_EXPIRATION: Duration = 10 minutes
- val DEFAULT_WRITE_EXPIRATION: Duration = 1 hour
+ val DEFAULT_READ_EXPIRATION: Duration = 10.minutes
+ val DEFAULT_WRITE_EXPIRATION: Duration = 1.hour
def apply[K <: AnyRef, V <: AnyRef](
name: String,
diff --git a/src/main/scala/xyz/driver/core/core.scala b/src/main/scala/xyz/driver/core/core.scala
index 72237b9..a654e85 100644
--- a/src/main/scala/xyz/driver/core/core.scala
+++ b/src/main/scala/xyz/driver/core/core.scala
@@ -7,9 +7,12 @@ import xyz.driver.core.rest.errors.ExternalServiceException
import scala.concurrent.{ExecutionContext, Future}
-package object core {
+// TODO: this package seems too complex, look at all the features we need!
+import scala.language.reflectiveCalls
+import scala.language.higherKinds
+import scala.language.implicitConversions
- import scala.language.reflectiveCalls
+package object core {
def make[T](v: => T)(f: T => Unit): T = {
val value = v
diff --git a/src/main/scala/xyz/driver/core/database/Repository.scala b/src/main/scala/xyz/driver/core/database/Repository.scala
index 31c79ad..5d7f787 100644
--- a/src/main/scala/xyz/driver/core/database/Repository.scala
+++ b/src/main/scala/xyz/driver/core/database/Repository.scala
@@ -6,6 +6,7 @@ import slick.lifted.{AbstractTable, CanBeQueryCondition, RunnableCompiled}
import slick.{lifted => sl}
import scala.concurrent.{ExecutionContext, Future}
+import scala.language.higherKinds
trait Repository {
type T[D]
diff --git a/src/main/scala/xyz/driver/core/file/S3Storage.scala b/src/main/scala/xyz/driver/core/file/S3Storage.scala
index 5158d4d..a869919 100644
--- a/src/main/scala/xyz/driver/core/file/S3Storage.scala
+++ b/src/main/scala/xyz/driver/core/file/S3Storage.scala
@@ -64,20 +64,24 @@ class S3Storage(s3: AmazonS3, bucket: Name[Bucket], executionContext: ExecutionC
def isInSubFolder(path: Path)(fileLink: FileLink) =
fileLink.location.toString.replace(path.toString + "/", "").contains("/")
- Iterator.continually(s3.listObjectsV2(req)).takeWhile { result =>
- req.setContinuationToken(result.getNextContinuationToken)
- result.isTruncated
- } flatMap { result =>
- result.getObjectSummaries.asScala.toList.map { summary =>
- FileLink(
- Name[File](summary.getKey),
- Paths.get(path.toString + "/" + summary.getKey),
- Revision[File](summary.getETag),
- Time(summary.getLastModified.getTime),
- summary.getSize
- )
- } filterNot isInSubFolder(path)
- } toList
+ Iterator
+ .continually(s3.listObjectsV2(req))
+ .takeWhile { result =>
+ req.setContinuationToken(result.getNextContinuationToken)
+ result.isTruncated
+ }
+ .flatMap { result =>
+ result.getObjectSummaries.asScala.toList.map { summary =>
+ FileLink(
+ Name[File](summary.getKey),
+ Paths.get(path.toString + "/" + summary.getKey),
+ Revision[File](summary.getETag),
+ Time(summary.getLastModified.getTime),
+ summary.getSize
+ )
+ } filterNot isInSubFolder(path)
+ }
+ .toList
})
override def exists(path: Path): Future[Boolean] = Future {
diff --git a/src/main/scala/xyz/driver/core/messaging/Bus.scala b/src/main/scala/xyz/driver/core/messaging/Bus.scala
index e2ee76a..599af92 100644
--- a/src/main/scala/xyz/driver/core/messaging/Bus.scala
+++ b/src/main/scala/xyz/driver/core/messaging/Bus.scala
@@ -2,6 +2,7 @@ package xyz.driver.core
package messaging
import scala.concurrent._
+import scala.language.higherKinds
/** Base trait for representing message buses.
*
diff --git a/src/main/scala/xyz/driver/core/rest/package.scala b/src/main/scala/xyz/driver/core/rest/package.scala
index 7d67138..c778b62 100644
--- a/src/main/scala/xyz/driver/core/rest/package.scala
+++ b/src/main/scala/xyz/driver/core/rest/package.scala
@@ -191,18 +191,21 @@ object `package` {
request.headers.find(_.name == ContextHeaders.StacktraceHeader).fold("")(_.value()).split("->")
def extractContextHeaders(request: HttpRequest): Map[String, String] = {
- request.headers.filter { h =>
- h.name === ContextHeaders.AuthenticationTokenHeader || h.name === ContextHeaders.TrackingIdHeader ||
- h.name === ContextHeaders.PermissionsTokenHeader || h.name === ContextHeaders.StacktraceHeader ||
- h.name === ContextHeaders.TraceHeaderName || h.name === ContextHeaders.SpanHeaderName ||
- h.name === ContextHeaders.OriginatingIpHeader || h.name === ContextHeaders.ClientFingerprintHeader
- } map { header =>
- if (header.name === ContextHeaders.AuthenticationTokenHeader) {
- header.name -> header.value.stripPrefix(ContextHeaders.AuthenticationHeaderPrefix).trim
- } else {
- header.name -> header.value
+ request.headers
+ .filter { h =>
+ h.name === ContextHeaders.AuthenticationTokenHeader || h.name === ContextHeaders.TrackingIdHeader ||
+ h.name === ContextHeaders.PermissionsTokenHeader || h.name === ContextHeaders.StacktraceHeader ||
+ h.name === ContextHeaders.TraceHeaderName || h.name === ContextHeaders.SpanHeaderName ||
+ h.name === ContextHeaders.OriginatingIpHeader || h.name === ContextHeaders.ClientFingerprintHeader
+ }
+ .map { header =>
+ if (header.name === ContextHeaders.AuthenticationTokenHeader) {
+ header.name -> header.value.stripPrefix(ContextHeaders.AuthenticationHeaderPrefix).trim
+ } else {
+ header.name -> header.value
+ }
}
- } toMap
+ .toMap
}
private[rest] def escapeScriptTags(byteString: ByteString): ByteString = {
diff --git a/src/main/scala/xyz/driver/core/swagger.scala b/src/main/scala/xyz/driver/core/swagger.scala
index 6567290..0c1e15d 100644
--- a/src/main/scala/xyz/driver/core/swagger.scala
+++ b/src/main/scala/xyz/driver/core/swagger.scala
@@ -69,24 +69,27 @@ object swagger {
chain: util.Iterator[ModelConverter]): Property = {
val javaType = Json.mapper().constructType(`type`)
- Option(javaType.getRawClass) flatMap { cls =>
- customProperties.get(cls)
- } orElse {
- `type` match {
- case rt: ReferenceType if isOption(javaType.getRawClass) && chain.hasNext =>
- val nextType = rt.getContentType
- val nextResolved = Option(resolveProperty(nextType, context, annotations, chain)).getOrElse(
- chain.next().resolveProperty(nextType, context, annotations, chain))
- nextResolved.setRequired(false)
- Option(nextResolved)
- case t if chain.hasNext =>
- val nextResolved = chain.next().resolveProperty(t, context, annotations, chain)
- nextResolved.setRequired(true)
- Option(nextResolved)
- case _ =>
- Option.empty[Property]
+ Option(javaType.getRawClass)
+ .flatMap { cls =>
+ customProperties.get(cls)
}
- } orNull
+ .orElse {
+ `type` match {
+ case rt: ReferenceType if isOption(javaType.getRawClass) && chain.hasNext =>
+ val nextType = rt.getContentType
+ val nextResolved = Option(resolveProperty(nextType, context, annotations, chain)).getOrElse(
+ chain.next().resolveProperty(nextType, context, annotations, chain))
+ nextResolved.setRequired(false)
+ Option(nextResolved)
+ case t if chain.hasNext =>
+ val nextResolved = chain.next().resolveProperty(t, context, annotations, chain)
+ nextResolved.setRequired(true)
+ Option(nextResolved)
+ case _ =>
+ Option.empty[Property]
+ }
+ }
+ .orNull
}
@SuppressWarnings(Array("org.wartremover.warts.Null"))
diff --git a/src/main/scala/xyz/driver/core/time.scala b/src/main/scala/xyz/driver/core/time.scala
index c7a32ad..1622068 100644
--- a/src/main/scala/xyz/driver/core/time.scala
+++ b/src/main/scala/xyz/driver/core/time.scala
@@ -8,6 +8,7 @@ import java.util.concurrent.TimeUnit
import xyz.driver.core.date.Month
import scala.concurrent.duration._
+import scala.language.implicitConversions
import scala.util.Try
object time {