monix.reactive.Observer Scala Examples

The following examples show how to use monix.reactive.Observer. 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: RollbackBenchmark.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform

import java.io.File

import com.google.common.primitives.Ints
import com.google.protobuf.ByteString
import com.wavesplatform.account.{Address, AddressScheme, KeyPair}
import com.wavesplatform.block.Block
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.common.utils._
import com.wavesplatform.database.{LevelDBWriter, openDB}
import com.wavesplatform.protobuf.transaction.PBRecipients
import com.wavesplatform.state.{Diff, Portfolio}
import com.wavesplatform.transaction.Asset.IssuedAsset
import com.wavesplatform.transaction.assets.IssueTransaction
import com.wavesplatform.transaction.{GenesisTransaction, Proofs}
import com.wavesplatform.utils.{NTP, ScorexLogging}
import monix.reactive.Observer

object RollbackBenchmark extends ScorexLogging {
  def main(args: Array[String]): Unit = {
    val settings      = Application.loadApplicationConfig(Some(new File(args(0))))
    val db            = openDB(settings.dbSettings.directory)
    val time          = new NTP(settings.ntpServer)
    val levelDBWriter = LevelDBWriter(db, Observer.stopped, settings)

    val issuer = KeyPair(new Array[Byte](32))

    log.info("Generating addresses")

    val addresses = 1 to 18000 map { i =>
      PBRecipients.toAddress(Ints.toByteArray(i) ++ new Array[Byte](Address.HashLength - 4), AddressScheme.current.chainId).explicitGet()
    }

    log.info("Generating issued assets")

    val assets = 1 to 200 map { i =>
      IssueTransaction(
        1.toByte,
        issuer.publicKey,
        ByteString.copyFromUtf8("asset-" + i),
        ByteString.EMPTY,
        100000e2.toLong,
        2.toByte,
        false,
        None,
        1e8.toLong,
        time.getTimestamp(),
        Proofs(ByteStr(new Array[Byte](64))),
        AddressScheme.current.chainId
      )
    }

    log.info("Building genesis block")
    val genesisBlock = Block
      .buildAndSign(
        1.toByte,
        time.getTimestamp(),
        Block.GenesisReference,
        1000,
        Block.GenesisGenerationSignature,
        GenesisTransaction.create(issuer.publicKey.toAddress, 100000e8.toLong, time.getTimestamp()).explicitGet() +: assets,
        issuer,
        Seq.empty,
        -1
      )
      .explicitGet()

    val map = assets.map(it => IssuedAsset(it.id()) -> 1L).toMap
    val portfolios = for {
      address <- addresses
    } yield address -> Portfolio(assets = map)

    log.info("Appending genesis block")
    levelDBWriter.append(
      Diff.empty.copy(portfolios = portfolios.toMap),
      0,
      0,
      None,
      genesisBlock.header.generationSignature,
      genesisBlock
    )

    val nextBlock =
      Block
        .buildAndSign(2.toByte, time.getTimestamp(), genesisBlock.id(), 1000, Block.GenesisGenerationSignature, Seq.empty, issuer, Seq.empty, -1)
        .explicitGet()
    val nextDiff = Diff.empty.copy(portfolios = addresses.map(_ -> Portfolio(1, assets = Map(IssuedAsset(assets.head.id()) -> 1L))).toMap)

    log.info("Appending next block")
    levelDBWriter.append(nextDiff, 0, 0, None, ByteStr.empty, nextBlock)

    log.info("Rolling back")
    val start = System.nanoTime()
    levelDBWriter.rollbackTo(genesisBlock.id())
    val end = System.nanoTime()
    log.info(f"Rollback took ${(end - start) * 1e-6}%.3f ms")
    levelDBWriter.close()
  }
} 
Example 2
Source File: WithBlockchain.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.events

import java.nio.file.Files

import com.wavesplatform.database.TestStorageFactory
import com.wavesplatform.settings.{WavesSettings, loadConfig}
import com.wavesplatform.state.Blockchain
import com.wavesplatform.transaction.BlockchainUpdater
import com.wavesplatform.{NTPTime, TestHelpers, database}
import monix.reactive.Observer
import org.scalatest.{BeforeAndAfterAll, BeforeAndAfterEach, Suite}

trait WithBlockchain extends BeforeAndAfterEach with BeforeAndAfterAll with NTPTime { _: Suite =>
  protected def settings: WavesSettings = WavesSettings.fromRootConfig(loadConfig(None))

  private val path = Files.createTempDirectory("leveldb-test")
  private val db   = database.openDB(path.toAbsolutePath.toString)
  private val (bcu, _) = TestStorageFactory(
    settings,
    db,
    ntpTime,
    Observer.stopped,
    BlockchainUpdateTriggers.noop
  )

  protected def blockchain: Blockchain = bcu

  
  protected def initBlockchain(blockchainUpdater: Blockchain with BlockchainUpdater): Unit = ()

  override protected def beforeAll(): Unit = {
    initBlockchain(bcu)
    super.beforeAll()
  }

  override def afterAll(): Unit = {
    bcu.shutdown()
    db.close()
    TestHelpers.deleteRecursively(path)
    super.afterAll()
  }
} 
Example 3
Source File: package.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.state

import com.wavesplatform.account.Address
import com.wavesplatform.api.common.AddressTransactions
import com.wavesplatform.common.state.ByteStr
import com.wavesplatform.database.{DBResource, LevelDBWriter, TestStorageFactory}
import com.wavesplatform.events.BlockchainUpdateTriggers
import com.wavesplatform.settings.TestSettings._
import com.wavesplatform.settings.{BlockchainSettings, FunctionalitySettings, GenesisSettings, RewardsSettings, TestSettings}
import com.wavesplatform.transaction.{Asset, Transaction}
import com.wavesplatform.utils.SystemTime
import monix.reactive.Observer
import org.iq80.leveldb.DB

package object utils {

  def addressTransactions(
      db: DB,
      diff: => Option[(Height, Diff)],
      address: Address,
      types: Set[Transaction.Type],
      fromId: Option[ByteStr]
  ): Seq[(Height, Transaction)] = {
    val resource = DBResource(db)
    try AddressTransactions.allAddressTransactions(resource, diff, address, None, types, fromId).map { case (h, tx, _) => h -> tx }.toSeq
    finally resource.close()
  }

  object TestLevelDB {
    def withFunctionalitySettings(
        writableDB: DB,
        spendableBalanceChanged: Observer[(Address, Asset)],
        fs: FunctionalitySettings
    ): LevelDBWriter =
      TestStorageFactory(
        TestSettings.Default.withFunctionalitySettings(fs),
        writableDB,
        SystemTime,
        spendableBalanceChanged,
        BlockchainUpdateTriggers.noop
      )._2

    def createTestBlockchainSettings(fs: FunctionalitySettings): BlockchainSettings =
      BlockchainSettings('T', fs, GenesisSettings.TESTNET, RewardsSettings.TESTNET)
  }
} 
Example 4
Source File: TestStorageFactory.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.database

import com.google.common.hash.{Funnels, BloomFilter => GBloomFilter}
import com.wavesplatform.account.Address
import com.wavesplatform.events.BlockchainUpdateTriggers
import com.wavesplatform.settings.WavesSettings
import com.wavesplatform.state.BlockchainUpdaterImpl
import com.wavesplatform.transaction.Asset
import com.wavesplatform.utils.Time
import monix.reactive.Observer
import org.iq80.leveldb.DB

object TestStorageFactory {
  private def wrappedFilter(): BloomFilter = new Wrapper(GBloomFilter.create(Funnels.byteArrayFunnel(), 1000L))

  def apply(
      settings: WavesSettings,
      db: DB,
      time: Time,
      spendableBalanceChanged: Observer[(Address, Asset)],
      blockchainUpdateTriggers: BlockchainUpdateTriggers
  ): (BlockchainUpdaterImpl, LevelDBWriter) = {
    val levelDBWriter: LevelDBWriter = new LevelDBWriter(db, spendableBalanceChanged, settings.blockchainSettings, settings.dbSettings) {
      override val orderFilter: BloomFilter        = wrappedFilter()
      override val dataKeyFilter: BloomFilter      = wrappedFilter()
      override val wavesBalanceFilter: BloomFilter = wrappedFilter()
      override val assetBalanceFilter: BloomFilter = wrappedFilter()
    }
    (
      new BlockchainUpdaterImpl(levelDBWriter, spendableBalanceChanged, settings, time, blockchainUpdateTriggers, loadActiveLeases(db, _, _)),
      levelDBWriter
    )
  }
} 
Example 5
Source File: ObservedLoadingCacheSpecification.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.utils

import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicLong

import com.google.common.base.Ticker
import com.google.common.cache.{CacheBuilder, CacheLoader, LoadingCache}
import com.wavesplatform.utils.ObservedLoadingCacheSpecification.FakeTicker
import monix.execution.Ack
import monix.reactive.Observer
import org.scalamock.scalatest.MockFactory
import org.scalatest.{FreeSpec, Matchers}

import scala.jdk.CollectionConverters._
import scala.concurrent.Future
import scala.concurrent.duration.DurationInt

class ObservedLoadingCacheSpecification extends FreeSpec with Matchers with MockFactory {
  private val ExpiringTime = 10.minutes

  "notifies" - {
    "on refresh" in test { (loadingCache, changes, _) =>
      (changes.onNext _).expects("foo").returning(Future.successful(Ack.Continue)).once()

      loadingCache.refresh("foo")
    }

    "on put" in test { (loadingCache, changes, _) =>
      (changes.onNext _).expects("foo").returning(Future.successful(Ack.Continue)).once()

      loadingCache.put("foo", 10)
    }

    "on putAll" in test { (loadingCache, changes, _) =>
      (changes.onNext _).expects("foo").returning(Future.successful(Ack.Continue)).once()
      (changes.onNext _).expects("bar").returning(Future.successful(Ack.Continue)).once()

      loadingCache.putAll(Map[String, Integer]("foo" -> 10, "bar" -> 11).asJava)
    }

    "on invalidate" in test { (loadingCache, changes, _) =>
      (changes.onNext _).expects("foo").returning(Future.successful(Ack.Continue)).once()

      loadingCache.invalidate("foo")
    }

    "on invalidateAll" in test { (loadingCache, changes, _) =>
      (changes.onNext _).expects("foo").returning(Future.successful(Ack.Continue)).once()
      (changes.onNext _).expects("bar").returning(Future.successful(Ack.Continue)).once()

      loadingCache.invalidateAll(Seq("foo", "bar").asJava)
    }
  }

  "don't notify" - {
    "on cache expiration" in test { (loadingCache, changes, ticker) =>
      (changes.onNext _).expects("foo").returning(Future.successful(Ack.Continue)).once()
      loadingCache.put("foo", 1)
      ticker.advance(ExpiringTime.toMillis + 100, TimeUnit.MILLISECONDS)
    }
  }

  private def test(f: (LoadingCache[String, Integer], Observer[String], FakeTicker) => Unit): Unit = {
    val changes = mock[Observer[String]]
    val ticker  = new FakeTicker()

    val delegate = CacheBuilder
      .newBuilder()
      .expireAfterWrite(ExpiringTime.toMillis, TimeUnit.MILLISECONDS)
      .ticker(ticker)
      .build(new CacheLoader[String, Integer] {
        override def load(key: String): Integer = key.length
      })

    val loadingCache = new ObservedLoadingCache(delegate, changes)
    f(loadingCache, changes, ticker)
  }
}

private object ObservedLoadingCacheSpecification {

  // see https://github.com/google/guava/blob/master/guava-testlib/src/com/google/common/testing/FakeTicker.java
  class FakeTicker extends Ticker {
    private val nanos                  = new AtomicLong()
    private var autoIncrementStepNanos = 0L

    def advance(time: Long, timeUnit: TimeUnit): FakeTicker = advance(timeUnit.toNanos(time))
    def advance(nanoseconds: Long): FakeTicker = {
      nanos.addAndGet(nanoseconds)
      this
    }

    def setAutoIncrementStep(autoIncrementStep: Long, timeUnit: TimeUnit): FakeTicker = {
      require(autoIncrementStep >= 0, "May not auto-increment by a negative amount")
      this.autoIncrementStepNanos = timeUnit.toNanos(autoIncrementStep)
      this
    }

    override def read: Long = nanos.getAndAdd(autoIncrementStepNanos)
  }
} 
Example 6
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 7
Source File: StorageFactory.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.history

import com.wavesplatform.account.Address
import com.wavesplatform.database.{DBExt, Keys, LevelDBWriter, loadActiveLeases}
import com.wavesplatform.events.BlockchainUpdateTriggers
import com.wavesplatform.mining.Miner
import com.wavesplatform.settings.WavesSettings
import com.wavesplatform.state.BlockchainUpdaterImpl
import com.wavesplatform.transaction.Asset
import com.wavesplatform.utils.{ScorexLogging, Time, UnsupportedFeature, forceStopApplication}
import monix.reactive.Observer
import org.iq80.leveldb.DB

object StorageFactory extends ScorexLogging {
  private val StorageVersion = 5

  def apply(
      settings: WavesSettings,
      db: DB,
      time: Time,
      spendableBalanceChanged: Observer[(Address, Asset)],
      blockchainUpdateTriggers: BlockchainUpdateTriggers,
      miner: Miner = _ => ()
  ): (BlockchainUpdaterImpl, AutoCloseable) = {
    checkVersion(db)
    val levelDBWriter = LevelDBWriter(db, spendableBalanceChanged, settings)
    val bui = new BlockchainUpdaterImpl(
      levelDBWriter,
      spendableBalanceChanged,
      settings,
      time,
      blockchainUpdateTriggers,
      (minHeight, maxHeight) => loadActiveLeases(db, minHeight, maxHeight),
      miner
    )
    (bui, levelDBWriter)
  }

  private def checkVersion(db: DB): Unit = db.readWrite { rw =>
    val version = rw.get(Keys.version)
    val height  = rw.get(Keys.height)
    if (version != StorageVersion) {
      if (height == 0) {
        // The storage is empty, set current version
        rw.put(Keys.version, StorageVersion)
      } else {
        // Here we've detected that the storage is not empty and doesn't contain version
        log.error(
          s"Storage version $version is not compatible with expected version $StorageVersion! Please, rebuild node's state, use import or sync from scratch."
        )
        log.error("FOR THIS REASON THE NODE STOPPED AUTOMATICALLY")
        forceStopApplication(UnsupportedFeature)
      }
    }
  }
} 
Example 8
Source File: ObservedLoadingCache.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.utils

import com.google.common.cache.{ForwardingLoadingCache, LoadingCache}
import monix.reactive.Observer

import scala.reflect.ClassTag

class ObservedLoadingCache[K, V](override val delegate: LoadingCache[K, V], changed: Observer[K])(implicit ct: ClassTag[K])
    extends ForwardingLoadingCache[K, V] {

  override def refresh(key: K): Unit = {
    super.refresh(key)
    changed.onNext(key)
  }

  override def put(key: K, value: V): Unit = {
    super.put(key, value)
    changed.onNext(key)
  }

  override def putAll(m: java.util.Map[_ <: K, _ <: V]): Unit = {
    super.putAll(m)
    m.keySet().forEach(k => changed.onNext(k))
  }

  override def invalidate(key: Any): Unit = {
    super.invalidate(key)
    onNext(key)
  }

  override def invalidateAll(keys: java.lang.Iterable[_]): Unit = {
    super.invalidateAll(keys)
    keys.forEach(onNext)
  }

  private def onNext(key: Any): Unit = key match {
    case k: K => changed.onNext(k)
    case _    =>
  }

} 
Example 9
Source File: BaseTargetChecker.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.it

import com.typesafe.config.ConfigFactory.{defaultApplication, defaultReference}
import com.wavesplatform.account.KeyPair
import com.wavesplatform.block.Block
import com.wavesplatform.common.utils.EitherExt2
import com.wavesplatform.consensus.PoSSelector
import com.wavesplatform.database.openDB
import com.wavesplatform.events.BlockchainUpdateTriggers
import com.wavesplatform.history.StorageFactory
import com.wavesplatform.settings._
import com.wavesplatform.transaction.Asset.Waves
import com.wavesplatform.utils.NTP
import monix.execution.UncaughtExceptionReporter
import monix.reactive.Observer
import net.ceedubs.ficus.Ficus._

object BaseTargetChecker {
  def main(args: Array[String]): Unit = {
    implicit val reporter: UncaughtExceptionReporter = UncaughtExceptionReporter.default
    val sharedConfig = Docker.genesisOverride
      .withFallback(Docker.configTemplate)
      .withFallback(defaultApplication())
      .withFallback(defaultReference())
      .resolve()

    val settings          = WavesSettings.fromRootConfig(sharedConfig)
    val db                = openDB("/tmp/tmp-db")
    val ntpTime           = new NTP("ntp.pool.org")
    val (blockchainUpdater, _) = StorageFactory(settings, db, ntpTime, Observer.empty, BlockchainUpdateTriggers.noop)
    val poSSelector       = PoSSelector(blockchainUpdater, settings.synchronizationSettings)

    try {
      val genesisBlock = Block.genesis(settings.blockchainSettings.genesisSettings).explicitGet()
      blockchainUpdater.processBlock(genesisBlock, genesisBlock.header.generationSignature)

      NodeConfigs.Default.map(_.withFallback(sharedConfig)).collect {
        case cfg if cfg.as[Boolean]("waves.miner.enable") =>
          val account = KeyPair.fromSeed(cfg.getString("account-seed")).explicitGet()
          val address   = account.toAddress
          val balance   = blockchainUpdater.balance(address, Waves)
          val timeDelay = poSSelector
            .getValidBlockDelay(blockchainUpdater.height, account, genesisBlock.header.baseTarget, balance)
            .explicitGet()

          f"$address: ${timeDelay * 1e-3}%10.3f s"
      }
    } finally ntpTime.close()
  }
} 
Example 10
Source File: TestObserver.scala    From gbf-raidfinder   with MIT License 5 votes vote down vote up
package walfie.gbf.raidfinder.util

import monix.execution.Ack
import monix.reactive.Observer
import scala.concurrent.Future

class TestObserver[T] extends Observer[T] {
  var received = Vector.empty[T]
  var errorsReceived = Vector.empty[Throwable]
  var isComplete: Boolean = false

  def onNext(elem: T): Future[Ack] = {
    received = received :+ elem
    Ack.Continue
  }

  def onError(e: Throwable): Unit = {
    errorsReceived = errorsReceived :+ e
  }

  def onComplete(): Unit = {
    isComplete = true
  }
} 
Example 11
Source File: Graph.scala    From monix-sample   with Apache License 2.0 5 votes vote down vote up
package client

import monix.execution.Ack
import monix.execution.Ack.Continue
import monix.reactive.Observer
import shared.models.Signal

import scala.concurrent.Future
import scala.scalajs.js
import scala.scalajs.js.Dynamic.{literal => obj, _}

final class Graph(elementId: String)
  extends Observer[(Signal, Signal, Signal, Signal)] {

  private[this] var chart: js.Dynamic = _

  def initChart(signal: (Signal, Signal, Signal, Signal)): js.Dynamic = {
    val (first, second, third, fourth) = signal
    val timestamp = Seq(first.timestamp, second.timestamp, third.timestamp, fourth.timestamp).max / 1000

    global.jQuery(s"#$elementId").epoch(obj(
      "type" -> "time.line",
      "data" -> js.Array(
        obj(
          "label" -> "Series 1",
          "axes" -> js.Array("left", "bottom", "right"),
          "values" -> js.Array(obj(
            "time" -> timestamp,
            "y" -> first.value.toInt
          ))
        ),
        obj(
          "label" -> "Series 2",
          "axes" -> js.Array("left", "bottom", "right"),
          "values" -> js.Array(obj(
            "time" -> timestamp,
            "y" -> second.value.toInt
          ))
        ),
        obj(
          "label" -> "Series 3",
          "axes" -> js.Array("left", "bottom", "right"),
          "values" -> js.Array(obj(
            "time" -> timestamp,
            "y" -> third.value.toInt
          ))
        ),
        obj(
          "label" -> "Series 4",
          "axes" -> js.Array("left", "bottom", "right"),
          "values" -> js.Array(obj(
            "time" -> timestamp,
            "y" -> fourth.value.toInt
          ))
        )
      )
    ))
  }
    
  private def serialize(signal: (Signal, Signal, Signal, Signal)) = {
    val (first, second, third, fourth) = signal
    val timestamp = Seq(first.timestamp, second.timestamp, third.timestamp, fourth.timestamp).max / 1000

    js.Array(
      obj(
        "time" -> timestamp,
        "y" -> first.value.toInt
      ),
      obj(
        "time" -> timestamp,
        "y" -> second.value.toInt
      ),
      obj(
        "time" -> timestamp,
        "y" -> third.value.toInt
      ),
      obj(
        "time" -> timestamp,
        "y" -> fourth.value.toInt
      ))
  }

  def onNext(signal: (Signal, Signal, Signal, Signal)): Future[Ack] = {
    if (chart == null)
      chart = initChart(signal)
    else
      chart.push(serialize(signal))

    Continue
  }

  def onComplete(): Unit = ()
  def onError(ex: Throwable): Unit = {
    System.err.println(s"ERROR: $ex")
  }
} 
Example 12
Source File: LanguageClient.scala    From lsp4s   with Apache License 2.0 5 votes vote down vote up
package scala.meta.jsonrpc

import cats.syntax.either._
import io.circe.Decoder
import io.circe.Encoder
import io.circe.syntax._
import java.io.OutputStream
import java.nio.ByteBuffer
import monix.eval.Callback
import monix.eval.Task
import monix.execution.Ack
import monix.execution.Cancelable
import monix.execution.atomic.Atomic
import monix.execution.atomic.AtomicInt
import monix.reactive.Observer
import scala.collection.concurrent.TrieMap
import scala.concurrent.Future
import scala.concurrent.duration.Duration
import MonixEnrichments._
import scribe.LoggerSupport

class LanguageClient(out: Observer[ByteBuffer], logger: LoggerSupport)
    extends JsonRpcClient {
  def this(out: OutputStream, logger: LoggerSupport) =
    this(Observer.fromOutputStream(out, logger), logger)
  private val writer = new MessageWriter(out, logger)
  private val counter: AtomicInt = Atomic(1)
  private val activeServerRequests =
    TrieMap.empty[RequestId, Callback[Response]]
  def notify[A: Encoder](method: String, notification: A): Future[Ack] =
    writer.write(Notification(method, Some(notification.asJson)))
  def serverRespond(response: Response): Future[Ack] = response match {
    case Response.Empty => Ack.Continue
    case x: Response.Success => writer.write(x)
    case x: Response.Error =>
      logger.error(s"Response error: $x")
      writer.write(x)
  }
  def clientRespond(response: Response): Unit =
    for {
      id <- response match {
        case Response.Empty => None
        case Response.Success(_, requestId) => Some(requestId)
        case Response.Error(_, requestId) => Some(requestId)
      }
      callback <- activeServerRequests.get(id).orElse {
        logger.error(s"Response to unknown request: $response")
        None
      }
    } {
      activeServerRequests.remove(id)
      callback.onSuccess(response)
    }

  def request[A: Encoder, B: Decoder](
      method: String,
      request: A
  ): Task[Either[Response.Error, B]] = {
    val nextId = RequestId(counter.incrementAndGet())
    val response = Task.create[Response] { (out, cb) =>
      val scheduled = out.scheduleOnce(Duration(0, "s")) {
        val json = Request(method, Some(request.asJson), nextId)
        activeServerRequests.put(nextId, cb)
        writer.write(json)
      }
      Cancelable { () =>
        scheduled.cancel()
        this.notify("$/cancelRequest", CancelParams(nextId.value))
      }
    }
    response.map {
      case Response.Empty =>
        Left(
          Response.invalidParams(
            s"Got empty response for request $request",
            nextId
          )
        )
      case err: Response.Error =>
        Left(err)
      case Response.Success(result, _) =>
        result.as[B].leftMap { err =>
          Response.invalidParams(err.toString, nextId)
        }
    }
  }
}

object LanguageClient {
  def fromOutputStream(out: OutputStream, logger: LoggerSupport) =
    new LanguageClient(Observer.fromOutputStream(out, logger), logger)
} 
Example 13
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 14
Source File: MessageWriter.scala    From lsp4s   with Apache License 2.0 5 votes vote down vote up
package scala.meta.jsonrpc

import java.io.ByteArrayOutputStream
import java.io.OutputStream
import java.io.OutputStreamWriter
import java.io.PrintWriter
import java.nio.ByteBuffer
import java.nio.charset.StandardCharsets
import scala.concurrent.Future
import io.circe.syntax._
import monix.execution.Ack
import monix.reactive.Observer
import scribe.LoggerSupport


  def write(msg: Message): Future[Ack] = lock.synchronized {
    baos.reset()
    val json = msg.asJson
    val protocol = BaseProtocolMessage.fromJson(json)
    logger.trace(s" --> $json")
    val byteBuffer = MessageWriter.write(protocol, baos, headerOut)
    out.onNext(byteBuffer)
  }
}

object MessageWriter {

  def headerWriter(out: OutputStream): PrintWriter = {
    new PrintWriter(new OutputStreamWriter(out, StandardCharsets.US_ASCII))
  }

  def write(message: BaseProtocolMessage): ByteBuffer = {
    val out = new ByteArrayOutputStream()
    val header = headerWriter(out)
    write(message, out, header)
  }

  def write(
      message: BaseProtocolMessage,
      out: ByteArrayOutputStream,
      headerOut: PrintWriter
  ): ByteBuffer = {
    message.header.foreach {
      case (key, value) =>
        headerOut.write(key)
        headerOut.write(": ")
        headerOut.write(value)
        headerOut.write("\r\n")
    }
    headerOut.write("\r\n")
    out.write(message.content)
    out.flush()
    val buffer = ByteBuffer.wrap(out.toByteArray, 0, out.size())
    buffer
  }
} 
Example 15
Source File: Cp.scala    From benchmarks   with Apache License 2.0 5 votes vote down vote up
package com.rossabaker
package benchmarks

import org.openjdk.jmh.annotations._

@State(Scope.Thread)
@Fork(2)
@Measurement(iterations = 10)
@Warmup(iterations = 10)
@Threads(1)
class Cp extends BenchmarkUtils {
  @Benchmark
  def fs2Sync(): Unit = {
    import _root_.fs2._, Stream._
    import java.nio.file.Paths
    io.file.readAll[Task](Paths.get("testdata/lorem-ipsum.txt"), 4096)
      .to(io.file.writeAll[Task](Paths.get("out/lorem-ipsum.txt")))
      .run
      .unsafeRun
  }

  @Benchmark
  def fs2Async(): Unit = {
    import _root_.fs2._, Stream._
    import java.nio.file.Paths
    io.file.readAllAsync[Task](Paths.get("testdata/lorem-ipsum.txt"), 4096)
      .to(io.file.writeAllAsync[Task](Paths.get("out/lorem-ipsum.txt")))
      .run
      .unsafeRun
  }

  @Benchmark
  def scalazStreamIo(): Unit = {
    import _root_.scalaz.stream._, Process._
    constant(4096)
      .through(io.fileChunkR("testdata/lorem-ipsum.txt"))
      .to(io.fileChunkW("out/lorem-ipsum.txt"))
      .run
      .unsafePerformSync
  }

  @Benchmark
  def scalazStreamNio(): Unit = {
    import _root_.scalaz.stream._, Process._
    constant(4096)
      .through(nio.file.chunkR("testdata/lorem-ipsum.txt"))
      .to(nio.file.chunkW("out/lorem-ipsum.txt"))
      .run
      .unsafePerformSync
  }

   }
            callback.onError(ex)
          }

          def onComplete(): Unit = {
            try {
              out.close()
              callback.onSuccess(())
            } catch {
              case NonFatal(ex) =>
                callback.onError(ex)
            }
          }
        }
      }

    Await.result(
      copyFile(new File("testdata/lorem-ipsum.txt"), new File("out/lorem-ipsum.txt"), 4096)
        .runAsync(monixScheduler),
      Duration.Inf
    )
  }
} 
Example 16
Source File: ObservableSpec.scala    From gbf-raidfinder   with MIT License 5 votes vote down vote up
package walfie.gbf.raidfinder.util

import monix.eval.Task
import monix.execution.Ack
import monix.execution.schedulers.TestScheduler
import monix.reactive.{Observable, Observer}
import org.scalatest._
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.Matchers._
import scala.concurrent.Future

class ObservableSpec extends FreeSpec with ScalaFutures {
  case class Item(id: Int)
  object ItemRepository {
    def getItems(count: Int, pageNum: Int): Future[Seq[Item]] =
      Future.successful {
        (0 until count).map(i => Item(pageNum * count + i))
      }
  }

  // This was added as [[ObservableUtil.fromAsyncStateAction]] before
  // [[Observable.fromAsyncStateAction]] existed in Monix. Keeping these
  // tests around because why not.
  "fromAsyncStateAction" - {
    implicit val scheduler = TestScheduler()

    "yield an observable" in {

      val itemsPerPage = 5

      val observable = Observable.fromAsyncStateAction { pageNum: Int =>
        val nextPage = pageNum + 1
        val itemsF = ItemRepository.getItems(itemsPerPage, pageNum)
        Task.fromFuture(itemsF).map(_ -> nextPage)
      }(0)

      val resultF = observable.take(3).toListL.runAsync
      scheduler.tick()

      resultF.futureValue shouldBe Seq(
        (0 to 4).map(Item.apply),
        (5 to 9).map(Item.apply),
        (10 to 14).map(Item.apply)
      )
    }

    "stop on error" in {
      implicit val scheduler = TestScheduler()

      // Create an observable counter that errors when it gets to 5
      val error = new RuntimeException("Oh no!")
      val observable = Observable
        .fromAsyncStateAction[Int, Int] { counter: Int =>
          Task.fromFuture {
            if (counter == 5) Future.failed(error)
            else Future.successful(counter -> (counter + 1))
          }
        }(0)

      val observer = new TestObserver[Int]

      observable.take(10).subscribe(observer)
      scheduler.tick()

      observer.received shouldBe (0 to 4)
    }
  }
} 
Example 17
Source File: KnownBossesObserverSpec.scala    From gbf-raidfinder   with MIT License 4 votes vote down vote up
package walfie.gbf.raidfinder

import java.util.Date
import monix.execution.schedulers.TestScheduler
import monix.reactive.Observer
import monix.reactive.subjects._
import org.mockito.Mockito._
import org.scalatest._
import org.scalatest.concurrent.{Eventually, ScalaFutures}
import org.scalatest.Matchers._
import org.scalatest.mockito.MockitoSugar
import scala.concurrent.{ExecutionContext, Future}
import scala.util.Random
import walfie.gbf.raidfinder.domain._

class KnownBossesObserverSpec extends KnownBossesObserverSpecHelpers {
  "Start with initial value" in new ObserverFixture {
    val boss1 = mockRaidInfo("A").boss
    val boss2 = mockRaidInfo("B").boss
    override val initialBosses = Seq(boss1, boss2)

    observer.get shouldBe Map("A" -> boss1, "B" -> boss2)
    cancelable.cancel()
  }

  "Keep last known of each boss" in new ObserverFixture {
    val bosses1 = (1 to 5).map(_ => mockRaidInfo("A"))
    val bosses2 = (1 to 10).map(_ => mockRaidInfo("B"))

    bosses1.foreach(raidInfos.onNext)
    bosses2.foreach(raidInfos.onNext)

    eventually {
      scheduler.tick()
      observer.get shouldBe Map(
        "A" -> bosses1.last.boss,
        "B" -> bosses2.last.boss
      )
    }
    cancelable.cancel()
  }

  "purgeOldBosses" - {
    "remove old bosses" in new ObserverFixture {
      val bosses = (1 to 10).map { i =>
        RaidBoss(name = i.toString, level = i, image = None, lastSeen = new Date(i), language = Language.Japanese)
      }
      override val initialBosses = bosses

      scheduler.tick()
      observer.get shouldBe bosses.map(boss => boss.name -> boss).toMap

      val resultF = observer.purgeOldBosses(minDate = new Date(5), levelThreshold = Some(100))
      scheduler.tick()

      resultF.futureValue shouldBe
        bosses.drop(5).map(boss => boss.name -> boss).toMap
    }

    "keep bosses that are above a certain level" in new ObserverFixture {
      val bosses = Seq(10, 50, 100, 120, 150).map { i =>
        RaidBoss(name = i.toString, level = i, image = None, lastSeen = new Date(0), language = Language.English)
      }
      override val initialBosses = bosses

      scheduler.tick()
      observer.get.values.toSet shouldBe bosses.toSet

      val resultF = observer.purgeOldBosses(minDate = new Date(5), levelThreshold = Some(100))
      scheduler.tick()

      resultF.futureValue.values.toSet shouldBe
        bosses.filter(_.level >= 100).toSet
    }
  }

}

trait KnownBossesObserverSpecHelpers extends FreeSpec
  with MockitoSugar with Eventually with ScalaFutures {

  trait ObserverFixture {
    implicit val scheduler = TestScheduler()
    val initialBosses: Seq[RaidBoss] = Seq.empty
    val raidInfos = ConcurrentSubject.replay[RaidInfo]
    lazy val (observer, cancelable) = KnownBossesObserver
      .fromRaidInfoObservable(raidInfos, initialBosses)
  }

  def mockRaidInfo(bossName: String): RaidInfo = {
    val tweet = mock[RaidTweet]
    when(tweet.bossName) thenReturn bossName
    when(tweet.createdAt) thenReturn (new Date(Random.nextLong.abs * 1000))
    val boss = mock[RaidBoss]
    when(boss.name) thenReturn bossName
    RaidInfo(tweet, boss)
  }
}