monix.execution.Scheduler Scala Examples

The following examples show how to use monix.execution.Scheduler. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: Components.scala    From gbf-raidfinder   with MIT License 6 votes vote down vote up
package walfie.gbf.raidfinder.server

import akka.actor.ActorSystem
import akka.stream.Materializer
import com.trueaccord.scalapb.json.JsonFormat
import monix.execution.Scheduler
import play.api.BuiltInComponents
import play.api.http.{ContentTypes, DefaultHttpErrorHandler}
import play.api.libs.json.Json
import play.api.Mode.Mode
import play.api.mvc._
import play.api.routing.Router
import play.api.routing.sird._
import play.core.server._
import play.filters.cors.{CORSConfig, CORSFilter}
import play.filters.gzip.GzipFilterComponents
import scala.concurrent.duration.FiniteDuration
import scala.concurrent.Future
import walfie.gbf.raidfinder.protocol.{RaidBossesResponse, BinaryProtobuf}
import walfie.gbf.raidfinder.RaidFinder
import walfie.gbf.raidfinder.server.controller._
import walfie.gbf.raidfinder.server.syntax.ProtocolConverters.RaidBossDomainOps

class Components(
  raidFinder:                 RaidFinder[BinaryProtobuf],
  translator:                 BossNameTranslator,
  port:                       Int,
  mode:                       Mode,
  websocketKeepAliveInterval: FiniteDuration,
  metricsCollector:           MetricsCollector
) extends NettyServerComponents
  with BuiltInComponents with GzipFilterComponents with Controller {

  override lazy val serverConfig = ServerConfig(port = Some(port), mode = mode)

  private val corsFilter = new CORSFilter(corsConfig = CORSConfig().withAnyOriginAllowed)
  override lazy val httpFilters = List(gzipFilter, corsFilter)

  lazy val websocketController = new WebsocketController(
    raidFinder, translator, websocketKeepAliveInterval, metricsCollector
  )(actorSystem, materializer, Scheduler.Implicits.global)

  // The charset isn't necessary, but without it, Chrome displays Japanese incorrectly
  // if you try to view the JSON directly.
  // https://bugs.chromium.org/p/chromium/issues/detail?id=438464
  private val ContentTypeJsonWithUtf8 = "application/json; charset=utf-8"

  lazy val router = Router.from {
    case GET(p"/") =>
      controllers.Assets.at(path = "/public", "index.html")

    case GET(p"/api/bosses.json" ? q_s"name=$names") =>
      val bosses = if (names.nonEmpty) {
        val knownBossesMap = raidFinder.getKnownBosses
        names.collect(knownBossesMap)
      } else raidFinder.getKnownBosses.values

      val responseProtobuf = RaidBossesResponse(
        raidBosses = bosses.map(_.toProtocol(translator)).toSeq
      )
      val responseJson = JsonFormat.toJsonString(responseProtobuf)
      Action(Ok(responseJson).as(ContentTypeJsonWithUtf8))

    case GET(p"/api/metrics.json") =>
      val activeUsers = metricsCollector.getActiveWebSocketCount()
      val json = Json.obj("activeUsers" -> activeUsers)
      Action(Ok(json))

    case GET(p"/ws/raids" ? q_o"keepAlive=${ bool(keepAlive) }") =>
      websocketController.raids(keepAlive = keepAlive.getOrElse(false))

    case GET(p"/$file*") =>
      controllers.Assets.at(path = "/public", file = file)
  }

  override lazy val httpErrorHandler = new ErrorHandler

  override def serverStopHook = () => Future.successful {
    actorSystem.terminate()
  }
} 
Example 2
Source File: MockHttpServer.scala    From cornichon   with Apache License 2.0 6 votes vote down vote up
package com.github.agourlay.cornichon.http.server

import java.net.NetworkInterface

import com.github.agourlay.cornichon.core.CornichonError
import monix.eval.Task
import monix.execution.Scheduler
import org.http4s.HttpRoutes
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.implicits._

import scala.jdk.CollectionConverters._
import scala.concurrent.duration._
import scala.util.Random

class MockHttpServer[A](interface: Option[String], port: Option[Range], mockService: HttpRoutes[Task], maxRetries: Int = 5)(useFromAddress: String => Task[A])(implicit scheduler: Scheduler) {

  private val selectedInterface = interface.getOrElse(bestInterface())
  private val randomPortOrder = port.fold(0 :: Nil)(r => Random.shuffle(r.toList))

  private val mockRouter = Router("/" -> mockService).orNotFound

  def useServer(): Task[A] =
    if (randomPortOrder.isEmpty)
      Task.raiseError(MockHttpServerError.toException)
    else
      startServerTryPorts(randomPortOrder)

  private def startServerTryPorts(ports: List[Int], retry: Int = 0): Task[A] =
    startBlazeServer(ports.head).onErrorHandleWith {
      case _: java.net.BindException if ports.length > 1 =>
        startServerTryPorts(ports.tail, retry)
      case _: java.net.BindException if retry < maxRetries =>
        val sleepFor = retry + 1
        println(s"Could not start server on any port. Retrying in $sleepFor seconds...")
        startServerTryPorts(randomPortOrder, retry = retry + 1).delayExecution(sleepFor.seconds)
    }

  private def startBlazeServer(port: Int): Task[A] =
    BlazeServerBuilder[Task](executionContext = scheduler)
      .bindHttp(port, selectedInterface)
      .withoutBanner
      .withHttpApp(mockRouter)
      .withNio2(true)
      .resource
      .use(server => useFromAddress(s"http://${server.address.getHostString}:${server.address.getPort}"))

  private def bestInterface(): String =
    NetworkInterface.getNetworkInterfaces.asScala
      .filter(_.isUp)
      .flatMap(_.getInetAddresses.asScala)
      .find(_.isSiteLocalAddress)
      .map(_.getHostAddress)
      .getOrElse("localhost")
}

case object MockHttpServerError extends CornichonError {
  val baseErrorMessage = "the range of ports provided for the HTTP mock is invalid"
} 
Example 3
Source File: TwitterStreamer.scala    From gbf-raidfinder   with MIT License 5 votes vote down vote up
package walfie.gbf.raidfinder

import monix.execution.Scheduler
import monix.reactive._
import monix.reactive.subjects.ConcurrentSubject
import twitter4j._

// TODO: Write tests
trait TwitterStreamer {
  def observable: Observable[Status]
}

object TwitterStreamer {
  val DefaultFilterTerms = Seq("参加者募集!", ":参戦ID", "I need backup!", ":Battle ID")

  def apply(
    twitterStream: twitter4j.TwitterStream = TwitterStreamFactory.getSingleton,
    filterTerms:   Seq[String]             = DefaultFilterTerms
  )(implicit scheduler: Scheduler): Twitter4jStreamer =
    new Twitter4jStreamer(twitterStream, filterTerms)
}

class Twitter4jStreamer(
  twitterStream: twitter4j.TwitterStream,
  filterTerms:   Seq[String]
)(implicit scheduler: Scheduler) extends TwitterStreamer {
  private val subject = ConcurrentSubject.publish[Status]
  val observable: Observable[Status] = subject

  private val listener = new StatusAdapter() {
    override def onStatus(status: Status): Unit = subject.onNext(status)
    override def onException(e: Exception): Unit = println(e) // TODO: Better error handling
  }

  twitterStream.addListener(listener)
  twitterStream.filter(new FilterQuery(filterTerms: _*))
} 
Example 4
Source File: BlockingIO.scala    From gbf-raidfinder   with MIT License 5 votes vote down vote up
package walfie.gbf.raidfinder.util

import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.{Executors, ThreadFactory}
import scala.concurrent.{ExecutionContext, ExecutionContextExecutor, Future, Promise, blocking}
import scala.util.control.NonFatal
import monix.execution.Scheduler

// https://github.com/alexandru/scala-best-practices/blob/master/sections/4-concurrency-parallelism.md
object BlockingIO {
  private val ioThreadPool = Scheduler.io(name = "io-thread")

  def future[T](t: => T): Future[T] = {
    val p = Promise[T]()

    val runnable = new Runnable {
      def run() = try {
        p.success(blocking(t))
      } catch {
        case NonFatal(ex) => p.failure(ex)
      }
    }

    ioThreadPool.execute(runnable)

    p.future
  }
} 
Example 5
Source File: ObservablesPartitioner.scala    From gbf-raidfinder   with MIT License 5 votes vote down vote up
package walfie.gbf.raidfinder.util

import akka.agent.Agent
import monix.execution.{Ack, Cancelable, Scheduler}
import monix.reactive._
import monix.reactive.observables.GroupedObservable
import monix.reactive.observers.Subscriber
import monix.reactive.subjects.PublishSubject
import scala.concurrent.{ExecutionContext, Future}

trait ObservablesPartitioner[K, V] {
  def getObservable(key: K): Observable[V]
}

object CachedObservablesPartitioner {
  def fromUngroupedObservable[K, InputV, OutputV](
    observable:      Observable[InputV],
    cacheSizePerKey: Int,
    keySelector:     InputV => K,
    mappingFunction: InputV => OutputV
  )(implicit scheduler: Scheduler): (CachedObservablesPartitioner[K, InputV, OutputV], Cancelable) = {
    val partitioner = new CachedObservablesPartitioner[K, InputV, OutputV](cacheSizePerKey, mappingFunction)
    val cancelable = observable.groupBy(keySelector).subscribe(partitioner)
    (partitioner, cancelable)
  }
}

class CachedObservablesPartitioner[K, InputV, OutputV](
  cacheSizePerKey: Int, mappingFunction: InputV => OutputV
)(implicit ec: ExecutionContext)
  extends Observer[GroupedObservable[K, InputV]] with ObservablesPartitioner[K, OutputV] {

  private val observablesByKey = Agent[Map[K, Observable[OutputV]]](Map.empty)
  private val incomingKeys = PublishSubject[K]()

  def onComplete(): Unit = {
    incomingKeys.onComplete()
  }

  def onError(e: Throwable): Unit = {
    System.err.println(e) // TODO: Better logging?
    incomingKeys.onError(e)
  }

  
  def getObservable(key: K): Observable[OutputV] = {
    observablesByKey.get.getOrElse(
      key,
      incomingKeys.findF(_ == key).flatMap(_ => getObservable(key))
    )
  }
} 
Example 6
Source File: RaidFinder.scala    From gbf-raidfinder   with MIT License 5 votes vote down vote up
package walfie.gbf.raidfinder

import java.util.Date
import monix.eval.Task
import monix.execution.{Cancelable, Scheduler}
import monix.reactive._
import scala.concurrent.duration._
import scala.concurrent.Future
import twitter4j._
import walfie.gbf.raidfinder.domain._
import walfie.gbf.raidfinder.util.CachedObservablesPartitioner

trait RaidFinder[T] {
  def getRaidTweets(bossName: BossName): Observable[T]
  def newBossObservable: Observable[RaidBoss]
  def getKnownBosses(): Map[BossName, RaidBoss]
  def purgeOldBosses(
    minDate:        Date,
    levelThreshold: Option[Int]
  ): Future[Map[BossName, RaidBoss]]

  def shutdown(): Unit
}

object RaidFinder {
  val DefaultCacheSizePerBoss = 20
  val DefaultBackfillSize = 200

  
  protected def onShutdown(): Unit = ()

  // TODO: Parsing happens twice somewhere -- should figure out where
  private val raidInfos = statusesObservable
    .collect(Function.unlift(StatusParser.parse))
    .publish

  private val (partitioner, partitionerCancelable) =
    CachedObservablesPartitioner.fromUngroupedObservable(
      raidInfos.map(_.tweet),
      cachedTweetsPerBoss,
      (_: RaidTweet).bossName,
      fromRaidTweet.from // TODO
    )

  private val (knownBosses, knownBossesCancelable) = KnownBossesObserver
    .fromRaidInfoObservable(raidInfos, initialBosses)

  val newBossObservable = knownBosses.newBossObservable

  private val raidInfosCancelable = raidInfos.connect()

  private val cancelable = Cancelable { () =>
    List(
      raidInfosCancelable,
      partitionerCancelable,
      knownBossesCancelable
    ).foreach(_.cancel)
    onShutdown()
  }

  def shutdown(): Unit = cancelable.cancel()
  def getKnownBosses(): Map[BossName, RaidBoss] =
    knownBosses.get()
  def getRaidTweets(bossName: BossName): Observable[T] =
    partitioner.getObservable(bossName)

  def purgeOldBosses(
    minDate:        Date,
    levelThreshold: Option[Int]
  ): Future[Map[BossName, RaidBoss]] =
    knownBosses.purgeOldBosses(minDate, levelThreshold)
} 
Example 7
Source File: WebsocketController.scala    From gbf-raidfinder   with MIT License 5 votes vote down vote up
package walfie.gbf.raidfinder.server.controller

import akka.actor._
import akka.stream.scaladsl.Flow
import akka.stream.{Materializer, OverflowStrategy}
import monix.execution.Scheduler
import play.api.http.websocket.Message
import play.api.libs.streams._
import play.api.mvc._
import play.api.mvc.WebSocket.MessageFlowTransformer
import scala.concurrent.duration.FiniteDuration
import scala.concurrent.Future
import walfie.gbf.raidfinder.domain._
import walfie.gbf.raidfinder.protocol._
import walfie.gbf.raidfinder.RaidFinder
import walfie.gbf.raidfinder.server.actor.WebsocketRaidsHandler
import walfie.gbf.raidfinder.server.util.MessageFlowTransformerUtil
import walfie.gbf.raidfinder.server.{BossNameTranslator, MetricsCollector}

class WebsocketController(
  raidFinder:        RaidFinder[BinaryProtobuf],
  translator:        BossNameTranslator,
  keepAliveInterval: FiniteDuration,
  metricsCollector:  MetricsCollector
)(implicit system: ActorSystem, materializer: Materializer, scheduler: Scheduler) extends Controller {
  private val jsonTransformer = MessageFlowTransformerUtil.protobufJsonMessageFlowTransformer
  private val binaryTransformer = MessageFlowTransformerUtil.protobufBinaryMessageFlowTransformer
  private val defaultTransformer = jsonTransformer

  
        val flow = ActorFlow.actorRef(props = props)
        transformer.transform(flow)
      }
      case None => Left {
        val unsupportedProtocols = requestedProtocols.mkString("[", ", ", "]")
        Results.BadRequest("Unsupported websocket subprotocols " + unsupportedProtocols)
      }
    }

    Future.successful(result)
  }
} 
Example 8
Source File: BossNameTranslator.scala    From gbf-raidfinder   with MIT License 5 votes vote down vote up
package walfie.gbf.raidfinder.server

import akka.agent.Agent
import com.pastebin.Pj9d8jt5.ImagePHash
import java.awt.image.BufferedImage
import java.net.URL
import javax.imageio.ImageIO
import monix.execution.Scheduler
import monix.reactive._
import monix.reactive.subjects.ConcurrentSubject
import scala.concurrent.{ExecutionContext, Future}
import walfie.gbf.raidfinder.domain._
import walfie.gbf.raidfinder.util.BlockingIO

trait BossNameTranslator {
  import BossNameTranslator.Translation

  def translate(bossName: BossName): Option[BossName]
  def update(latestBosses: Map[BossName, RaidBoss]): Future[Unit]
  def observable(): Observable[Translation]
}

object BossNameTranslator {
  case class Translation(from: BossName, to: BossName)
}


  private def croppedImageFromUrl(url: URL): BufferedImage = {
    // TODO: Use a real HTTP client to get the image
    val image = ImageIO.read(url.openStream())
    image.getSubimage(0, 0, image.getWidth(), image.getHeight() * 3 / 4);
  }

  // This assumes there are only two languages (which is true currently)
  private def findTranslation(newData: TranslationData): Option[BossName] = {
    translationDataAgent.get.values.find { existingData =>
      newData.hash == existingData.hash &&
        newData.language != existingData.language &&
        newData.level == existingData.level
    }.map(_.name)
  }
}

object ImageBasedBossNameTranslator {
  case class TranslationData(name: BossName, level: Int, language: Language, hash: ImageHash)

  case class ImageHash(value: Long) extends AnyVal
} 
Example 9
Source File: NTP.scala    From matcher   with MIT License 5 votes vote down vote up
package com.wavesplatform.dex.time

import java.net.{InetAddress, SocketTimeoutException}
import java.util.concurrent.RejectedExecutionException
import java.util.concurrent.atomic.AtomicBoolean

import com.wavesplatform.dex.domain.utils.ScorexLogging
import monix.eval.Task
import monix.execution.schedulers.SchedulerService
import monix.execution.{ExecutionModel, Scheduler}
import org.apache.commons.net.ntp.NTPUDPClient

import scala.concurrent.duration.DurationInt

class NTP(ntpServer: String) extends Time with ScorexLogging with AutoCloseable {

  private val offsetPanicThreshold = 1000000L
  private val ExpirationTimeout    = 60.seconds
  private val RetryDelay           = 10.seconds
  private val ResponseTimeout      = 10.seconds

  private val duringShutdown = new AtomicBoolean(false)

  private implicit val scheduler: SchedulerService = Scheduler.singleThread(
    name = "time-impl",
    daemonic = false,
    executionModel = ExecutionModel.AlwaysAsyncExecution,
    reporter = {
      case _: RejectedExecutionException if duringShutdown.get() => // ignore
      case e: Throwable                                          => log.error("An uncaught error", e)
    }
  )

  private val client = new NTPUDPClient()
  client.setDefaultTimeout(ResponseTimeout.toMillis.toInt)

  @volatile private var offset = 0L
  private val updateTask: Task[Unit] = {
    def newOffsetTask: Task[Option[(InetAddress, java.lang.Long)]] = Task {
      try {
        val info = client.getTime(InetAddress.getByName(ntpServer))
        info.computeDetails()
        Option(info.getOffset).map { offset =>
          val r = if (Math.abs(offset) > offsetPanicThreshold) throw new Exception("Offset is suspiciously large") else offset
          (info.getAddress, r)
        }
      } catch {
        case _: SocketTimeoutException =>
          None
        case t: Throwable =>
          log.warn("Problems with NTP: ", t)
          None
      }
    }

    newOffsetTask.flatMap {
      case None if !scheduler.isShutdown => updateTask.delayExecution(RetryDelay)
      case Some((server, newOffset)) if !scheduler.isShutdown =>
        log.trace(s"Adjusting time with $newOffset milliseconds, source: ${server.getHostAddress}.")
        offset = newOffset
        updateTask.delayExecution(ExpirationTimeout)
      case _ => Task.unit
    }
  }

  def correctedTime(): Long = System.currentTimeMillis() + offset

  private var txTime: Long = 0

  def getTimestamp(): Long = {
    txTime = Math.max(correctedTime(), txTime + 1)
    txTime
  }

  private val taskHandle = updateTask.runAsync {
    case Left(e) => log.error(s"Error executing task", e)
    case _       =>
  }

  override def close(): Unit = if (duringShutdown.compareAndSet(false, true)) {
    log.info("Shutting down Time")
    taskHandle.cancel()
    if (client.isOpen) client.close()
    scheduler.shutdown()
  }
} 
Example 10
Source File: DEXExtension.scala    From matcher   with MIT License 5 votes vote down vote up
package com.wavesplatform.dex.grpc.integration

import java.net.InetSocketAddress
import java.util.concurrent.TimeUnit

import com.wavesplatform.dex.grpc.integration.services._
import com.wavesplatform.dex.grpc.integration.settings.DEXExtensionSettings
import com.wavesplatform.extensions.{Extension, Context => ExtensionContext}
import com.wavesplatform.utils.ScorexLogging
import io.grpc.Server
import io.grpc.netty.NettyServerBuilder
import monix.execution.{ExecutionModel, Scheduler}
import net.ceedubs.ficus.Ficus._
import net.ceedubs.ficus.readers.ArbitraryTypeReader._
import net.ceedubs.ficus.readers.NameMapper

import scala.concurrent.Future

class DEXExtension(context: ExtensionContext) extends Extension with ScorexLogging {

  @volatile
  private var server: Server                            = _
  private var apiService: WavesBlockchainApiGrpcService = _

  implicit val chosenCase: NameMapper = net.ceedubs.ficus.readers.namemappers.implicits.hyphenCase
  implicit private val apiScheduler: Scheduler = Scheduler(
    ec = context.actorSystem.dispatchers.lookup("akka.actor.waves-dex-grpc-scheduler"),
    executionModel = ExecutionModel.AlwaysAsyncExecution
  )

  override def start(): Unit = {
    val settings    = context.settings.config.as[DEXExtensionSettings]("waves.dex.grpc.integration")
    val bindAddress = new InetSocketAddress(settings.host, settings.port)
    apiService = new WavesBlockchainApiGrpcService(context, settings.balanceChangesBatchLinger)
    server = NettyServerBuilder
      .forAddress(bindAddress)
      .permitKeepAliveWithoutCalls(true)
      .permitKeepAliveTime(500, TimeUnit.MILLISECONDS)
      .addService(WavesBlockchainApiGrpc.bindService(apiService, apiScheduler))
      .build()
      .start()

    log.info(s"gRPC DEX extension was bound to $bindAddress")
  }

  override def shutdown(): Future[Unit] = {
    log.info("Shutting down gRPC DEX extension")
    if (server != null) server.shutdownNow()
    Future.successful(())
  }
} 
Example 11
Source File: WavesBlockchainCachingClient.scala    From matcher   with MIT License 5 votes vote down vote up
package com.wavesplatform.dex.grpc.integration.clients

import java.net.InetAddress
import java.time.Duration

import com.wavesplatform.dex.domain.account.Address
import com.wavesplatform.dex.domain.asset.Asset
import com.wavesplatform.dex.domain.bytes.ByteStr
import com.wavesplatform.dex.domain.order.Order
import com.wavesplatform.dex.domain.transaction.ExchangeTransaction
import com.wavesplatform.dex.domain.utils.ScorexLogging
import com.wavesplatform.dex.grpc.integration.caches.{AssetDescriptionsCache, FeaturesCache}
import com.wavesplatform.dex.grpc.integration.clients.WavesBlockchainClient.SpendableBalanceChanges
import com.wavesplatform.dex.grpc.integration.dto.BriefAssetDescription
import monix.execution.Scheduler
import monix.reactive.Observable

import scala.concurrent.duration.FiniteDuration
import scala.concurrent.{ExecutionContext, Future}

class WavesBlockchainCachingClient(underlying: WavesBlockchainClient[Future], defaultCacheExpiration: FiniteDuration, monixScheduler: Scheduler)(
    implicit grpcExecutionContext: ExecutionContext)
    extends WavesBlockchainClient[Future]
    with ScorexLogging {

  private val cacheExpiration: Duration = Duration.ofMillis(defaultCacheExpiration.toMillis)

  private val featuresCache          = new FeaturesCache(underlying.isFeatureActivated, invalidationPredicate = !_) // we don't keep knowledge about unactivated features
  private val assetDescriptionsCache = new AssetDescriptionsCache(underlying.assetDescription, cacheExpiration)

  // TODO remove after release 2.1.3
  override def spendableBalance(address: Address, asset: Asset): Future[Long] = underlying.spendableBalance(address, asset)

  override def spendableBalanceChanges: Observable[SpendableBalanceChanges]                      = underlying.spendableBalanceChanges
  override def realTimeBalanceChanges: Observable[WavesBlockchainClient.BalanceChanges]          = underlying.realTimeBalanceChanges
  override def spendableBalances(address: Address, assets: Set[Asset]): Future[Map[Asset, Long]] = underlying.spendableBalances(address, assets)
  override def allAssetsSpendableBalance(address: Address): Future[Map[Asset, Long]]             = underlying.allAssetsSpendableBalance(address)

  override def isFeatureActivated(id: Short): Future[Boolean] = featuresCache.get(id) map Boolean2boolean

  override def assetDescription(asset: Asset.IssuedAsset): Future[Option[BriefAssetDescription]] = assetDescriptionsCache.get(asset)

  override def hasScript(asset: Asset.IssuedAsset): Future[Boolean]                                     = underlying.hasScript(asset)
  override def runScript(asset: Asset.IssuedAsset, input: ExchangeTransaction): Future[RunScriptResult] = underlying.runScript(asset, input)

  override def hasScript(address: Address): Future[Boolean]                       = underlying.hasScript(address)
  override def runScript(address: Address, input: Order): Future[RunScriptResult] = underlying.runScript(address, input)

  override def wereForged(txIds: Seq[ByteStr]): Future[Map[ByteStr, Boolean]] = underlying.wereForged(txIds)
  override def broadcastTx(tx: ExchangeTransaction): Future[Boolean]          = underlying.broadcastTx(tx)

  override def forgedOrder(orderId: ByteStr): Future[Boolean] = underlying.forgedOrder(orderId)

  override def getNodeAddress: Future[InetAddress] = underlying.getNodeAddress

  override def close(): Future[Unit] = underlying.close()
} 
Example 12
Source File: WavesBlockchainClientBuilder.scala    From matcher   with MIT License 5 votes vote down vote up
package com.wavesplatform.dex.grpc.integration

import com.wavesplatform.dex.domain.utils.ScorexLogging
import com.wavesplatform.dex.grpc.integration.clients.{WavesBlockchainCachingClient, WavesBlockchainClient, WavesBlockchainGrpcAsyncClient}
import com.wavesplatform.dex.grpc.integration.settings.WavesBlockchainClientSettings
import io.grpc.ManagedChannel
import io.grpc.internal.DnsNameResolverProvider
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioSocketChannel
import monix.execution.Scheduler

import scala.concurrent.{ExecutionContext, Future}

object WavesBlockchainClientBuilder extends ScorexLogging {

  def async(wavesBlockchainClientSettings: WavesBlockchainClientSettings,
            monixScheduler: Scheduler,
            grpcExecutionContext: ExecutionContext): WavesBlockchainClient[Future] = {

    log.info(s"Building gRPC client for server: ${wavesBlockchainClientSettings.grpc.target}")

    val eventLoopGroup = new NioEventLoopGroup

    val channel: ManagedChannel =
      wavesBlockchainClientSettings.grpc.toNettyChannelBuilder
        .nameResolverFactory(new DnsNameResolverProvider)
        .executor((command: Runnable) => grpcExecutionContext.execute(command))
        .eventLoopGroup(eventLoopGroup)
        .channelType(classOf[NioSocketChannel])
        .usePlaintext()
        .build

    new WavesBlockchainCachingClient(
      new WavesBlockchainGrpcAsyncClient(eventLoopGroup, channel, monixScheduler)(grpcExecutionContext),
      wavesBlockchainClientSettings.defaultCachesExpiration,
      monixScheduler
    )(grpcExecutionContext)
  }
} 
Example 13
Source File: ScorexLogging.scala    From matcher   with MIT License 5 votes vote down vote up
package com.wavesplatform.dex.domain.utils

import monix.eval.Task
import monix.execution.{CancelableFuture, Scheduler}
import org.slf4j.{Logger, LoggerFactory}

case class LoggerFacade(logger: Logger) {

  def trace(message: => String): Unit                       = if (logger.isTraceEnabled) logger.trace(message)
  def debug(message: => String, arg: Any): Unit             = if (logger.isDebugEnabled) logger.debug(message, arg)
  def debug(message: => String): Unit                       = if (logger.isDebugEnabled) logger.debug(message)
  def info(message: => String): Unit                        = if (logger.isInfoEnabled) logger.info(message)
  def info(message: => String, arg: Any): Unit              = if (logger.isInfoEnabled) logger.info(message, arg)
  def info(message: => String, throwable: Throwable): Unit  = if (logger.isInfoEnabled) logger.info(message, throwable)
  def warn(message: => String): Unit                        = if (logger.isWarnEnabled) logger.warn(message)
  def warn(message: => String, throwable: Throwable): Unit  = if (logger.isWarnEnabled) logger.warn(message, throwable)
  def error(message: => String): Unit                       = if (logger.isErrorEnabled) logger.error(message)
  def error(message: => String, throwable: Throwable): Unit = if (logger.isErrorEnabled) logger.error(message, throwable)
}

trait ScorexLogging {

  protected lazy val log: LoggerFacade = LoggerFacade(LoggerFactory.getLogger(this.getClass))

  implicit class TaskExt[A](t: Task[A]) {

    def runAsyncLogErr(implicit s: Scheduler): CancelableFuture[A] = logErr.runToFuture(s)

    def logErr: Task[A] = t.onErrorHandleWith { ex =>
      log.error(s"Error executing task", ex)
      Task.raiseError[A](ex)
    }
  }
} 
Example 14
Source File: VNodeConstructionBenchmark.scala    From outwatch   with Apache License 2.0 5 votes vote down vote up
package outwatch

import outwatch._
import outwatch.dsl._
import monix.execution.ExecutionModel.SynchronousExecution
import monix.execution.schedulers.TrampolineScheduler
import monix.execution.Scheduler
import outwatch.interpreter.SnabbdomOps

import org.scalajs.dom.{ document, window }
import scala.scalajs.js
import scala.scalajs.js.annotation._
import bench._

object VNodeConstructionBenchmark extends js.JSApp {

  implicit val scheduler: Scheduler = TrampolineScheduler(Scheduler.global, SynchronousExecution)

  def main(): Unit = {
    import scala.concurrent.duration._

    bench.util.runComparison(vnodes, List(1), 60.seconds)
  }

  val vnodes = Comparison("VNode Construction", Seq(
    BenchmarkWithoutInit(
      "10 literal tags",
      { _ =>
        SnabbdomOps.toSnabbdom(div(span(), a(), img(), hr(), button(), input(), form(), label(), b(), i()))
      }
    ),
    BenchmarkWithoutInit(
      "10 literal attrs",
      { size =>
        SnabbdomOps.toSnabbdom(div(
          id := "a",
          min := "wo",
          max := "wa",
          src := "x",
          href := "k",
          target := "j",
          value := "jo",
          contentEditable := true,
          name := "hui",
          autoComplete := "true"
        ))
      }
    )
  ))

} 
Example 15
Source File: DomLiteralBenchmark.scala    From outwatch   with Apache License 2.0 5 votes vote down vote up
package outwatch

import outwatch._
import outwatch.dsl._
import monix.execution.ExecutionModel.SynchronousExecution
import monix.execution.schedulers.TrampolineScheduler
import monix.execution.Scheduler

import org.scalajs.dom.{ document, window }
import scala.scalajs.js
import scala.scalajs.js.annotation._
import bench._

object DomLiteralBenchmark extends js.JSApp {
  def main(): Unit = {
    import scala.concurrent.duration._

    bench.util.runComparison(domLiterals, List(1), 60.seconds)
  }

  val domLiterals = Comparison("Dom Literals", Seq(
    BenchmarkWithoutInit(
      "10 literal tags",
      { _ =>
        div(span(), a(), img(), hr(), button(), input(), form(), label(), b(), i())
      }
    ),
    BenchmarkWithoutInit(
      "10 literal attrs",
      { size =>
        div(
          id := "a",
          min := "wo",
          max := "wa",
          src := "x",
          href := "k",
          target := "j",
          value := "jo",
          contentEditable := true,
          name := "hui",
          autoComplete := "true"
        )
      }
    )
  ))

} 
Example 16
Source File: OutwatchSpec.scala    From outwatch   with Apache License 2.0 5 votes vote down vote up
package outwatch

import scala.concurrent.Future
import cats.effect.ContextShift
import cats.effect.IO
import monix.execution.Ack.Continue
import monix.execution.ExecutionModel.SynchronousExecution
import monix.execution.schedulers.TrampolineScheduler
import monix.execution.{Cancelable, Scheduler}
import monix.reactive.Observable
import org.scalajs.dom.{document, window}
import org.scalatest.BeforeAndAfterEach
import org.scalatest._
import outwatch.Deprecated.IgnoreWarnings.initEvent
import org.scalatest.flatspec.{ AnyFlatSpec, AsyncFlatSpec }
import org.scalatest.matchers.should.Matchers

trait EasySubscribe {

  implicit class Subscriber[T](obs: Observable[T]) {
    def apply(next: T => Unit)(implicit s: Scheduler): Cancelable = obs.subscribe { t =>
      next(t)
      Continue
    }
  }
}

// TODO: We need this mock until localStorage is implemented in jsdom (https://github.com/tmpvar/jsdom/pull/2076)
trait LocalStorageMock {
  import scala.collection.mutable
  import scala.scalajs.js


  if (js.isUndefined(window.localStorage)) {
    val storageObject = new js.Object {
      private val map = new mutable.HashMap[String, String]

      def getItem(key: String): String = map.getOrElse(key, null)

      def setItem(key: String, value: String): Unit = {
        map += key -> value
      }

      def removeItem(key: String): Unit = {
        map -= key
      }

      def clear(): Unit = map.clear()
    }

    js.Dynamic.global.window.updateDynamic("localStorage")(storageObject)
  }

  def dispatchStorageEvent(key: String, newValue: String, oldValue: String): Unit = {
    if (key == null) window.localStorage.clear()
    else window.localStorage.setItem(key, newValue)

    val event = document.createEvent("Events")
    initEvent(event)("storage", canBubbleArg = true, cancelableArg = false)
    event.asInstanceOf[js.Dynamic].key = key
    event.asInstanceOf[js.Dynamic].newValue = newValue
    event.asInstanceOf[js.Dynamic].oldValue = oldValue
    event.asInstanceOf[js.Dynamic].storageArea = window.localStorage
    window.dispatchEvent(event)
    ()
  }
}

trait OutwatchSpec extends Matchers with BeforeAndAfterEach with EasySubscribe with LocalStorageMock { self: Suite =>

  implicit val scheduler: TrampolineScheduler = TrampolineScheduler(Scheduler.global, SynchronousExecution)
  implicit val cs: ContextShift[IO] = IO.contextShift(scheduler)

  override def beforeEach(): Unit = {

    document.body.innerHTML = ""

    window.localStorage.clear()

    // prepare body with <div id="app"></div>
    val root = document.createElement("div")
    root.id = "app"
    document.body.appendChild(root)
    ()
  }

}

abstract class JSDomSpec extends AnyFlatSpec with OutwatchSpec {
  implicit def executionContext = scheduler
}
abstract class JSDomAsyncSpec extends AsyncFlatSpec with OutwatchSpec {
  override def executionContext = scheduler

  implicit def ioAssertionToFutureAssertion(io: IO[Assertion]): Future[Assertion] = io.unsafeToFuture()
} 
Example 17
Source File: Mdl.scala    From outwatch-extras   with Apache License 2.0 5 votes vote down vote up
package outwatch.extras.mdl

import monix.execution.Ack.Continue
import monix.execution.Scheduler
import org.scalajs.dom
import outwatch.Sink
import outwatch.dom.VDomModifier
import outwatch.dom.dsl.attributes.lifecycle._

import scala.scalajs.js


trait Mdl {

  implicit def scheduler: Scheduler

  private def componentHandler = js.Dynamic.global.componentHandler

  private def updateElement(e: dom.Element): Unit = {
    e.removeAttribute("data-upgraded")
    if (!js.isUndefined(componentHandler)) componentHandler.upgradeElement(e).asInstanceOf[Unit]
  }

  private val insertHook = Sink.create[dom.Element] { e =>
    updateElement(e)
    Continue
  }

  private val postPatchHook = Sink.create[(dom.Element, dom.Element)] { case (_, e) =>
    updateElement(e)
    Continue
  }

  val material: VDomModifier = VDomModifier(
    insertHook.flatMap(sink => onInsert --> sink),
    postPatchHook.flatMap(sink => onPostPatch --> sink)
  )

  def material(id: String): VDomModifier = {

    val update = () => {
      Option(dom.document.getElementById(id)).foreach(updateElement)
      Continue
    }

    val insertHook = Sink.create[dom.Element](_ => update())
    val postPatchHook = Sink.create[(dom.Element, dom.Element)](_ => update() )

    VDomModifier(
      insertHook.flatMap(sink => onInsert --> sink),
      postPatchHook.flatMap(sink => onPostPatch --> sink)
    )
  }

} 
Example 18
Source File: DemoStyles.scala    From outwatch-extras   with Apache License 2.0 5 votes vote down vote up
package demo.styles

import monix.execution.Scheduler
import outwatch.extras.styles.{ComponentStyle, Styles}

import scalacss.DevDefaults._

trait GlobalScheduler {
  def scheduler = Scheduler.global
}

trait LogAreaStyle extends ComponentStyle {

  class Style extends StyleSheet with MdlStyles with GlobalScheduler {

    import dsl._

    val textfield = style(
      mdl.textfield,
      height(400.px),
      width(400.px).important,
      fontFamily :=! "Courier New",
      fontSize(14.px).important
    )
  }

  object Style {
    implicit object default extends Style with Styles.Publish
  }
}



trait TextFieldStyle extends ComponentStyle {

  class Style extends StyleSheet with MdlStyles with GlobalScheduler {

    import dsl._

    val textfield = style (
      mdl.textfield,
      marginRight(8.px).important
    )

    val textinput = style (
      mdl.textinput
    )

    val textlabel = style (
      mdl.textlabel
    )

    val button = style (
      mdl.button
    )
  }

  object Style {
    implicit object default extends Style with Styles.Publish
  }
}

trait TodoModuleStyle extends ComponentStyle {

  class Style extends StyleSheet with MdlStyles with GlobalScheduler {

    import dsl._

    val textinput = style(
      mdl.textinput
    )

    val textlabel = style(
      mdl.textlabel
    )

    val button = style(
      mdl.button,
      marginLeft(8.px)
    )
  }

  object Style {
    implicit object default extends Style with Styles.Publish
  }
} 
Example 19
Source File: MonixRestImplicits.scala    From udash-core   with Apache License 2.0 5 votes vote down vote up
package io.udash
package rest.monix

import com.avsystem.commons._
import com.avsystem.commons.meta.MacroInstances
import com.avsystem.commons.misc.ImplicitNotFound
import io.udash.rest.raw.HttpResponseType
import io.udash.rest.raw.RawRest.{Async, AsyncEffect}
import io.udash.rest.{GenCodecRestImplicits, OpenApiFullInstances, RestOpenApiCompanion}
import monix.eval.Task
import monix.execution.Scheduler

import scala.annotation.implicitNotFound

trait MonixRestImplicits extends GenCodecRestImplicits {
  implicit def scheduler: Scheduler = Scheduler.global

  implicit def taskToAsync: AsyncEffect[Task] =
    new AsyncEffect[Task] {
      def toAsync[A](task: Task[A]): Async[A] =
        callback => task.runAsync(res => callback(res.fold(Failure(_), Success(_))))
      def fromAsync[A](async: Async[A]): Task[A] =
        Task.async(callback => async(res => callback(res.fold(Left(_), Right(_)))))
    }

  @implicitNotFound("${T} is not a valid HTTP method result type - it must be wrapped into a Task")
  implicit def httpResponseTypeNotFound[T]: ImplicitNotFound[HttpResponseType[T]] =
    ImplicitNotFound()
}
object MonixRestImplicits extends MonixRestImplicits

abstract class MonixRestApiCompanion[Real](
  implicit macroInstances: MacroInstances[MonixRestImplicits, OpenApiFullInstances[Real]]
) extends RestOpenApiCompanion[MonixRestImplicits, Real](MonixRestImplicits) 
Example 20
Source File: IOBenchmarks.scala    From zio   with Apache License 2.0 5 votes vote down vote up
package zio

import scala.concurrent.ExecutionContext

import cats._
import cats.effect.{ ContextShift, IO => CIO }
import cats.effect.{ Fiber => CFiber }
import monix.eval.{ Task => MTask }

import zio.internal._

object IOBenchmarks extends BootstrapRuntime {

  override val platform: Platform = Platform.benchmark

  val TracedRuntime = new BootstrapRuntime {
    override val platform = Platform.benchmark.withTracing(Tracing.enabled)
  }

  import monix.execution.Scheduler
  implicit val contextShift: ContextShift[CIO] = CIO.contextShift(ExecutionContext.global)

  implicit val monixScheduler: Scheduler = {
    import monix.execution.ExecutionModel.SynchronousExecution
    Scheduler.global.withExecutionModel(SynchronousExecution)
  }

  def repeat[R, E, A](n: Int)(zio: ZIO[R, E, A]): ZIO[R, E, A] =
    if (n <= 1) zio
    else zio *> repeat(n - 1)(zio)

  def verify(cond: Boolean)(message: => String): IO[AssertionError, Unit] =
    ZIO.when(!cond)(IO.fail(new AssertionError(message)))

  def catsForkAll[A](as: Iterable[CIO[A]]): CIO[CFiber[CIO, List[A]]] = {
    type Fiber[A] = CFiber[CIO, A]

    as.foldRight[CIO[CFiber[CIO, List[A]]]](CIO(Applicative[Fiber].pure(Nil))) { (io, listFiber) =>
      Applicative[CIO].map2(listFiber, io.start)((f1, f2) => Applicative[Fiber].map2(f1, f2)((as, a) => a :: as))
    }
  }

  def catsRepeat[A](n: Int)(io: CIO[A]): CIO[A] =
    if (n <= 1) io
    else io.flatMap(_ => catsRepeat(n - 1)(io))

  def monixForkAll[A](as: Iterable[MTask[A]]): MTask[CFiber[MTask, List[A]]] = {
    type Fiber[A] = CFiber[MTask, A]

    as.foldRight[MTask[CFiber[MTask, List[A]]]](MTask(Applicative[Fiber].pure(Nil))) { (io, listFiber) =>
      MTask.map2(listFiber, io.start)((f1, f2) => Applicative[Fiber].map2(f1, f2)((as, a) => a :: as))
    }
  }

  def monixRepeat[A](n: Int)(mio: MTask[A]): MTask[A] =
    if (n <= 1) mio
    else mio.flatMap(_ => monixRepeat(n - 1)(mio))

  class Thunk[A](val unsafeRun: () => A) {
    def map[B](ab: A => B): Thunk[B] =
      new Thunk(() => ab(unsafeRun()))
    def flatMap[B](afb: A => Thunk[B]): Thunk[B] =
      new Thunk(() => afb(unsafeRun()).unsafeRun())
    def attempt: Thunk[Either[Throwable, A]] =
      new Thunk(() =>
        try Right(unsafeRun())
        catch {
          case t: Throwable => Left(t)
        }
      )
  }
  object Thunk {
    def apply[A](a: => A): Thunk[A] = new Thunk(() => a)

    def fail[A](t: Throwable): Thunk[A] = new Thunk(() => throw t)
  }
} 
Example 21
Source File: Connection.scala    From lsp4s   with Apache License 2.0 5 votes vote down vote up
package scala.meta.jsonrpc

import monix.execution.Cancelable
import monix.execution.CancelableFuture
import monix.execution.Scheduler
import scribe.Logger
import scribe.LoggerSupport


final case class Connection(
    client: LanguageClient,
    server: CancelableFuture[Unit]
) extends Cancelable {
  override def cancel(): Unit = server.cancel()
}

object Connection {

  def simple(io: InputOutput, name: String)(
      f: LanguageClient => Services
  )(implicit s: Scheduler): Connection =
    Connection(
      io,
      Logger(s"$name-server"),
      Logger(s"$name-client")
    )(f)

  def apply(
      io: InputOutput,
      serverLogger: LoggerSupport,
      clientLogger: LoggerSupport
  )(
      f: LanguageClient => Services
  )(implicit s: Scheduler): Connection = {
    val messages =
      BaseProtocolMessage.fromInputStream(io.in, serverLogger)
    val client =
      LanguageClient.fromOutputStream(io.out, clientLogger)
    val server =
      new LanguageServer(messages, client, f(client), s, serverLogger)
    Connection(client, server.startTask.executeAsync.runAsync)
  }

} 
Example 22
Source File: MonixEnrichments.scala    From lsp4s   with Apache License 2.0 5 votes vote down vote up
package scala.meta.jsonrpc

import java.io.IOException
import java.io.OutputStream
import java.nio.ByteBuffer
import monix.execution.Ack
import monix.execution.Cancelable
import monix.execution.Scheduler
import monix.reactive.Observable
import monix.reactive.Observer
import scribe.LoggerSupport

object MonixEnrichments {

  
  class ObservableCurrentValue[+A](obs: Observable[A])(implicit s: Scheduler)
      extends (() => A)
      with Cancelable {
    private var value: Any = _
    private val cancelable = obs.foreach(newValue => value = newValue)
    override def apply(): A = {
      if (value == null) {
        throw new NoSuchElementException(
          "Reading from empty Observable, consider using MulticastStrategy.behavior(initialValue)"
        )
      } else {
        value.asInstanceOf[A]
      }
    }
    override def cancel(): Unit = cancelable.cancel()
  }

  implicit class XtensionObservable[A](val obs: Observable[A]) extends AnyVal {

    def focus[B: cats.Eq](f: A => B): Observable[B] =
      obs.distinctUntilChangedByKey(f).map(f)

    def toFunction0()(implicit s: Scheduler): () => A =
      toObservableCurrentValue()

    def toObservableCurrentValue()(
        implicit s: Scheduler
    ): ObservableCurrentValue[A] =
      new ObservableCurrentValue[A](obs)
  }

  implicit class XtensionObserverCompanion[A](val `_`: Observer.type)
      extends AnyVal {
    def fromOutputStream(
        out: OutputStream,
        logger: LoggerSupport
    ): Observer.Sync[ByteBuffer] = {
      new Observer.Sync[ByteBuffer] {
        private[this] var isClosed: Boolean = false
        override def onNext(elem: ByteBuffer): Ack = {
          if (isClosed) Ack.Stop
          else {
            try {
              while (elem.hasRemaining) out.write(elem.get())
              out.flush()
              Ack.Continue
            } catch {
              case _: IOException =>
                logger.error("OutputStream closed!")
                isClosed = true
                Ack.Stop
            }
          }
        }
        override def onError(ex: Throwable): Unit = ()
        override def onComplete(): Unit = out.close()
      }
    }
  }

} 
Example 23
Source File: TestConnection.scala    From lsp4s   with Apache License 2.0 5 votes vote down vote up
package scala.meta.jsonrpc.testkit

import java.io.PipedInputStream
import java.io.PipedOutputStream
import monix.execution.Cancelable
import monix.execution.Scheduler
import scala.meta.jsonrpc.Connection
import scala.meta.jsonrpc.InputOutput
import scala.meta.jsonrpc.LanguageClient
import scala.meta.jsonrpc.Services


  def apply(
      clientServices: LanguageClient => Services,
      serverServices: LanguageClient => Services
  )(implicit s: Scheduler): TestConnection = {
    val inAlice = new PipedInputStream()
    val inBob = new PipedInputStream()
    val outAlice = new PipedOutputStream(inBob)
    val outBob = new PipedOutputStream(inAlice)
    val aliceIO = new InputOutput(inAlice, outAlice)
    val bobIO = new InputOutput(inBob, outBob)
    val alice = Connection.simple(aliceIO, "alice")(clientServices)
    val bob = Connection.simple(bobIO, "bob")(serverServices)
    new TestConnection(alice, aliceIO, bob, bobIO)
  }

} 
Example 24
Source File: WatchServiceObservable.scala    From monix-nio   with Apache License 2.0 5 votes vote down vote up
package monix.nio

import java.nio.file.WatchEvent

import monix.eval.Task
import monix.execution.Ack.{ Continue, Stop }
import monix.execution.atomic.Atomic
import monix.execution.cancelables.SingleAssignCancelable
import monix.execution.exceptions.APIContractViolationException
import monix.execution.{ Callback, Cancelable, Scheduler }
import monix.reactive.Observable
import monix.reactive.observers.Subscriber

import scala.concurrent.Future
import scala.util.control.NonFatal

abstract class WatchServiceObservable extends Observable[Array[WatchEvent[_]]] {
  def watchService: Option[WatchService]

  private[this] val wasSubscribed = Atomic(false)
  override def unsafeSubscribeFn(subscriber: Subscriber[Array[WatchEvent[_]]]): Cancelable = {
    if (wasSubscribed.getAndSet(true)) {
      subscriber.onError(APIContractViolationException(this.getClass.getName))
      Cancelable.empty
    } else try startPolling(subscriber) catch {
      case NonFatal(e) =>
        subscriber.onError(e)
        Cancelable.empty
    }
  }

  def init(subscriber: Subscriber[Array[WatchEvent[_]]]): Future[Unit] =
    Future.successful(())

  private def startPolling(subscriber: Subscriber[Array[WatchEvent[_]]]): Cancelable = {
    import subscriber.scheduler

    val taskCallback = new Callback[Throwable, Array[WatchEvent[_]]]() {
      override def onSuccess(value: Array[WatchEvent[_]]): Unit = {}
      override def onError(ex: Throwable): Unit = {
        subscriber.onError(ex)
      }
    }
    val cancelable = Task
      .fromFuture(init(subscriber))
      .flatMap { _ =>
        loop(subscriber)
      }
      .executeWithOptions(_.enableAutoCancelableRunLoops)
      .runAsync(taskCallback)

    val extraCancelable = Cancelable(() => {
      cancelable.cancel()
    })
    SingleAssignCancelable.plusOne(extraCancelable)
  }

  private def loop(subscriber: Subscriber[Array[WatchEvent[_]]])(implicit scheduler: Scheduler): Task[Array[WatchEvent[_]]] = {
    import collection.JavaConverters._
    watchService.map { ws =>
      ws.take()
        .doOnCancel(Task.defer(ws.close()))
        .flatMap { key =>
          val events = key.pollEvents().asScala.toArray
          key.reset()
          Task.fromFuture(subscriber.onNext(events)).flatMap {
            case Continue => loop(subscriber)
            case Stop => emptyTask
          }
        }
    }
  }.getOrElse(emptyTask)

  private val emptyTask = Task.create[Array[WatchEvent[_]]]((_, _) => Cancelable.empty)
} 
Example 25
Source File: AsyncSocketChannelClient.scala    From monix-nio   with Apache License 2.0 5 votes vote down vote up
package monix.nio.tcp

import monix.eval.Task
import monix.execution.Scheduler


  def close(): Task[Unit] =
    taskSocketChannel.fold(Task.pure(()))(_.close())
}

object AsyncSocketChannelClient {

  def apply(
    host: String,
    port: Int,
    bufferSize: Int)(implicit scheduler: Scheduler): AsyncSocketChannelClient = {

    val client = new AsyncSocketChannelClient(host, port, bufferSize)
    client.init()
    client
  }

  def apply(
    taskSocketChannel: TaskSocketChannel,
    bufferSize: Int)(implicit scheduler: Scheduler): AsyncSocketChannelClient = {

    val client = new AsyncSocketChannelClient(taskSocketChannel, bufferSize)
    client.init()
    client
  }
} 
Example 26
Source File: AsyncChannelConsumer.scala    From monix-nio   with Apache License 2.0 5 votes vote down vote up
package monix.nio

import java.nio.ByteBuffer

import monix.execution.Ack.{ Continue, Stop }
import monix.execution.{ Ack, Callback, Cancelable, Scheduler }
import monix.execution.atomic.Atomic
import monix.execution.cancelables.{ AssignableCancelable, SingleAssignCancelable }
import monix.reactive.Consumer
import monix.reactive.observers.Subscriber

import scala.concurrent.{ Future, Promise }
import scala.util.control.NonFatal

private[nio] abstract class AsyncChannelConsumer extends Consumer[Array[Byte], Long] {
  def channel: Option[AsyncChannel]
  def withInitialPosition: Long = 0L
  def init(subscriber: AsyncChannelSubscriber): Future[Unit] = Future.successful(())

  class AsyncChannelSubscriber(consumerCallback: Callback[Throwable, Long])(implicit val scheduler: Scheduler)
    extends Subscriber[Array[Byte]] { self =>

    private[this] lazy val initFuture = init(self)
    private[this] val callbackCalled = Atomic(false)
    private[this] var position = withInitialPosition

    override def onNext(elem: Array[Byte]): Future[Ack] = {
      def write(): Future[Ack] = {
        val promise = Promise[Ack]()
        channel.foreach { sc =>
          try {
            sc
              .write(ByteBuffer.wrap(elem), position)
              .runAsync(
                new Callback[Throwable, Int] {
                  override def onError(exc: Throwable) = {
                    closeChannel()
                    sendError(exc)
                    promise.success(Stop)
                  }

                  override def onSuccess(result: Int): Unit = {
                    position += result
                    promise.success(Continue)
                  }
                })
          } catch {
            case NonFatal(ex) =>
              sendError(ex)
              promise.success(Stop)
          }
        }

        promise.future
      }

      if (initFuture.value.isEmpty) {
        initFuture.flatMap(_ => write())
      } else {
        write()
      }
    }

    override def onComplete(): Unit = {
      channel.collect { case sc if sc.closeOnComplete => closeChannel() }
      if (callbackCalled.compareAndSet(expect = false, update = true))
        consumerCallback.onSuccess(position)
    }

    override def onError(ex: Throwable): Unit = {
      closeChannel()
      sendError(ex)
    }

    private[nio] def onCancel(): Unit = {
      callbackCalled.set(true) 
      closeChannel()
    }

    private[nio] def sendError(t: Throwable) =
      if (callbackCalled.compareAndSet(expect = false, update = true)) {
        scheduler.execute(new Runnable {
          def run() = consumerCallback.onError(t)
        })
      }

    private[nio] final def closeChannel()(implicit scheduler: Scheduler) =
      channel.foreach(_.close().runToFuture)
  }

  override def createSubscriber(cb: Callback[Throwable, Long], s: Scheduler): (Subscriber[Array[Byte]], AssignableCancelable) = {
    val out = new AsyncChannelSubscriber(cb)(s)

    val extraCancelable = Cancelable(() => out.onCancel())
    val conn = SingleAssignCancelable.plusOne(extraCancelable)
    (out, conn)
  }
} 
Example 27
Source File: AsyncChannelObservable.scala    From monix-nio   with Apache License 2.0 5 votes vote down vote up
package monix.nio

import java.nio.ByteBuffer

import monix.eval.Task
import monix.execution.Ack.{ Continue, Stop }
import monix.execution.{ Callback, Cancelable, Scheduler }
import monix.execution.atomic.Atomic
import monix.execution.cancelables.SingleAssignCancelable
import monix.execution.exceptions.APIContractViolationException
import monix.nio.internal.{ Bytes, EmptyBytes, NonEmptyBytes }
import monix.reactive.Observable
import monix.reactive.observers.Subscriber

import scala.concurrent.Future
import scala.util.control.NonFatal

private[nio] abstract class AsyncChannelObservable extends Observable[Array[Byte]] {
  def bufferSize: Int
  def channel: Option[AsyncChannel]
  def init(subscriber: Subscriber[Array[Byte]]): Future[Unit] =
    Future.successful(())

  private[this] val wasSubscribed = Atomic(false)
  override def unsafeSubscribeFn(subscriber: Subscriber[Array[Byte]]): Cancelable = {
    import subscriber.scheduler
    if (wasSubscribed.getAndSet(true)) {
      subscriber.onError(APIContractViolationException(this.getClass.getName))
      Cancelable.empty
    } else try startReading(subscriber) catch {
      case NonFatal(e) =>
        subscriber.onError(e)
        closeChannel()
        Cancelable.empty
    }
  }

  private def startReading(subscriber: Subscriber[Array[Byte]]): Cancelable = {
    import subscriber.scheduler

    val taskCallback = new Callback[Throwable, Array[Byte]]() {
      override def onSuccess(value: Array[Byte]): Unit = {
        channel.collect { case sc if sc.closeOnComplete => closeChannel() }
      }
      override def onError(ex: Throwable): Unit = {
        closeChannel()
        subscriber.onError(ex)
      }
    }
    val cancelable = Task
      .fromFuture(init(subscriber))
      .flatMap { _ =>
        loop(subscriber, 0)
      }
      .executeWithOptions(_.enableAutoCancelableRunLoops)
      .runAsync(taskCallback)

    val extraCancelable = Cancelable(() => {
      cancelable.cancel()
      closeChannel()
    })
    SingleAssignCancelable.plusOne(extraCancelable)
  }

  private[this] val buffer = ByteBuffer.allocate(bufferSize)
  private def loop(subscriber: Subscriber[Array[Byte]], position: Long)(implicit scheduler: Scheduler): Task[Array[Byte]] = {
    buffer.clear()
    channel.map { ch =>
      ch
        .read(buffer, position)
        .doOnCancel(Task.defer(ch.close()))
        .flatMap { result =>
          val bytes = Bytes(buffer, result)
          bytes match {
            case EmptyBytes =>
              subscriber.onComplete()
              Task.now(Bytes.emptyBytes)

            case NonEmptyBytes(arr) =>
              Task.fromFuture(subscriber.onNext(arr)).flatMap {
                case Continue =>
                  loop(subscriber, position + result)

                case Stop =>
                  Task.now(Bytes.emptyBytes)
              }
          }
        }
    }.getOrElse(Task.now(Bytes.emptyBytes))
  }

  private[nio] final def closeChannel()(implicit scheduler: Scheduler) =
    channel.foreach(_.close().runToFuture)
} 
Example 28
Source File: ExecutorServiceWrapper.scala    From monix-nio   with Apache License 2.0 5 votes vote down vote up
package monix.nio.internal

import java.util
import java.util.concurrent.{ AbstractExecutorService, ExecutorService, TimeUnit }

import monix.execution.schedulers.{ ReferenceScheduler, SchedulerService }
import monix.execution.{ Cancelable, ExecutionModel, Scheduler }

import scala.collection.JavaConverters._
import scala.concurrent.duration.Duration
import scala.concurrent.{ Await, ExecutionContextExecutorService }


  private val currentThread: Scheduler =
    new ReferenceScheduler {
      import monix.execution.Scheduler.global
      def execute(r: Runnable): Unit = r.run()
      def reportFailure(t: Throwable): Unit = throw t
      def scheduleOnce(initialDelay: Long, unit: TimeUnit, r: Runnable): Cancelable =
        global.scheduleOnce(initialDelay, unit, r)
      def executionModel: ExecutionModel =
        ExecutionModel.Default
    }
} 
Example 29
Source File: file.scala    From monix-nio   with Apache License 2.0 5 votes vote down vote up
package monix.nio

import java.nio.ByteBuffer
import java.nio.file.WatchEvent.Kind
import java.nio.file.{ Path, StandardOpenOption }

import monix.execution.Scheduler

package object file {
  def readAsync(path: Path, chunkSize: Int)(implicit s: Scheduler): AsyncFileChannelObservable = {
    require(chunkSize > 1)

    val channel = TaskFileChannel(path, StandardOpenOption.READ)
    new AsyncFileChannelObservable(channel, chunkSize)
  }

  def writeAsync(
    path: Path,
    flags: Seq[StandardOpenOption] = Seq.empty)(implicit s: Scheduler): AsyncFileChannelConsumer = {

    appendAsync(path, 0, flags)
  }

  def appendAsync(
    path: Path,
    startPosition: Long,
    flags: Seq[StandardOpenOption] = Seq.empty)(implicit s: Scheduler): AsyncFileChannelConsumer = {

    val flagsWithWriteOptions = flags :+ StandardOpenOption.WRITE :+ StandardOpenOption.CREATE
    val channel = TaskFileChannel(path, flagsWithWriteOptions: _*)
    new AsyncFileChannelConsumer(channel, startPosition)
  }

  def watchAsync(
    path: Path,
    events: Seq[Kind[_]] = Seq.empty)(implicit s: Scheduler): WatchServiceObservable = {
    val watcher = TaskWatchService(path, events: _*)
    new AsyncWatchServiceObservable(watcher)
  }

  private[file] def asyncChannelWrapper(taskFileChannel: TaskFileChannel) = new AsyncChannel {
    override val closeOnComplete: Boolean = true

    override def read(dst: ByteBuffer, position: Long) = taskFileChannel.read(dst, position)
    override def write(b: ByteBuffer, position: Long) = taskFileChannel.write(b, position)
    override def close() = taskFileChannel.close()
  }
} 
Example 30
Source File: WatchService.scala    From monix-nio   with Apache License 2.0 5 votes vote down vote up
package monix.nio.file

import java.nio.file.StandardWatchEventKinds.{ ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY }
import java.nio.file.WatchEvent.Kind
import java.nio.file.{ Path, WatchEvent, WatchKey }

import com.sun.nio.file.SensitivityWatchEventModifier
import monix.execution.{ Callback, Cancelable, Scheduler }

import scala.concurrent.{ Future, Promise }
import scala.concurrent.duration.TimeUnit
import scala.util.control.NonFatal


abstract class WatchService extends AutoCloseable {
  def poll(timeout: Long, timeUnit: TimeUnit, cb: Callback[Throwable, Option[WatchKey]]): Unit

  def poll(timeout: Long, timeUnit: TimeUnit): Future[Option[WatchKey]] = {
    val p = Promise[Option[WatchKey]]()
    poll(timeout, timeUnit, Callback.fromPromise(p))
    p.future
  }

  def poll(cb: Callback[Throwable, Option[WatchKey]]): Unit

  def poll(): Future[Option[WatchKey]] = {
    val p = Promise[Option[WatchKey]]()
    poll(Callback.fromPromise(p))
    p.future
  }

  def take(cb: Callback[Throwable, WatchKey]): Unit

  def take(): Future[WatchKey] = {
    val p = Promise[WatchKey]()
    take(Callback.fromPromise(p))
    p.future
  }
}

object WatchService {
  val SupportedEvents: Set[Kind[_]] = Set(ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY)

  def apply(path: Path, events: Kind[_]*)(implicit scheduler: Scheduler): WatchService = {
    val watcher = path.getFileSystem.newWatchService()
    val watchFor = if (events.isEmpty) SupportedEvents else events

    path.register(
      watcher,
      watchFor.toArray,
      SensitivityWatchEventModifier.HIGH.asInstanceOf[WatchEvent.Modifier])

    new NIOWatcherServiceImplementation(watcher)
  }

  private final class NIOWatcherServiceImplementation(watcher: java.nio.file.WatchService)(implicit scheduler: Scheduler) extends WatchService {
    override def poll(timeout: Long, timeUnit: TimeUnit, cb: Callback[Throwable, Option[WatchKey]]): Unit = {
      try {
        val key = Option(watcher.poll(timeout, timeUnit))
        cb.onSuccess(key)
      } catch {
        case NonFatal(ex) =>
          cb.onError(ex)
      }
    }

    override def poll(cb: Callback[Throwable, Option[WatchKey]]): Unit = {
      try {
        val key = Option(watcher.poll())
        cb.onSuccess(key)
      } catch {
        case NonFatal(ex) =>
          cb.onError(ex)
      }
    }

    override def take(cb: Callback[Throwable, WatchKey]): Unit = {
      try {
        val key = watcher.take()
        cb.onSuccess(key)
      } catch {
        case NonFatal(ex) =>
          cb.onError(ex)
      }
    }

    override def close(): Unit = cancelable.cancel()

    private[this] val cancelable: Cancelable =
      Cancelable { () =>
        try watcher.close() catch {
          case NonFatal(ex) => scheduler.reportFailure(ex)
        }
      }
  }
} 
Example 31
Source File: TaskWatchService.scala    From monix-nio   with Apache License 2.0 5 votes vote down vote up
package monix.nio.file

import java.nio.file.WatchEvent.Kind
import java.nio.file.{ Path, WatchKey }

import monix.eval.Task
import monix.execution.{ Callback, Scheduler }

import scala.concurrent.duration.TimeUnit


abstract class TaskWatchService {

  protected val watchService: WatchService

  def poll(timeout: Long, timeUnit: TimeUnit): Task[Option[WatchKey]] =
    Task.create { (scheduler, cb) =>
      watchService.poll(timeout, timeUnit, Callback.forked(cb)(scheduler))
    }

  def poll(): Task[Option[WatchKey]] =
    Task.create { (scheduler, cb) =>
      watchService.poll(Callback.forked(cb)(scheduler))
    }

  def take(): Task[WatchKey] =
    Task.create { (scheduler, cb) =>
      watchService.take(Callback.forked(cb)(scheduler))
    }

  def close(): Task[Unit] =
    Task.now(watchService.close())
}

object TaskWatchService {
  def apply(path: Path, events: Kind[_]*)(implicit s: Scheduler): TaskWatchService = {
    new TaskWatchService {
      override val watchService: WatchService = WatchService.apply(path, events: _*)
    }
  }
} 
Example 32
Source File: FileChannelForTesting.scala    From monix-nio   with Apache License 2.0 5 votes vote down vote up
package monix.nio.file

import java.nio.ByteBuffer

import monix.eval.Task
import monix.execution.{ Callback, Scheduler }
import monix.execution.atomic.Atomic
import monix.nio.AsyncChannel

class FileChannelForTesting(
  readingSeq: Vector[Array[Byte]],
  writeSeq: Atomic[Vector[Array[Byte]]])(implicit s: Scheduler) extends TaskFileChannel with AsyncChannel {

  private val asyncFileChannelForTesting =
    new AsyncFileChannelForTesting(readingSeq, writeSeq)

  override val closeOnComplete: Boolean = true
  override val asyncFileChannel: AsyncFileChannel = asyncFileChannelForTesting

  def isClosed = asyncFileChannelForTesting.isClosed
  def getBytesReadPosition = asyncFileChannelForTesting.getBytesReadPosition
  def getBytesWritePosition = asyncFileChannelForTesting.getBytesWritePosition
  def createReadException() = asyncFileChannelForTesting.createReadException()
  def createWriteException() = asyncFileChannelForTesting.createWriteException()

  private final class AsyncFileChannelForTesting(
    readingSeq: Vector[Array[Byte]],
    writeSeq: Atomic[Vector[Array[Byte]]])(implicit s: Scheduler) extends AsyncFileChannel {

    private val readChannelPosition = Atomic(0)
    private val writeChannelPosition = Atomic(0)
    private val channelClosed = Atomic(false)
    private val readException = Atomic(false)
    private val writeException = Atomic(false)

    def isClosed = channelClosed.get
    def getBytesReadPosition = readChannelPosition.get
    def getBytesWritePosition = writeChannelPosition.get
    def createReadException() = readException.set(true)
    def createWriteException() = writeException.set(true)

    def taskCallback(handler: Callback[Throwable, Int]) = new Callback[Throwable, Array[Byte]]() {
      override def onSuccess(value: Array[Byte]): Unit = handler.onSuccess(value.length)
      override def onError(ex: Throwable): Unit = handler.onError(ex)
    }

    override def isOpen: Boolean = !isClosed
    override def flush(writeMetaData: Boolean, cb: Callback[Throwable, Unit]): Unit = ???
    override def size(cb: Callback[Throwable, Long]): Unit = () //not really used
    override def read(dst: ByteBuffer, position: Long, handler: Callback[Throwable, Int]) = {
      if (readException.get) handler.onError(new Exception("Test Exception"))
      else if (readChannelPosition.get < readingSeq.size) {
        val pos = readChannelPosition.getAndIncrement()

        val r = Task {
          val elem = readingSeq(pos)
          dst.put(elem)
          elem
        }
        r.runAsync(taskCallback(handler))
      } else {
        handler.onSuccess(-1)
      }

    }
    override def write(b: ByteBuffer, position: Long, handler: Callback[Throwable, Int]) = {
      if (writeException.get) handler.onError(new Exception("Test Exception"))
      else {
        val pos = writeChannelPosition.getAndIncrement()
        val r = Task {
          val bytes = b.array()
          writeSeq.transform { v =>
            if (v.size > pos) v.updated(pos, bytes)
            else v :+ bytes
          }
          bytes
        }
        r.runAsync(taskCallback(handler))
      }
    }
    override def close() = {
      channelClosed.set(true)
    }
  }
} 
Example 33
Source File: MongoObservableReactivePublisherTest.scala    From scala-commons   with MIT License 5 votes vote down vote up
package com.avsystem.commons
package mongo.async

import com.avsystem.commons.concurrent.RunNowEC
import com.github.ghik.silencer.silent
import com.mongodb.async.{client => mongo}
import monix.execution.{Cancelable, Scheduler}
import org.mockito.ArgumentMatchers.{eq => eqTo, _}
import org.mockito.Mockito
import org.mockito.Mockito._
import org.mongodb.scala.{Completed, Document, FindObservable, MongoCollection, SingleObservable}
import org.scalactic.source.Position
import org.scalatest.freespec.AnyFreeSpec

import scala.concurrent.duration.Duration

@silent("deprecated")
class MongoObservableReactivePublisherTest extends AnyFreeSpec {

  abstract class MockedObservableTests(implicit position: Position) extends MongoObservableExtensions {

    def subscribe[T](obs: mongo.Observable[T], testSubscriber: TestSubscriber[T]): Unit

    "should drop test collection" in {
      val collection = Mockito.mock(classOf[MongoCollection[Document]])
      when(collection.drop()).thenReturn(SingleObservable(Completed()))
      val dropSubscriber = TestSubscriber[Completed]()

      subscribe(collection.drop(), dropSubscriber)

      dropSubscriber.assertNoTerminalEvent()
      dropSubscriber.requestMore(1)
      dropSubscriber.awaitTerminalEvent(Duration(100, "ms"))
      dropSubscriber.assertNoErrors()
      dropSubscriber.assertReceivedOnNext(Seq(Completed()))

      verify(collection).drop()
      verifyNoMoreInteractions(collection)
    }

    "should insert documents" in {
      val collection = Mockito.mock(classOf[MongoCollection[Document]])
      val insertSubscriber = TestSubscriber[Completed]()
      when(collection.insertMany(any())).thenReturn(SingleObservable(Completed()))

      val documents: IndexedSeq[Document] = (1 to 100) map { i: Int => Document("_id" -> i) }
      subscribe(collection.insertMany(documents), insertSubscriber)
      insertSubscriber.requestMore(1)
      insertSubscriber.awaitTerminalEvent(Duration(100, "ms"))
      insertSubscriber.assertNoErrors()
      insertSubscriber.assertReceivedOnNext(Seq(Completed()))

      verify(collection).insertMany(eqTo(documents))
      verifyNoMoreInteractions(collection)
    }

    "should find documents" in {
      val documents: IndexedSeq[Document] = (1 to 100) map { i: Int => Document("_id" -> i) }
      val original = Mockito.mock(classOf[FindObservable[Document]])
      val findSubscriber = TestSubscriber[Document]()
      doNothing().when(original).subscribe(any())

      subscribe(original, findSubscriber)
      findSubscriber.assertNoTerminalEvent()
      findSubscriber.requestMore(101)
      documents.foreach(findSubscriber.onNext)
      findSubscriber.onComplete()
      findSubscriber.awaitTerminalEvent(Duration(100, "ms"))
      findSubscriber.assertNoErrors()
      findSubscriber.assertReceivedOnNext(documents)


      verify(original).subscribe(any(classOf[mongo.Observer[_ >: Document]]))
      verifyNoMoreInteractions(original)
    }
  }

  "A Mongo-Reactive observable" - new MockedObservableTests {
    override def subscribe[T](obs: mongo.Observable[T], testSubscriber: TestSubscriber[T]): Unit =
      obs.asReactive.subscribe(testSubscriber)
  }
  "A Mongo-Monix observable" - new MockedObservableTests {
    override def subscribe[T](obs: mongo.Observable[T], testSubscriber: TestSubscriber[T]): Unit =
      obs.asMonix.subscribe(
        monix.reactive.observers.Subscriber.fromReactiveSubscriber(testSubscriber, Cancelable.empty)(Scheduler(RunNowEC))
      )
  }
} 
Example 34
Source File: PathDirectives.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.admin.directives

import java.util.UUID

import akka.http.scaladsl.server.Directive1
import akka.http.scaladsl.server.Directives._
import ch.epfl.bluebrain.nexus.admin.index.{OrganizationCache, ProjectCache}
import monix.eval.Task
import monix.execution.Scheduler

import scala.util.Try

object PathDirectives {

  
  def project(implicit cache: ProjectCache[Task], s: Scheduler): Directive1[(String, String)] =
    pathPrefix(Segment / Segment).tflatMap {
      case (orgSegment, projSegment) =>
        Try((UUID.fromString(orgSegment), UUID.fromString(projSegment)))
          .map {
            case (orgUuid, projUuid) =>
              onSuccess(cache.get(orgUuid, projUuid).runToFuture).flatMap {
                case Some(resource) => provide((resource.value.organizationLabel, resource.value.label))
                case None           => provide((orgSegment, projSegment))
              }
          }
          .getOrElse(provide((orgSegment, projSegment)))
    }

} 
Example 35
Source File: RepairFromMessages.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.admin

import java.util.UUID

import akka.actor.ActorSystem
import akka.persistence.cassandra.query.scaladsl.CassandraReadJournal
import akka.persistence.query.PersistenceQuery
import ch.epfl.bluebrain.nexus.admin.organizations.Organizations
import ch.epfl.bluebrain.nexus.admin.projects.Projects
import com.typesafe.scalalogging.Logger
import monix.eval.Task
import monix.execution.Scheduler

import scala.concurrent.Future
import scala.util.Try


object RepairFromMessages {

  private val log = Logger[RepairFromMessages.type]

  def repair(
      o: Organizations[Task],
      p: Projects[Task]
  )(implicit as: ActorSystem, sc: Scheduler): Future[Unit] = {
    val pq = PersistenceQuery(as).readJournalFor[CassandraReadJournal](CassandraReadJournal.Identifier)

    pq.currentPersistenceIds()
      .mapAsync(1) {
        case OrgId(uuid)  => (o.fetch(uuid) >> Task.unit).runToFuture
        case ProjId(uuid) => (p.fetch(uuid) >> Task.unit).runToFuture
        case other        =>
          log.warn(s"Unknown persistence id '$other'")
          Future.successful(())
      }
      .runFold(0) {
        case (acc, _) =>
          if (acc % 100 == 0) log.info(s"Processed '$acc' persistence ids.")
          acc + 1
      }
      .map(_ => ())
  }

  sealed abstract class PersistenceId(prefix: String) {
    private val len                        = prefix.length
    def unapply(arg: String): Option[UUID] =
      if (arg.startsWith(prefix)) Try(UUID.fromString(arg.drop(len))).toOption
      else None
  }
  object OrgId extends PersistenceId("organizations-")
  object ProjId extends PersistenceId("projects-")
} 
Example 36
Source File: ProjectDirectives.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.kg.directives

import java.util.UUID

import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.{Directive0, Directive1}
import cats.implicits._
import ch.epfl.bluebrain.nexus.admin.client.AdminClient
import ch.epfl.bluebrain.nexus.admin.client.types.{Organization, Project}
import ch.epfl.bluebrain.nexus.iam.client.types.AuthToken
import ch.epfl.bluebrain.nexus.iam.types.Identity.Subject
import ch.epfl.bluebrain.nexus.kg.KgError.{OrganizationNotFound, ProjectIsDeprecated, ProjectNotFound}
import ch.epfl.bluebrain.nexus.kg.cache.ProjectCache
import ch.epfl.bluebrain.nexus.kg.config.Schemas
import ch.epfl.bluebrain.nexus.kg.resources.{OrganizationRef, ProjectInitializer}
import ch.epfl.bluebrain.nexus.kg.resources.ProjectIdentifier._
import ch.epfl.bluebrain.nexus.kg.resources.syntax._
import ch.epfl.bluebrain.nexus.rdf.Iri.AbsoluteIri
import ch.epfl.bluebrain.nexus.service.config.Vocabulary.nxv
import monix.eval.Task
import monix.execution.Scheduler

import scala.util.{Success, Try}

object ProjectDirectives {

  // TODO: Remove when migrating ADMIN client
  implicit private val fakeToken: Option[AuthToken] = None

  val defaultPrefixMapping: Map[String, AbsoluteIri] = Map(
    "resource"        -> Schemas.unconstrainedSchemaUri,
    "schema"          -> Schemas.shaclSchemaUri,
    "view"            -> Schemas.viewSchemaUri,
    "resolver"        -> Schemas.resolverSchemaUri,
    "file"            -> Schemas.fileSchemaUri,
    "storage"         -> Schemas.storageSchemaUri,
    "nxv"             -> nxv.base,
    "documents"       -> nxv.defaultElasticSearchIndex.value,
    "graph"           -> nxv.defaultSparqlIndex.value,
    "defaultResolver" -> nxv.defaultResolver.value,
    "defaultStorage"  -> nxv.defaultStorage.value
  )

  
  def projectNotDeprecated(implicit proj: Project): Directive0 =
    if (proj.deprecated) failWith(ProjectIsDeprecated(proj.projectLabel))
    else pass
} 
Example 37
Source File: RepairFromMessages.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.kg

import java.net.URLDecoder
import java.util.UUID

import akka.actor.ActorSystem
import akka.persistence.cassandra.query.scaladsl.CassandraReadJournal
import akka.persistence.query.PersistenceQuery
import ch.epfl.bluebrain.nexus.kg.resources.{Id, Repo, ResId}
import ch.epfl.bluebrain.nexus.kg.resources.ProjectIdentifier.ProjectRef
import ch.epfl.bluebrain.nexus.rdf.Iri
import com.typesafe.scalalogging.Logger
import monix.eval.Task
import monix.execution.Scheduler
import monix.execution.schedulers.CanBlock

import scala.concurrent.Future
import scala.util.Try


object RepairFromMessages {
  // $COVERAGE-OFF$

  private val log = Logger[RepairFromMessages.type]

  def repair(repo: Repo[Task])(implicit as: ActorSystem, sc: Scheduler, pm: CanBlock): Unit = {
    log.info("Repairing dependent tables from messages.")
    val pq = PersistenceQuery(as).readJournalFor[CassandraReadJournal](CassandraReadJournal.Identifier)
    Task
      .fromFuture {
        pq.currentPersistenceIds()
          .mapAsync(1) {
            case ResourceId(id) => (repo.get(id, None).value >> Task.unit).runToFuture
            case other          =>
              log.warn(s"Unknown persistence id '$other'")
              Future.successful(())
          }
          .runFold(0) {
            case (acc, _) =>
              if (acc % 1000 == 0) log.info(s"Processed '$acc' persistence ids.")
              acc + 1
          }
          .map(_ => ())
      }
      .runSyncUnsafe()
    log.info("Finished repairing dependent tables from messages.")
  }

  object ResourceId {
    private val regex                       =
      "^resources\\-([0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12})\\-(.+)$".r
    def unapply(arg: String): Option[ResId] =
      arg match {
        case regex(stringUuid, stringId) =>
          for {
            uuid <- Try(UUID.fromString(stringUuid)).toOption
            iri  <- Iri.absolute(URLDecoder.decode(stringId, "UTF-8")).toOption
          } yield Id(ProjectRef(uuid), iri)
        case _                           => None
      }
  }
  // $COVERAGE-ON$
} 
Example 38
Source File: RepairFromMessages.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.iam

import java.net.URLDecoder

import akka.actor.ActorSystem
import akka.persistence.cassandra.query.scaladsl.CassandraReadJournal
import akka.persistence.query.PersistenceQuery
import ch.epfl.bluebrain.nexus.iam.acls.Acls
import ch.epfl.bluebrain.nexus.iam.permissions.Permissions
import ch.epfl.bluebrain.nexus.iam.realms.Realms
import ch.epfl.bluebrain.nexus.iam.types.Label
import ch.epfl.bluebrain.nexus.rdf.Iri.Path
import com.typesafe.scalalogging.Logger
import monix.eval.Task
import monix.execution.Scheduler
import monix.execution.schedulers.CanBlock

import scala.concurrent.Future


object RepairFromMessages {
  // $COVERAGE-OFF$

  private val log = Logger[RepairFromMessages.type]

  def repair(
      p: Permissions[Task],
      r: Realms[Task],
      a: Acls[Task]
  )(implicit as: ActorSystem, sc: Scheduler, pm: CanBlock): Unit = {
    val pq = PersistenceQuery(as).readJournalFor[CassandraReadJournal](CassandraReadJournal.Identifier)

    pq.currentPersistenceIds()
      .mapAsync(1) {
        case PermissionsId() => p.agg.currentState(p.persistenceId).runToFuture
        case RealmId(label)  => r.agg.currentState(label.value).runToFuture
        case AclId(path)     => a.agg.currentState(path.asString).runToFuture
        case other           =>
          log.warn(s"Unknown persistence id '$other'")
          Future.successful(())
      }
      .runFold(0) {
        case (acc, _) =>
          if (acc % 100 == 0) log.info(s"Processed '$acc' persistence ids.")
          acc + 1
      }
      .runSyncDiscard()

    log.info("Repair from messages table completed.")
  }

  sealed abstract class PersistenceId(prefix: String) {
    private val len                                       = prefix.length
    protected def dropPrefix(arg: String): Option[String] =
      if (arg.startsWith(prefix)) Some(arg.drop(len))
      else None
  }
  object RealmId extends PersistenceId("realms-") {
    def unapply(arg: String): Option[Label] =
      dropPrefix(arg).map(Label.unsafe)
  }
  object AclId extends PersistenceId("acls-") {
    def unapply(arg: String): Option[Path] =
      dropPrefix(arg).flatMap(str => Path(URLDecoder.decode(str, "UTF-8")).toOption)
  }
  object PermissionsId                                {
    def unapply(arg: String): Boolean =
      arg == "permissions-permissions"
  }

  implicit class RichFuture[A](val future: Future[A]) extends AnyVal {
    def runSyncDiscard()(implicit s: Scheduler, permit: CanBlock): Unit =
      Task.fromFuture(future).map(_ => ()).runSyncUnsafe()
  }
  // $COVERAGE-ON$
} 
Example 39
Source File: AuthDirectives.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.service.directives

import akka.http.scaladsl.model.headers.OAuth2BearerToken
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.directives.Credentials
import akka.http.scaladsl.server.directives.FutureDirectives.onComplete
import akka.http.scaladsl.server.{Directive0, Directive1}
import cats.implicits._
import ch.epfl.bluebrain.nexus.admin.exceptions.AdminError.AuthorizationFailed
import ch.epfl.bluebrain.nexus.iam.acls.{AccessControlLists, Acls}
import ch.epfl.bluebrain.nexus.iam.auth.AccessToken
import ch.epfl.bluebrain.nexus.iam.realms.Realms
import ch.epfl.bluebrain.nexus.iam.types.IamError.InvalidAccessToken
import ch.epfl.bluebrain.nexus.iam.types.{Caller, Permission}
import ch.epfl.bluebrain.nexus.kg.KgError.AuthenticationFailed
import ch.epfl.bluebrain.nexus.rdf.Iri.{AbsoluteIri, Path}
import ch.epfl.bluebrain.nexus.rdf.Iri.Path._
import ch.epfl.bluebrain.nexus.rdf.implicits._
import ch.epfl.bluebrain.nexus.service.config.ServiceConfig.HttpConfig
import ch.epfl.bluebrain.nexus.service.exceptions.ServiceError.InternalError
import com.typesafe.scalalogging.Logger
import monix.eval.Task
import monix.execution.Scheduler

import scala.concurrent.Future
import scala.util.{Failure, Success}


  def extractCallerAcls(path: Path)(implicit c: Caller): Directive1[AccessControlLists] =
    onComplete(acls.list(path, ancestors = true, self = true).runToFuture).flatMap {
      case Success(AccessControlLists.empty) => failWith(AuthorizationFailed)
      case Success(result)                   => provide(result)
      case Failure(err)                      =>
        val message = "Error when trying to check for permissions"
        logger.error(message, err)
        failWith(InternalError(message))
    }
} 
Example 40
Source File: instances.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.service.marshallers

import akka.http.scaladsl.marshalling.GenericMarshallers.eitherMarshaller
import akka.http.scaladsl.marshalling._
import akka.http.scaladsl.model.MediaTypes.`application/json`
import akka.http.scaladsl.model._
import ch.epfl.bluebrain.nexus.admin.exceptions.AdminError
import ch.epfl.bluebrain.nexus.admin.organizations.OrganizationRejection
import ch.epfl.bluebrain.nexus.admin.projects.ProjectRejection
import ch.epfl.bluebrain.nexus.commons.circe.syntax._
import ch.epfl.bluebrain.nexus.commons.http.JsonLdCirceSupport.OrderedKeys
import ch.epfl.bluebrain.nexus.commons.http.RdfMediaTypes._
import ch.epfl.bluebrain.nexus.commons.http.directives.StatusFrom
import ch.epfl.bluebrain.nexus.iam.acls.AclRejection
import ch.epfl.bluebrain.nexus.iam.permissions.PermissionsRejection
import ch.epfl.bluebrain.nexus.iam.realms.RealmRejection
import ch.epfl.bluebrain.nexus.service.config.ServiceConfig.orderedKeys
import ch.epfl.bluebrain.nexus.service.exceptions.ServiceError
import ch.epfl.bluebrain.nexus.service.exceptions.ServiceError.InternalError
import ch.epfl.bluebrain.nexus.service.routes.ResourceRejection
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport
import io.circe._
import io.circe.syntax._
import monix.eval.Task
import monix.execution.Scheduler

import scala.collection.immutable.Seq
import scala.concurrent.Future
import scala.concurrent.duration.FiniteDuration

object instances extends FailFastCirceSupport {

  implicit val finiteDurationEncoder: Encoder[FiniteDuration] =
    Encoder.encodeString.contramap(fd => s"${fd.toMillis} ms")

  implicit val resourceRejectionEncoder: Encoder[ResourceRejection] =
    Encoder.instance {
      case r: ProjectRejection      => Encoder[ProjectRejection].apply(r)
      case r: OrganizationRejection => Encoder[OrganizationRejection].apply(r)
      case r: AclRejection          => Encoder[AclRejection].apply(r)
      case r: RealmRejection        => Encoder[RealmRejection].apply(r)
      case r: PermissionsRejection  => Encoder[PermissionsRejection].apply(r)
      case _                        => Encoder[ServiceError].apply(InternalError("unspecified"))
    }

  implicit val resourceRejectionStatusFrom: StatusFrom[ResourceRejection] =
    StatusFrom {
      case r: OrganizationRejection => OrganizationRejection.organizationStatusFrom(r)
      case r: ProjectRejection      => ProjectRejection.projectStatusFrom(r)
      case r: AclRejection          => AclRejection.aclRejectionStatusFrom(r)
      case r: RealmRejection        => RealmRejection.realmRejectionStatusFrom(r)
      case r: PermissionsRejection  => PermissionsRejection.permissionsRejectionStatusFrom(r)
    }

  override def unmarshallerContentTypes: Seq[ContentTypeRange] =
    List(`application/json`, `application/ld+json`, `application/sparql-results+json`)

  
  implicit final def rejection[A <: ResourceRejection: Encoder](implicit
      statusFrom: StatusFrom[A],
      printer: Printer = Printer.noSpaces.copy(dropNullValues = true),
      ordered: OrderedKeys = orderedKeys
  ): ToResponseMarshaller[A] = {
    val marshallers = Seq(`application/ld+json`, `application/json`).map { contentType =>
      Marshaller.withFixedContentType[A, HttpResponse](contentType) { rejection =>
        HttpResponse(
          status = statusFrom(rejection),
          entity = HttpEntity(contentType, printer.print(rejection.asJson.sortKeys))
        )
      }
    }
    Marshaller.oneOf(marshallers: _*)
  }

  implicit class EitherTask[R <: ResourceRejection, A](task: Task[Either[R, A]])(implicit s: Scheduler) {
    def runWithStatus(code: StatusCode): Future[Either[R, (StatusCode, A)]] =
      task.map(_.map(code -> _)).runToFuture
  }

  implicit class OptionTask[A](task: Task[Option[A]])(implicit s: Scheduler) {
    def runNotFound: Future[A] =
      task.flatMap {
        case Some(a) => Task.pure(a)
        case None    => Task.raiseError(AdminError.NotFound)
      }.runToFuture
  }
} 
Example 41
Source File: instances.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.storage.routes

import akka.http.scaladsl.marshalling.GenericMarshallers.eitherMarshaller
import akka.http.scaladsl.marshalling._
import akka.http.scaladsl.model.MediaTypes._
import akka.http.scaladsl.model._
import ch.epfl.bluebrain.nexus.commons.http.RdfMediaTypes._
import ch.epfl.bluebrain.nexus.storage.JsonLdCirceSupport.sortKeys
import ch.epfl.bluebrain.nexus.storage.JsonLdCirceSupport.OrderedKeys
import ch.epfl.bluebrain.nexus.storage.Rejection
import ch.epfl.bluebrain.nexus.storage.config.AppConfig._
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport
import io.circe._
import io.circe.syntax._
import monix.eval.Task
import monix.execution.Scheduler

import scala.collection.immutable.Seq
import scala.concurrent.Future

object instances extends LowPriority {

  
  implicit final def valueWithStatusCodeMarshaller[A: Encoder](implicit
      printer: Printer = defaultPrinter,
      keys: OrderedKeys = orderedKeys
  ): ToResponseMarshaller[(StatusCode, A)] =
    jsonLdWithStatusCodeMarshaller.compose { case (status, value) => status -> value.asJson }

  private[routes] def onOf[A, Response](
      fMarshaller: MediaType.WithFixedCharset => Marshaller[A, Response]
  ): Marshaller[A, Response] = {
    val marshallers = Seq(`application/ld+json`, `application/json`).map(fMarshaller)
    Marshaller.oneOf(marshallers: _*)
  }
} 
Example 42
Source File: Main.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.storage

import java.nio.file.Paths
import java.time.Clock

import akka.actor.ActorSystem
import akka.event.{Logging, LoggingAdapter}
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Route
import akka.util.Timeout
import cats.effect.Effect
import ch.epfl.bluebrain.nexus.storage.Storages.DiskStorage
import ch.epfl.bluebrain.nexus.storage.attributes.AttributesCache
import ch.epfl.bluebrain.nexus.storage.config.{AppConfig, Settings}
import ch.epfl.bluebrain.nexus.storage.config.AppConfig._
import ch.epfl.bluebrain.nexus.storage.routes.Routes
import com.typesafe.config.{Config, ConfigFactory}
import kamon.Kamon
import monix.eval.Task
import monix.execution.Scheduler

import scala.concurrent.duration._
import scala.concurrent.{Await, ExecutionContext, Future}
import scala.util.{Failure, Success}

//noinspection TypeAnnotation
// $COVERAGE-OFF$
object Main {

  def loadConfig(): Config = {
    val cfg = sys.env.get("STORAGE_CONFIG_FILE") orElse sys.props.get("storage.config.file") map { str =>
      val file = Paths.get(str).toAbsolutePath.toFile
      ConfigFactory.parseFile(file)
    } getOrElse ConfigFactory.empty()
    (cfg withFallback ConfigFactory.load()).resolve()
  }

  def setupMonitoring(config: Config): Unit = {
    if (sys.env.getOrElse("KAMON_ENABLED", "false").toBoolean) {
      Kamon.reconfigure(config)
      Kamon.loadModules()
    }
  }

  def shutdownMonitoring(): Unit = {
    if (sys.env.getOrElse("KAMON_ENABLED", "false").toBoolean) {
      Await.result(Kamon.stopModules(), 10.seconds)
    }
  }

  @SuppressWarnings(Array("UnusedMethodParameter"))
  def main(args: Array[String]): Unit = {
    val config = loadConfig()
    setupMonitoring(config)

    implicit val appConfig: AppConfig = Settings(config).appConfig

    implicit val as: ActorSystem                          = ActorSystem(appConfig.description.fullName, config)
    implicit val ec: ExecutionContext                     = as.dispatcher
    implicit val eff: Effect[Task]                        = Task.catsEffect(Scheduler.global)
    implicit val iamIdentities: IamIdentitiesClient[Task] = new IamIdentitiesClient[Task](appConfig.iam)
    implicit val timeout                                  = Timeout(1.minute)
    implicit val clock                                    = Clock.systemUTC

    val storages: Storages[Task, AkkaSource] =
      new DiskStorage(appConfig.storage, appConfig.digest, AttributesCache[Task, AkkaSource])

    val logger: LoggingAdapter = Logging(as, getClass)

    logger.info("==== Cluster is Live ====")
    val routes: Route = Routes(storages)

    val httpBinding: Future[Http.ServerBinding] = {
      Http().bindAndHandle(routes, appConfig.http.interface, appConfig.http.port)
    }
    httpBinding onComplete {
      case Success(binding) =>
        logger.info(s"Bound to ${binding.localAddress.getHostString}: ${binding.localAddress.getPort}")
      case Failure(th)      =>
        logger.error(th, "Failed to perform an http binding on {}:{}", appConfig.http.interface, appConfig.http.port)
        Await.result(as.terminate(), 10.seconds)
    }

    as.registerOnTermination {
      shutdownMonitoring()
    }
    // attempt to leave the cluster before shutting down
    val _ = sys.addShutdownHook {
      Await.result(as.terminate().map(_ => ()), 10.seconds)
    }
  }
}
// $COVERAGE-ON$ 
Example 43
Source File: SimpleWebSocketActor.scala    From monix-sample   with Apache License 2.0 5 votes vote down vote up
package engine

import akka.actor.{Actor, ActorRef, Props}
import engine.SimpleWebSocketActor.Next
import monix.execution.Scheduler
import monix.reactive.Observable
import monix.execution.Ack.Continue
import monix.execution.cancelables.CompositeCancelable
import org.joda.time.{DateTime, DateTimeZone}
import play.api.libs.json.{JsValue, Json, Writes}

import scala.concurrent.duration._
import engine.BackPressuredWebSocketActor._


class SimpleWebSocketActor[T: Writes]
  (producer: Observable[T], out: ActorRef)(implicit s: Scheduler)
  extends Actor {

  def receive: Receive = {
    case Next(jsValue) =>
      out ! jsValue
  }

  private[this] val subscription =
    CompositeCancelable()

  override def preStart(): Unit = {
    super.preStart()

    val source = {
      val initial = Observable.evalOnce(initMessage(now()))
      val obs = initial ++ producer.map(x => Json.toJson(x))
      val timeout = obs.debounce(3.seconds).map(_ => keepAliveMessage(now()))
      Observable.merge(obs, timeout)
    }

    subscription += source.subscribe { jsValue =>
      self ! Next(jsValue)
      Continue
    }
  }

  override def postStop(): Unit = {
    subscription.cancel()
    super.postStop()
  }

  def now(): Long =
    DateTime.now(DateTimeZone.UTC).getMillis
}

object SimpleWebSocketActor {
  
  case class Next(value: JsValue)
} 
Example 44
Source File: BackPressuredWebSocketActor.scala    From monix-sample   with Apache License 2.0 5 votes vote down vote up
package engine

import akka.actor.{Actor, ActorRef, Props}
import com.typesafe.scalalogging.LazyLogging
import engine.BackPressuredWebSocketActor._
import monix.execution.Scheduler
import monix.execution.rstreams.SingleAssignmentSubscription
import monix.reactive.Observable
import org.reactivestreams.{Subscriber, Subscription}
import play.api.libs.json._

import scala.concurrent.duration._
import scala.util.Try


class BackPressuredWebSocketActor[T: Writes]
  (producer: Observable[T], out: ActorRef)(implicit s: Scheduler)
  extends Actor with LazyLogging {

  def receive: Receive = {
    case JsNumber(nr) if nr > 0 =>
      Try(nr.toLongExact).foreach(subscription.request)
  }

  private[this] val subscription = SingleAssignmentSubscription()

  def now(): Long =
    System.currentTimeMillis()

  override def preStart(): Unit = {
    super.preStart()

    val source = {
      val initial = Observable.evalOnce(initMessage(now()))
      val obs = initial ++ producer.map(x => Json.toJson(x))
      val timeout = obs.debounceRepeated(5.seconds).map(_ => keepAliveMessage(now()))

      Observable
        .merge(obs, timeout)
        .whileBusyDropEventsAndSignal(nr => onOverflow(nr, now()))
    }

    source.toReactivePublisher.subscribe(new Subscriber[JsValue] {
      def onSubscribe(s: Subscription): Unit = {
        subscription := s
      }

      def onNext(json: JsValue): Unit = {
        out ! json
      }

      def onError(t: Throwable): Unit = {
        logger.warn(s"Error while serving a web-socket stream", t)
        out ! Json.obj(
          "event" -> "error",
          "type" -> t.getClass.getName,
          "message" -> t.getMessage,
          "timestamp" -> now())

        context.stop(self)
      }

      def onComplete(): Unit = {
        out ! Json.obj("event" -> "complete", "timestamp" -> now())
        context.stop(self)
      }
    })
  }

  override def postStop(): Unit = {
    subscription.cancel()
    super.postStop()
  }
}

object BackPressuredWebSocketActor {
  
  def initMessage(now: Long) = {
    Json.obj("event" -> "init", "timestamp" -> now)
  }
} 
Example 45
Source File: Runner.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.context.monix
import io.getquill.context.ContextEffect
import monix.eval.Task
import monix.execution.Scheduler
import monix.reactive.Observable

object Runner {
  def default = new Runner {}
  def using(scheduler: Scheduler) = new Runner {
    override def schedule[T](t: Task[T]): Task[T] = t.executeOn(scheduler, true)
    override def boundary[T](t: Task[T]): Task[T] = t.executeOn(scheduler, true)
    override def scheduleObservable[T](o: Observable[T]): Observable[T] = o.executeOn(scheduler, true)
  }
}

trait Runner extends ContextEffect[Task] {
  override def wrap[T](t: => T): Task[T] = Task(t)
  override def push[A, B](result: Task[A])(f: A => B): Task[B] = result.map(f)
  override def seq[A, B](list: List[Task[A]]): Task[List[A]] = Task.sequence(list)
  def schedule[T](t: Task[T]): Task[T] = t
  def scheduleObservable[T](o: Observable[T]): Observable[T] = o
  def boundary[T](t: Task[T]): Task[T] = t.asyncBoundary

  
  def wrapClose(t: => Unit): Task[Unit] = Task(t)
} 
Example 46
Source File: RunnerSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.context.monix

import io.getquill.Spec
import monix.eval.Task
import monix.execution.Scheduler
import monix.execution.schedulers.CanBlock
import org.scalatest.matchers.should.Matchers._

import scala.util.Failure

class RunnerSpec extends Spec {

  class SideEffect {
    private var state = 0
    def apply() = state = 1
    def applied = state == 1
  }

  implicit val scheduler = Scheduler.global

  "plain runner" - {
    val runner = Runner.default
    import runner._

    "should lazily evaluate" in {
      val sideEffect = new SideEffect
      val task = wrap(sideEffect())
      sideEffect.applied should equal(false)
      task.runSyncUnsafe()
      sideEffect.applied should equal(true)
    }

    "should encapsulate exception throw" in {
      wrap(throw new RuntimeException("Surprise!")).materialize.runSyncUnsafe() should matchPattern {
        case Failure(e) if (e.getMessage == "Surprise!") =>
      }
    }

    "should push an effect correctly" in {
      push(Task(1))(_ + 1).runSyncUnsafe() should equal(2)
    }

    "should convert a sequence correctly" in {
      seq(List(Task(1), Task(2), Task(3))).runSyncUnsafe() should equal(List(1, 2, 3))
    }

    "plain schedule should be a no-op" in {
      val t = Task(1)
      (schedule(t) eq (t)) must equal(true)
    }

    "boundary operator must force async boundary" in {
      val (first, second) =
        boundary(Task(Thread.currentThread().getName))
          .flatMap(prevName => Task((prevName, Thread.currentThread().getName)))
          .runSyncUnsafe()
      first must not equal (second)
    }
  }

  "using scheduler runner" - {
    val prefix = "quill-test-pool"
    val customScheduler = Scheduler.io(prefix)
    val runner = Runner.using(customScheduler)
    import runner._

    "should run in specified scheduler" in {
      // the global scheduler is imported but want to explicitly tell this to run on it, just for clarity
      val threadName =
        schedule(Task(Thread.currentThread().getName)).runSyncUnsafe()(Scheduler.global, CanBlock.permit)

      threadName.startsWith(prefix) must equal(true)
    }

    "should async-boundary in specified scheduler" in {
      // the global scheduler is imported but want to explicitly tell this to run on it, just for clarity
      val threadName =
        boundary(Task(Thread.currentThread().getName)).runSyncUnsafe()(Scheduler.global, CanBlock.permit)

      threadName.startsWith(prefix) must equal(true)
    }

    "should async-boundary correctly" in {
      val prefix2 = "quill-test-pool2"
      // the global scheduler is imported but want to explicitly tell this to run on it, just for clarity
      val (first, second) =
        Task(Thread.currentThread().getName)
          .executeOn(Scheduler.io(prefix2))
          .flatMap(prevName => boundary(Task((prevName, Thread.currentThread().getName))))
          .runSyncUnsafe()(Scheduler.global, CanBlock.permit)

      first.startsWith(prefix2) must equal(true)
      second.startsWith(prefix) must equal(true)
      first must not equal second
    }
  }
} 
Example 47
Source File: CassandraStreamContext.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill

import com.datastax.driver.core.{ Cluster, ResultSet, Row }
import com.typesafe.config.Config
import io.getquill.context.cassandra.util.FutureConversions._
import io.getquill.util.{ ContextLogger, LoadConfig }
import monix.eval.Task
import monix.execution.Scheduler
import monix.execution.Scheduler.Implicits
import monix.reactive.Observable

import scala.jdk.CollectionConverters._
import scala.util.{ Failure, Success }

class CassandraStreamContext[N <: NamingStrategy](
  naming:                     N,
  cluster:                    Cluster,
  keyspace:                   String,
  preparedStatementCacheSize: Long
)
  extends CassandraClusterSessionContext[N](naming, cluster, keyspace, preparedStatementCacheSize) {

  def this(naming: N, config: CassandraContextConfig) = this(naming, config.cluster, config.keyspace, config.preparedStatementCacheSize)
  def this(naming: N, config: Config) = this(naming, CassandraContextConfig(config))
  def this(naming: N, configPrefix: String) = this(naming, LoadConfig(configPrefix))

  private val logger = ContextLogger(classOf[CassandraStreamContext[_]])

  override type Result[T] = Observable[T]
  override type RunQueryResult[T] = T
  override type RunQuerySingleResult[T] = T
  override type RunActionResult = Unit
  override type RunBatchActionResult = Unit

  protected def page(rs: ResultSet): Task[Iterable[Row]] = Task.defer {
    val available = rs.getAvailableWithoutFetching
    val page = rs.asScala.take(available)

    if (rs.isFullyFetched)
      Task.now(page)
    else
      Task.fromFuture(rs.fetchMoreResults().asScala(Implicits.global)).map(_ => page)
  }

  def executeQuery[T](cql: String, prepare: Prepare = identityPrepare, extractor: Extractor[T] = identityExtractor): Observable[T] = {

    Observable
      .fromTask(prepareRowAndLog(cql, prepare))
      .mapEvalF(p => session.executeAsync(p).asScala(Implicits.global))
      .flatMap(Observable.fromAsyncStateAction((rs: ResultSet) => page(rs).map((_, rs)))(_))
      .takeWhile(_.nonEmpty)
      .flatMap(Observable.fromIterable)
      .map(extractor)
  }

  def executeQuerySingle[T](cql: String, prepare: Prepare = identityPrepare, extractor: Extractor[T] = identityExtractor): Observable[T] =
    executeQuery(cql, prepare, extractor)

  def executeAction[T](cql: String, prepare: Prepare = identityPrepare): Observable[Unit] = {
    Observable
      .fromTask(prepareRowAndLog(cql, prepare))
      .mapEvalF(p => session.executeAsync(p).asScala(Implicits.global))
      .map(_ => ())
  }

  def executeBatchAction(groups: List[BatchGroup]): Observable[Unit] =
    Observable.fromIterable(groups).flatMap {
      case BatchGroup(cql, prepare) =>
        Observable.fromIterable(prepare)
          .flatMap(executeAction(cql, _))
          .map(_ => ())
    }

  private def prepareRowAndLog(cql: String, prepare: Prepare = identityPrepare): Task[PrepareRow] = {
    Task.async0[PrepareRow] { (scheduler, callback) =>
      implicit val executor: Scheduler = scheduler

      super.prepareAsync(cql)
        .map(prepare)
        .onComplete {
          case Success((params, bs)) =>
            logger.logQuery(cql, params)
            callback.onSuccess(bs)
          case Failure(ex) =>
            callback.onError(ex)
        }
    }
  }
} 
Example 48
Source File: CassandraMonixContext.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill

import com.datastax.driver.core.{ Cluster, ResultSet, Row }
import com.typesafe.config.Config
import io.getquill.context.cassandra.CqlIdiom
import io.getquill.context.monix.{ MonixContext, Runner }
import io.getquill.util.{ ContextLogger, LoadConfig }
import io.getquill.context.cassandra.util.FutureConversions._
import monix.eval.Task
import monix.execution.Scheduler
import monix.reactive.Observable

import scala.jdk.CollectionConverters._
import scala.util.{ Failure, Success }

class CassandraMonixContext[N <: NamingStrategy](
  naming:                     N,
  cluster:                    Cluster,
  keyspace:                   String,
  preparedStatementCacheSize: Long
)
  extends CassandraClusterSessionContext[N](naming, cluster, keyspace, preparedStatementCacheSize)
  with MonixContext[CqlIdiom, N] {

  // not using this here
  override val effect = Runner.default

  def this(naming: N, config: CassandraContextConfig) = this(naming, config.cluster, config.keyspace, config.preparedStatementCacheSize)
  def this(naming: N, config: Config) = this(naming, CassandraContextConfig(config))
  def this(naming: N, configPrefix: String) = this(naming, LoadConfig(configPrefix))

  private val logger = ContextLogger(classOf[CassandraMonixContext[_]])

  override type StreamResult[T] = Observable[T]
  override type RunActionResult = Unit
  override type Result[T] = Task[T]

  override type RunQueryResult[T] = List[T]
  override type RunQuerySingleResult[T] = T
  override type RunBatchActionResult = Unit

  protected def page(rs: ResultSet): Task[Iterable[Row]] = Task.defer {
    val available = rs.getAvailableWithoutFetching
    val page = rs.asScala.take(available)

    if (rs.isFullyFetched)
      Task.now(page)
    else
      Task.fromFuture(rs.fetchMoreResults().asScalaWithDefaultGlobal).map(_ => page)
  }

  def streamQuery[T](fetchSize: Option[Int], cql: String, prepare: Prepare = identityPrepare, extractor: Extractor[T] = identityExtractor): Observable[T] = {

    Observable
      .fromTask(prepareRowAndLog(cql, prepare))
      .mapEvalF(p => session.executeAsync(p).asScalaWithDefaultGlobal)
      .flatMap(Observable.fromAsyncStateAction((rs: ResultSet) => page(rs).map((_, rs)))(_))
      .takeWhile(_.nonEmpty)
      .flatMap(Observable.fromIterable)
      .map(extractor)
  }

  def executeQuery[T](cql: String, prepare: Prepare = identityPrepare, extractor: Extractor[T] = identityExtractor): Task[List[T]] = {
    streamQuery[T](None, cql, prepare, extractor)
      .foldLeftL(List[T]())({ case (l, r) => r +: l }).map(_.reverse)
  }

  def executeQuerySingle[T](cql: String, prepare: Prepare = identityPrepare, extractor: Extractor[T] = identityExtractor): Task[T] =
    executeQuery(cql, prepare, extractor).map(handleSingleResult(_))

  def executeAction[T](cql: String, prepare: Prepare = identityPrepare): Task[Unit] = {
    prepareRowAndLog(cql, prepare)
      .flatMap(r => Task.fromFuture(session.executeAsync(r).asScalaWithDefaultGlobal))
      .map(_ => ())
  }

  def executeBatchAction(groups: List[BatchGroup]): Task[Unit] =
    Observable.fromIterable(groups).flatMap {
      case BatchGroup(cql, prepare) =>
        Observable.fromIterable(prepare)
          .flatMap(prep => Observable.fromTask(executeAction(cql, prep)))
          .map(_ => ())
    }.completedL

  private def prepareRowAndLog(cql: String, prepare: Prepare = identityPrepare): Task[PrepareRow] = {
    Task.async0[PrepareRow] { (scheduler, callback) =>
      implicit val executor: Scheduler = scheduler

      super.prepareAsync(cql)
        .map(prepare)
        .onComplete {
          case Success((params, bs)) =>
            logger.logQuery(cql, params)
            callback.onSuccess(bs)
          case Failure(ex) =>
            callback.onError(ex)
        }
    }
  }
} 
Example 49
Source File: StreamResultsOrBlowUpSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.integration

import java.sql.{ Connection, ResultSet }

import io.getquill._
import io.getquill.context.monix.Runner
import monix.execution.Scheduler
import monix.execution.schedulers.CanBlock
import org.scalatest.matchers.should.Matchers._

import scala.concurrent.duration.Duration


class StreamResultsOrBlowUpSpec extends Spec {

  case class Person(name: String, age: Int)

  private implicit val scheduler = Scheduler.io()

  // set to true in order to create a ResultSet type (i.e. a rewindable one)
  // that will force jdbc to load the entire ResultSet into memory and crash this test.
  val doBlowUp = false

  val ctx = new PostgresMonixJdbcContext(Literal, "testPostgresDB", Runner.default) {
    override protected def prepareStatementForStreaming(sql: String, conn: Connection, fetchSize: Option[Int]) = {
      val stmt =
        conn.prepareStatement(
          sql,
          if (doBlowUp) ResultSet.TYPE_SCROLL_SENSITIVE
          else ResultSet.TYPE_FORWARD_ONLY,
          ResultSet.CONCUR_READ_ONLY
        )
      fetchSize.foreach(stmt.setFetchSize(_))
      stmt
    }
  }
  import ctx.{ run => runQuill, _ }

  val numRows = 1000000L

  "stream a large result set without blowing up" in {
    val deletes = runQuill { query[Person].delete }
    deletes.runSyncUnsafe(Duration.Inf)(scheduler, CanBlock.permit)

    val inserts = quote {
      (numRows: Long) =>
        infix"""insert into person (name, age) select md5(random()::text), random()*10+1 from generate_series(1, ${numRows}) s(i)""".as[Insert[Int]]
    }

    runQuill(inserts(lift(numRows))).runSyncUnsafe(Duration.Inf)(scheduler, CanBlock.permit)

    // not sure why but foreachL causes a OutOfMemory exception anyhow, and firstL causes a ResultSet Closed exception
    val result = stream(query[Person], 100)
      .zipWithIndex
      .foldLeftL(0L)({
        case (totalYears, (person, index)) => {
          // Need to print something out as we stream or travis will thing the build is stalled and kill it with the following message:
          // "No output has been received in the last 10m0s..."
          if (index % 10000 == 0) println(s"Streaming Test Row: ${index}")
          totalYears + person.age
        }
      })
      .runSyncUnsafe(Duration.Inf)(scheduler, CanBlock.permit)
    result should be > numRows
  }
} 
Example 50
Source File: PeopleMonixSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill
import io.getquill.context.monix.MonixJdbcContext
import io.getquill.context.sql.PeopleSpec
import monix.execution.Scheduler
import monix.reactive.Observable

trait PeopleMonixSpec extends PeopleSpec {

  implicit val scheduler = Scheduler.global

  val context: MonixJdbcContext[_, _]

  import context._

  def collect[T](o: Observable[T]) =
    o.foldLeft(List[T]())({ case (l, elem) => elem +: l })
      .firstL
      .runSyncUnsafe()

  val `Ex 11 query` = quote(query[Person])
  val `Ex 11 expected` = peopleEntries
} 
Example 51
Source File: ProductJdbcSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.oracle

import io.getquill.context.sql.ProductSpec
import monix.eval.Task
import monix.execution.Scheduler

class ProductJdbcSpec extends ProductSpec {

  val context = testContext
  import testContext._

  implicit val scheduler = Scheduler.global

  override def beforeAll = {
    testContext.run(quote(query[Product].delete)).runSyncUnsafe()
    ()
  }

  "Product" - {
    "Insert multiple products" in {
      val (inserted, product) =
        (for {
          i <- Task.sequence(productEntries.map(product => testContext.run(productInsert(lift(product)))))
          ps <- testContext.run(productById(lift(i(2))))
        } yield (i, ps.head)).runSyncUnsafe()

      product.description mustEqual productEntries(2).description
      product.id mustEqual inserted(2)
    }

    "Single insert product" in {
      val (inserted, product) =
        (for {
          i <- testContext.run(productSingleInsert)
          ps <- testContext.run(productById(lift(i)))
        } yield (i, ps.head)).runSyncUnsafe()
      product.description mustEqual "Window"
      product.id mustEqual inserted
    }

    "Single insert with inlined free variable" in {
      val prd = Product(0L, "test1", 1L)
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run {
            product.insert(_.sku -> lift(prd.sku), _.description -> lift(prd.description)).returning(_.id)
          }
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test1"
      returnedProduct.sku mustEqual 1L
      returnedProduct.id mustEqual inserted
    }

    "Single insert with free variable and explicit quotation" in {
      val prd = Product(0L, "test2", 2L)
      val q1 = quote {
        product.insert(_.sku -> lift(prd.sku), _.description -> lift(prd.description)).returning(_.id)
      }
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run(q1)
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test2"
      returnedProduct.sku mustEqual 2L
      returnedProduct.id mustEqual inserted
    }

    "Single product insert with a method quotation" in {
      val prd = Product(0L, "test3", 3L)
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run(productInsert(lift(prd)))
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test3"
      returnedProduct.sku mustEqual 3L
      returnedProduct.id mustEqual inserted
    }
  }
} 
Example 52
Source File: PrepareJdbcSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.oracle

import java.sql.ResultSet

import io.getquill.PrepareMonixJdbcSpecBase
import monix.execution.Scheduler
import org.scalatest.BeforeAndAfter

class PrepareJdbcSpec extends PrepareMonixJdbcSpecBase with BeforeAndAfter {

  val context = testContext
  import testContext._
  implicit val scheduler = Scheduler.global

  before {
    testContext.run(query[Product].delete).runSyncUnsafe()
  }

  def productExtractor = (rs: ResultSet) => materializeQueryMeta[Product].extract(rs)
  val prepareQuery = prepare(query[Product])

  "single" in {
    val prepareInsert = prepare(query[Product].insert(lift(productEntries.head)))
    singleInsert(dataSource.getConnection)(prepareInsert).runSyncUnsafe() mustEqual false
    extractProducts(dataSource.getConnection)(prepareQuery).runSyncUnsafe() === List(productEntries.head)
  }

  "batch" in {
    val prepareBatchInsert = prepare(
      liftQuery(withOrderedIds(productEntries)).foreach(p => query[Product].insert(p))
    )

    batchInsert(dataSource.getConnection)(prepareBatchInsert).runSyncUnsafe().distinct mustEqual List(false)
    extractProducts(dataSource.getConnection)(prepareQuery).runSyncUnsafe() === withOrderedIds(productEntries)
  }
} 
Example 53
Source File: ConnectionLeakTest.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.postgres

import java.util.UUID

import io.getquill.context.monix.Runner
import io.getquill.{ JdbcContextConfig, Literal, PostgresMonixJdbcContext }
import io.getquill.context.sql.ProductSpec
import io.getquill.util.LoadConfig
import monix.execution.Scheduler

import scala.util.Random

class ConnectionLeakTest extends ProductSpec {

  implicit val scheduler = Scheduler.global

  val dataSource = JdbcContextConfig(LoadConfig("testPostgresLeakDB")).dataSource

  val context = new PostgresMonixJdbcContext(Literal, dataSource, Runner.default)
  import context._

  override def beforeAll = {
    context.run(quote(query[Product].delete)).runSyncUnsafe()
    ()
  }

  "insert and select without leaking" in {
    val result =
      context.transaction {
        for {
          _ <- context.run {
            quote {
              query[Product].insert(
                lift(Product(1, UUID.randomUUID().toString, Random.nextLong()))
              )
            }
          }
          result <- context.run {
            query[Product].filter(p => query[Product].map(_.id).max.exists(_ == p.id))
          }
        } yield (result)
      }
        .map(_.headOption.map(_.id))
        .runSyncUnsafe()

    Thread.sleep(2000)

    result mustEqual Option(1)
    dataSource.getHikariPoolMXBean.getActiveConnections mustEqual 0

    context.close()
  }

} 
Example 54
Source File: ProductJdbcSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.postgres

import io.getquill.context.sql.ProductSpec
import monix.execution.Scheduler

class ProductJdbcSpec extends ProductSpec {

  val context = testContext
  import testContext._

  implicit val scheduler = Scheduler.global

  override def beforeAll = {
    testContext.run(quote(query[Product].delete)).runSyncUnsafe()
    ()
  }

  "Product" - {
    "Insert multiple products" in {
      val (inserted, product) =
        (for {
          i <- testContext.run(liftQuery(productEntries).foreach(e => productInsert(e)))
          ps <- testContext.run(productById(lift(i(2))))
        } yield (i, ps.head)).runSyncUnsafe()

      product.description mustEqual productEntries(2).description
      product.id mustEqual inserted(2)
    }

    "Single insert product" in {
      val (inserted, product) =
        (for {
          i <- testContext.run(productSingleInsert)
          ps <- testContext.run(productById(lift(i)))
        } yield (i, ps.head)).runSyncUnsafe()
      product.description mustEqual "Window"
      product.id mustEqual inserted
    }

    "Single insert with inlined free variable" in {
      val prd = Product(0L, "test1", 1L)
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run {
            product.insert(_.sku -> lift(prd.sku), _.description -> lift(prd.description)).returning(_.id)
          }
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test1"
      returnedProduct.sku mustEqual 1L
      returnedProduct.id mustEqual inserted
    }

    "Single insert with free variable and explicit quotation" in {
      val prd = Product(0L, "test2", 2L)
      val q1 = quote {
        product.insert(_.sku -> lift(prd.sku), _.description -> lift(prd.description)).returning(_.id)
      }
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run(q1)
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test2"
      returnedProduct.sku mustEqual 2L
      returnedProduct.id mustEqual inserted
    }

    "Single product insert with a method quotation" in {
      val prd = Product(0L, "test3", 3L)
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run(productInsert(lift(prd)))
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test3"
      returnedProduct.sku mustEqual 3L
      returnedProduct.id mustEqual inserted
    }
  }
} 
Example 55
Source File: PrepareJdbcSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.postgres

import java.sql.ResultSet

import io.getquill.PrepareMonixJdbcSpecBase
import monix.execution.Scheduler
import org.scalatest.BeforeAndAfter

class PrepareJdbcSpec extends PrepareMonixJdbcSpecBase with BeforeAndAfter {

  val context = testContext
  import testContext._
  implicit val scheduler = Scheduler.global

  before {
    testContext.run(query[Product].delete).runSyncUnsafe()
  }

  def productExtractor = (rs: ResultSet) => materializeQueryMeta[Product].extract(rs)
  val prepareQuery = prepare(query[Product])

  "single" in {
    val prepareInsert = prepare(query[Product].insert(lift(productEntries.head)))
    singleInsert(dataSource.getConnection)(prepareInsert).runSyncUnsafe() mustEqual false
    extractProducts(dataSource.getConnection)(prepareQuery).runSyncUnsafe() === List(productEntries.head)
  }

  "batch" in {
    val prepareBatchInsert = prepare(
      liftQuery(withOrderedIds(productEntries)).foreach(p => query[Product].insert(p))
    )

    batchInsert(dataSource.getConnection)(prepareBatchInsert).runSyncUnsafe().distinct mustEqual List(false)
    extractProducts(dataSource.getConnection)(prepareQuery).runSyncUnsafe() === withOrderedIds(productEntries)
  }
} 
Example 56
Source File: ProductJdbcSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.sqlserver

import io.getquill.context.sql.ProductSpec
import monix.eval.Task
import monix.execution.Scheduler

class ProductJdbcSpec extends ProductSpec {

  val context = testContext
  import testContext._

  implicit val scheduler = Scheduler.global

  override def beforeAll = {
    testContext.run(quote(query[Product].delete)).runSyncUnsafe()
    ()
  }

  "Product" - {
    "Insert multiple products" in {
      val (inserted, product) =
        (for {
          i <- Task.sequence(productEntries.map(product => testContext.run(productInsert(lift(product)))))
          ps <- testContext.run(productById(lift(i(2))))
        } yield (i, ps.head)).runSyncUnsafe()

      product.description mustEqual productEntries(2).description
      product.id mustEqual inserted(2)
    }

    "Single insert product" in {
      val (inserted, product) =
        (for {
          i <- testContext.run(productSingleInsert)
          ps <- testContext.run(productById(lift(i)))
        } yield (i, ps.head)).runSyncUnsafe()
      product.description mustEqual "Window"
      product.id mustEqual inserted
    }

    "Single insert with inlined free variable" in {
      val prd = Product(0L, "test1", 1L)
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run {
            product.insert(_.sku -> lift(prd.sku), _.description -> lift(prd.description)).returningGenerated(_.id)
          }
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test1"
      returnedProduct.sku mustEqual 1L
      returnedProduct.id mustEqual inserted
    }

    "Single insert with free variable and explicit quotation" in {
      val prd = Product(0L, "test2", 2L)
      val q1 = quote {
        product.insert(_.sku -> lift(prd.sku), _.description -> lift(prd.description)).returningGenerated(_.id)
      }
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run(q1)
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test2"
      returnedProduct.sku mustEqual 2L
      returnedProduct.id mustEqual inserted
    }

    "Single product insert with a method quotation" in {
      val prd = Product(0L, "test3", 3L)
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run(productInsert(lift(prd)))
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test3"
      returnedProduct.sku mustEqual 3L
      returnedProduct.id mustEqual inserted
    }
  }
} 
Example 57
Source File: PrepareJdbcSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.sqlserver

import java.sql.ResultSet

import io.getquill.PrepareMonixJdbcSpecBase
import monix.execution.Scheduler
import org.scalatest.BeforeAndAfter

class PrepareJdbcSpec extends PrepareMonixJdbcSpecBase with BeforeAndAfter {

  val context = testContext
  import testContext._
  implicit val scheduler = Scheduler.global

  before {
    testContext.run(query[Product].delete).runSyncUnsafe()
  }

  def productExtractor = (rs: ResultSet) => materializeQueryMeta[Product].extract(rs)
  val prepareQuery = prepare(query[Product])
  implicit val im = insertMeta[Product](_.id)

  "single" in {
    val prepareInsert = prepare(query[Product].insert(lift(productEntries.head)))
    singleInsert(dataSource.getConnection)(prepareInsert).runSyncUnsafe() mustEqual false
    extractProducts(dataSource.getConnection)(prepareQuery).runSyncUnsafe() === List(productEntries.head)
  }

  "batch" in {
    val prepareBatchInsert = prepare(
      liftQuery(withOrderedIds(productEntries)).foreach(p => query[Product].insert(p))
    )

    batchInsert(dataSource.getConnection)(prepareBatchInsert).runSyncUnsafe().distinct mustEqual List(false)
    extractProducts(dataSource.getConnection)(prepareQuery).runSyncUnsafe() === withOrderedIds(productEntries)
  }
} 
Example 58
Source File: ProductJdbcSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.mysql

import io.getquill.context.sql.ProductSpec
import monix.execution.Scheduler

class ProductJdbcSpec extends ProductSpec {

  val context = testContext
  import testContext._

  implicit val scheduler = Scheduler.global

  override def beforeAll = {
    testContext.run(quote(query[Product].delete)).runSyncUnsafe()
    ()
  }

  "Product" - {
    "Insert multiple products" in {
      val (inserted, product) =
        (for {
          i <- testContext.run(liftQuery(productEntries).foreach(e => productInsert(e)))
          ps <- testContext.run(productById(lift(i(2))))
        } yield (i, ps.head)).runSyncUnsafe()

      product.description mustEqual productEntries(2).description
      product.id mustEqual inserted(2)
    }

    "Single insert product" in {
      val (inserted, product) =
        (for {
          i <- testContext.run(productSingleInsert)
          ps <- testContext.run(productById(lift(i)))
        } yield (i, ps.head)).runSyncUnsafe()
      product.description mustEqual "Window"
      product.id mustEqual inserted
    }

    "Single insert with inlined free variable" in {
      val prd = Product(0L, "test1", 1L)
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run {
            product.insert(_.sku -> lift(prd.sku), _.description -> lift(prd.description)).returningGenerated(_.id)
          }
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test1"
      returnedProduct.sku mustEqual 1L
      returnedProduct.id mustEqual inserted
    }

    "Single insert with free variable and explicit quotation" in {
      val prd = Product(0L, "test2", 2L)
      val q1 = quote {
        product.insert(_.sku -> lift(prd.sku), _.description -> lift(prd.description)).returningGenerated(_.id)
      }
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run(q1)
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test2"
      returnedProduct.sku mustEqual 2L
      returnedProduct.id mustEqual inserted
    }

    "Single product insert with a method quotation" in {
      val prd = Product(0L, "test3", 3L)
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run(productInsert(lift(prd)))
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test3"
      returnedProduct.sku mustEqual 3L
      returnedProduct.id mustEqual inserted
    }
  }
} 
Example 59
Source File: PrepareJdbcSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.mysql

import java.sql.ResultSet

import io.getquill.PrepareMonixJdbcSpecBase
import monix.execution.Scheduler
import org.scalatest.BeforeAndAfter

class PrepareJdbcSpec extends PrepareMonixJdbcSpecBase with BeforeAndAfter {

  val context = testContext
  import testContext._
  implicit val scheduler = Scheduler.global

  before {
    testContext.run(query[Product].delete).runSyncUnsafe()
  }

  def productExtractor = (rs: ResultSet) => materializeQueryMeta[Product].extract(rs)
  val prepareQuery = prepare(query[Product])

  "single" in {
    val prepareInsert = prepare(query[Product].insert(lift(productEntries.head)))
    singleInsert(dataSource.getConnection)(prepareInsert).runSyncUnsafe() mustEqual false
    extractProducts(dataSource.getConnection)(prepareQuery).runSyncUnsafe() === List(productEntries.head)
  }

  "batch" in {
    val prepareBatchInsert = prepare(
      liftQuery(withOrderedIds(productEntries)).foreach(p => query[Product].insert(p))
    )

    batchInsert(dataSource.getConnection)(prepareBatchInsert).runSyncUnsafe().distinct mustEqual List(false)
    extractProducts(dataSource.getConnection)(prepareQuery).runSyncUnsafe() === withOrderedIds(productEntries)
  }
} 
Example 60
Source File: ProductJdbcSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.sqlite

import io.getquill.context.sql.ProductSpec
import monix.eval.Task
import monix.execution.Scheduler

class ProductJdbcSpec extends ProductSpec {

  val context = testContext
  import testContext._

  implicit val scheduler = Scheduler.global

  override def beforeAll = {
    testContext.run(quote(query[Product].delete)).runSyncUnsafe()
    ()
  }

  "Product" - {
    "Insert multiple products" in {
      val (inserted, product) =
        (for {
          i <- Task.sequence(productEntries.map(product => testContext.run(productInsert(lift(product)))))
          ps <- testContext.run(productById(lift(i(2))))
        } yield (i, ps.head)).runSyncUnsafe()

      product.description mustEqual productEntries(2).description
      product.id mustEqual inserted(2)
    }

    "Single insert product" in {
      val (inserted, product) =
        (for {
          i <- testContext.run(productSingleInsert)
          ps <- testContext.run(productById(lift(i)))
        } yield (i, ps.head)).runSyncUnsafe()
      product.description mustEqual "Window"
      product.id mustEqual inserted
    }

    "Single insert with inlined free variable" in {
      val prd = Product(0L, "test1", 1L)
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run {
            product.insert(_.sku -> lift(prd.sku), _.description -> lift(prd.description)).returningGenerated(_.id)
          }
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test1"
      returnedProduct.sku mustEqual 1L
      returnedProduct.id mustEqual inserted
    }

    "Single insert with free variable and explicit quotation" in {
      val prd = Product(0L, "test2", 2L)
      val q1 = quote {
        product.insert(_.sku -> lift(prd.sku), _.description -> lift(prd.description)).returningGenerated(_.id)
      }
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run(q1)
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test2"
      returnedProduct.sku mustEqual 2L
      returnedProduct.id mustEqual inserted
    }

    "Single product insert with a method quotation" in {
      val prd = Product(0L, "test3", 3L)
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run(productInsert(lift(prd)))
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test3"
      returnedProduct.sku mustEqual 3L
      returnedProduct.id mustEqual inserted
    }
  }
} 
Example 61
Source File: PrepareJdbcSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.sqlite

import java.sql.ResultSet

import io.getquill.PrepareMonixJdbcSpecBase
import monix.execution.Scheduler
import org.scalatest.BeforeAndAfter

class PrepareJdbcSpec extends PrepareMonixJdbcSpecBase with BeforeAndAfter {

  val context = testContext
  import testContext._
  implicit val scheduler = Scheduler.global

  before {
    testContext.run(query[Product].delete).runSyncUnsafe()
  }

  def productExtractor = (rs: ResultSet) => materializeQueryMeta[Product].extract(rs)
  val prepareQuery = prepare(query[Product])

  "single" in {
    val prepareInsert = prepare(query[Product].insert(lift(productEntries.head)))
    singleInsert(dataSource.getConnection)(prepareInsert).runSyncUnsafe() mustEqual false
    extractProducts(dataSource.getConnection)(prepareQuery).runSyncUnsafe() === List(productEntries.head)
  }

  "batch" in {
    val prepareBatchInsert = prepare(
      liftQuery(withOrderedIds(productEntries)).foreach(p => query[Product].insert(p))
    )

    batchInsert(dataSource.getConnection)(prepareBatchInsert).runSyncUnsafe().distinct mustEqual List(false)
    extractProducts(dataSource.getConnection)(prepareQuery).runSyncUnsafe() === withOrderedIds(productEntries)
  }
} 
Example 62
Source File: ProductJdbcSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.h2

import io.getquill.context.sql.ProductSpec
import monix.execution.Scheduler

class ProductJdbcSpec extends ProductSpec {

  val context = testContext
  import testContext._

  implicit val scheduler = Scheduler.global

  override def beforeAll = {
    testContext.run(quote(query[Product].delete)).runSyncUnsafe()
    ()
  }

  "Product" - {
    "Insert multiple products" in {
      val (inserted, product) =
        (for {
          i <- testContext.run(liftQuery(productEntries).foreach(e => productInsert(e)))
          ps <- testContext.run(productById(lift(i(2))))
        } yield (i, ps.head)).runSyncUnsafe()

      product.description mustEqual productEntries(2).description
      product.id mustEqual inserted(2)
    }

    "Single insert product" in {
      val (inserted, product) =
        (for {
          i <- testContext.run(productSingleInsert)
          ps <- testContext.run(productById(lift(i)))
        } yield (i, ps.head)).runSyncUnsafe()
      product.description mustEqual "Window"
      product.id mustEqual inserted
    }

    "Single insert with inlined free variable" in {
      val prd = Product(0L, "test1", 1L)
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run {
            product.insert(_.sku -> lift(prd.sku), _.description -> lift(prd.description)).returningGenerated(_.id)
          }
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test1"
      returnedProduct.sku mustEqual 1L
      returnedProduct.id mustEqual inserted
    }

    "Single insert with free variable and explicit quotation" in {
      val prd = Product(0L, "test2", 2L)
      val q1 = quote {
        product.insert(_.sku -> lift(prd.sku), _.description -> lift(prd.description)).returningGenerated(_.id)
      }
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run(q1)
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test2"
      returnedProduct.sku mustEqual 2L
      returnedProduct.id mustEqual inserted
    }

    "Single product insert with a method quotation" in {
      val prd = Product(0L, "test3", 3L)
      val (inserted, returnedProduct) =
        (for {
          i <- testContext.run(productInsert(lift(prd)))
          rps <- testContext.run(productById(lift(i)))
        } yield (i, rps.head)).runSyncUnsafe()

      returnedProduct.description mustEqual "test3"
      returnedProduct.sku mustEqual 3L
      returnedProduct.id mustEqual inserted
    }
  }
} 
Example 63
Source File: PrepareJdbcSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.h2

import java.sql.ResultSet

import io.getquill.PrepareMonixJdbcSpecBase
import monix.execution.Scheduler
import org.scalatest.BeforeAndAfter

class PrepareJdbcSpec extends PrepareMonixJdbcSpecBase with BeforeAndAfter {

  val context = testContext
  import testContext._
  implicit val scheduler = Scheduler.global

  before {
    testContext.run(query[Product].delete).runSyncUnsafe()
  }

  def productExtractor = (rs: ResultSet) => materializeQueryMeta[Product].extract(rs)
  val prepareQuery = prepare(query[Product])

  "single" in {
    val prepareInsert = prepare(query[Product].insert(lift(productEntries.head)))
    singleInsert(dataSource.getConnection)(prepareInsert).runSyncUnsafe() mustEqual false
    extractProducts(dataSource.getConnection)(prepareQuery).runSyncUnsafe() === List(productEntries.head)
  }

  "batch" in {
    val prepareBatchInsert = prepare(
      liftQuery(withOrderedIds(productEntries)).foreach(p => query[Product].insert(p))
    )

    batchInsert(dataSource.getConnection)(prepareBatchInsert).runSyncUnsafe().distinct mustEqual List(false)
    extractProducts(dataSource.getConnection)(prepareQuery).runSyncUnsafe() === withOrderedIds(productEntries)
  }
} 
Example 64
Source File: ResultSetIteratorSpec.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill

import io.getquill.context.monix.Runner
import io.getquill.util.LoadConfig
import monix.eval.Task
import monix.execution.Scheduler
import org.scalatest.BeforeAndAfterAll
import org.scalatest.freespec.AnyFreeSpec
import org.scalatest.matchers.must.Matchers
import org.scalatest.matchers.should.Matchers._

import scala.collection.mutable.ArrayBuffer

class ResultSetIteratorSpec extends AnyFreeSpec with Matchers with BeforeAndAfterAll {

  val ds = JdbcContextConfig(LoadConfig("testPostgresDB")).dataSource
  implicit val scheduler = Scheduler.global

  val ctx = new PostgresMonixJdbcContext(Literal, ds, Runner.default)
  import ctx._

  case class Person(name: String, age: Int)

  val peopleInsert =
    quote((p: Person) => query[Person].insert(p))

  val peopleEntries = List(
    Person("Alex", 60),
    Person("Bert", 55),
    Person("Cora", 33)
  )

  override def beforeAll = {
    ctx.transaction {
      for {
        _ <- ctx.run(query[Person].delete)
        _ <- ctx.run(liftQuery(peopleEntries).foreach(p => peopleInsert(p)))
      } yield ()
    }.runSyncUnsafe()
  }

  "traverses correctly" in {
    val results =
      Task(ds.getConnection).bracket { conn =>
        Task {
          val stmt = conn.prepareStatement("select * from person")
          val rs = new ResultSetIterator[String](stmt.executeQuery(), extractor = (rs) => { rs.getString(1) })
          val accum = ArrayBuffer[String]()
          while (rs.hasNext) accum += rs.next()
          accum
        }
      } { conn => Task(conn.close()) }.runSyncUnsafe()

    results should contain theSameElementsAs (peopleEntries.map(_.name))
  }

  "can take head element" in {
    val result =
      Task(ds.getConnection).bracket { conn =>
        Task {
          val stmt = conn.prepareStatement("select * from person where name = 'Alex'")
          val rs = new ResultSetIterator(stmt.executeQuery(), extractor = (rs) => { rs.getString(1) })
          rs.head
        }
      } { conn => Task(conn.close()) }.runSyncUnsafe()

    result must equal("Alex")
  }
} 
Example 65
Source File: AuthDirectives.scala    From nexus-iam   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.iam.directives

import akka.http.scaladsl.model.headers.OAuth2BearerToken
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.directives.Credentials
import akka.http.scaladsl.server.{Directive0, Directive1}
import cats.implicits._
import ch.epfl.bluebrain.nexus.rdf.implicits._
import ch.epfl.bluebrain.nexus.iam.acls.Acls
import ch.epfl.bluebrain.nexus.iam.auth.AccessToken
import ch.epfl.bluebrain.nexus.iam.config.AppConfig.HttpConfig
import ch.epfl.bluebrain.nexus.iam.realms.Realms
import ch.epfl.bluebrain.nexus.iam.types.IamError.AccessDenied
import ch.epfl.bluebrain.nexus.iam.types.{Caller, Permission}
import ch.epfl.bluebrain.nexus.rdf.Iri.{AbsoluteIri, Path}
import monix.eval.Task
import monix.execution.Scheduler

import scala.concurrent.Future

object AuthDirectives {

  
  def authorizeFor(permission: Permission)(
      implicit
      acls: Acls[Task],
      s: Scheduler,
      c: Caller,
      hc: HttpConfig
  ): Directive0 =
    extractResourceAddress.flatMap { address =>
      onSuccess {
        acls
          .hasPermission(Path./, permission, ancestors = false)
          .ifM(Task.unit, Task.raiseError(AccessDenied(address, permission)))
          .runToFuture
      }
    }
} 
Example 66
Source File: instances.scala    From nexus-iam   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.iam.marshallers

import akka.http.scaladsl.marshalling.GenericMarshallers.eitherMarshaller
import akka.http.scaladsl.marshalling._
import akka.http.scaladsl.model.MediaTypes.`application/json`
import akka.http.scaladsl.model._
import ch.epfl.bluebrain.nexus.commons.circe.syntax._
import ch.epfl.bluebrain.nexus.commons.http.JsonLdCirceSupport.OrderedKeys
import ch.epfl.bluebrain.nexus.commons.http.RdfMediaTypes._
import ch.epfl.bluebrain.nexus.commons.http.directives.StatusFrom
import ch.epfl.bluebrain.nexus.iam.acls.AclRejection
import ch.epfl.bluebrain.nexus.iam.config.AppConfig._
import ch.epfl.bluebrain.nexus.iam.permissions.PermissionsRejection
import ch.epfl.bluebrain.nexus.iam.realms.RealmRejection
import ch.epfl.bluebrain.nexus.iam.types.IamError.InternalError
import ch.epfl.bluebrain.nexus.iam.types.{IamError, ResourceRejection}
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport
import io.circe._
import io.circe.syntax._
import monix.eval.Task
import monix.execution.Scheduler

import scala.collection.immutable.Seq
import scala.concurrent.Future
import scala.concurrent.duration.FiniteDuration

object instances extends FailFastCirceSupport {

  implicit val finiteDurationEncoder: Encoder[FiniteDuration] =
    Encoder.encodeString.contramap(fd => s"${fd.toMillis} ms")

  implicit val resourceRejectionEncoder: Encoder[ResourceRejection] =
    Encoder.instance {
      case r: AclRejection         => Encoder[AclRejection].apply(r)
      case r: RealmRejection       => Encoder[RealmRejection].apply(r)
      case r: PermissionsRejection => Encoder[PermissionsRejection].apply(r)
      case _                       => Encoder[IamError].apply(InternalError("unspecified"))
    }

  implicit val resourceRejectionStatusFrom: StatusFrom[ResourceRejection] =
    StatusFrom {
      case r: AclRejection         => AclRejection.aclRejectionStatusFrom(r)
      case r: RealmRejection       => RealmRejection.realmRejectionStatusFrom(r)
      case r: PermissionsRejection => PermissionsRejection.permissionsRejectionStatusFrom(r)
    }

  override def unmarshallerContentTypes: Seq[ContentTypeRange] =
    List(`application/json`, `application/ld+json`, `application/sparql-results+json`)

  
  implicit final def rejection[A <: ResourceRejection: Encoder](
      implicit statusFrom: StatusFrom[A],
      printer: Printer = Printer.noSpaces.copy(dropNullValues = true),
      ordered: OrderedKeys = orderedKeys
  ): ToResponseMarshaller[A] = {
    val marshallers = Seq(`application/ld+json`, `application/json`).map { contentType =>
      Marshaller.withFixedContentType[A, HttpResponse](contentType) { rejection =>
        HttpResponse(
          status = statusFrom(rejection),
          entity = HttpEntity(contentType, printer.print(rejection.asJson.sortKeys))
        )
      }
    }
    Marshaller.oneOf(marshallers: _*)
  }

  implicit class EitherTask[R <: ResourceRejection, A](task: Task[Either[R, A]])(implicit s: Scheduler) {
    def runWithStatus(code: StatusCode): Future[Either[R, (StatusCode, A)]] =
      task.map(_.map(code -> _)).runToFuture
  }

  implicit class OptionTask[A](task: Task[Option[A]])(implicit s: Scheduler) {
    def runNotFound: Future[A] =
      task.flatMap {
        case Some(a) => Task.pure(a)
        case None    => Task.raiseError(IamError.NotFound)
      }.runToFuture
  }
} 
Example 67
Source File: RepairFromMessages.scala    From nexus-iam   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.iam

import java.net.URLDecoder

import akka.actor.ActorSystem
import akka.persistence.cassandra.query.scaladsl.CassandraReadJournal
import akka.persistence.query.PersistenceQuery
import ch.epfl.bluebrain.nexus.iam.acls.Acls
import ch.epfl.bluebrain.nexus.iam.permissions.Permissions
import ch.epfl.bluebrain.nexus.iam.realms.Realms
import ch.epfl.bluebrain.nexus.iam.types.Label
import ch.epfl.bluebrain.nexus.rdf.Iri.Path
import com.typesafe.scalalogging.Logger
import monix.eval.Task
import monix.execution.Scheduler
import monix.execution.schedulers.CanBlock

import scala.concurrent.Future


object RepairFromMessages {
  // $COVERAGE-OFF$

  private val log = Logger[RepairFromMessages.type]

  def repair(
      p: Permissions[Task],
      r: Realms[Task],
      a: Acls[Task]
  )(implicit as: ActorSystem, sc: Scheduler, pm: CanBlock): Unit = {
    val pq = PersistenceQuery(as).readJournalFor[CassandraReadJournal](CassandraReadJournal.Identifier)

    pq.currentPersistenceIds()
      .mapAsync(1) {
        case PermissionsId() => p.agg.currentState(p.persistenceId).runToFuture
        case RealmId(label)  => r.agg.currentState(label.value).runToFuture
        case AclId(path)     => a.agg.currentState(path.asString).runToFuture
        case other =>
          log.warn(s"Unknown persistence id '$other'")
          Future.successful(())
      }
      .runFold(0) {
        case (acc, _) =>
          if (acc % 100 == 0) log.info(s"Processed '$acc' persistence ids.")
          acc + 1
      }
      .runSyncDiscard()

    log.info("Repair from messages table completed.")
  }

  sealed abstract class PersistenceId(prefix: String) {
    private val len = prefix.length
    protected def dropPrefix(arg: String): Option[String] =
      if (arg.startsWith(prefix)) Some(arg.drop(len))
      else None
  }
  object RealmId extends PersistenceId("realms-") {
    def unapply(arg: String): Option[Label] =
      dropPrefix(arg).map(Label.unsafe)
  }
  object AclId extends PersistenceId("acls-") {
    def unapply(arg: String): Option[Path] =
      dropPrefix(arg).flatMap(str => Path(URLDecoder.decode(str, "UTF-8")).toOption)
  }
  object PermissionsId {
    def unapply(arg: String): Boolean =
      arg == "permissions-permissions"
  }

  implicit class RichFuture[A](val future: Future[A]) extends AnyVal {
    def runSyncDiscard()(implicit s: Scheduler, permit: CanBlock): Unit =
      Task.fromFuture(future).map(_ => ()).runSyncUnsafe()
  }
  // $COVERAGE-ON$
} 
Example 68
Source File: HttpMockServerResource.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.http.server

import com.github.agourlay.cornichon.core.{ RunState, Session }
import com.github.agourlay.cornichon.dsl.BlockScopedResource
import com.github.agourlay.cornichon.http.server.HttpMockServerResource.SessionKeys._
import io.circe.Json
import monix.eval.Task
import monix.execution.Scheduler

case class HttpMockServerResource(interface: Option[String], label: String, portRange: Option[Range])
  extends BlockScopedResource {

  implicit val scheduler = Scheduler.Implicits.global

  val sessionTarget: String = label
  val openingTitle: String = s"Starting HTTP mock server '$label'"
  val closingTitle: String = s"Shutting down HTTP mock server '$label'"

  def use[A](outsideRunState: RunState)(f: RunState => Task[A]): Task[(Session, A)] = {
    val mockRequestHandler = new MockServerRequestHandler()

    val initSession: String => Session = id => Session.newEmpty.addValueUnsafe(s"$label-url", id)
    val resourceContext: RunState => Session => RunState = r1 => s1 => r1.mergeSessions(s1)
    val runWithServer = initSession.andThen(resourceContext(outsideRunState)).andThen(f)

    val mockServer = new MockHttpServer(interface, portRange, mockRequestHandler.mockService)(runWithServer)

    mockServer.useServer().map { res =>
      val resourceResults = requestsResults(mockRequestHandler)
      (resourceResults, res)
    }
  }

  def requestsResults(mockRequestHandler: MockServerRequestHandler): Session = {
    val jsonRequests = mockRequestHandler.fetchRecordedRequestsAsJson()
    Session.newEmpty
      .addValueUnsafe(s"$sessionTarget$receivedBodiesSuffix", Json.fromValues(jsonRequests).spaces2)
      .addValueUnsafe(s"$sessionTarget$nbReceivedCallsSuffix", jsonRequests.size.toString)
  }
}

object HttpMockServerResource {
  object SessionKeys {
    val nbReceivedCallsSuffix = "-nb-received-calls"
    val receivedBodiesSuffix = "-received-bodies"
  }
} 
Example 69
Source File: CheckStepBench.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package step

import java.util.concurrent.{ ExecutorService, Executors }

import com.github.agourlay.cornichon.core._
import monix.execution.Scheduler
import org.openjdk.jmh.annotations._
import com.github.agourlay.cornichon.steps.check.checkModel._
import com.github.agourlay.cornichon.steps.cats.EffectStep

import scala.concurrent.Await
import scala.concurrent.duration.Duration
import step.JsonStepBench._

@State(Scope.Benchmark)
@BenchmarkMode(Array(Mode.Throughput))
@Warmup(iterations = 10)
@Measurement(iterations = 10)
@Fork(value = 1, jvmArgsAppend = Array(
  "-XX:+FlightRecorder",
  "-XX:StartFlightRecording=filename=./CheckStepBench-profiling-data.jfr,name=profile,settings=profile",
  "-Xmx1G"))
class CheckStepBench {

  //sbt:benchmarks> jmh:run .*CheckStep.* -prof gc -foe true -gc true -rf csv

  @Param(Array("10", "20", "50", "100", "200"))
  var transitionNumber: String = ""

  var es: ExecutorService = _
  var scheduler: Scheduler = _

  @Setup(Level.Trial)
  final def beforeAll(): Unit = {
    es = Executors.newFixedThreadPool(1)
    scheduler = Scheduler(es)
  }

  @TearDown(Level.Trial)
  final def afterAll(): Unit = {
    es.shutdown()
  }
  

  @Benchmark
  def runModel() = {
    val checkStep = CheckModelStep(maxNumberOfRuns = 1, maxNumberOfTransitions = transitionNumber.toInt, CheckStepBench.modelRunner)
    val s = Scenario("scenario with checkStep", checkStep :: Nil)
    val f = ScenarioRunner.runScenario(session)(s)
    val res = Await.result(f.runToFuture(scheduler), Duration.Inf)
    assert(res.isSuccess)
  }

}

object CheckStepBench {
  def integerGen(rc: RandomContext): ValueGenerator[Int] = ValueGenerator(
    name = "integer",
    gen = () => rc.nextInt(10000))

  def dummyProperty1(name: String): PropertyN[Int, NoValue, NoValue, NoValue, NoValue, NoValue] =
    Property1(
      description = name,
      invariant = g => EffectStep.fromSyncE("add generated", _.session.addValue("generated", g().toString)))

  val starting = dummyProperty1("starting action")
  val otherAction = dummyProperty1("other action")
  val otherActionTwo = dummyProperty1("other action two")
  val transitions = Map(
    starting -> ((100, otherAction) :: Nil),
    otherAction -> ((100, otherActionTwo) :: Nil),
    otherActionTwo -> ((100, otherAction) :: Nil))
  val model = Model("model with empty transition for starting", starting, transitions)
  val modelRunner = ModelRunner.make(integerGen)(model)

} 
Example 70
Source File: RunScenarioBench.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package scenario

import java.util.concurrent.{ ExecutorService, Executors }

import cats.instances.int._
import com.github.agourlay.cornichon.core.{ ScenarioRunner, Scenario, Session }
import com.github.agourlay.cornichon.steps.cats.EffectStep
import com.github.agourlay.cornichon.steps.regular.assertStep.{ AssertStep, Assertion, GenericEqualityAssertion }
import org.openjdk.jmh.annotations._
import scenario.RunScenarioBench._
import monix.execution.Scheduler

import scala.concurrent.Await
import scala.concurrent.duration._

@State(Scope.Benchmark)
@BenchmarkMode(Array(Mode.Throughput))
@Warmup(iterations = 10)
@Measurement(iterations = 10)
@Fork(value = 1, jvmArgsAppend = Array(
  "-XX:+FlightRecorder",
  "-XX:StartFlightRecording=filename=./RunScenarioBench-profiling-data.jfr,name=profile,settings=profile",
  "-Xmx1G"))
class RunScenarioBench {

  //sbt:benchmarks> jmh:run .*RunScenario.* -prof gc -foe true -gc true -rf csv

  @Param(Array("10", "20", "50", "100", "200"))
  var stepsNumber: String = ""
  var es: ExecutorService = _
  var scheduler: Scheduler = _

  @Setup(Level.Trial)
  final def beforeAll(): Unit = {
    es = Executors.newFixedThreadPool(1)
    scheduler = Scheduler(es)
  }

  @TearDown(Level.Trial)
  final def afterAll(): Unit = {
    es.shutdown()
  }

  

  @Benchmark
  def lotsOfSteps() = {
    val half = stepsNumber.toInt / 2
    val assertSteps = List.fill(half)(assertStep)
    val effectSteps = List.fill(half)(effectStep)
    val scenario = Scenario("test scenario", setupSession +: (assertSteps ++ effectSteps))
    val f = ScenarioRunner.runScenario(Session.newEmpty)(scenario)
    val res = Await.result(f.runToFuture(scheduler), Duration.Inf)
    assert(res.isSuccess)
  }
}

object RunScenarioBench {
  val setupSession = EffectStep.fromSyncE("setup session", _.session.addValues("v1" -> "2", "v2" -> "1"))
  val assertStep = AssertStep(
    "addition step",
    sc => Assertion.either {
      for {
        two <- sc.session.get("v1").map(_.toInt)
        one <- sc.session.get("v2").map(_.toInt)
      } yield GenericEqualityAssertion(two + one, 3)
    })
  val effectStep = EffectStep.fromSync("identity", _.session)
} 
Example 71
Source File: RequestEffectBench.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package httpService

import java.util.concurrent.{ ExecutorService, Executors }

import cats.instances.string._
import com.github.agourlay.cornichon.core.{ Config, ScenarioContext }
import com.github.agourlay.cornichon.http.{ HttpMethods, HttpRequest, HttpService }
import org.openjdk.jmh.annotations._
import RequestEffectBench._
import com.github.agourlay.cornichon.http.client.NoOpHttpClient
import monix.execution.Scheduler

import scala.concurrent.Await
import scala.concurrent.duration._

@State(Scope.Benchmark)
@BenchmarkMode(Array(Mode.Throughput))
@Warmup(iterations = 10)
@Measurement(iterations = 10)
@Fork(value = 1, jvmArgsAppend = Array(
  "-XX:+FlightRecorder",
  "-XX:StartFlightRecording=filename=./RequestEffectBench-profiling-data.jfr,name=profile,settings=profile",
  "-Xmx1G"))
class RequestEffectBench {

  //sbt:benchmarks> jmh:run .*RequestEffect.*

  var es: ExecutorService = _
  val client = new NoOpHttpClient
  var httpService: HttpService = _

  @Setup(Level.Trial)
  final def beforeAll(): Unit = {
    es = Executors.newFixedThreadPool(1)
    val scheduler = Scheduler(es)
    httpService = new HttpService("", 2000.millis, client, Config())(scheduler)
  }

  @TearDown(Level.Trial)
  final def afterAll(): Unit = {
    es.shutdown()
  }
  

  @Benchmark
  def singleRequest() = {
    val f = httpService.requestEffect(request)
    val res = Await.result(f(scenarioContext), Duration.Inf)
    assert(res.isRight)
  }
}

object RequestEffectBench {
  val scenarioContext = ScenarioContext.empty
  val request = HttpRequest[String](
    method = HttpMethods.GET,
    url = "https://myUrl/my/segment",
    body = Some(""" { "k1":"v1", "k2":"v2","k3":"v3","k4":"v4" } """),
    params = ("q1", "v1") :: ("q2", "v2") :: ("q3", "v3") :: Nil,
    headers = ("h1", "v1") :: ("h2", "v2") :: ("h3", "v3") :: Nil)
} 
Example 72
Source File: TurnstileAPI.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.framework.examples.propertyCheck.turnstile

import com.github.agourlay.cornichon.framework.examples.HttpServer
import monix.eval.Task
import monix.execution.atomic.AtomicBoolean
import monix.execution.{ CancelableFuture, Scheduler }
import org.http4s._
import org.http4s.implicits._
import org.http4s.dsl._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder

class TurnstileAPI extends Http4sDsl[Task] {

  implicit val s = Scheduler.Implicits.global

  private val turnstileLocked = AtomicBoolean(true)

  private val turnstileService = HttpRoutes.of[Task] {
    case POST -> Root / "push-coin" =>
      if (turnstileLocked.get()) {
        turnstileLocked.set(false)
        Ok("payment accepted")
      } else
        BadRequest("payment refused")

    case POST -> Root / "walk-through" =>
      if (turnstileLocked.get())
        BadRequest("door blocked")
      else {
        turnstileLocked.set(true)
        Ok("door turns")
      }
  }

  private val routes = Router(
    "/" -> turnstileService
  )

  def start(httpPort: Int): CancelableFuture[HttpServer] =
    BlazeServerBuilder[Task](executionContext = s)
      .bindHttp(httpPort, "localhost")
      .withoutBanner
      .withNio2(true)
      .withHttpApp(routes.orNotFound)
      .allocated
      .map { case (_, stop) => new HttpServer(stop) }
      .runToFuture

} 
Example 73
Source File: ReverseAPI.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.framework.examples.propertyCheck.stringReverse

import com.github.agourlay.cornichon.framework.examples.HttpServer
import monix.eval.Task
import monix.execution.{ CancelableFuture, Scheduler }
import org.http4s._
import org.http4s.implicits._
import org.http4s.dsl._
import org.http4s.server.Router
import org.http4s.server.blaze.BlazeServerBuilder

class ReverseAPI extends Http4sDsl[Task] {

  implicit val s = Scheduler.Implicits.global

  object WordQueryParamMatcher extends QueryParamDecoderMatcher[String]("word")

  private val reverseService = HttpRoutes.of[Task] {
    case POST -> Root / "double-reverse" :? WordQueryParamMatcher(word) =>
      Ok(word.reverse.reverse)
  }

  private val routes = Router(
    "/" -> reverseService
  )

  def start(httpPort: Int): CancelableFuture[HttpServer] =
    BlazeServerBuilder[Task](executionContext = s)
      .bindHttp(httpPort, "localhost")
      .withoutBanner
      .withNio2(true)
      .withHttpApp(routes.orNotFound)
      .allocated
      .map { case (_, stop) => new HttpServer(stop) }
      .runToFuture
} 
Example 74
Source File: BaseFeature.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.dsl

import java.util.concurrent.ConcurrentLinkedDeque

import com.github.agourlay.cornichon.core.{ Config, Done, FeatureDef, Step }
import com.github.agourlay.cornichon.matchers.Matcher
import com.github.agourlay.cornichon.resolver.Mapper
import monix.execution.Scheduler
import pureconfig.error.{ ConvertFailure, KeyNotFound }

import scala.annotation.tailrec
import scala.collection.mutable.ListBuffer
import scala.concurrent.Future

trait BaseFeature {

  protected[cornichon] val beforeFeature: ListBuffer[() => Unit] = ListBuffer.empty
  protected[cornichon] val afterFeature: ListBuffer[() => Unit] = ListBuffer.empty

  protected[cornichon] val beforeEachScenario: ListBuffer[Step] = ListBuffer.empty
  protected[cornichon] val afterEachScenario: ListBuffer[Step] = ListBuffer.empty

  private[cornichon] lazy val config = BaseFeature.config
  lazy val executeScenariosInParallel: Boolean = config.executeScenariosInParallel

  lazy val seed: Option[Long] = None

  // Convenient implicits for the custom DSL
  implicit lazy val ec = Scheduler.Implicits.global

  def feature: FeatureDef

  def registerExtractors: Map[String, Mapper] = Map.empty

  def registerMatchers: List[Matcher] = Nil

  def beforeFeature(before: => Unit): Unit =
    beforeFeature += (() => before)

  def afterFeature(after: => Unit): Unit =
    (() => after) +=: afterFeature

  def beforeEachScenario(step: Step): Unit =
    beforeEachScenario += step

  def afterEachScenario(step: Step): Unit =
    step +=: afterEachScenario
}

// Protect and free resources
object BaseFeature {
  import pureconfig.generic.auto._
  import pureconfig.ConfigSource
  import pureconfig.error.{ ConfigReaderException, ConfigReaderFailures }

  lazy val config = ConfigSource.default.at("cornichon").load[Config] match {
    case Right(v)                                                                          => v
    case Left(ConfigReaderFailures(ConvertFailure(KeyNotFound("cornichon", _), _, _), _*)) => Config()
    case Left(failures)                                                                    => throw new ConfigReaderException[Config](failures)
  }

  private val hooks = new ConcurrentLinkedDeque[() => Future[_]]()

  def addShutdownHook(h: () => Future[_]): Unit =
    hooks.push(h)

  def shutDownGlobalResources(): Future[Done] = {
    import scala.concurrent.ExecutionContext.Implicits.global
    @tailrec
    def clearHooks(previous: Future[Any] = Future.successful[Any](())): Future[Any] =
      Option(hooks.poll()) match {
        case None => previous
        case Some(f) =>
          clearHooks {
            previous.flatMap { _ => f().recover { case _ => Done } }
          }
      }

    clearHooks().map(_ => Done)
  }
} 
Example 75
Source File: EffectStep.scala    From cornichon   with Apache License 2.0 5 votes vote down vote up
package com.github.agourlay.cornichon.steps.cats

import cats.data.{ EitherT, NonEmptyList }
import cats.effect.Effect
import cats.syntax.either._
import com.github.agourlay.cornichon.core.ScenarioRunner.{ errorsToFailureStep, successLog }
import com.github.agourlay.cornichon.core._
import monix.eval.Task
import monix.execution.Scheduler

import scala.concurrent.duration.Duration

case class EffectStep[F[_]: Effect](title: String, effect: ScenarioContext => F[Either[CornichonError, Session]], show: Boolean = true) extends SessionValueStep {

  def setTitle(newTitle: String): Step = copy(title = newTitle)

  override def runSessionValueStep(runState: RunState): Task[Either[NonEmptyList[CornichonError], Session]] =
    Task.fromEffect(effect(runState.scenarioContext)).map(_.leftMap(NonEmptyList.one))

  override def onError(errors: NonEmptyList[CornichonError], runState: RunState, executionTime: Duration): (LogInstruction, FailedStep) =
    errorsToFailureStep(this, runState.depth, errors, Some(executionTime))

  override def logOnSuccess(result: Session, runState: RunState, executionTime: Duration): LogInstruction =
    successLog(title, runState.depth, show, executionTime)

}

object EffectStep {

  def fromEitherT[F[_]: Effect](title: String, effect: ScenarioContext => EitherT[F, CornichonError, Session], show: Boolean = true): Step = {
    val effectT: ScenarioContext => F[Either[CornichonError, Session]] = s => effect(s).value
    EffectStep(title, effectT, show)
  }

  def fromSync(title: String, effect: ScenarioContext => Session, show: Boolean = true): Step = {
    import Scheduler.Implicits.global
    val effectF: ScenarioContext => Task[Either[CornichonError, Session]] = s => Task.now(effect(s).asRight)
    EffectStep(title, effectF, show)
  }

  def fromSyncE(title: String, effect: ScenarioContext => Either[CornichonError, Session], show: Boolean = true): Step = {
    import Scheduler.Implicits.global
    val effectF: ScenarioContext => Task[Either[CornichonError, Session]] = s => Task.now(effect(s))
    EffectStep(title, effectF, show)
  }

  def fromAsync[F[_]: Effect](title: String, effect: ScenarioContext => F[Session], show: Boolean = true): Step = {
    import Scheduler.Implicits.global
    val effectF: ScenarioContext => Task[Either[CornichonError, Session]] = s => Task.fromEffect(effect(s)).map(Right.apply)
    EffectStep(title, effectF, show)
  }

} 
Example 76
Source File: DoobieInstancesSuite.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.doobie

import cats.Applicative
import cats.data.ReaderT
import cats.effect.{IO, SyncIO}
import com.github.ghik.silencer.silent
import doobie.ConnectionIO
import monix.eval.{Coeval, Task}
import monix.execution.Scheduler
import tofu.doobie.instances.implicits._
import tofu.env.Env
import tofu.lift.Lift
import tofu.zioInstances.implicits._
import zio.interop.catz._

object DoobieInstancesSuite {

  def summonImplicitsViaLiftToIO[F[_]: Applicative, R](implicit L: Lift[F, IO]): Unit = {
    Lift[F, ConnectionIO]
    Lift[F, ConnectionRIO[R, *]]
    Lift[ReaderT[F, R, *], ConnectionRIO[R, *]]
    ()
  }

  def summonCatsEffectImplicits[R](): Unit = {
    Lift[SyncIO, ConnectionIO]
    Lift[SyncIO, ConnectionRIO[R, *]]
    Lift[ReaderT[SyncIO, R, *], ConnectionRIO[R, *]]

    Lift[IO, ConnectionIO]
    Lift[IO, ConnectionRIO[R, *]]
    Lift[ReaderT[IO, R, *], ConnectionRIO[R, *]]

    ()
  }

  def summonMonixImplicitsViaScheduler[R](implicit sc: Scheduler): Unit = {
    Lift[Coeval, ConnectionIO]
    Lift[Coeval, ConnectionRIO[R, *]]
    Lift[ReaderT[Coeval, R, *], ConnectionRIO[R, *]]

    Lift[Task, ConnectionIO]
    Lift[Task, ConnectionRIO[R, *]]
    Lift[ReaderT[Task, R, *], ConnectionRIO[R, *]]

    Lift[Env[R, *], ConnectionRIO[R, *]]

    ()
  }

  def summonMonixImplicitsUnambiguously[R](implicit @silent sc: Scheduler, L: Lift[Task, IO]): Unit = {
    Lift[Task, ConnectionIO]
    Lift[Task, ConnectionRIO[R, *]]
    Lift[ReaderT[Task, R, *], ConnectionRIO[R, *]]
    ()
  }

  def summonZioImplicits[R](): zio.Task[Unit] =
    zio.Task.concurrentEffect.map { implicit CE =>
      Lift[zio.Task, ConnectionIO]
      Lift[zio.Task, ConnectionRIO[R, *]]
      Lift[zio.RIO[R, *], ConnectionRIO[R, *]]
      ()
    }

  def summonLiftConnectionIO[R](): Unit = {
    LiftConnectionIO[ConnectionIO]
    LiftConnectionIO[ConnectionRIO[R, *]]
    ()
  }

} 
Example 77
Source File: EnvInstances.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.env

import cats.arrow.{ArrowChoice, FunctionK, Profunctor}
import cats.effect.IO
import cats.{Applicative, Monad, Parallel, ~>}
import monix.eval.{Task, TaskLift}
import monix.execution.Scheduler
import tofu.lift.{UnliftIO, UnsafeExecFuture}
import tofu.optics.Contains
import tofu.syntax.funk._

import scala.concurrent.Future

private[env] trait EnvInstances {
  self: Env.type =>

  private object anyEnvInstance extends EnvFunctorstance[Any]

  final implicit def envInstance[E]: EnvFunctorstance[E] = anyEnvInstance.asInstanceOf[EnvFunctorstance[E]]

  private object envParallelInstance extends Applicative[Env[Any, *]] {
    override def pure[A](x: A): Env[Any, A]                                                   = Env.pure(x)
    override def ap[A, B](ff: Env[Any, A => B])(fa: Env[Any, A]): Env[Any, B]                 =
      Env.parMap2(ff, fa)(_.apply(_))
    override def map2[A, B, Z](fa: Env[Any, A], fb: Env[Any, B])(f: (A, B) => Z): Env[Any, Z] =
      Env.parMap2(fa, fb)(f)
    override val unit: Env[Any, Unit]                                                         = Env.unit
    override def map[A, B](fa: Env[Any, A])(f: A => B): Env[Any, B]                           = fa.map(f)
    override def replicateA[A](n: Int, fa: Env[Any, A]): Env[Any, List[A]]                    =
      fa.mapTask(t => Task.parSequence(Iterable.fill(n)(t)).map(_.toList))
  }

  private object anyEnvParallelInstance extends Parallel[Env[Any, *]] {
    type F[a] = Env[Any, a]
    override def applicative: Applicative[Env[Any, *]]    = envParallelInstance
    override def monad: Monad[Env[Any, *]]                = anyEnvInstance
    override val sequential: ~>[Env[Any, *], Env[Any, *]] = FunctionK.id
    override val parallel: ~>[Env[Any, *], Env[Any, *]]   = FunctionK.id
  }

  final implicit def envParallelInstance[E]: Parallel[Env[E, *]] =
    anyEnvParallelInstance.asInstanceOf[Parallel[Env[E, *]]]

  final implicit val envProfuctorInstance: Profunctor[Env] with ArrowChoice[Env] =
    new Profunctor[Env] with ArrowChoice[Env] {
      override def choose[A, B, C, D](f: Env[A, C])(g: Env[B, D]): Env[Either[A, B], Either[C, D]] =
        Env {
          case Left(a)  => f.run(a).map(Left(_))
          case Right(b) => g.run(b).map(Right(_))
        }

      override def lift[A, B](f: A => B): Env[A, B]                                   = Env(a => Task.pure(f(a)))
      override def first[A, B, C](fa: Env[A, B]): Env[(A, C), (B, C)]                 =
        fa.first[C]
      override def second[A, B, C](fa: Env[A, B]): Env[(C, A), (C, B)]                =
        fa.second[C]
      override def compose[A, B, C](f: Env[B, C], g: Env[A, B]): Env[A, C]            =
        f.compose(g)
      override def rmap[A, B, C](fab: Env[A, B])(f: B => C): Env[A, C]                =
        fab.map(f)
      override def lmap[A, B, C](fab: Env[A, B])(f: C => A): Env[C, B]                =
        fab.localP(f)
      override def id[A]: Env[A, A]                                                   = Env.context
      override def dimap[A, B, C, D](fab: Env[A, B])(f: C => A)(g: B => D): Env[C, D] = fab.dimap(f)(g)
      override def split[A, B, C, D](f: Env[A, B], g: Env[C, D]): Env[(A, C), (B, D)] =
        f.split(g)
      override def left[A, B, C](fab: Env[A, B]): Env[Either[A, C], Either[B, C]]     = fab.left[C]
      override def right[A, B, C](fab: Env[A, B]): Env[Either[C, A], Either[C, B]]    = fab.right[C]
      override def choice[A, B, C](f: Env[A, C], g: Env[B, C]): Env[Either[A, B], C]  =
        f.choice(g)
      override def merge[A, B, C](f: Env[A, B], g: Env[A, C]): Env[A, (B, C)]         =
        Env.parZip2(f, g)
    }

  final implicit def envUnliftSubContext[E, E1: E Contains *]: EnvUnliftSubContext[E, E1] = new EnvUnliftSubContext

  def envUnsafeExecFuture[E](implicit sc: Scheduler): UnsafeExecFuture[Env[E, *]] =
    new UnsafeExecFuture[Env[E, *]] {
      def lift[A](fa: Future[A]): Env[E, A]   = Env.fromFuture(fa)
      def unlift: Env[E, Env[E, *] ~> Future] = Env.fromFunc(r => makeFunctionK(_.run(r).runToFuture))
    }

  implicit def envUnliftIO[E](implicit toIO: TaskLift[IO]): UnliftIO[Env[E, *]] = new UnliftIO[Env[E, *]] {
    def lift[A](fa: IO[A]): Env[E, A]   = Env.fromIO(fa)
    def unlift: Env[E, Env[E, *] ~> IO] = Env.fromFunc(r => funK(_.run(r).to[IO]))
  }
} 
Example 78
Source File: EnvFunctions.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.env

import java.util.concurrent.TimeUnit.MILLISECONDS

import cats.Eval
import cats.data.ReaderT
import cats.effect._
import monix.eval.{Coeval, Task}
import monix.execution.Scheduler

import scala.concurrent.duration.FiniteDuration
import scala.concurrent.{ExecutionContext, Future}
import scala.util.Try

private[env] trait EnvFunctions
    extends EnvProducts with EnvTraversing with EnvRacing with EnvSyntax with EnvTransformations {
  self: Env.type =>
  def apply[E, A](f: E => Task[A]): Env[E, A] = EnvCtx(f)
  def later[E, A](x: => A): Env[E, A]         = fromTask(Task.delay(x))
  def pure[E, A](x: A): Env[E, A]             = fromTask(Task.pure(x))

  def context[E]: Env[E, E]                            = Env(ctx => Task.now(ctx))
  def withContextNow[E, A](f: E => A): Env[E, A]       = Env(ctx => Task.now(f(ctx)))
  def withContext[E, A](f: E => Env[E, A]): Env[E, A]  = Env(ctx => f(ctx).run(ctx))
  def withContextFork[E, A](f: E => A): Env[E, A]      = Env(ctx => Task(f(ctx)))
  def withContextDelay[E, A](f: E => A): Env[E, A]     = Env(ctx => Task.delay(f(ctx)))
  private[this] val anyUnit: Env[Any, Unit]            = fromTask(Task.unit)
  def unit[E]: Env[E, Unit]                            = anyUnit.asInstanceOf[Env[E, Unit]]
  def scheduler[E]: Env[E, Scheduler]                  =
    fromTask(Task.deferAction(scheduler => Task.pure(scheduler)))
  def millis[E]: Env[E, Long]                          =
    fromTask(Task.deferAction(scheduler => Task.pure(scheduler.clockRealTime(MILLISECONDS))))
  def shift[E]: Env[E, Unit]                           = fromTask(Task.shift)
  def shift[E](ec: ExecutionContext): Env[E, Unit]     = fromTask(Task.shift(ec))
  def sleep[E](duration: FiniteDuration): Env[E, Unit] =
    fromTask(Task.sleep(duration))

  def fromTask[E, A](task: Task[A]): Env[E, A]                           = EnvTask(task)
  def delay[E, A](x: => A): Env[E, A]                                    = later(x)
  def defer[E, A](x: => Env[E, A]): Env[E, A]                            =
    Env(ctx => Task.defer(x.run(ctx)))
  def deferTask[E, A](x: => Task[A]): Env[E, A]                          = fromTask(Task.defer(x))
  def deferFuture[E, A](future: => Future[A]): Env[E, A]                 =
    EnvTask(Task.deferFuture(future))
  def deferFutureContext[E, A](future: E => Future[A]): Env[E, A]        =
    Env(ctx => Task.deferFuture(future(ctx)))
  def deferFutureAction[E, A](futAct: Scheduler => Future[A]): Env[E, A] =
    EnvTask(Task.deferFutureAction(futAct))
  def raiseError[E, A](throwable: Throwable): Env[E, A]                  =
    EnvTask(Task.raiseError(throwable))
  def attempt[E, A](e: Env[E, A]): Env[E, Either[Throwable, A]]          = e.attempt

  def fromFunc[E, A](f: E => A): Env[E, A]                          = Env.withContextNow(f)
  def fromReaderT[E, A](reader: ReaderT[Task, E, A]): Env[E, A]     =
    Env(reader.run)
  def fromTry[E, A](t: Try[A]): Env[E, A]                           = fromTask(Task.fromTry(t))
  def fromEither[E, A](e: Either[Throwable, A]): Env[E, A]          = fromTask(Task.fromTry(e.toTry))
  def fromFuture[E, A](future: Future[A]): Env[E, A]                = EnvTask(Task.fromFuture(future))
  def fromTryFunc[E, A](ft: E => Try[A]): Env[E, A]                 =
    Env(ctx => Task.fromTry(ft(ctx)))
  def fromEffect[F[_]: Effect, E, A](fa: F[A]): Env[E, A]           =
    fromTask(Task.fromEffect(fa))
  def fromEffectFunc[F[_]: Effect, E, A](ffa: E => F[A]): Env[E, A] =
    Env(ctx => Task.fromEffect(ffa(ctx)))
  def fromEval[E, A](ea: Eval[A]): Env[E, A]                        = fromTask(Task.from(ea))
  def fromEvalFunc[E, A](fea: E => Eval[A]): Env[E, A]              =
    Env(ctx => Task.from(fea(ctx)))
  def fromIO[E, A](ioa: IO[A]): Env[E, A]                           = fromTask(Task.from(ioa))
  def fromIOFunc[E, A](fioa: E => IO[A]): Env[E, A]                 =
    Env(ctx => Task.from(fioa(ctx)))
  def fromCoeval[E, A](ca: Coeval[A]): Env[E, A]                    = fromTask(ca.to[Task])
  def fromCoevalFunc[E, A](fca: E => Coeval[A]): Env[E, A]          =
    Env(ctx => fca(ctx).to[Task])

  def tailRecM[E, A, B](a: A)(f: (A) => Env[E, Either[A, B]]): Env[E, B] =
    Env(ctx => Task.tailRecM(a)(a1 => f(a1).run(ctx)))

  def when[E](cond: => Boolean)(io: => Env[E, _]): Env[E, Unit] =
    whenF(delay[E, Boolean](cond))(io)

  def whenF[E](cond: Env[E, Boolean])(io: => Env[E, _]): Env[E, Unit] =
    cond.flatMap(run => if (run) io.flatMap(_ => Env.unit[E]) else Env.unit[E])
} 
Example 79
Source File: MonixWebSocketHandler.scala    From sttp   with Apache License 2.0 5 votes vote down vote up
package sttp.client.httpclient.monix

import monix.eval.Task
import monix.execution.Scheduler
import sttp.client.httpclient.WebSocketHandler
import sttp.client.httpclient.internal.NativeWebSocketHandler
import sttp.client.impl.monix.{MonixAsyncQueue, TaskMonadAsyncError}
import sttp.client.ws.{WebSocket, WebSocketEvent}

object MonixWebSocketHandler {
  val IncomingBufferCapacity = 2 // has to be at least 2 (opening frame + one data frame)

  
  def apply()(implicit
      s: Scheduler
  ): Task[WebSocketHandler[WebSocket[Task]]] = {
    Task {
      val queue =
        new MonixAsyncQueue[WebSocketEvent](Some(IncomingBufferCapacity))
      NativeWebSocketHandler(queue, TaskMonadAsyncError)
    }
  }
} 
Example 80
Source File: HttpClientMonixBackend.scala    From sttp   with Apache License 2.0 5 votes vote down vote up
package sttp.client.httpclient.monix

import java.io.InputStream
import java.net.http.HttpRequest.BodyPublishers
import java.net.http.{HttpClient, HttpRequest}
import java.nio.ByteBuffer

import cats.effect.Resource
import monix.eval.Task
import monix.execution.Scheduler
import monix.reactive.Observable
import org.reactivestreams.FlowAdapters
import sttp.client.httpclient.HttpClientBackend.EncodingHandler
import sttp.client.httpclient.{HttpClientAsyncBackend, HttpClientBackend, WebSocketHandler}
import sttp.client.impl.monix.TaskMonadAsyncError
import sttp.client.testing.SttpBackendStub
import sttp.client.{FollowRedirectsBackend, SttpBackend, SttpBackendOptions}

import scala.util.{Success, Try}

class HttpClientMonixBackend private (
    client: HttpClient,
    closeClient: Boolean,
    customizeRequest: HttpRequest => HttpRequest,
    customEncodingHandler: EncodingHandler
)(implicit s: Scheduler)
    extends HttpClientAsyncBackend[Task, Observable[ByteBuffer]](
      client,
      TaskMonadAsyncError,
      closeClient,
      customizeRequest,
      customEncodingHandler
    ) {
  override def streamToRequestBody(stream: Observable[ByteBuffer]): Task[HttpRequest.BodyPublisher] = {
    monad.eval(BodyPublishers.fromPublisher(FlowAdapters.toFlowPublisher(stream.toReactivePublisher)))
  }

  override def responseBodyToStream(responseBody: InputStream): Try[Observable[ByteBuffer]] = {
    Success(
      Observable
        .fromInputStream(Task.now(responseBody))
        .map(ByteBuffer.wrap)
        .guaranteeCase(_ => Task(responseBody.close()))
    )
  }
}

object HttpClientMonixBackend {
  private def apply(
      client: HttpClient,
      closeClient: Boolean,
      customizeRequest: HttpRequest => HttpRequest,
      customEncodingHandler: EncodingHandler
  )(implicit
      s: Scheduler
  ): SttpBackend[Task, Observable[ByteBuffer], WebSocketHandler] =
    new FollowRedirectsBackend(
      new HttpClientMonixBackend(client, closeClient, customizeRequest, customEncodingHandler)(s)
    )

  def apply(
      options: SttpBackendOptions = SttpBackendOptions.Default,
      customizeRequest: HttpRequest => HttpRequest = identity,
      customEncodingHandler: EncodingHandler = PartialFunction.empty
  )(implicit
      s: Scheduler = Scheduler.global
  ): Task[SttpBackend[Task, Observable[ByteBuffer], WebSocketHandler]] =
    Task.eval(
      HttpClientMonixBackend(
        HttpClientBackend.defaultClient(options),
        closeClient = true,
        customizeRequest,
        customEncodingHandler
      )(s)
    )

  def resource(
      options: SttpBackendOptions = SttpBackendOptions.Default,
      customizeRequest: HttpRequest => HttpRequest = identity,
      customEncodingHandler: EncodingHandler = PartialFunction.empty
  )(implicit
      s: Scheduler = Scheduler.global
  ): Resource[Task, SttpBackend[Task, Observable[ByteBuffer], WebSocketHandler]] =
    Resource.make(apply(options, customizeRequest, customEncodingHandler))(_.close())

  def usingClient(
      client: HttpClient,
      customizeRequest: HttpRequest => HttpRequest = identity,
      customEncodingHandler: EncodingHandler = PartialFunction.empty
  )(implicit s: Scheduler = Scheduler.global): SttpBackend[Task, Observable[ByteBuffer], WebSocketHandler] =
    HttpClientMonixBackend(client, closeClient = false, customizeRequest, customEncodingHandler)(s)

  
  def stub: SttpBackendStub[Task, Observable[ByteBuffer], WebSocketHandler] = SttpBackendStub(TaskMonadAsyncError)
} 
Example 81
Source File: GrpcMonix.scala    From grpcmonix   with MIT License 5 votes vote down vote up
package grpcmonix

import com.google.common.util.concurrent.ListenableFuture
import io.grpc.stub.StreamObserver
import monix.eval.{Callback, Task}
import monix.execution.Ack.{Continue, Stop}
import monix.execution.{Ack, Scheduler}
import monix.reactive.Observable
import monix.reactive.observables.ObservableLike.{Operator, Transformer}
import monix.reactive.observers.Subscriber
import monix.reactive.subjects.PublishSubject
import org.reactivestreams.{Subscriber => SubscriberR}
import scalapb.grpc.Grpc

import scala.concurrent.Future

object GrpcMonix {

  type GrpcOperator[I, O] = StreamObserver[O] => StreamObserver[I]

  def guavaFutureToMonixTask[T](future: ListenableFuture[T]): Task[T] =
    Task.deferFuture {
      Grpc.guavaFuture2ScalaFuture(future)
    }

  def grpcOperatorToMonixOperator[I,O](grpcOperator: GrpcOperator[I,O]): Operator[I,O] = {
    outputSubsriber: Subscriber[O] =>
      val outputObserver: StreamObserver[O] = monixSubscriberToGrpcObserver(outputSubsriber)
      val inputObserver: StreamObserver[I] = grpcOperator(outputObserver)
      grpcObserverToMonixSubscriber(inputObserver, outputSubsriber.scheduler)
  }

  def monixSubscriberToGrpcObserver[T](subscriber: Subscriber[T]): StreamObserver[T] =
    new StreamObserver[T] {
      override def onError(t: Throwable): Unit = subscriber.onError(t)
      override def onCompleted(): Unit = subscriber.onComplete()
      override def onNext(value: T): Unit = subscriber.onNext(value)
    }

  def reactiveSubscriberToGrpcObserver[T](subscriber: SubscriberR[_ >: T]): StreamObserver[T] =
    new StreamObserver[T] {
      override def onError(t: Throwable): Unit = subscriber.onError(t)
      override def onCompleted(): Unit = subscriber.onComplete()
      override def onNext(value: T): Unit = subscriber.onNext(value)
    }

  def grpcObserverToMonixSubscriber[T](observer: StreamObserver[T], s: Scheduler): Subscriber[T] =
    new Subscriber[T] {
      override implicit def scheduler: Scheduler = s
      override def onError(t: Throwable): Unit = observer.onError(t)
      override def onComplete(): Unit = observer.onCompleted()
      override def onNext(value: T): Future[Ack] =
        try {
          observer.onNext(value)
          Continue
        } catch {
          case t: Throwable =>
            observer.onError(t)
            Stop
        }
    }

  def grpcObserverToMonixCallback[T](observer: StreamObserver[T]): Callback[T] =
    new Callback[T] {
      override def onError(t: Throwable): Unit = observer.onError(t)
      override def onSuccess(value: T): Unit = {
        observer.onNext(value)
        observer.onCompleted()
      }
    }

  def liftByGrpcOperator[I, O](observable: Observable[I], operator: GrpcOperator[I, O]): Observable[O] =
    observable.liftByOperator(
      grpcOperatorToMonixOperator(operator)
    )

  def unliftByTransformer[I, O](transformer: Transformer[I, O], subscriber: Subscriber[O]): Subscriber[I] =
    new Subscriber[I] {
      private[this] val subject = PublishSubject[I]()
      subject.transform(transformer).subscribe(subscriber)

      override implicit def scheduler: Scheduler = subscriber.scheduler
      override def onError(t: Throwable): Unit = subject.onError(t)
      override def onComplete(): Unit = subject.onComplete()
      override def onNext(value: I): Future[Ack] = subject.onNext(value)
    }

} 
Example 82
Source File: MigrateV12ToV13.scala    From nexus-kg   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.kg

import akka.actor.ActorSystem
import akka.persistence.cassandra.query.scaladsl.CassandraReadJournal
import akka.persistence.query.{EventEnvelope, NoOffset, PersistenceQuery}
import cats.implicits._
import ch.epfl.bluebrain.nexus.admin.client.AdminClient
import ch.epfl.bluebrain.nexus.admin.client.types.Project
import ch.epfl.bluebrain.nexus.commons.test.Resources
import ch.epfl.bluebrain.nexus.iam.client.types._
import ch.epfl.bluebrain.nexus.kg.config.AppConfig
import ch.epfl.bluebrain.nexus.kg.config.Vocabulary.nxv
import ch.epfl.bluebrain.nexus.kg.resources.Event.{Created, Updated}
import ch.epfl.bluebrain.nexus.kg.resources.{OrganizationRef, ResId, Views}
import com.typesafe.scalalogging.Logger
import io.circe.Json
import io.circe.parser.parse
import monix.eval.Task
import monix.execution.Scheduler
import monix.execution.schedulers.CanBlock

import scala.concurrent.Future

object MigrateV12ToV13 extends Resources {
  private val log                                     = Logger[MigrateV12ToV13.type]
  private val newMapping                              = jsonContentOf("/elasticsearch/mapping.json")
  private val defaultEsId                             = nxv.defaultElasticSearchIndex.value
  private implicit val mockedAcls: AccessControlLists = AccessControlLists.empty

  def migrate(
      views: Views[Task],
      adminClient: AdminClient[Task]
  )(implicit config: AppConfig, as: ActorSystem, sc: Scheduler, pm: CanBlock): Unit = {

    implicit val token: Option[AuthToken] = config.iam.serviceAccountToken

    def checkAndUpdateMapping(id: ResId, rev: Long, source: Json)(
        implicit project: Project,
        caller: Caller
    ): Task[Unit] = {

      source.hcursor.get[String]("mapping").flatMap(parse) match {
        case Left(err) =>
          log.error(s"Error while fetching mapping for view id ${id.show}. Reason: '$err'")
          Task.unit
        case Right(mapping) if mapping == newMapping =>
          Task.unit
        case _ =>
          views.update(id, rev, source deepMerge Json.obj("mapping" -> newMapping)).value.flatMap {
            case Left(err) =>
              log.error(s"Error updating the view with id '${id.show}' and rev '$rev'. Reason: '$err'")
              Task.unit
            case _ =>
              log.info(s"View with id '${id.show}' and rev '$rev' was successfully updated.")
              Task.unit
          }
      }
    }

    def fetchProject(orgRef: OrganizationRef, id: ResId)(f: Project => Task[Unit]): Task[Unit] = {
      adminClient.fetchProject(orgRef.id, id.parent.id).flatMap {
        case Some(project) => f(project)
        case None =>
          log.error(s"Project with id '${id.parent.id}' was not found for view with id '${id.show}'")
          Task.unit

      }
    }

    log.info("Migrating views mappings.")
    val pq = PersistenceQuery(as).readJournalFor[CassandraReadJournal](CassandraReadJournal.Identifier)
    Task
      .fromFuture {
        pq.currentEventsByTag(s"type=${nxv.ElasticSearchView.value.asString}", NoOffset)
          .mapAsync(1) {
            case EventEnvelope(_, _, _, Created(id, orgRef, _, _, source, _, subject)) if id.value == defaultEsId =>
              fetchProject(orgRef, id) { project =>
                checkAndUpdateMapping(id, 1L, source)(project, Caller(subject, Set(subject)))
              }.runToFuture
            case EventEnvelope(_, _, _, Updated(id, orgRef, rev, _, source, _, subject)) if id.value == defaultEsId =>
              fetchProject(orgRef, id) { project =>
                checkAndUpdateMapping(id, rev, source)(project, Caller(subject, Set(subject)))
              }.runToFuture
            case _ =>
              Future.unit

          }
          .runFold(0) {
            case (acc, _) =>
              if (acc % 10 == 0) log.info(s"Processed '$acc' persistence ids.")
              acc + 1
          }
          .map(_ => ())
      }
      .runSyncUnsafe()
    log.info("Finished migrating views mappings.")
  }

} 
Example 83
Source File: RepairFromMessages.scala    From nexus-kg   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.kg

import java.net.URLDecoder
import java.util.UUID

import akka.actor.ActorSystem
import akka.persistence.cassandra.query.scaladsl.CassandraReadJournal
import akka.persistence.query.PersistenceQuery
import ch.epfl.bluebrain.nexus.kg.resources.{Id, Repo, ResId}
import ch.epfl.bluebrain.nexus.kg.resources.ProjectIdentifier.ProjectRef
import ch.epfl.bluebrain.nexus.rdf.Iri
import com.typesafe.scalalogging.Logger
import monix.eval.Task
import monix.execution.Scheduler
import monix.execution.schedulers.CanBlock

import scala.concurrent.Future
import scala.util.Try


object RepairFromMessages {
  // $COVERAGE-OFF$

  private val log = Logger[RepairFromMessages.type]

  def repair(repo: Repo[Task])(implicit as: ActorSystem, sc: Scheduler, pm: CanBlock): Unit = {
    log.info("Repairing dependent tables from messages.")
    val pq = PersistenceQuery(as).readJournalFor[CassandraReadJournal](CassandraReadJournal.Identifier)
    Task
      .fromFuture {
        pq.currentPersistenceIds()
          .mapAsync(1) {
            case ResourceId(id) => (repo.get(id, None).value >> Task.unit).runToFuture
            case other =>
              log.warn(s"Unknown persistence id '$other'")
              Future.successful(())
          }
          .runFold(0) {
            case (acc, _) =>
              if (acc % 1000 == 0) log.info(s"Processed '$acc' persistence ids.")
              acc + 1
          }
          .map(_ => ())
      }
      .runSyncUnsafe()
    log.info("Finished repairing dependent tables from messages.")
  }

  object ResourceId {
    private val regex =
      "^resources\\-([0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12})\\-(.+)$".r
    def unapply(arg: String): Option[ResId] =
      arg match {
        case regex(stringUuid, stringId) =>
          for {
            uuid <- Try(UUID.fromString(stringUuid)).toOption
            iri  <- Iri.absolute(URLDecoder.decode(stringId, "UTF-8")).toOption
          } yield Id(ProjectRef(uuid), iri)
        case _ => None
      }
  }
  // $COVERAGE-ON$
} 
Example 84
Source File: GRPCServerExtension.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.api.grpc

import java.net.InetSocketAddress

import com.wavesplatform.extensions.{Extension, Context => ExtensionContext}
import com.wavesplatform.settings.GRPCSettings
import com.wavesplatform.utils.ScorexLogging
import io.grpc.Server
import io.grpc.netty.NettyServerBuilder
import monix.execution.Scheduler
import net.ceedubs.ficus.Ficus._
import net.ceedubs.ficus.readers.ArbitraryTypeReader._

import scala.concurrent.Future

class GRPCServerExtension(context: ExtensionContext) extends Extension with ScorexLogging {
  @volatile
  var server: Server = _

  override def start(): Unit = {
    val settings = context.settings.config.as[GRPCSettings]("waves.grpc")
    this.server = startServer(settings)
  }

  override def shutdown(): Future[Unit] = {
    log.debug("Shutting down gRPC server")
    if (server != null) {
      server.shutdown()
      Future(server.awaitTermination())(context.actorSystem.dispatcher)
    } else {
      Future.successful(())
    }
  }

  private[this] def startServer(settings: GRPCSettings): Server = {
    implicit val apiScheduler: Scheduler = Scheduler(context.actorSystem.dispatcher)

    val bindAddress = new InetSocketAddress(settings.host, settings.port)
    val server: Server = NettyServerBuilder
      .forAddress(bindAddress)
      .addService(TransactionsApiGrpc.bindService(new TransactionsApiGrpcImpl(context.transactionsApi), apiScheduler))
      .addService(BlocksApiGrpc.bindService(new BlocksApiGrpcImpl(context.blocksApi), apiScheduler))
      .addService(AccountsApiGrpc.bindService(new AccountsApiGrpcImpl(context.accountsApi), apiScheduler))
      .addService(AssetsApiGrpc.bindService(new AssetsApiGrpcImpl(context.assetsApi, context.accountsApi), apiScheduler))
      .addService(BlockchainApiGrpc.bindService(new BlockchainApiGrpcImpl(context.blockchain, context.settings.featuresSettings), apiScheduler))
      .build()
      .start()

    log.info(s"gRPC API was bound to $bindAddress")
    server
  }
} 
Example 85
Source File: AccountsApiGrpcImpl.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.api.grpc

import com.google.protobuf.ByteString
import com.google.protobuf.wrappers.{BytesValue, StringValue}
import com.wavesplatform.account.{Address, Alias}
import com.wavesplatform.api.common.CommonAccountsApi
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.protobuf.Amount
import com.wavesplatform.protobuf.transaction.PBTransactions
import com.wavesplatform.transaction.Asset
import io.grpc.stub.StreamObserver
import monix.execution.Scheduler
import monix.reactive.Observable

import scala.concurrent.Future

class AccountsApiGrpcImpl(commonApi: CommonAccountsApi)(implicit sc: Scheduler) extends AccountsApiGrpc.AccountsApi {

  private def loadWavesBalance(address: Address): BalanceResponse = {
    val details = commonApi.balanceDetails(address)
    BalanceResponse().withWaves(
      BalanceResponse.WavesBalances(
        details.regular,
        details.generating,
        details.available,
        details.effective,
        details.leaseIn,
        details.leaseOut
      )
    )
  }

  private def assetBalanceResponse(v: (Asset.IssuedAsset, Long)): BalanceResponse =
    BalanceResponse().withAsset(Amount(v._1.id.toPBByteString, v._2))

  override def getBalances(request: BalancesRequest, responseObserver: StreamObserver[BalanceResponse]): Unit = responseObserver.interceptErrors {
    val addressOption: Option[Address] = if (request.address.isEmpty) None else Some(request.address.toAddress)
    val assetIds: Seq[Asset]           = request.assets.map(id => if (id.isEmpty) Asset.Waves else Asset.IssuedAsset(ByteStr(id.toByteArray)))

    val responseStream = (addressOption, assetIds) match {
      case (Some(address), Seq()) =>
        Observable(loadWavesBalance(address)) ++ commonApi.portfolio(address).map(assetBalanceResponse)
      case (Some(address), nonEmptyList) =>
        Observable
          .fromIterable(nonEmptyList)
          .map {
            case Asset.Waves           => loadWavesBalance(address)
            case ia: Asset.IssuedAsset => assetBalanceResponse(ia -> commonApi.assetBalance(address, ia))
          }
      case (None, Seq(_)) => // todo: asset distribution
        Observable.empty
      case (None, _) => // multiple distributions are not supported
        Observable.empty
    }

    responseObserver.completeWith(responseStream)
  }

  override def getScript(request: AccountRequest): Future[ScriptData] = Future {
    commonApi.script(request.address.toAddress) match {
      case Some(desc) => ScriptData(PBTransactions.toPBScript(Some(desc.script)), desc.script.expr.toString, desc.verifierComplexity)
      case None       => ScriptData()
    }
  }

  override def getActiveLeases(request: AccountRequest, responseObserver: StreamObserver[TransactionResponse]): Unit =
    responseObserver.interceptErrors {
      val transactions = commonApi.activeLeases(request.address.toAddress)
      val result       = transactions.map { case (height, transaction) => TransactionResponse(transaction.id(), height, Some(transaction.toPB)) }
      responseObserver.completeWith(result)
    }

  override def getDataEntries(request: DataRequest, responseObserver: StreamObserver[DataEntryResponse]): Unit = responseObserver.interceptErrors {
    val stream = if (request.key.nonEmpty) {
      Observable.fromIterable(commonApi.data(request.address.toAddress, request.key))
    } else {
      commonApi.dataStream(request.address.toAddress, Option(request.key).filter(_.nonEmpty))
    }

    responseObserver.completeWith(stream.map(de => DataEntryResponse(request.address, Some(PBTransactions.toPBDataEntry(de)))))
  }

  override def resolveAlias(request: StringValue): Future[BytesValue] =
    Future {
      val result = for {
        alias   <- Alias.create(request.value)
        address <- commonApi.resolveAlias(alias)
      } yield BytesValue(ByteString.copyFrom(address.bytes))

      result.explicitGetErr()
    }
} 
Example 86
Source File: AssetsApiGrpcImpl.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.api.grpc

import com.wavesplatform.account.Address
import com.wavesplatform.api.common.{CommonAccountsApi, CommonAssetsApi}
import com.wavesplatform.api.http.ApiError.TransactionDoesNotExist
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.protobuf.transaction.PBTransactions
import com.wavesplatform.state.AssetScriptInfo
import com.wavesplatform.state.AssetDescription
import com.wavesplatform.transaction.Asset.IssuedAsset
import io.grpc.stub.StreamObserver
import monix.execution.Scheduler
import monix.reactive.Observable

import scala.concurrent.Future

class AssetsApiGrpcImpl(assetsApi: CommonAssetsApi, accountsApi: CommonAccountsApi)(implicit sc: Scheduler) extends AssetsApiGrpc.AssetsApi {
  override def getInfo(request: AssetRequest): Future[AssetInfoResponse] = Future {
    val result =
      for (info <- assetsApi.fullInfo(IssuedAsset(request.assetId)))
        yield {
          val result = assetInfoResponse(info.description).withSponsorBalance(info.sponsorBalance.getOrElse(0))
          info.issueTransaction.map(_.toPB).fold(result)(result.withIssueTransaction)
        }
    result.explicitGetErr(TransactionDoesNotExist)
  }

  override def getNFTList(request: NFTRequest, responseObserver: StreamObserver[NFTResponse]): Unit = responseObserver.interceptErrors {
    val addressOption: Option[Address]    = if (request.address.isEmpty) None else Some(request.address.toAddress)
    val afterAssetId: Option[IssuedAsset] = if (request.afterAssetId.isEmpty) None else Some(IssuedAsset(ByteStr(request.afterAssetId.toByteArray)))

    val responseStream = addressOption match {
      case Some(address) =>
        accountsApi
          .nftList(address, afterAssetId)
          .map {
            case (a, d) => NFTResponse(a.id.toPBByteString, Some(assetInfoResponse(d)))
          }
          .take(request.limit)
      case _ => Observable.empty
    }

    responseObserver.completeWith(responseStream)
  }

  private def assetInfoResponse(d: AssetDescription): AssetInfoResponse =
    AssetInfoResponse(
      d.issuer,
      d.name.toStringUtf8,
      d.description.toStringUtf8,
      d.decimals,
      d.reissuable,
      d.totalVolume.longValue,
      d.script.map {
        case AssetScriptInfo(script, complexity) =>
          ScriptData(
            PBTransactions.toPBScript(Some(script)),
            script.expr.toString,
            complexity
          )
      },
      d.sponsorship
    )
} 
Example 87
Source File: BlockchainApiGrpcImpl.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.api.grpc

import com.google.protobuf.ByteString
import com.google.protobuf.empty.Empty
import com.wavesplatform.features.{BlockchainFeatureStatus, BlockchainFeatures}
import com.wavesplatform.settings.FeaturesSettings
import com.wavesplatform.state.Blockchain
import monix.execution.Scheduler

import scala.concurrent.Future

class BlockchainApiGrpcImpl(blockchain: Blockchain, featuresSettings: FeaturesSettings)(implicit sc: Scheduler)
    extends BlockchainApiGrpc.BlockchainApi {

  override def getActivationStatus(request: ActivationStatusRequest): Future[ActivationStatusResponse] = Future {
    val functionalitySettings = blockchain.settings.functionalitySettings

    ActivationStatusResponse(
      request.height,
      functionalitySettings.activationWindowSize(request.height),
      functionalitySettings.blocksForFeatureActivation(request.height),
      functionalitySettings.activationWindow(request.height).last,
      (blockchain.featureVotes(request.height).keySet ++
        blockchain.approvedFeatures.keySet ++
        BlockchainFeatures.implemented).toSeq.sorted.map(id => {
        val status = blockchain.featureStatus(id, request.height) match {
          case BlockchainFeatureStatus.Undefined => FeatureActivationStatus.BlockchainFeatureStatus.UNDEFINED
          case BlockchainFeatureStatus.Approved  => FeatureActivationStatus.BlockchainFeatureStatus.APPROVED
          case BlockchainFeatureStatus.Activated => FeatureActivationStatus.BlockchainFeatureStatus.ACTIVATED
        }

        FeatureActivationStatus(
          id,
          BlockchainFeatures.feature(id).fold("Unknown feature")(_.description),
          status,
          (BlockchainFeatures.implemented.contains(id), featuresSettings.supported.contains(id)) match {
            case (false, _) => FeatureActivationStatus.NodeFeatureStatus.NOT_IMPLEMENTED
            case (_, true)  => FeatureActivationStatus.NodeFeatureStatus.VOTED
            case _          => FeatureActivationStatus.NodeFeatureStatus.IMPLEMENTED
          },
          blockchain.featureActivationHeight(id).getOrElse(0),
          if (status.isUndefined) blockchain.featureVotes(request.height).getOrElse(id, 0) else 0
        )
      })
    )
  }

  override def getBaseTarget(request: Empty): Future[BaseTargetResponse] = Future {
    BaseTargetResponse(blockchain.lastBlockHeader.get.header.baseTarget)
  }

  override def getCumulativeScore(request: Empty): Future[ScoreResponse] = Future {
    ScoreResponse(ByteString.copyFrom(blockchain.score.toByteArray))
  }
} 
Example 88
Source File: BlocksApiGrpcImpl.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.api.grpc

import com.google.protobuf.empty.Empty
import com.google.protobuf.wrappers.UInt32Value
import com.wavesplatform.api.BlockMeta
import com.wavesplatform.api.common.CommonBlocksApi
import com.wavesplatform.api.grpc.BlockRangeRequest.Filter
import com.wavesplatform.api.grpc.BlockRequest.Request
import com.wavesplatform.api.http.ApiError.BlockDoesNotExist
import com.wavesplatform.protobuf.block.PBBlock
import com.wavesplatform.transaction.Transaction
import io.grpc.stub.StreamObserver
import monix.execution.Scheduler

import scala.concurrent.Future

class BlocksApiGrpcImpl(commonApi: CommonBlocksApi)(implicit sc: Scheduler) extends BlocksApiGrpc.BlocksApi {
  import BlocksApiGrpcImpl._

  override def getCurrentHeight(request: Empty): Future[UInt32Value] = {
    Future.successful(UInt32Value(commonApi.currentHeight))
  }

  override def getBlockRange(request: BlockRangeRequest, responseObserver: StreamObserver[BlockWithHeight]): Unit = responseObserver.interceptErrors {
    val stream =
      if (request.includeTransactions)
        commonApi
          .blocksRange(request.fromHeight, request.toHeight)
          .map(toBlockWithHeight)
      else
        commonApi
          .metaRange(request.fromHeight, request.toHeight)
          .map { meta =>
            BlockWithHeight(Some(PBBlock(Some(meta.header.toPBHeader), meta.signature)), meta.height)
          }

    responseObserver.completeWith(request.filter match {
      case Filter.GeneratorPublicKey(publicKey) => stream.filter(_.getBlock.getHeader.generator.toPublicKey == publicKey.toPublicKey)
      case Filter.GeneratorAddress(address)     => stream.filter(_.getBlock.getHeader.generator.toAddress == address.toAddress)
      case Filter.Empty                         => stream
    })
  }

  override def getBlock(request: BlockRequest): Future[BlockWithHeight] = Future {
    val result = request.request match {
      case Request.BlockId(blockId) =>
        commonApi
          .block(blockId)
          .map(toBlockWithHeight)

      case Request.Height(height) =>
        val actualHeight = if (height > 0) height else commonApi.currentHeight + height
        commonApi
          .blockAtHeight(actualHeight)
          .map(toBlockWithHeight)

      case Request.Empty =>
        None
    }

    val finalResult = if (request.includeTransactions) result else result.map(_.update(_.block.transactions := Nil))
    finalResult.explicitGetErr(BlockDoesNotExist)
  }
}

object BlocksApiGrpcImpl {
  private def toBlockWithHeight(v: (BlockMeta, Seq[(Transaction, Boolean)])) = {
    BlockWithHeight(Some(PBBlock(Some(v._1.header.toPBHeader), v._1.signature.toPBByteString, v._2.map(_._1.toPB))), v._1.height)
  }
} 
Example 89
Source File: Signed.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.transaction

import com.wavesplatform.transaction.TxValidationError.InvalidSignature
import monix.eval.{Coeval, Task}
import monix.execution.Scheduler
import monix.execution.schedulers.SchedulerService

import scala.concurrent.Await
import scala.concurrent.duration.Duration

trait Signed extends Authorized {
  protected val signatureValid: Coeval[Boolean]

  protected val signedDescendants: Coeval[Seq[Signed]] =
    Coeval(Nil)

  protected val signaturesValidMemoized: Task[Either[InvalidSignature, this.type]] =
    Signed.validateTask[this.type](this).memoize

  val signaturesValid: Coeval[Either[InvalidSignature, this.type]] =
    Coeval.evalOnce(Await.result(signaturesValidMemoized.runToFuture(Signed.scheduler), Duration.Inf))
}

object Signed {
  type E[A] = Either[InvalidSignature, A]

  private implicit lazy val scheduler: SchedulerService = {
    val parallelism = (Runtime.getRuntime.availableProcessors() / 2).max(1).min(4)
    Scheduler.computation(parallelism, "sig-validator")
  }

  def validateOrdered[S <: Signed](ss: Seq[S]): E[Seq[S]] =
    Await.result(
      Task
        .parTraverse(ss)(s => s.signaturesValidMemoized)
        .map(
          _.collectFirst { case Left(v) => Left(v) }.getOrElse(Right(ss))
        )
        .runAsyncLogErr,
      Duration.Inf
    )

  private def validateTask[S <: Signed](signedEntity: S): Task[E[S]] =
    Task {
      import cats.instances.either._
      import cats.instances.list._
      import cats.syntax.traverse._

      if (!signedEntity.signatureValid()) {
        Task.now(Left(InvalidSignature(signedEntity, None)))
      } else if (signedEntity.signedDescendants().isEmpty) {
        Task.now(Right(signedEntity))
      } else {
        Task
          .parTraverseUnordered(signedEntity.signedDescendants())(s => s.signaturesValidMemoized)
          .map(_.sequence.map(_ => signedEntity))
      }
    }.flatten
} 
Example 90
Source File: ChannelClosedHandler.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel._
import monix.execution.Scheduler
import monix.reactive.Observable
import monix.reactive.subjects.ConcurrentSubject

@Sharable
class ChannelClosedHandler private extends ChannelHandlerAdapter {
  private val closedChannelsSubject = ConcurrentSubject.publish[Channel](Scheduler.global)

  override def handlerAdded(ctx: ChannelHandlerContext): Unit = {
    ctx.channel().closeFuture().addListener((cf: ChannelFuture) => closedChannelsSubject.onNext(cf.channel()))
    super.handlerAdded(ctx)
  }

  def shutdown(): Unit = {
    closedChannelsSubject.onComplete()
  }
}

object ChannelClosedHandler {
  def apply(): (ChannelClosedHandler, Observable[Channel]) = {
    val h = new ChannelClosedHandler()
    (h, h.closedChannelsSubject)
  }
} 
Example 91
Source File: CustomDirectives.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.api.http

import akka.http.scaladsl.server.{Directive1, _}
import com.wavesplatform.http.ApiMarshallers
import com.wavesplatform.utils.ScorexLogging
import monix.execution.{Scheduler, UncaughtExceptionReporter}
import play.api.libs.json.JsObject

trait CustomDirectives extends Directives with ApiMarshallers with ScorexLogging {

  def anyParam(paramName: String): Directive1[Iterable[String]] =
    (get & parameter(paramName.as[String].*).map(_.toSeq.reverse)) |
      post & (formField(paramName.as[String].*) |
        entity(as[JsObject]).map { jso =>
          (jso \ s"${paramName}s").as[Iterable[String]]
        })

  def extractScheduler: Directive1[Scheduler] =
    extractExecutionContext.map(ec => Scheduler(ec, UncaughtExceptionReporter((t: Throwable) => log.debug("Error processing request", t))))
} 
Example 92
Source File: TimeLimitedRoute.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.api.http

import akka.http.scaladsl.marshalling.ToResponseMarshallable
import akka.http.scaladsl.server.{Directive1, ExceptionHandler, Route}
import com.google.common.util.concurrent.{ExecutionError, UncheckedExecutionException}
import com.wavesplatform.utils.Schedulers
import monix.execution.Scheduler

import scala.concurrent.ExecutionException

trait TimeLimitedRoute { self: ApiRoute =>
  def limitedScheduler: Scheduler

  def executeLimited[T](f: => T): Directive1[T] = {
    val handler = ExceptionHandler {
      case _: InterruptedException | _: ExecutionException | _: ExecutionError | _: UncheckedExecutionException =>
        complete(ApiError.CustomValidationError("The request took too long to complete"))
    }
    handleExceptions(handler) & onSuccess(Schedulers.executeCatchingInterruptedException(limitedScheduler)(f))
  }

  def completeLimited(f: => ToResponseMarshallable): Route =
    executeLimited(f)(complete(_))
} 
Example 93
Source File: ScorexLogging.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.utils

import monix.eval.Task
import monix.execution.{CancelableFuture, Scheduler}
import monix.reactive.Observable
import org.slf4j.{Logger, LoggerFactory}

case class LoggerFacade(logger: Logger) {
  def trace(message: => String, throwable: Throwable): Unit = {
    if (logger.isTraceEnabled)
      logger.trace(message, throwable)
  }

  def trace(message: => String): Unit = {
    if (logger.isTraceEnabled)
      logger.trace(message)
  }

  def debug(message: => String, arg: Any): Unit = {
    if (logger.isDebugEnabled)
      logger.debug(message, arg)
  }

  def debug(message: => String): Unit = {
    if (logger.isDebugEnabled)
      logger.debug(message)
  }

  def info(message: => String): Unit = {
    if (logger.isInfoEnabled)
      logger.info(message)
  }

  def info(message: => String, arg: Any): Unit = {
    if (logger.isInfoEnabled)
      logger.info(message, arg)
  }

  def info(message: => String, throwable: Throwable): Unit = {
    if (logger.isInfoEnabled)
      logger.info(message, throwable)
  }

  def warn(message: => String): Unit = {
    if (logger.isWarnEnabled)
      logger.warn(message)
  }

  def warn(message: => String, throwable: Throwable): Unit = {
    if (logger.isWarnEnabled)
      logger.warn(message, throwable)
  }

  def error(message: => String): Unit = {
    if (logger.isErrorEnabled)
      logger.error(message)
  }

  def error(message: => String, throwable: Throwable): Unit = {
    if (logger.isErrorEnabled)
      logger.error(message, throwable)
  }
}

trait ScorexLogging {
  protected lazy val log = LoggerFacade(LoggerFactory.getLogger(this.getClass))

  implicit class TaskExt[A](t: Task[A]) {
    def runAsyncLogErr(implicit s: Scheduler): CancelableFuture[A] =
      logErr.runToFuture(s)

    def logErr: Task[A] = {
      t.onErrorHandleWith(ex => {
        log.error(s"Error executing task", ex)
        Task.raiseError[A](ex)
      })
    }
  }

  implicit class ObservableExt[A](o: Observable[A]) {

    def logErr: Observable[A] = {
      o.onErrorHandleWith(ex => {
        log.error(s"Error observing item", ex)
        Observable.raiseError[A](ex)
      })
    }
  }
} 
Example 94
Source File: MicroblockAppender.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.state.appender

import cats.data.EitherT
import com.wavesplatform.block.Block.BlockId
import com.wavesplatform.block.MicroBlock
import com.wavesplatform.lang.ValidationError
import com.wavesplatform.metrics.{BlockStats, _}
import com.wavesplatform.network.MicroBlockSynchronizer.MicroblockData
import com.wavesplatform.network._
import com.wavesplatform.state.Blockchain
import com.wavesplatform.transaction.BlockchainUpdater
import com.wavesplatform.transaction.TxValidationError.InvalidSignature
import com.wavesplatform.utils.ScorexLogging
import com.wavesplatform.utx.UtxPool
import io.netty.channel.Channel
import io.netty.channel.group.ChannelGroup
import kamon.Kamon
import monix.eval.Task
import monix.execution.Scheduler

import scala.util.{Left, Right}

object MicroblockAppender extends ScorexLogging {
  def apply(blockchainUpdater: BlockchainUpdater with Blockchain, utxStorage: UtxPool, scheduler: Scheduler, verify: Boolean = true)(
      microBlock: MicroBlock
  ): Task[Either[ValidationError, BlockId]] = {

    Task(metrics.microblockProcessingTimeStats.measureSuccessful {
      blockchainUpdater
        .processMicroBlock(microBlock, verify)
        .map { totalBlockId =>
          utxStorage.removeAll(microBlock.transactionData)
          totalBlockId
        }
    }).executeOn(scheduler)
  }

  def apply(
      blockchainUpdater: BlockchainUpdater with Blockchain,
      utxStorage: UtxPool,
      allChannels: ChannelGroup,
      peerDatabase: PeerDatabase,
      scheduler: Scheduler
  )(ch: Channel, md: MicroblockData): Task[Unit] = {
    import md.microBlock
    val microblockTotalResBlockSig = microBlock.totalResBlockSig
    (for {
      _ <- EitherT(Task.now(microBlock.signaturesValid()))
      _ <- EitherT(apply(blockchainUpdater, utxStorage, scheduler)(microBlock))
    } yield ()).value.map {
      case Right(_) =>
        md.invOpt match {
          case Some(mi) => allChannels.broadcast(mi, except = md.microblockOwners())
          case None     => log.warn(s"${id(ch)} Not broadcasting MicroBlockInv")
        }
        BlockStats.applied(microBlock)
      case Left(is: InvalidSignature) =>
        peerDatabase.blacklistAndClose(ch, s"Could not append microblock $microblockTotalResBlockSig: $is")
      case Left(ve) =>
        BlockStats.declined(microBlock)
        log.debug(s"${id(ch)} Could not append microblock $microblockTotalResBlockSig: $ve")
    }
  }

  private[this] object metrics {
    val microblockProcessingTimeStats = Kamon.timer("microblock-appender.processing-time").withoutTags()
  }
} 
Example 95
Source File: RxScheduler.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform

import com.wavesplatform.account.KeyPair
import com.wavesplatform.block.{Block, MicroBlock}
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.common.utils.EitherExt2
import com.wavesplatform.crypto._
import com.wavesplatform.lagonaki.mocks.TestBlock
import com.wavesplatform.transaction.Asset.Waves
import com.wavesplatform.transaction.transfer._
import monix.execution.schedulers.SchedulerService
import monix.execution.{Ack, Scheduler}
import monix.reactive.Observer
import org.scalatest.{BeforeAndAfterAll, Suite}

import scala.concurrent.duration._
import scala.concurrent.{Await, Future}

trait RxScheduler extends BeforeAndAfterAll { _: Suite =>
  implicit val implicitScheduler: SchedulerService = Scheduler.singleThread("rx-scheduler")

  def testSchedulerName: String
  lazy val testScheduler: SchedulerService = Scheduler.singleThread(testSchedulerName)

  def test[A](f: => Future[A]): A = Await.result(f, 10.seconds)

  def send[A](p: Observer[A])(a: A): Future[Ack] =
    p.onNext(a)
      .map(ack => {
        Thread.sleep(500)
        ack
      })

  def byteStr(id: Int): ByteStr = ByteStr(Array.concat(Array.fill(SignatureLength - 1)(0), Array(id.toByte)))

  val signer: KeyPair = TestBlock.defaultSigner

  def block(id: Int): Block = TestBlock.create(Seq.empty).copy(signature = byteStr(id))

  def microBlock(total: Int, prev: Int): MicroBlock = {
    val tx = TransferTransaction.selfSigned(1.toByte, signer, signer.toAddress, Waves, 1, Waves, 1, ByteStr.empty, 1).explicitGet()
    MicroBlock.buildAndSign(3.toByte, signer, Seq(tx), byteStr(prev), byteStr(total)).explicitGet()
  }

  override protected def afterAll(): Unit = {
    super.afterAll()
    implicitScheduler.shutdown()
    testScheduler.shutdown()
  }
} 
Example 96
Source File: MicroBlockMinerSpec.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.mining

import com.wavesplatform.account.Alias
import com.wavesplatform.block.Block
import com.wavesplatform.common.utils._
import com.wavesplatform.db.WithDomain
import com.wavesplatform.features.BlockchainFeatures
import com.wavesplatform.lagonaki.mocks.TestBlock
import com.wavesplatform.mining.microblocks.MicroBlockMinerImpl
import com.wavesplatform.mining.microblocks.MicroBlockMinerImpl.MicroBlockMiningResult
import com.wavesplatform.settings.TestFunctionalitySettings
import com.wavesplatform.transaction.{CreateAliasTransaction, GenesisTransaction, TxVersion}
import com.wavesplatform.utils.Schedulers
import com.wavesplatform.utx.UtxPoolImpl
import com.wavesplatform.{TestValues, TransactionGen}
import monix.eval.Task
import monix.execution.Scheduler
import org.scalamock.scalatest.PathMockFactory
import org.scalatest.{FlatSpec, Matchers, PrivateMethodTester}

import scala.concurrent.duration._
import scala.util.Random

class MicroBlockMinerSpec extends FlatSpec with Matchers with PrivateMethodTester with PathMockFactory with WithDomain with TransactionGen {
  "Micro block miner" should "generate microblocks in flat interval" in {
    val scheduler = Schedulers.singleThread("test")
    val acc       = TestValues.keyPair
    val genesis   = GenesisTransaction.create(acc.toAddress, TestValues.bigMoney, TestValues.timestamp).explicitGet()
    val settings  = domainSettingsWithFS(TestFunctionalitySettings.withFeatures(BlockchainFeatures.NG))
    withDomain(settings) { d =>
      d.appendBlock(TestBlock.create(Seq(genesis)))
      val utxPool = new UtxPoolImpl(ntpTime, d.blockchainUpdater, ignoreSpendableBalanceChanged, settings.utxSettings, enablePriorityPool = true)
      val microBlockMiner = new MicroBlockMinerImpl(
        _ => (),
        null,
        d.blockchainUpdater,
        utxPool,
        settings.minerSettings,
        scheduler,
        scheduler
      )
      val generateOneMicroBlockTask = PrivateMethod[Task[MicroBlockMiningResult]](Symbol("generateOneMicroBlockTask"))

      def generateBlocks(
          block: Block,
          constraint: MiningConstraint,
          lastMicroBlock: Long
      ): Block = {
        val task = microBlockMiner invokePrivate generateOneMicroBlockTask(
          acc,
          block,
          MiningConstraints(d.blockchainUpdater, d.blockchainUpdater.height, Some(settings.minerSettings)),
          constraint,
          lastMicroBlock
        )
        import Scheduler.Implicits.global
        val startTime = System.nanoTime()
        val tx = CreateAliasTransaction
          .selfSigned(TxVersion.V1, acc, Alias.create("test" + Random.nextInt()).explicitGet(), TestValues.fee, TestValues.timestamp)
          .explicitGet()
        utxPool.putIfNew(tx).resultE.explicitGet()
        val result = task.runSyncUnsafe()
        result match {
          case res @ MicroBlockMinerImpl.Success(b, totalConstraint) =>
            val isFirstBlock = block.transactionData.isEmpty
            val elapsed = (res.nanoTime - startTime).nanos.toMillis

            if (isFirstBlock) elapsed should be < 1000L
            else elapsed shouldBe settings.minerSettings.microBlockInterval.toMillis +- 1000

            generateBlocks(b, totalConstraint, res.nanoTime)
          case MicroBlockMinerImpl.Stop =>
            d.blockchainUpdater.liquidBlock(d.blockchainUpdater.lastBlockId.get).get
          case MicroBlockMinerImpl.Retry =>
            throw new IllegalStateException()
        }
      }

      val baseBlock = Block
        .buildAndSign(
          3,
          TestValues.timestamp,
          d.lastBlockId,
          d.lastBlock.header.baseTarget,
          d.lastBlock.header.generationSignature,
          Nil,
          acc,
          Nil,
          0
        )
        .explicitGet()

      d.appendBlock(baseBlock)

      val constraint = OneDimensionalMiningConstraint(5, TxEstimators.one, "limit")
      val lastBlock = generateBlocks(baseBlock, constraint, 0)
      lastBlock.transactionData should have size constraint.rest.toInt
    }
    }
} 
Example 97
Source File: EnvRouting.scala    From typed-schema   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.tschema.finagle.envRouting

import cats.syntax.semigroup._
import com.twitter
import com.twitter.finagle.http.{Request, Response, Status}
import com.twitter.finagle.{Service, http}
import com.twitter.util.{Future, Promise}
import monix.eval.Task
import monix.execution.Scheduler
import ru.tinkoff.tschema.finagle.Rejection.Recover
import ru.tinkoff.tschema.finagle._
import ru.tinkoff.tschema.finagle.envRouting.EnvRouting.EnvHttp
import ru.tinkoff.tschema.utils.SubString
import tofu.env.Env

final case class EnvRouting[+R](
    request: http.Request,
    path: CharSequence,
    matched: Int,
    embedded: R
)

object EnvRouting extends EnvInstanceDecl {

  type EnvHttp[R, +A] = Env[EnvRouting[R], A]

  implicit def taskRouted[R]
      : RoutedPlus[EnvHttp[R, *]] with ConvertService[EnvHttp[R, *]] with LiftHttp[EnvHttp[R, *], Env[R, *]] =
    envRoutedAny.asInstanceOf[EnvRoutedConvert[R]]

  implicit def envRunnable[R](implicit
      recover: Recover[EnvHttp[R, *]] = Recover.default[EnvHttp[R, *]]
  ): RunHttp[EnvHttp[R, *], Env[R, *]] =
    response => {
      val handled = response.onErrorRecoverWith { case Rejected(rej) => recover(rej) }
      Env(r => Task.deferAction(implicit sched => Task.delay(execResponse(r, handled, _))))
    }

  private[this] def execResponse[R](r: R, envResponse: EnvHttp[R, Response], request: Request)(implicit
      sc: Scheduler
  ): Future[Response] = {
    val promise = Promise[Response]
    val routing = EnvRouting(request, SubString(request.path), 0, r)

    val cancelable = envResponse.run(routing).runAsync {
      case Right(res) => promise.setValue(res)
      case Left(ex)   =>
        val resp    = Response(Status.InternalServerError)
        val message = Option(ex.getLocalizedMessage).getOrElse(ex.toString)
        resp.setContentString(message)
        promise.setValue(resp)
    }

    promise.setInterruptHandler { case _ => cancelable.cancel() }

    promise
  }
}

private[finagle] class EnvInstanceDecl {

  protected trait EnvRoutedConvert[R]
      extends RoutedPlus[EnvHttp[R, *]] with ConvertService[EnvHttp[R, *]] with LiftHttp[EnvHttp[R, *], Env[R, *]] {
    private type F[a] = EnvHttp[R, a]
    implicit private[this] val self: RoutedPlus[F] = this

    def matched: F[Int] = Env.fromFunc(_.matched)

    def withMatched[A](m: Int, fa: F[A]): F[A] = fa.local(_.copy(matched = m))

    def path: F[CharSequence]                 = Env.fromFunc(_.path)
    def request: F[http.Request]              = Env.fromFunc(_.request)
    def reject[A](rejection: Rejection): F[A] =
      Routed.unmatchedPath[F].flatMap(path => throwRej(rejection withPath path.toString))

    def combineK[A](x: F[A], y: F[A]): F[A] =
      catchRej(x)(xrs => catchRej(y)(yrs => throwRej(xrs |+| yrs)))

    def convertService[A](svc: Service[http.Request, A]): F[A] =
      Env { r =>
        Task.cancelable { cb =>
          val fut = svc(r.request).respond {
            case twitter.util.Return(a) => cb.onSuccess(a)
            case twitter.util.Throw(ex) => cb.onError(ex)
          }

          Task(fut.raise(new InterruptedException))
        }
      }

    def apply[A](fa: Env[R, A]): EnvHttp[R, A]                                 = fa.localP(_.embedded)
    @inline private[this] def catchRej[A](z: F[A])(f: Rejection => F[A]): F[A] =
      z.onErrorRecoverWith { case Rejected(xrs) => f(xrs) }

    @inline private[this] def throwRej[A](map: Rejection): F[A]                = Env.raiseError(envRouting.Rejected(map))
  }

  protected object envRoutedAny extends EnvRoutedConvert[Any]
} 
Example 98
Source File: TaskRouting.scala    From typed-schema   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.tschema.finagle.envRouting

import cats.syntax.semigroup._
import com.twitter
import com.twitter.finagle.http.{Request, Response, Status}
import com.twitter.finagle.{Service, http}
import com.twitter.util.{Future, Promise}
import monix.eval.Task
import monix.execution.Scheduler
import ru.tinkoff.tschema.finagle.Rejection.Recover
import ru.tinkoff.tschema.finagle._
import ru.tinkoff.tschema.finagle.envRouting.TaskRouting.TaskHttp
import ru.tinkoff.tschema.utils.SubString
import tofu.env.Env

final case class TaskRouting(
    request: http.Request,
    path: CharSequence,
    matched: Int
)

object TaskRouting extends TaskInstanceDecl {

  type TaskHttp[+A] = Env[TaskRouting, A]

  implicit val taskRouted: RoutedPlus[TaskHttp] with ConvertService[TaskHttp] with LiftHttp[TaskHttp, Task] =
    new TaskRoutedConvert

  implicit def envRunnable(implicit
      recover: Recover[TaskHttp] = Recover.default[TaskHttp]
  ): RunHttp[TaskHttp, Task] =
    response => Task.deferAction(implicit sched => Task.delay(execResponse(response, _)))

  private[this] def execResponse(
      envResponse: TaskHttp[Response],
      request: Request
  )(implicit sc: Scheduler, recover: Recover[TaskHttp]): Future[Response] = {
    val promise = Promise[Response]
    val routing = TaskRouting(request, SubString(request.path), 0)

    val cancelable = envResponse.onErrorRecoverWith { case Rejected(rej) => recover(rej) }.run(routing).runAsync {
      case Right(res) => promise.setValue(res)
      case Left(ex)   =>
        val resp = Response(Status.InternalServerError)
        resp.setContentString(ex.getMessage)
        promise.setValue(resp)
    }

    promise.setInterruptHandler { case _ => cancelable.cancel() }

    promise
  }
}

private[finagle] class TaskInstanceDecl {

  protected class TaskRoutedConvert
      extends RoutedPlus[TaskHttp] with ConvertService[TaskHttp] with LiftHttp[TaskHttp, Task] {
    private type F[a] = TaskHttp[a]
    implicit private[this] val self: RoutedPlus[F] = this

    def matched: F[Int] = Env.fromFunc(_.matched)

    def withMatched[A](m: Int, fa: F[A]): F[A] = fa.local(_.copy(matched = m))

    def path: F[CharSequence]                 = Env.fromFunc(_.path)
    def request: F[http.Request]              = Env.fromFunc(_.request)
    def reject[A](rejection: Rejection): F[A] =
      Routed.unmatchedPath[F].flatMap(path => throwRej(rejection withPath path.toString))

    def combineK[A](x: F[A], y: F[A]): F[A] =
      catchRej(x)(xrs => catchRej(y)(yrs => throwRej(xrs |+| yrs)))

    def convertService[A](svc: Service[http.Request, A]): F[A] =
      Env { r =>
        Task.cancelable { cb =>
          val fut = svc(r.request).respond {
            case twitter.util.Return(a) => cb.onSuccess(a)
            case twitter.util.Throw(ex) => cb.onError(ex)
          }

          Task(fut.raise(new InterruptedException))
        }
      }

    def apply[A](fa: Task[A]): TaskHttp[A] = Env.fromTask(fa)

    @inline private[this] def catchRej[A](z: F[A])(f: Rejection => F[A]): F[A] =
      z.onErrorRecoverWith { case Rejected(xrs) => f(xrs) }

    @inline private[this] def throwRej[A](map: Rejection): F[A]                = Env.raiseError(envRouting.Rejected(map))
  }

} 
Example 99
Source File: MonixTest.scala    From phobos   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.phobos.test

import java.util.concurrent.Executors

import monix.execution.Scheduler
import monix.reactive.Observable
import org.scalatest.AsyncWordSpec
import ru.tinkoff.phobos.annotations.{ElementCodec, XmlCodec}
import ru.tinkoff.phobos.decoding.XmlDecoder
import ru.tinkoff.phobos.syntax.text
import ru.tinkoff.phobos.monix._

class MonixTest extends AsyncWordSpec {
  implicit val scheduler: Scheduler = Scheduler(Executors.newScheduledThreadPool(4))

  "Monix decoder" should {
    "decode case classes correctly" in {
      @ElementCodec
      case class Bar(@text txt: Int)
      @XmlCodec("foo")
      case class Foo(qux: Int, maybeBar: Option[Bar], bars: List[Bar])

      val xml = """
        |<foo>
        | <qux>1234</qux>
        | <bars>2</bars>
        | <maybeBar>1</maybeBar>
        | <bars>3</bars>
        |</foo>
        |""".stripMargin

      val foo = Foo(1234, Some(Bar(1)), List(Bar(2), Bar(3)))
      val observable = Observable.fromIterable(xml.toIterable.map(x => Array(x.toByte)))
      XmlDecoder[Foo]
        .decodeFromObservable(observable)
        .map(result => assert(result == foo))
        .runToFuture
    }
  }
} 
Example 100
Source File: MultiPartBody.scala    From RosHTTP   with MIT License 5 votes vote down vote up
package fr.hmil.roshttp.body

import java.nio.ByteBuffer

import monix.execution.Scheduler
import monix.reactive.Observable

import scala.util.Random


class MultiPartBody(parts: Map[String, BodyPart], subtype: String = "form-data")(implicit scheduler: Scheduler)
  extends BodyPart {

  val boundary = "----" + Random.alphanumeric.take(24).mkString.toLowerCase

  override def contentType: String = s"multipart/$subtype; boundary=$boundary"

  override def content: Observable[ByteBuffer] = {
    parts.
      // Prepend multipart encapsulation boundary and body part headers to
      // each body part.
      map({ case (name, part) =>
        ByteBuffer.wrap(
          ("\r\n--" + boundary + "\r\n" +
            "Content-Disposition: form-data; name=\"" + name + "\"\r\n" +
            s"Content-Type: ${part.contentType}\r\n" +
            "\r\n").getBytes("utf-8")
        ) +: part.content
      }).
      // Join body parts
      reduceLeft((acc, elem) => acc ++ elem).
      // Append the closing boundary
      :+(ByteBuffer.wrap(s"\r\n--$boundary--\r\n".getBytes("utf-8")))
  }
}

object MultiPartBody {
  def apply(parts: (String, BodyPart)*)(implicit scheduler: Scheduler): MultiPartBody =
    new MultiPartBody(Map(parts: _*))
} 
Example 101
Source File: SimpleHttpResponse.scala    From RosHTTP   with MIT License 5 votes vote down vote up
package fr.hmil.roshttp.response

import java.nio.ByteBuffer

import fr.hmil.roshttp.BackendConfig
import fr.hmil.roshttp.exceptions.ResponseException
import fr.hmil.roshttp.util.{HeaderMap, Utils}
import monix.execution.Scheduler
import monix.reactive.Observable

import scala.collection.mutable
import scala.concurrent.{Future, Promise}
import scala.util.{Failure, Success}


class SimpleHttpResponse(
    val statusCode: Int,
    val headers: HeaderMap[String],
    val body: String)
  extends HttpResponse

object SimpleHttpResponse extends HttpResponseFactory[SimpleHttpResponse] {
  override def apply(
      header: HttpResponseHeader,
      bodyStream: Observable[ByteBuffer],
      config: BackendConfig)
      (implicit scheduler: Scheduler): Future[SimpleHttpResponse] = {

    val charset = Utils.charsetFromContentType(header.headers.getOrElse("content-type", null))
    val buffers = mutable.Queue[ByteBuffer]()
    val promise = Promise[SimpleHttpResponse]()

    val streamCollector = bodyStream.
      foreach(elem => buffers.enqueue(elem)).
      map({_ =>
        val body = recomposeBody(buffers, config.maxChunkSize, charset)
        new SimpleHttpResponse(header.statusCode, header.headers, body)
      })

    streamCollector.onComplete({
      case res:Success[SimpleHttpResponse] =>
        promise.trySuccess(res.value)
      case e:Failure[_] =>
        promise.tryFailure(new ResponseException(e.exception, header))
    })

    promise.future
  }

  private def recomposeBody(seq: mutable.Queue[ByteBuffer], maxChunkSize: Int, charset: String): String = {
    // Allocate maximum expected body length
    val buffer = ByteBuffer.allocate(seq.length * maxChunkSize)
    val totalBytes = seq.foldLeft(0)({ (count, chunk) =>
      buffer.put(chunk)
      count + chunk.limit()
    })
    buffer.limit(totalBytes)
    Utils.getStringFromBuffer(buffer, charset)
  }
} 
Example 102
Source File: StreamHttpResponse.scala    From RosHTTP   with MIT License 5 votes vote down vote up
package fr.hmil.roshttp.response

import java.nio.ByteBuffer

import fr.hmil.roshttp.BackendConfig
import fr.hmil.roshttp.util.HeaderMap
import monix.execution.Scheduler
import monix.reactive.Observable

import scala.concurrent.Future


class StreamHttpResponse(
    val statusCode: Int,
    val headers: HeaderMap[String],
    val body: Observable[ByteBuffer])
extends HttpResponse

object StreamHttpResponse extends HttpResponseFactory[StreamHttpResponse] {
  override def apply(
      header: HttpResponseHeader,
      bodyStream: Observable[ByteBuffer],
      config: BackendConfig)
      (implicit scheduler: Scheduler): Future[StreamHttpResponse] =
    Future.successful(new StreamHttpResponse(header.statusCode, header.headers, bodyStream))
} 
Example 103
Source File: HttpDriver.scala    From RosHTTP   with MIT License 5 votes vote down vote up
package fr.hmil.roshttp

import fr.hmil.roshttp.node.Modules.{HttpModule, HttpsModule}
import fr.hmil.roshttp.response.{HttpResponse, HttpResponseFactory}
import monix.execution.Scheduler

import scala.concurrent.Future

private object HttpDriver extends DriverTrait {

  private var _driver: Option[DriverTrait] = None

  def send[T <: HttpResponse](req: HttpRequest, factory: HttpResponseFactory[T])(implicit scheduler: Scheduler):
      Future[T] = {
    _driver.getOrElse(chooseBackend()).send(req, factory)
  }

  private def chooseBackend(): DriverTrait = {
    if (HttpModule.isAvailable && HttpsModule.isAvailable) {
      _driver = Some(NodeDriver)
    } else {
      _driver = Some(BrowserDriver)
    }
    _driver.get
  }
} 
Example 104
Source File: KnownBossesMap.scala    From gbf-raidfinder   with MIT License 3 votes vote down vote up
package walfie.gbf.raidfinder

import akka.agent.Agent
import java.util.Date
import monix.execution.{Ack, Cancelable, Scheduler}
import monix.reactive._
import monix.reactive.subjects.ConcurrentSubject
import scala.concurrent.{ExecutionContext, Future}
import walfie.gbf.raidfinder.domain._

trait KnownBossesMap {
  def get(): Map[BossName, RaidBoss]
  def newBossObservable(): Observable[RaidBoss]

  
class KnownBossesObserver(
  initialBosses: Seq[RaidBoss]
)(implicit scheduler: Scheduler) extends Observer[RaidInfo] with KnownBossesMap {
  private val agent = Agent[Map[BossName, RaidBoss]](
    initialBosses.map(boss => boss.name -> boss)(scala.collection.breakOut)
  )

  // TODO: Write test for this
  private val subject = ConcurrentSubject.publish[RaidBoss]
  val newBossObservable: Observable[RaidBoss] = subject

  def onComplete(): Unit = ()
  def onError(e: Throwable): Unit = ()
  def onNext(elem: RaidInfo): Future[Ack] = {
    val name = elem.tweet.bossName
    val raidBoss = elem.boss
    if (!agent.get.isDefinedAt(name)) {
      subject.onNext(raidBoss)
    }
    agent.alter(_.updated(name, raidBoss)).flatMap(_ => Ack.Continue)
  }

  def get(): Map[BossName, RaidBoss] = agent.get()
  def purgeOldBosses(
    minDate:        Date,
    levelThreshold: Option[Int]
  ): Future[Map[BossName, RaidBoss]] = {
    agent.alter(_.filter {
      case (name, boss) => boss.lastSeen.after(minDate) || levelThreshold.exists(boss.level >= _)
    })
  }
}