All Downloads are FREE. Search and download functionalities are using the official Maven repository.

geotrellis.server.ogc.Main.scala Maven / Gradle / Ivy

Go to download

GeoTrellis Server is a set of components designed to simplify viewing, processing, and serving raster data from arbitrary sources with an emphasis on doing so in a functional style.

The newest version!
/*
 * Copyright 2020 Azavea
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package geotrellis.server.ogc

import geotrellis.server.ogc.conf._
import geotrellis.server.ogc.wms._
import geotrellis.server.ogc.wcs._
import geotrellis.server.ogc.wmts._
import cats.effect._
import cats.implicits._
import com.monovore.decline._
import org.http4s._
import org.http4s.server._
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.server.middleware.CORS
import org.http4s.syntax.kleisli._
import org.backuity.ansi.AnsiFormatter.FormattedHelper
import com.google.common.util.concurrent.ThreadFactoryBuilder
import org.typelevel.log4cats.Logger
import org.typelevel.log4cats.slf4j.Slf4jLogger
import sttp.client3.http4s.Http4sBackend

import scala.concurrent.duration._
import scala.concurrent.ExecutionContext
import java.net.URL
import java.util.concurrent.Executors
import cats.effect.unsafe.implicits.global

object Main
    extends CommandApp(
      name = "java -jar geotrellis-pointcloud-server-assembly.jar",
      header = "Host GT layers through WMS, WMTS, and WCS services",
      main = {
        implicit val logger: Logger[IO] = Slf4jLogger.getLogger

        // TODO: remove it
        val loggerSync = org.log4s.getLogger

        val publicUrlReq =
          Opts.option[String](
            "public-url",
            short = "u",
            help = "Public URL for services to advertise"
          )

        val interfaceOpt = Opts
          .option[String](
            "interface",
            short = "i",
            help = "The interface for this server to bind on"
          )
          .withDefault("0.0.0.0")

        val portOpt = Opts
          .option[Int](
            "port",
            short = "p",
            help = "The port for this server to bind on"
          )
          .withDefault(9000)

        val configPathOpt = Opts
          .option[String](
            "conf",
            short = "c",
            help = "Full path to a HOCON configuration file (https://github.com/lightbend/config/blob/master/HOCON.md)"
          )
          .orNone

        (publicUrlReq, interfaceOpt, portOpt, configPathOpt).mapN { (publicUrl, interface, port, configPath) =>
          loggerSync.info(ansi"%green{Locally binding services to ${interface}:${port}}")
          loggerSync.info(ansi"%green{Advertising services at ${publicUrl}}")
          configPath match {
            case Some(path) => loggerSync.info(ansi"%green{Layer and style configurations loaded from ${path}.}")
            case None       => loggerSync.info(ansi"%red{Warning}: No configuration path provided. Loading defaults.")
          }

          /**
           * Server endpoints pool.
           */
          implicit val executionContext: ExecutionContext =
            ExecutionContext.fromExecutor(
              Executors.newCachedThreadPool(
                new ThreadFactoryBuilder()
                  .setNameFormat("raster-io-%d")
                  .build()
              )
            )

          val commonMiddleware: HttpMiddleware[IO] = { (routes: HttpRoutes[IO]) => CORS(routes) }

          def logOptState[A](opt: Option[A], upLog: String, downLog: String): IO[Unit] =
            opt.fold(logger.info(downLog))(_ => logger.info(upLog))

          def createServer: Resource[IO, Server] =
            for {
              conf <- Conf.loadResourceF[IO](configPath)
              /**
               * MosaicRasterSources pool init for the graceful shutdown.
               */
              /**
               * Uses server pool.
               */
              http4sClient <- Http4sBackend.usingDefaultBlazeClientBuilder[IO]()
              simpleSources = conf.layers.values.collect { case rsc: RasterSourceConf => rsc.toLayer }.toList
              _ <- Resource.eval(
                logOptState(
                  conf.wms,
                  ansi"%green{WMS configuration detected}, starting Web Map Service",
                  ansi"%red{No WMS configuration detected}, unable to start Web Map Service"
                )
              )
              wmsModel = conf.wms.map { svc =>
                WmsModel[IO](
                  svc.serviceMetadata,
                  svc.parentLayerMeta,
                  svc.layerSources(simpleSources, http4sClient),
                  ExtendedParameters.extendedParametersBinding
                )
              }
              _ <- Resource.eval(
                logOptState(
                  conf.wmts,
                  ansi"%green{WMTS configuration detected}, starting Web Map Tiling Service",
                  ansi"%red{No WMTS configuration detected}, unable to start Web Map Tiling Service"
                )
              )
              wmtsModel = conf.wmts.map { svc =>
                WmtsModel[IO](
                  svc.serviceMetadata,
                  svc.tileMatrixSets,
                  svc.layerSources(simpleSources, http4sClient)
                )
              }
              _ <- Resource.eval(
                logOptState(
                  conf.wcs,
                  ansi"%green{WCS configuration detected}, starting Web Coverage Service",
                  ansi"%red{No WCS configuration detected}, unable to start Web Coverage Service"
                )
              )
              wcsModel = conf.wcs.map { svc =>
                WcsModel[IO](
                  svc.serviceMetadata,
                  svc.layerSources(simpleSources, http4sClient),
                  svc.supportedProjections,
                  ExtendedParameters.extendedParametersBinding
                )
              }

              ogcService = new OgcService[IO](
                wmsModel,
                wcsModel,
                wmtsModel,
                new URL(publicUrl)
              )
              server <- BlazeServerBuilder[IO](executionContext)
                .withIdleTimeout(Duration.Inf)
                .withResponseHeaderTimeout(Duration.Inf)
                .enableHttp2(true)
                .bindHttp(port, interface)
                .withHttpApp(
                  Router(
                    "/" -> commonMiddleware(ogcService.routes)
                  ).orNotFound
                )
                .resource
            } yield server

          createServer
            .use(_ => IO.never)
            .as(ExitCode.Success)
            .void
            .unsafeRunSync
        }
      }
    )




© 2015 - 2025 Weber Informatics LLC | Privacy Policy