Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quick milestone fixes #909

Merged
merged 4 commits into from
Aug 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
ALTER TABLE
item_asset_histograms DROP CONSTRAINT item_asset_histograms_item_id_fkey;

ALTER TABLE
item_asset_histograms
ADD
CONSTRAINT item_asset_histograms_item_id_fkey FOREIGN KEY (item_id) REFERENCES collection_items (id) ON DELETE CASCADE;
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.azavea.franklin.api.endpoints.{
SearchEndpoints,
TileEndpoints
}
import com.azavea.franklin.api.middleware.AccessLoggingMiddleware
import com.azavea.franklin.api.services._
import com.azavea.franklin.extensions.validation.{collectionExtensionsRef, itemExtensionsRef}
import com.azavea.stac4s.{`application/json`, StacLink, StacLinkType}
Expand Down Expand Up @@ -141,9 +142,10 @@ $$$$
).routes
landingPageRoutes = new LandingPageService[IO](apiConfig).routes
router = CORS(
ResponseLogger.httpRoutes(false, false)(
collectionRoutes <+> searchRoutes <+> tileRoutes <+> landingPageRoutes <+> docRoutes
)
new AccessLoggingMiddleware(
collectionRoutes <+> searchRoutes <+> tileRoutes <+> landingPageRoutes <+> docRoutes,
logger
).withLogging(true)
).orNotFound
serverBuilderBlocker <- Blocker[IO]
server <- {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,12 @@ class TileEndpoints[F[_]: Concurrent](enableTiles: Boolean, pathPrefix: Option[S
.name("collectionFootprintTileJSON")

val collectionMosaicEndpoint
: Endpoint[CollectionMosaicRequest, Unit, Array[Byte], Fs2Streams[F]] =
: Endpoint[CollectionMosaicRequest, NotFound, Array[Byte], Fs2Streams[F]] =
endpoint.get
.in(collectionRasterTileParameters)
.out(rawBinaryBody[Array[Byte]])
.out(header("content-type", "image/png"))
.errorOut(oneOf(statusMapping(NF, jsonBody[NotFound].description("not found"))))
.description(
"Raster tile endpoint for collection mosaic"
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.azavea.franklin.api.middleware

import cats.data.Kleisli
import cats.data.OptionT
import cats.effect.Sync
import cats.syntax.functor._
import io.chrisdavenport.log4cats.Logger
import io.circe.syntax._
import org.http4s.util.CaseInsensitiveString
import org.http4s.{HttpRoutes, Request}

import java.time.Instant

class AccessLoggingMiddleware[F[_]: Sync](
service: HttpRoutes[F],
logger: Logger[F]
) {

def withLogging(enabled: Boolean) = {
if (!enabled) service
else {
Kleisli { (request: Request[F]) =>
val requestStart = Instant.now
val headerWhitelist: Set[CaseInsensitiveString] =
Set(
CaseInsensitiveString("user-agent"),
CaseInsensitiveString("accept-encoding"),
CaseInsensitiveString("referer"),
CaseInsensitiveString("origin"),
CaseInsensitiveString("X-Amzn-Trace-Id")
)
val headers =
Map(
request.headers.toList.filter(header => headerWhitelist.contains(header.name)) map {
header => header.name.toString.toLowerCase -> header.value.asJson
}: _*
)
val requestData =
Map(
"method" -> request.method.toString.asJson,
"uri" -> s"${request.uri}".asJson,
"httpVersion" -> s"${request.httpVersion}".asJson,
"requesterIp" -> (request.remote map { _.toString }).asJson,
"forwardedFor" -> (request.from map { _.toString }).asJson
) ++ headers
service.run(request) flatMap { resp =>
val requestEnd = Instant.now
val duration = (requestEnd.toEpochMilli - requestStart.toEpochMilli)
val responseData = Map(
"durationInMillis" -> duration.asJson,
"statusCode" -> resp.status.code.asJson
)
OptionT.liftF {
logger.info((requestData ++ responseData).asJson.noSpaces) map { _ => resp }
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ class SearchService[F[_]: Concurrent](
}
((items, links), count) <- (itemsFib, countFib).tupled.join
} yield {
val withApiHost = items map { _.updateLinksWithHost(apiConfig) }
val searchResult = StacSearchCollection(Context(items.length, count), withApiHost, links)
val withApiHost = items map { _.updateLinksWithHost(apiConfig) }
val searchResult =
StacSearchCollection(Context(limit, items.length, count), withApiHost, links)
val updatedFeatures = searchResult.features
.map { item =>
((item.collection, enableTiles) match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,56 +196,57 @@ class TileService[F[_]: Async: Concurrent: Parallel: Logger: Timer: ContextShift

def getCollectionMosaicTile(
tileRequest: CollectionMosaicRequest
): F[Either[Unit, Array[Byte]]] = {
): F[Either[NF, Array[Byte]]] = {
val (z, x, y) = tileRequest.zxy

for {
itemAssets <- getItemsList(tileRequest.collection, tileRequest.mosaicId, z, x, y)
_ <- Logger[F].debug(s"got items list with ${itemAssets.size} items")
assetHrefs <- itemAssets.parTraverseN(8) {
case ItemAsset(itemId, assetName) =>
getItemsList(tileRequest.collection, tileRequest.mosaicId, z, x, y) flatMap { itemAssets =>
itemAssets.toNel.fold(Either.left[NF, Array[Byte]](NF()).pure[F])(
(itemAssets: NonEmptyList[ItemAsset]) =>
for {
() <- Logger[F].debug(s"getting asset ${itemId}-${assetName}")
asset <- StacItemDao.unsafeGetAsset(itemId, assetName).transact(xa)
() <- Logger[F].debug(s"got asset ${itemId}-${assetName}")
} yield asset
}
histO <- getHistogram(tileRequest.mosaicId)
mosaicSource <- assetHrefs traverse { asset =>
getRasterSource(asset.href)
} map { sources =>
sources.toNel map { rs => MosaicRasterSource(rs, CRS.fromEpsgCode(3857)) }
}
tileO <- mosaicSource flatTraverse { rs =>
Sync[F].delay(
rs.tileToLayout(tmsLevels(tileRequest.z))
.read(SpatialKey(x, y), tileRequest.bands)
)
}
} yield {
val outCellTypeWithNoData =
mosaicSource
.flatMap({ src => getNoDataValue(src.cellType) map { _ => src.cellType } })
.fold(invisiCellType: CellType)(identity)
val outTile = (tileO, histO) mapN {
case (mbt, hists) =>
MultibandTile(mbt.bands.zip(hists).map {
case (tile, histogram) =>
val breaks = histogram.quantileBreaks(100)
val oldMin = breaks(tileRequest.lowerQuantile)
val oldMax = breaks(tileRequest.upperQuantile)
tile
.interpretAs(outCellTypeWithNoData)
.mapIfSet { cell =>
if (cell < oldMin) oldMin
else if (cell > oldMax) oldMax
else cell
}
.normalize(oldMin, oldMax, 1, 255)
_ <- Logger[F].debug(s"got items list with ${itemAssets.size} items")
assetHrefs <- itemAssets.parTraverseN(8) {
case ItemAsset(itemId, assetName) =>
for {
() <- Logger[F].debug(s"getting asset ${itemId}-${assetName}")
asset <- StacItemDao.unsafeGetAsset(itemId, assetName).transact(xa)
() <- Logger[F].debug(s"got asset ${itemId}-${assetName}")
} yield asset
}
histO <- getHistogram(tileRequest.mosaicId)
mosaicSource <- assetHrefs traverse { asset =>
getRasterSource(asset.href)
} map { sources => MosaicRasterSource(sources, CRS.fromEpsgCode(3857)) }
tileO <- Sync[F].delay(
mosaicSource
.tileToLayout(tmsLevels(tileRequest.z))
.read(SpatialKey(x, y), tileRequest.bands)
)
} yield {
val outCellTypeWithNoData =
getNoDataValue(mosaicSource.cellType).fold(invisiCellType: CellType)(_ =>
mosaicSource.cellType
)
val outTile = (tileO, histO) mapN {
case (mbt, hists) =>
MultibandTile(mbt.bands.zip(hists).map {
case (tile, histogram) =>
val breaks = histogram.quantileBreaks(100)
val oldMin = breaks(tileRequest.lowerQuantile)
val oldMax = breaks(tileRequest.upperQuantile)
tile
.interpretAs(outCellTypeWithNoData)
.mapIfSet { cell =>
if (cell < oldMin) oldMin
else if (cell > oldMax) oldMax
else cell
}
.normalize(oldMin, oldMax, 1, 255)

})
} getOrElse invisiMBTile
Right(outTile.renderPng.bytes)
})
} getOrElse invisiMBTile
Right(outTile.renderPng.bytes)
}
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ object Context {
}

case class Context(
limit: Int,
returned: Int,
matched: Int
)
5 changes: 0 additions & 5 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ lazy val commonSettings = Seq(
"org.slf4j",
"slf4j-simple"
),
unusedCompileDependenciesFilter -= moduleFilter(
"ch.qos.logback",
"logback-classic"
),
excludeDependencies ++= Seq(
"log4j" % "log4j",
"org.slf4j" % "slf4j-log4j12",
Expand Down Expand Up @@ -83,7 +79,6 @@ lazy val applicationSettings = commonSettings ++ Seq(
)

lazy val applicationDependencies = Seq(
"ch.qos.logback" % "logback-classic" % Versions.LogbackVersion,
"software.amazon.awssdk" % "sdk-core" % Versions.AWSSdk2Version,
"com.amazonaws" % "aws-java-sdk-core" % Versions.AWSVersion,
"com.amazonaws" % "aws-java-sdk-s3" % Versions.AWSVersion,
Expand Down