cats.effect.Sync Scala Examples
The following examples show how to use cats.effect.Sync.
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: NatPmpClient.scala From iotchain with MIT License | 6 votes |
package jbok.network.nat import cats.effect.Sync import cats.effect.concurrent.Ref import cats.implicits._ import com.offbynull.portmapper.gateways.network.NetworkGateway import com.offbynull.portmapper.gateways.network.internalmessages.KillNetworkRequest import com.offbynull.portmapper.gateways.process.ProcessGateway import com.offbynull.portmapper.gateways.process.internalmessages.KillProcessRequest import com.offbynull.portmapper.mapper.{MappedPort, PortType} import com.offbynull.portmapper.mappers.natpmp.NatPmpPortMapper import jbok.common.log.Logger object NatPmpClient { def apply[F[_]](implicit F: Sync[F]): F[Nat[F]] = for { network <- F.delay(NetworkGateway.create) networkBus = network.getBus process <- F.delay(ProcessGateway.create) processBus = process.getBus mappers <- F.delay(NatPmpPortMapper.identify(networkBus, processBus)) mapper <- F.delay(mappers.get(0)) mappedPorts <- Ref.of[F, Map[Int, MappedPort]](Map.empty) _ <- F.delay(network.getBus.send(new KillNetworkRequest())) _ <- F.delay(process.getBus.send(new KillProcessRequest())) } yield new Nat[F] { private[this] val log = Logger[F] override def addMapping(internalPort: Int, externalPort: Int, lifetime: Long): F[Unit] = for { _ <- deleteMapping(externalPort) port <- F .delay(mapper.mapPort(PortType.TCP, internalPort, externalPort, lifetime)) .handleErrorWith { e => log.error(s"add port mapping from ${internalPort} to ${externalPort} failed", e) >> F.raiseError(e) } _ <- mappedPorts.update(_ + (externalPort -> port)) } yield () override def deleteMapping(externalPort: Int): F[Unit] = for { portOpt <- mappedPorts.get.map(_.get(externalPort)) _ <- portOpt.fold(F.unit)(port => F.delay(mapper.unmapPort(port))) _ <- mappedPorts.update(_ - externalPort) } yield () } }
Example 2
Source File: Http4sRpcServer.scala From iotchain with MIT License | 5 votes |
package jbok.network.rpc.http import cats.effect.{ConcurrentEffect, Resource, Sync, Timer} import cats.implicits._ import io.circe.Json import io.circe.syntax._ import jbok.network.rpc.{RpcRequest, RpcService} import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityCodec._ import org.http4s.dsl.Http4sDsl import org.http4s.implicits._ import org.http4s.server.Server import org.http4s.server.blaze.BlazeServerBuilder object Http4sRpcServer { def routes[F[_]](service: RpcService[F, Json])(implicit F: Sync[F]): HttpRoutes[F] = { val dsl = Http4sDsl[F] import dsl._ HttpRoutes.of[F] { case req @ POST -> path => for { json <- req.as[Json] result <- service.handle(RpcRequest(path.toList, json)) resp <- Ok(result.asJson) } yield resp } } def server[F[_]](service: RpcService[F, Json])(implicit F: ConcurrentEffect[F], T: Timer[F]): Resource[F, Server[F]] = BlazeServerBuilder[F] .bindLocal(0) .withHttpApp(routes[F](service).orNotFound) .withWebSockets(true) .resource }
Example 3
Source File: implicits.scala From iotchain with MIT License | 5 votes |
package jbok.network.tcp import cats.effect.{Concurrent, ContextShift, IO, Sync} import cats.implicits._ import fs2.Chunk import fs2.io.tcp.Socket import javax.net.ssl.SSLContext import jbok.common.thread.ThreadUtil import jbok.crypto.ssl.SSLContextHelper import jbok.network.Message import spinoco.fs2.crypto.io.tcp.TLSSocket import scala.concurrent.ExecutionContext import scala.concurrent.duration._ object implicits { val maxBytes: Int = 4 * 1024 * 1024 val timeout = Some(10.seconds) val sslEC: ExecutionContext = ThreadUtil.blockingThreadPool[IO]("jbok-tls").allocated.unsafeRunSync()._1 implicit class TcpSocketOps[F[_]](val socket: Socket[F]) extends AnyVal { def readMessage(implicit F: Sync[F]): F[Message[F]] = socket.read(maxBytes, timeout).flatMap { case Some(chunk) => Message.decodeChunk(chunk) case None => F.raiseError(new Exception(s"socket already closed")) } def writeMessage(message: Message[F]): F[Unit] = socket.write(Chunk.array(Message.encodeBytes(message).byteArray), timeout) def toTLSSocket(sslOpt: Option[SSLContext], client: Boolean)(implicit F: Concurrent[F], cs: ContextShift[F]): F[Socket[F]] = sslOpt match { case Some(ssl) => if (client) TLSSocket.instance(socket, SSLContextHelper.clientEngine(ssl).engine, sslEC).widen[Socket[F]] else TLSSocket.instance(socket, SSLContextHelper.serverEngine(ssl).engine, sslEC).widen[Socket[F]] case None => F.pure(socket) } } }
Example 4
Source File: MetricsMiddleware.scala From iotchain with MIT License | 5 votes |
package jbok.network.http.server.middleware import cats.effect.{Clock, Effect, Sync} import cats.implicits._ import jbok.common.metrics.PrometheusMetrics import org.http4s.HttpRoutes import org.http4s.metrics.prometheus.{Prometheus, PrometheusExportService} import org.http4s.server.middleware object MetricsMiddleware { def exportService[F[_]](implicit F: Sync[F]): F[HttpRoutes[F]] = for { _ <- PrometheusExportService.addDefaults[F](PrometheusMetrics.registry) } yield PrometheusExportService.service[F](PrometheusMetrics.registry) def apply[F[_]](routes: HttpRoutes[F], enableMetrics: Boolean)(implicit F: Effect[F], clock: Clock[F]): F[HttpRoutes[F]] = if (enableMetrics) { Prometheus[F](PrometheusMetrics.registry, "iotchain_http_server").map { metricsOps => middleware.Metrics[F](metricsOps)(routes) } } else { F.pure(routes) } }
Example 5
Source File: HmacAuthMiddleware.scala From iotchain with MIT License | 5 votes |
package jbok.network.http.server.middleware import java.time.{Duration, Instant} import cats.data.{Kleisli, OptionT} import cats.effect.Sync import jbok.network.http.server.authentication.HMAC import org.http4s.headers.Authorization import org.http4s.util.CaseInsensitiveString import org.http4s.{AuthScheme, Credentials, HttpRoutes, Request, Response, Status} import tsec.mac.jca.{HMACSHA256, MacSigningKey} import scala.concurrent.duration.{FiniteDuration, _} sealed abstract class HmacAuthError(val message: String) extends Exception(message) object HmacAuthError { case object NoAuthHeader extends HmacAuthError("Could not find an Authorization header") case object NoDatetimeHeader extends HmacAuthError("Could not find an X-Datetime header") case object BadMAC extends HmacAuthError("Bad MAC") case object InvalidMacFormat extends HmacAuthError("The MAC is not a valid Base64 string") case object InvalidDatetime extends HmacAuthError("The datetime is not a valid UTC datetime string") case object Timeout extends HmacAuthError("The request time window is closed") } object HmacAuthMiddleware { val defaultDuration: FiniteDuration = 5.minutes private def verifyFromHeader[F[_]]( req: Request[F], key: MacSigningKey[HMACSHA256], duration: FiniteDuration ): Either[HmacAuthError, Unit] = for { authHeader <- req.headers .get(Authorization) .flatMap { t => t.credentials match { case Credentials.Token(scheme, token) if scheme == AuthScheme.Bearer => Some(token) case _ => None } } .toRight(HmacAuthError.NoAuthHeader) datetimeHeader <- req.headers .get(CaseInsensitiveString("X-Datetime")) .toRight(HmacAuthError.NoDatetimeHeader) instant <- HMAC.http.verifyFromHeader( req.method.name, req.uri.renderString, datetimeHeader.value, authHeader, key ) _ <- Either.cond( Instant.now().isBefore(instant.plus(Duration.ofNanos(duration.toNanos))), (), HmacAuthError.Timeout ) } yield () def apply[F[_]: Sync](key: MacSigningKey[HMACSHA256], duration: FiniteDuration = defaultDuration)(routes: HttpRoutes[F]): HttpRoutes[F] = Kleisli { req: Request[F] => verifyFromHeader(req, key, duration) match { case Left(error) => OptionT.some[F](Response[F](Status.Forbidden).withEntity(error.message)) case Right(_) => routes(req) } } }
Example 6
package jbok.network.nat import cats.effect.Sync sealed trait NatType case object NatPMP extends NatType case object NatUPnP extends NatType trait Nat[F[_]] { def addMapping(internalPort: Int, externalPort: Int, lifetime: Long): F[Unit] def deleteMapping(externalPort: Int): F[Unit] } object Nat { def apply[F[_]: Sync](natType: NatType): F[Nat[F]] = natType match { case NatPMP => NatPmpClient[F] case NatUPnP => NatUpnpClient[F] } }
Example 7
Source File: NatUpnpClient.scala From iotchain with MIT License | 5 votes |
package jbok.network.nat import cats.effect.Sync import cats.implicits._ import jbok.common.log.Logger import org.bitlet.weupnp.GatewayDiscover object NatUpnpClient { def apply[F[_]](implicit F: Sync[F]): F[Nat[F]] = for { discover <- F.delay(new GatewayDiscover) _ = discover.discover() device = discover.getValidGateway } yield new Nat[F] { private[this] val log = Logger[F] override def addMapping(internalPort: Int, externalPort: Int, lifetime: Long): F[Unit] = for { _ <- deleteMapping(externalPort) result <- F.delay(device.addPortMapping(externalPort, internalPort, device.getLocalAddress.getHostAddress, "TCP", "jbok")) _ <- log.debug(s"add port mapping result ${result}") } yield () override def deleteMapping(externalPort: Int): F[Unit] = F.delay(device.deletePortMapping(externalPort, "TCP")).void } }
Example 8
Source File: RpcService.scala From iotchain with MIT License | 5 votes |
package jbok.network.rpc import cats.effect.Sync import jbok.network.rpc.internal.RpcServiceMacro import scala.language.experimental.macros final class RpcService[F[_], P](val apiMap: RpcService.Map[F, P])(implicit F: Sync[F]) { def handle(request: RpcRequest[P]): F[RpcResponse[P]] = { def notFoundFailure(path: List[String]): F[RpcResponse[P]] = F.pure(RpcResponse.Failure[P](404, s"Path ${path.mkString("/")} not found")) request.path match { case apiName :: methodName :: Nil => val function: Option[P => F[RpcResponse[P]]] = apiMap.get(apiName).flatMap(_.get(methodName)) function.fold(notFoundFailure(apiName :: methodName :: Nil))(f => f(request.payload)) case _ => notFoundFailure(request.path) } } def mount[API](impl: API)(implicit F: Sync[F]): RpcService[F, P] = macro RpcServiceMacro.impl[API, F, P] def orElse(name: String, value: RpcService.MapValue[F, P]): RpcService[F, P] = new RpcService(apiMap + (name -> value)) } object RpcService { type MapValue[F[_], P] = collection.Map[String, P => F[RpcResponse[P]]] type Map[F[_], P] = collection.Map[String, MapValue[F, P]] def apply[F[_], P](implicit F: Sync[F]): RpcService[F, P] = new RpcService[F, P](collection.mutable.HashMap.empty) }
Example 9
Source File: RpcClientImpl.scala From iotchain with MIT License | 5 votes |
package jbok.network.rpc.internal import cats.effect.Sync import cats.implicits._ import jbok.codec._ import jbok.network.rpc.{RpcClient, RpcRequest, RpcResponse} final class RpcClientImpl[F[_], P](client: RpcClient[F, P])(implicit F: Sync[F]) { def execute[A <: Product, B](path: List[String], arguments: A)(implicit encoder: Encoder[A, P], decoder: Decoder[B, P]): F[B] = { val encoded = encoder.encode(arguments) val request = RpcRequest(path, encoded) client.transport.fetch(request).flatMap { case RpcResponse.Success(payload) => decoder.decode(payload) match { case Left(e) => F.raiseError[B](e) case Right(value) => F.pure[B](value) } case RpcResponse.Failure(code, reason, data) => F.raiseError[B](new Exception(s"client failure: code=${code},reason=${reason},data=${data}")) } } }
Example 10
Source File: RpcServiceImpl.scala From iotchain with MIT License | 5 votes |
package jbok.network.rpc.internal import cats.effect.Sync import cats.implicits._ import jbok.codec._ import jbok.common.log.Logger import jbok.network.rpc.RpcResponse final class RpcServiceImpl[F[_], P](implicit F: Sync[F]) { private[this] val log = Logger[F] def execute[A <: Product, B](payload: P)(call: A => F[B])(implicit decoder: Decoder[A, P], encoder: Encoder[B, P]): F[RpcResponse[P]] = decoder.decode(payload) match { case Left(err) => log.info(s"decode error:${err}") >> F.pure(RpcResponse.Failure[P](400, s"decode error")) case Right(arguments) => call(arguments).map { result => RpcResponse.Success(encoder.encode(result)) } } }
Example 11
Source File: StoreUpdateService.scala From iotchain with MIT License | 5 votes |
package jbok.app.service import cats.data.OptionT import cats.effect.{Sync, Timer} import cats.implicits._ import fs2._ import jbok.app.service.store.{BlockStore, TransactionStore} import jbok.common.log.Logger import jbok.common.math.N import jbok.core.ledger.History import spire.compat._ import scala.concurrent.duration._ final class StoreUpdateService[F[_]](history: History[F], blockStore: BlockStore[F], txStore: TransactionStore[F])(implicit F: Sync[F], T: Timer[F]) { private[this] val log = Logger[F] def findForkPoint(start: N): F[N] = for { hash1 <- blockStore.getBlockHashByNumber(start) hash2 <- history.getHashByBlockNumber(start) number <- (hash1, hash2) match { case (Some(h1), Some(h2)) if h1 == h2 => F.pure(start) case (Some(_), Some(_)) => findForkPoint(start - 1) case _ => F.raiseError(new Exception(s"fatal error")) } } yield number private def delRange(start: N, end: N): F[Unit] = List.range(start, end + 1).traverse_ { number => blockStore.delByBlockNumber(number) >> txStore.delByBlockNumber(number) } private def syncRange(start: N, end: N): F[Unit] = List.range(start, end + 1).traverse_ { number => syncBlock(number) >> syncTransactions(number) } private def syncBlock(number: N): F[Unit] = for { header <- history.getBlockHeaderByNumber(number) _ <- header.fold(F.unit)(header => blockStore.insert(header.number, header.hash)) } yield () private def syncTransactions(number: N): F[Unit] = (for { hash <- OptionT(history.getHashByBlockNumber(number)) block <- OptionT(history.getBlockByHash(hash)) receipts <- OptionT(history.getReceiptsByHash(hash)) _ <- OptionT.liftF(txStore.insertBlockTransactions(block, receipts)) } yield ()).value.void def sync: F[Unit] = for { currentOpt <- blockStore.getBestBlockNumber fork <- currentOpt.fold(N(0).pure[F])(current => findForkPoint(current)) best <- history.getBestBlockNumber _ <- log.i(s"current: ${fork}, best: ${best}") _ <- if (fork == best) { F.unit } else { delRange(fork, best) >> syncRange(fork, best) } } yield () val stream: Stream[F, Unit] = Stream.eval(log.i(s"starting App/StoreUpdateService")) ++ Stream.repeatEval(sync).metered(10.seconds) }
Example 12
Source File: PersonalService.scala From iotchain with MIT License | 5 votes |
package jbok.app.service import cats.effect.Sync import cats.implicits._ import jbok.common.math.N import jbok.core.api.PersonalAPI import jbok.core.config.HistoryConfig import jbok.core.keystore.KeyStore import jbok.core.ledger.History import jbok.core.models.{Address, Transaction} import jbok.core.pool.TxPool import scodec.bits.ByteVector import scala.util.Try final class PersonalService[F[_]]( historyConfig: HistoryConfig, keyStore: KeyStore[F], history: History[F], txPool: TxPool[F] )(implicit F: Sync[F]) extends PersonalAPI[F] { override def importRawKey(privateKey: ByteVector, passphrase: String): F[Address] = keyStore.importPrivateKey(privateKey, passphrase) override def newAccount(passphrase: String): F[Address] = keyStore.newAccount(passphrase) override def delAccount(address: Address): F[Boolean] = keyStore.deleteAccount(address) override def listAccounts: F[List[Address]] = keyStore.listAccounts override def sendTransaction( from: Address, passphrase: String, to: Option[Address], value: Option[N], gasLimit: Option[N], gasPrice: Option[N], nonce: Option[N], data: Option[ByteVector] ): F[ByteVector] = { val defaultGasPrice: N = 2 * N(10).pow(10) val defaultGasLimit: N = N(90000) for { wallet <- keyStore.unlockAccount(from, passphrase) pending <- txPool.getPendingTransactions latestNonceOpt = Try(pending.collect { case (stx, _) if stx.senderAddress.contains(wallet.address) => stx.nonce }.max).toOption bn <- history.getBestBlockNumber currentNonceOpt <- history.getAccount(from, bn).map(_.map(_.nonce.toN)) maybeNextTxNonce = latestNonceOpt.map(_ + 1).orElse(currentNonceOpt) tx = Transaction( nonce = nonce.getOrElse(maybeNextTxNonce.getOrElse(historyConfig.accountStartNonce)), gasPrice = gasPrice.getOrElse(defaultGasPrice), gasLimit = gasLimit.getOrElse(defaultGasLimit), receivingAddress = to, value = value.getOrElse(N(0)), payload = data.getOrElse(ByteVector.empty) ) stx <- wallet.signTx[F](tx, history.chainId) _ <- txPool.addOrUpdateTransaction(stx) } yield stx.hash } override def changePassphrase(address: Address, oldPassphrase: String, newPassphrase: String): F[Boolean] = keyStore.changePassphrase(address, oldPassphrase, newPassphrase) }
Example 13
Source File: AdminService.scala From iotchain with MIT License | 5 votes |
package jbok.app.service import cats.effect.Sync import cats.implicits._ import jbok.app.service.store.{BlockStore, TransactionStore} import jbok.common.log.Logger import jbok.common.math.N import jbok.core.CoreNode import jbok.core.config.FullConfig import jbok.core.models.SignedTransaction import jbok.core.peer.PeerUri import jbok.core.api.AdminAPI final class AdminService[F[_]]( core: CoreNode[F], blockStore: BlockStore[F], txStore: TransactionStore[F] )(implicit F: Sync[F]) extends AdminAPI[F] { private[this] val log = Logger[F] override def peerUri: F[String] = core.peerManager.incoming.localPeerUri.map(_.toString) override def addPeer(peerUri: String): F[Unit] = for { peerUri <- F.fromEither(PeerUri.fromStr(peerUri)) _ <- log.info(s"add a peer: ${peerUri}") _ <- core.peerManager.outgoing.store.add(peerUri) } yield () override def dropPeer(peerUri: String): F[Unit] = for { peerUri <- F.fromEither(PeerUri.fromStr(peerUri)) _ <- log.info(s"drop a peer: ${peerUri}") _ <- core.peerManager.close(peerUri) } yield () override def incomingPeers: F[List[PeerUri]] = core.peerManager.incoming.connected.get.map(_.values.map(_._1.uri).toList) override def outgoingPeers: F[List[PeerUri]] = core.peerManager.outgoing.connected.get.map(_.values.map(_._1.uri).toList) override def pendingTransactions: F[List[SignedTransaction]] = core.txPool.getPendingTransactions.map(_.keys.toList) override def getConfig: F[FullConfig] = F.pure(core.config) override def deleteBlockUntil(number: N): F[Unit] = { def delBlock(n: N, from: N): F[Unit] = { if (from > n) core.history.getBlockHeaderByNumber(from).flatMap{ case Some(block) => for { _ <- core.history.delBlock(block.hash) _ <- delBlock(n, from-1) }yield () case _ => F.unit } else F.unit } for { best <- core.history.getBestBlock bestNumber = best.header.number _ <- List.range((number+1).toBigInt, (bestNumber + 1).toBigInt).traverse_ { n => blockStore.delByBlockNumber(n) >> txStore.delByBlockNumber(n)} _ <- delBlock(number, bestNumber) _ <- core.history.putBestBlockNumber(number) }yield () } }
Example 14
Source File: AccountService.scala From iotchain with MIT License | 5 votes |
package jbok.app.service import cats.effect.Sync import cats.implicits._ import jbok.app.service.store.TransactionStore import jbok.common.math.N import jbok.core.config.HistoryConfig import jbok.core.ledger.History import jbok.core.models.{Account, Address, SignedTransaction} import jbok.core.pool.TxPool import jbok.core.api.{AccountAPI, BlockTag, HistoryTransaction} import scodec.bits.ByteVector final class AccountService[F[_]](config: HistoryConfig, history: History[F], txPool: TxPool[F], helper: ServiceHelper[F], txStore: TransactionStore[F])(implicit F: Sync[F]) extends AccountAPI[F] { override def getAccount(address: Address, tag: BlockTag): F[Account] = for { account <- helper.resolveAccount(address, tag) } yield account override def getCode(address: Address, tag: BlockTag): F[ByteVector] = for { block <- helper.resolveBlock(tag) world <- history.getWorldState(config.accountStartNonce, block.map(_.header.stateRoot)) code <- world.getCode(address) } yield code override def getBalance(address: Address, tag: BlockTag): F[N] = for { account <- helper.resolveAccount(address, tag) } yield account.balance.toN override def getStorageAt(address: Address, position: N, tag: BlockTag): F[ByteVector] = for { account <- helper.resolveAccount(address, tag) storage <- history.getStorage(account.storageRoot, position) } yield storage override def getTransactions(address: Address, page: Int, size: Int): F[List[HistoryTransaction]] = { val validSize = if (size < 0) 100 else 1000000.min(size) txStore.findTransactionsByAddress(address.toString, page.max(1), validSize) } override def getTransactionsByNumber(number: Int): F[List[HistoryTransaction]] = txStore.findTransactionsByNumber(number) override def getPendingTxs(address: Address): F[List[SignedTransaction]] = txPool.getPendingTransactions.map(_.keys.toList.filter(_.senderAddress.exists(_ == address))) override def getEstimatedNonce(address: Address): F[N] = for { pending <- txPool.getPendingTransactions latestNonceOpt = scala.util .Try(pending.collect { case (stx, _) if stx.senderAddress contains address => stx.nonce }.max) .toOption bn <- history.getBestBlockNumber currentNonceOpt <- history.getAccount(address, bn).map(_.map(_.nonce.toN)) defaultNonce = config.accountStartNonce.toN maybeNextTxNonce = latestNonceOpt.map(_ + 1).getOrElse(defaultNonce) max currentNonceOpt.getOrElse(defaultNonce) } yield maybeNextTxNonce }
Example 15
Source File: ServiceHelper.scala From iotchain with MIT License | 5 votes |
package jbok.app.service import cats.effect.Sync import cats.implicits._ import jbok.common.math.N import jbok.common.math.implicits._ import jbok.core.config.HistoryConfig import jbok.core.ledger.History import jbok.core.models.{Account, Address, Block} import jbok.core.api.BlockTag final class ServiceHelper[F[_]](config: HistoryConfig, history: History[F])(implicit F: Sync[F]) { def resolveBlock(tag: BlockTag): F[Option[Block]] = { def getBlock(number: N): F[Option[Block]] = history.getBlockByNumber(number) tag match { case BlockTag.Number(number) if number >= 0 => getBlock(number) case BlockTag.latest => history.getBestBlockNumber >>= getBlock case _ => F.pure(None) } } def resolveAccount(address: Address, tag: BlockTag): F[Account] = for { blockOpt <- resolveBlock(tag) account <- blockOpt match { case Some(block) => history .getAccount(address, block.header.number) .map(_.getOrElse(Account.empty(config.accountStartNonce))) case None => F.pure(Account.empty(config.accountStartNonce)) } } yield account }
Example 16
Source File: ContractService.scala From iotchain with MIT License | 5 votes |
package jbok.app.service import cats.effect.Sync import cats.implicits._ import jbok.common.math.N import jbok.core.ledger.{BlockExecutor, History} import jbok.core.models.{Address, Block, SignedTransaction, Transaction} import jbok.core.api.{BlockTag, CallTx, ContractAPI} import scodec.bits.ByteVector import spire.syntax.all._ import spire.compat._ final class ContractService[F[_]](history: History[F], executor: BlockExecutor[F], helper: ServiceHelper[F])(implicit F: Sync[F]) extends ContractAPI[F] { // override def getABI(address: Address): F[Option[Ast.ContractDef]] = ??? // // override def getSourceCode(address: Address): F[Option[String]] = ??? override def call(callTx: CallTx, tag: BlockTag): F[ByteVector] = for { (stx, block) <- doCall(callTx, tag) txResult <- executor.simulateTransaction(stx, callTx.from.getOrElse(Address.empty), block.header) } yield txResult.vmReturnData override def getEstimatedGas(callTx: CallTx, tag: BlockTag): F[N] = for { (stx, block) <- doCall(callTx, tag) gas <- executor.binarySearchGasEstimation(stx, callTx.from.getOrElse(Address.empty), block.header) } yield gas override def getGasPrice: F[N] = { val blockDifference = N(30) for { bestBlock <- history.getBestBlockNumber gasPrices <- List .range(bestBlock - blockDifference, bestBlock) .filter(_ >= N(0)) .traverse(history.getBlockByNumber) .map(_.flatten.flatMap(_.body.transactionList).map(_.gasPrice)) gasPrice = if (gasPrices.nonEmpty) { gasPrices.qsum / gasPrices.length } else { N(0) } } yield gasPrice } private def doCall[A](callTx: CallTx, tag: BlockTag): F[(SignedTransaction, Block)] = for { stx <- prepareTransaction(callTx, tag) blockOpt <- helper.resolveBlock(tag) block <- F.fromOption(blockOpt, new Exception()) } yield (stx, block) private def prepareTransaction(callTx: CallTx, tag: BlockTag): F[SignedTransaction] = for { gasLimit <- getGasLimit(callTx, tag) tx = Transaction(0, callTx.gasPrice, gasLimit, callTx.to, callTx.value, callTx.data) } yield SignedTransaction(tx, 0.toByte, ByteVector(0), ByteVector(0)) private def getGasLimit(callTx: CallTx, tag: BlockTag): F[N] = callTx.gas match { case Some(gas) => gas.pure[F] case None => helper.resolveBlock(tag).map(_.map(_.header.gasLimit).getOrElse(N(0))) } }
Example 17
Source File: TransactionService.scala From iotchain with MIT License | 5 votes |
package jbok.app.service import cats.data.OptionT import cats.effect.Sync import cats.implicits._ import jbok.codec.rlp.RlpEncoded import jbok.core.ledger.History import jbok.core.models.{Receipt, SignedTransaction} import jbok.core.pool.TxPool import jbok.core.api.{BlockTag, TransactionAPI} import scodec.bits.ByteVector final class TransactionService[F[_]](history: History[F], txPool: TxPool[F], helper: ServiceHelper[F])(implicit F: Sync[F]) extends TransactionAPI[F] { override def getTx(hash: ByteVector): F[Option[SignedTransaction]] = (for { loc <- OptionT(history.getTransactionLocation(hash)) block <- OptionT(history.getBlockByHash(loc.blockHash)) stx <- OptionT.fromOption[F](block.body.transactionList.lift(loc.txIndex)) } yield stx).value override def getPendingTx(hash: ByteVector): F[Option[SignedTransaction]] = txPool.getPendingTransactions.map(_.keys.toList.find(_.hash == hash)) override def getReceipt(hash: ByteVector): F[Option[Receipt]] = (for { loc <- OptionT(history.getTransactionLocation(hash)) block <- OptionT(history.getBlockByHash(loc.blockHash)) _ <- OptionT.fromOption[F](block.body.transactionList.lift(loc.txIndex)) receipts <- OptionT(history.getReceiptsByHash(loc.blockHash)) receipt <- OptionT.fromOption[F](receipts.lift(loc.txIndex)) } yield receipt).value override def getTxByBlockHashAndIndex(hash: ByteVector, index: Int): F[Option[SignedTransaction]] = (for { block <- OptionT(history.getBlockByHash(hash)) stx <- OptionT.fromOption[F](block.body.transactionList.lift(index)) } yield stx).value override def getTxByBlockTagAndIndex(tag: BlockTag, index: Int): F[Option[SignedTransaction]] = (for { block <- OptionT(helper.resolveBlock(tag)) stx <- OptionT.fromOption[F](block.body.transactionList.lift(index)) } yield stx).value override def sendTx(stx: SignedTransaction): F[ByteVector] = txPool.addOrUpdateTransaction(stx).as(stx.hash) override def sendRawTx(data: RlpEncoded): F[ByteVector] = for { stx <- F.fromEither(data.decoded[SignedTransaction]) _ <- txPool.addOrUpdateTransaction(stx) } yield stx.hash }
Example 18
Source File: DoobieTransactionStore.scala From iotchain with MIT License | 5 votes |
package jbok.app.service.store.doobie import cats.effect.Sync import cats.implicits._ import doobie.implicits._ import doobie.util.transactor.Transactor import doobie.util.update.Update import jbok.app.service.store.TransactionStore import jbok.common.math.N import jbok.core.api.HistoryTransaction import jbok.core.models.{Receipt, Block => CoreBlock} final class DoobieTransactionStore[F[_]](xa: Transactor[F])(implicit F: Sync[F]) extends TransactionStore[F] with DoobieSupport { def findTransactionsByAddress(address: String, page: Int, size: Int): F[List[HistoryTransaction]] = sql""" SELECT txHash, nonce, fromAddress, toAddress, value, payload, v, r, s, gasUsed, gasPrice, blockNumber, blockHash, location FROM transactions WHERE (fromAddress = ${address.toString} OR toAddress = ${address.toString}) ORDER BY blockNumber, location DESC limit ${size} offset ${(page - 1) * size} """ .query[HistoryTransaction] .to[List] .transact(xa) def findTransactionByHash(txHash: String): F[Option[HistoryTransaction]] = sql""" SELECT txHash, nonce, fromAddress, toAddress, value, payload, v, r, s, gasUsed, gasPrice, blockNumber, blockHash, location FROM transactions WHERE txHash = ${txHash} """ .query[HistoryTransaction] .option .transact(xa) override def findTransactionsByNumber(blockNumber: Int): F[List[HistoryTransaction]] = sql""" SELECT txHash, nonce, fromAddress, toAddress, value, payload, v, r, s, gasUsed, gasPrice, blockNumber, blockHash, location FROM transactions WHERE (blockNumber = ${blockNumber}) ORDER BY blockNumber, location DESC """ .query[HistoryTransaction] .to[List] .transact(xa) override def delByBlockNumber(number: N): F[Unit] = sql"""DELETE from transactions WHERE blockNumber = $number""".update.run.void.transact(xa) def insertBlockTransactions(block: CoreBlock, receipts: List[Receipt]): F[Unit] = { require(block.body.transactionList.length == receipts.length) val xs = block.body.transactionList.zip(receipts).zipWithIndex.map { case ((stx, receipt), idx) => ( stx.hash.toHex, stx.nonce.toInt, stx.senderAddress.map(_.toString).getOrElse(""), stx.receivingAddress.toString, stx.value.toString, stx.payload.toHex, stx.v.toString, stx.r.toString, stx.s.toString, receipt.gasUsed.toString, stx.gasPrice.toString, block.header.number.toLong, block.header.hash.toHex, idx ) } val holes = List.fill(14)("?").mkString(",") val sql = s"insert into transactions (txHash, nonce, fromAddress, toAddress, value, payload, v, r, s, gasUsed, gasPrice, blockNumber, blockHash, location) values ($holes)" Update[(String, Int, String, String, String, String, String, String, String, String, String, Long, String, Int)](sql) .updateMany(xs) .transact(xa) .void } }
Example 19
Source File: DoobieBlockStore.scala From iotchain with MIT License | 5 votes |
package jbok.app.service.store.doobie import cats.effect.Sync import cats.implicits._ import doobie.implicits._ import doobie.util.transactor.Transactor import jbok.app.service.store.BlockStore import jbok.common.math.N import scodec.bits.ByteVector final class DoobieBlockStore[F[_]](xa: Transactor[F])(implicit F: Sync[F]) extends BlockStore[F] with DoobieSupport { override def getBestBlockNumber: F[Option[N]] = sql""" SELECT blockNumber FROM blocks ORDER BY blockNumber DESC LIMIT 1 """ .query[N] .option .transact(xa) override def getBestBlockNumberAndHash: F[(N, ByteVector)] = sql""" SELECT blockNumber, blockHash FROM blocks ORDER BY blockNumber DESC LIMIT 1 """ .query[(N, ByteVector)] .unique .transact(xa) override def getBlockHashByNumber(number: N): F[Option[ByteVector]] = sql""" SELECT blockHash FROM blocks WHERE blockNumber = $number """ .query[ByteVector] .option .transact(xa) override def delByBlockNumber(number: N): F[Unit] = sql""" DELETE FROM blocks where blockNumber = $number """.update.run .transact(xa) .void override def insert(number: N, hash: ByteVector): F[Unit] = sql""" INSERT INTO blocks (blockNumber, blockHash) VALUES ($number, $hash) """.update.run.void.transact(xa) }
Example 20
Source File: Migration.scala From iotchain with MIT License | 5 votes |
package jbok.app.service.store import cats.effect.Sync import cats.implicits._ import jbok.core.config.DatabaseConfig import org.flywaydb.core.Flyway object Migration { private val flyway = new Flyway() flyway.setLocations("db/mysql", "db/sqlite") def migrate[F[_]: Sync](config: DatabaseConfig): F[Unit] = Sync[F].delay { config.driver match { case "org.sqlite.JDBC" => flyway.setLocations("db/sqlite") case _ => flyway.setLocations("db/mysql") } flyway.setDataSource(config.url, config.user, config.password) flyway.migrate() }.void }
Example 21
Source File: SSLContextHelper.scala From iotchain with MIT License | 5 votes |
package jbok.crypto.ssl import java.nio.file.Paths import java.security.KeyStore import cats.effect.Sync import cats.implicits._ import javax.net.ssl.{KeyManagerFactory, SSLContext, SSLEngine, TrustManagerFactory} import jbok.common.FileUtil import jbok.common.log.Logger final class ClientSSLEngine(val engine: SSLEngine) extends AnyVal final class ServerSSLEngine(val engine: SSLEngine) extends AnyVal object SSLContextHelper { def apply[F[_]](config: SSLConfig)(implicit F: Sync[F]): F[Option[SSLContext]] = if (!config.enabled) { F.pure(None) } else { Logger[F].i(s"init SSLContext from keyStore=${config.keyStorePath} trustStore=${config.trustStorePath}") >> FileUtil[F] .inputStream(Paths.get(config.keyStorePath)) .use { keyStoreIS => FileUtil[F].inputStream(Paths.get(config.trustStorePath)).use { trustStoreIS => F.delay { val keyStore = KeyStore.getInstance("JKS") keyStore.load(keyStoreIS, "changeit".toCharArray) val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm) keyManagerFactory.init(keyStore, "changeit".toCharArray) val trustStore = KeyStore.getInstance("JKS") trustStore.load(trustStoreIS, "changeit".toCharArray) val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm) trustManagerFactory.init(trustStore) val ctx = SSLContext.getInstance(config.protocol) ctx.init(keyManagerFactory.getKeyManagers, trustManagerFactory.getTrustManagers, null) ctx } } } .map(_.some) } def clientEngine(ctx: SSLContext): ClientSSLEngine = { val engine = ctx.createSSLEngine() engine.setUseClientMode(true) engine.setNeedClientAuth(true) new ClientSSLEngine(engine) } def serverEngine(ctx: SSLContext): ServerSSLEngine = { val engine = ctx.createSSLEngine() engine.setUseClientMode(false) engine.setNeedClientAuth(true) new ServerSSLEngine(engine) } }
Example 22
Source File: SignaturePlatform.scala From iotchain with MIT License | 5 votes |
package jbok.crypto.signature import java.math.BigInteger import java.util.Random import cats.effect.Sync import jbok.crypto.facade.{BN, EC, SignatureEC} import scala.scalajs.js.JSConverters._ import scala.scalajs.js.typedarray.Uint8Array trait SignaturePlatform { val ecdsa: Signature[ECDSA] = ECDSAPlatform } private object ECDSAPlatform extends Signature[ECDSA] { import ECDSACommon._ val secp256k1 = new EC("secp256k1") override def generateKeyPair[F[_]](random: Option[Random])(implicit F: Sync[F]): F[KeyPair] = F.delay { val keyPair = secp256k1.genKeyPair() val secret = KeyPair.Secret(keyPair.getPrivate("hex")) // drop uncompressed indicator, make it 64-bytes val pubkey = KeyPair.Public(keyPair.getPublic(false, "hex").drop(2)) KeyPair(pubkey, secret) } override def generatePublicKey[F[_]](secret: KeyPair.Secret)(implicit F: Sync[F]): F[KeyPair.Public] = F.delay { val keyPair = secp256k1.keyFromPrivate(secret.bytes.toHex, "hex") // drop uncompressed indicator, make it 64-bytes KeyPair.Public(keyPair.getPublic(false, "hex").drop(2)) } override def sign[F[_]](hash: Array[Byte], keyPair: KeyPair, chainId: BigInt)(implicit F: Sync[F]): F[CryptoSignature] = F.delay { val kp = secp256k1.keyFromPrivate(keyPair.secret.bytes.toHex, "hex") val sig = secp256k1.sign(new Uint8Array(hash.toJSArray), kp) val r = new BigInteger(sig.r.toString) val s = new BigInteger(sig.s.toString) val pointSign = calculatePointSign(r, toCanonicalS(s), keyPair, hash, chainId) match { case Some(recId) => recId case None => throw new Exception("unexpected error") } val rid: BigInt = getRecoveryId(chainId, pointSign).getOrElse(pointSign) CryptoSignature(r, toCanonicalS(s), rid) } override def verify[F[_]](hash: Array[Byte], sig: CryptoSignature, public: KeyPair.Public, chainId: BigInt)(implicit F: Sync[F]): F[Boolean] = F.delay { getPointSign(chainId, sig.v).exists { bigInt => val signatureEC = convert(sig.copy(v = bigInt)) val key = secp256k1.keyFromPublic(UNCOMPRESSED_INDICATOR_STRING + public.bytes.toHex, "hex") secp256k1.verify(new Uint8Array(hash.toJSArray), signatureEC, key) } } override def recoverPublic(hash: Array[Byte], sig: CryptoSignature, chainId: BigInt): Option[KeyPair.Public] = getPointSign(chainId, sig.v).map { bigInt => val signatureEC = convert(sig.copy(v = bigInt)) val msg = new Uint8Array(hash.toJSArray) val recId = secp256k1.getKeyRecoveryParam(msg, signatureEC) val point = secp256k1.recoverPubKey(new Uint8Array(hash.toJSArray), signatureEC, recId) KeyPair.Public(point.encode("hex", false).drop(2)) } private def convert(sig: CryptoSignature) = { val r = new BN(sig.r.toString(16), 16) val s = new BN(sig.s.toString(16), 16) SignatureEC(r, s, recoveryParam = (sig.v - NEGATIVE_POINT_SIGN).toInt) } private def calculatePointSign(r: BigInt, s: BigInt, keyPair: KeyPair, hash: Array[Byte], chainId: BigInt): Option[BigInt] = allowedPointSigns.find( v => recoverPublic(hash, CryptoSignature(r, s, getRecoveryId(chainId, v).getOrElse(v)), chainId) .contains(keyPair.public)) }
Example 23
Source File: Terminal.scala From iotchain with MIT License | 5 votes |
package jbok.common import cats.effect.Sync import cats.implicits._ object Terminal { private val reader = new scala.tools.jline_embedded.console.ConsoleReader def putStr[F[_]: Sync](s: String): F[Unit] = Sync[F].delay { print(s) System.out.flush() } def putStrLn[F[_]: Sync](s: String): F[Unit] = Sync[F].delay { println(s) } def readLn[F[_]: Sync](prompt: String): F[String] = Sync[F].delay { reader.readLine(prompt) } def readPassword[F[_]: Sync](prompt: String): F[String] = Sync[F].delay { reader.readLine(prompt, Character.valueOf(0)) } def choose[F[_]: Sync](prompt: String): F[Boolean] = readLn[F](s"${prompt} [Y/N]").map { case x if x.toLowerCase.startsWith("y") => true case _ => false } }
Example 24
Source File: LoggerPlatform.scala From iotchain with MIT License | 5 votes |
package jbok.common.log import java.nio.file.{Path, Paths} import cats.effect.Sync import cats.implicits._ import jbok.common.FileUtil import scribe.handler.LogHandler import scribe.writer.FileWriter import scribe.writer.file.LogPath import scala.concurrent.duration._ object LoggerPlatform { def initConfig[F[_]: Sync](config: LogConfig): F[Unit] = { val level = Level.fromName(config.level) Logger.setRootLevel(level) >> (config.logDir match { case "/dev/null" => Logger.setRootHandlers(Logger.consoleHandler(level.some)) case dir => FileUtil[F].open(Paths.get(config.logDir), create = true, asDirectory = true) >> Logger.setRootHandlers( Logger.consoleHandler(level.some), fileHandler(Paths.get(dir), level.some, config.maxLogs) ) }) } def fileHandler(directory: Path, minimumLevel: Option[Level] = None, maxLogs: Int = 15): LogHandler = LogHandler( Logger.fileFormatter, FileWriter().nio .path(LogPath.simple("iotchain.log", directory = directory)) .rolling(LogPath.daily(prefix = "iotchain", directory = directory)) .maxLogs(maxLogs, checkRate = 1.seconds), minimumLevel.map(Logger.fromJbokLevel) ) }
Example 25
Source File: ThreadUtil.scala From iotchain with MIT License | 5 votes |
package jbok.common.thread import java.lang.Thread.UncaughtExceptionHandler import java.nio.channels.AsynchronousChannelGroup import java.nio.channels.spi.AsynchronousChannelProvider import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.{Executors, ThreadFactory} import cats.effect.{Resource, Sync} import scala.concurrent.ExecutionContext import scala.util.control.NonFatal object ThreadUtil { def named(threadPrefix: String, daemon: Boolean, exitJvmOnFatalError: Boolean = true): ThreadFactory = new ThreadFactory { val defaultThreadFactory = Executors.defaultThreadFactory() val idx = new AtomicInteger(0) def newThread(r: Runnable) = { val t = defaultThreadFactory.newThread(r) t.setDaemon(daemon) t.setName(s"$threadPrefix-${idx.incrementAndGet()}") t.setUncaughtExceptionHandler(new UncaughtExceptionHandler { def uncaughtException(t: Thread, e: Throwable): Unit = { ExecutionContext.defaultReporter(e) if (exitJvmOnFatalError) { e match { case NonFatal(_) => () case _ => System.exit(-1) } } } }) t } } def blockingThreadPool[F[_]](name: String)(implicit F: Sync[F]): Resource[F, ExecutionContext] = Resource(F.delay { val factory = named(name, daemon = true) val executor = Executors.newCachedThreadPool(factory) val ec = ExecutionContext.fromExecutor(executor) (ec, F.delay(executor.shutdown())) }) def acg[F[_]](implicit F: Sync[F]): Resource[F, AsynchronousChannelGroup] = Resource(F.delay { val acg = acgUnsafe (acg, F.delay(acg.shutdownNow())) }) def acgUnsafe: AsynchronousChannelGroup = AsynchronousChannelProvider .provider() .openAsynchronousChannelGroup(8, named("jbok-ag-tcp", daemon = true)) lazy val acgGlobal: AsynchronousChannelGroup = acgUnsafe }
Example 26
Source File: Metrics.scala From iotchain with MIT License | 5 votes |
package jbok.common.metrics import cats.effect.{Resource, Sync, Timer} import cats.implicits._ import fs2._ import scala.concurrent.duration._ trait EffectMetrics[F[_]] { self: Metrics[F] => def observed[A](name: String, labels: String*)(fa: F[A])(implicit F: Sync[F], T: Timer[F]): F[A] = for { start <- T.clock.monotonic(NANOSECONDS) attempt <- fa.attempt end <- T.clock.monotonic(NANOSECONDS) elapsed = end - start a <- attempt match { case Left(e) => self.observe(name, "failure" :: labels.toList: _*)(elapsed.toDouble) >> F.raiseError(e) case Right(a) => self.observe(name, "success" :: labels.toList: _*)(elapsed.toDouble).as(a) } } yield a def monitored[A](name: String, labels: String*)(res: Resource[F, A])(implicit F: Sync[F]): Resource[F, A] = { val r = Resource { for { _ <- self.inc(name, labels: _*)(1.0) } yield () -> self.dec(name, labels: _*)(1.0) } r.flatMap(_ => res) } } trait StreamMetrics[F[_]] { self: Metrics[F] => // observe events occur in the stream def observePipe[A](name: String, labels: String*): Pipe[F, A, Unit] = _.chunks.through(observeChunkPipe[A](name, labels: _*)) def observeChunkPipe[A](name: String, labels: String*): Pipe[F, Chunk[A], Unit] = _.evalMap(c => self.observe(name, labels: _*)(c.size.toDouble)) } trait Metrics[F[_]] extends EffectMetrics[F] with StreamMetrics[F] { type Registry def registry: Registry // accumulate, e.g. the number of requests served, tasks completed, or errors. def acc(name: String, labels: String*)(n: Double = 1.0): F[Unit] // increase, e.g. the current memory usage, queue size, or active requests. def inc(name: String, labels: String*)(n: Double = 1.0): F[Unit] // decrease, e.g. the current memory usage, queue size, or active requests. def dec(name: String, labels: String*)(n: Double = 1.0): F[Unit] // equivalent to inc(name, labels)(delta) def set(name: String, labels: String*)(n: Double): F[Unit] // e.g. the request response latency, or the size of the response body def observe(name: String, labels: String*)(n: Double): F[Unit] } object Metrics { val METRIC_PREFIX = "iotchain" val TIMER_SUFFIX = "seconds" val GAUGE_SUFFIX = "active" sealed trait NoopRegistry object NoopRegistry extends NoopRegistry def nop[F[_]: Sync]: Metrics[F] = new Metrics[F] { override type Registry = NoopRegistry override def registry: Registry = NoopRegistry override def acc(name: String, labels: String*)(n: Double): F[Unit] = Sync[F].unit override def inc(name: String, labels: String*)(n: Double): F[Unit] = Sync[F].unit override def dec(name: String, labels: String*)(n: Double): F[Unit] = Sync[F].unit override def set(name: String, labels: String*)(n: Double): F[Unit] = Sync[F].unit override def observe(name: String, labels: String*)(n: Double): F[Unit] = Sync[F].unit } }
Example 27
Source File: MemoryKVStore.scala From iotchain with MIT License | 5 votes |
package jbok.persistent import cats.effect.Sync import cats.effect.concurrent.Ref import cats.implicits._ import fs2._ final class MemoryKVStore[F[_]](m: Ref[F, Map[ColumnFamily, Map[Seq[Byte], Array[Byte]]]])(implicit F: Sync[F]) extends KVStore[F] { override def put(cf: ColumnFamily, key: Array[Byte], value: Array[Byte]): F[Unit] = m.update(m => m.updated(cf, m.getOrElse(cf, Map.empty) + (key.toSeq -> value))) override def del(cf: ColumnFamily, key: Array[Byte]): F[Unit] = m.update(m => m.updated(cf, m.getOrElse(cf, Map.empty) - key)) override def writeBatch(cf: ColumnFamily, puts: List[(Array[Byte], Array[Byte])], dels: List[Array[Byte]]): F[Unit] = for { _ <- puts.traverse { case (key, value) => put(cf, key, value) } _ <- dels.traverse { key => del(cf, key) } } yield () override def writeBatch(cf: ColumnFamily, ops: List[(Array[Byte], Option[Array[Byte]])]): F[Unit] = ops.traverse_ { case (key, Some(value)) => put(cf, key, value) case (key, None) => del(cf, key) } override def writeBatch(puts: List[Put], dels: List[Del]): F[Unit] = for { _ <- puts.traverse { case (cf, key, value) => put(cf, key, value) } _ <- dels.traverse { case (cf, key) => del(cf, key) } } yield () override def get(cf: ColumnFamily, key: Array[Byte]): F[Option[Array[Byte]]] = m.get.map(_.get(cf).flatMap(_.get(key))) override def toStream(cf: ColumnFamily): Stream[F, (Array[Byte], Array[Byte])] = Stream.eval(toList(cf)).flatMap(Stream.emits) override def toList(cf: ColumnFamily): F[List[(Array[Byte], Array[Byte])]] = toMap(cf).map(_.toList) override def toMap(cf: ColumnFamily): F[Map[Array[Byte], Array[Byte]]] = m.get.map(_.getOrElse(cf, Map.empty).map { case (k, v) => k.toArray -> v }) override def size(cf: ColumnFamily): F[Int] = m.get.map(_.get(cf).map(_.size).getOrElse(0)) } object MemoryKVStore { def apply[F[_]](implicit F: Sync[F]): F[KVStore[F]] = Ref.of[F, Map[ColumnFamily, Map[Seq[Byte], Array[Byte]]]](Map.empty).map(ref => new MemoryKVStore[F](ref)) }
Example 28
Source File: StageKVStore.scala From iotchain with MIT License | 5 votes |
package jbok.persistent import cats.effect.Sync import cats.implicits._ final case class StageKVStore[F[_], K, V](inner: SingleColumnKVStore[F, K, V], stage: Map[K, Option[V]])(implicit F: Sync[F]) { def mustGet(key: K): F[V] = get(key).flatMap(opt => F.fromOption(opt, new Exception(s"fatal db failure, key=${key} not found"))) def put(key: K, value: V): StageKVStore[F, K, V] = copy(stage = stage + (key -> Some(value))) def get(key: K): F[Option[V]] = stage.get(key) match { case Some(valueOpt) => valueOpt.pure[F] case None => inner.get(key) } def del(key: K): StageKVStore[F, K, V] = copy(stage = stage + (key -> None)) def toMap: F[Map[K, V]] = inner.toMap.map(kvs => kvs ++ stage.collect { case (k, Some(v)) => k -> v }) def commit: F[StageKVStore[F, K, V]] = for { _ <- inner.writeBatch(stage.toList) } yield copy[F, K, V](stage = Map.empty) def +(kv: (K, V)): StageKVStore[F, K, V] = copy(stage = stage + (kv._1 -> Some(kv._2))) def ++(kvs: Map[K, V]): StageKVStore[F, K, V] = copy(stage = stage ++ kvs.mapValues(Some.apply)) } object StageKVStore { def apply[F[_]: Sync, K, V](inner: SingleColumnKVStore[F, K, V]): StageKVStore[F, K, V] = StageKVStore[F, K, V](inner, Map.empty[K, Option[V]]) }
Example 29
Source File: ProgramContext.scala From iotchain with MIT License | 5 votes |
package jbok.evm import cats.effect.Sync import jbok.common.math.N import jbok.core.models.{Address, BlockHeader, SignedTransaction, UInt256} import scodec.bits.ByteVector object ProgramContext { def apply[F[_]: Sync]( stx: SignedTransaction, senderAddress: Address, recipientAddress: Address, program: Program, blockHeader: BlockHeader, world: WorldState[F], config: EvmConfig ): ProgramContext[F] = { // YP eq (91) val inputData = if (stx.isContractInit) ByteVector.empty else stx.payload val env = ExecEnv( recipientAddress, senderAddress, senderAddress, UInt256(stx.gasPrice), inputData, UInt256(stx.value), program, blockHeader, callDepth = 0 ) val gasLimit = stx.gasLimit - config.calcTransactionIntrinsicGas(stx.payload, stx.isContractInit) ProgramContext[F](env, recipientAddress, gasLimit, world, config) } } final case class ProgramContext[F[_]: Sync]( env: ExecEnv, receivingAddr: Address, startGas: N, world: WorldState[F], config: EvmConfig, initialAddressesToDelete: Set[Address] = Set.empty, readOnly: Boolean = false )
Example 30
package jbok.evm import cats.data.OptionT import cats.effect.Sync import cats.implicits._ import jbok.common.log.Logger def run[F[_]: Sync](context: ProgramContext[F]): F[ProgramResult[F]] = { val state = ProgramState[F](context) OptionT.fromOption[F](PrecompiledContracts.runOptionally(state.config.preCompiledContracts, context)).getOrElseF { run(state).map { finalState => ProgramResult[F]( finalState.returnData, finalState.gas, finalState.world, finalState.addressesToDelete, finalState.logs, finalState.internalTxs, finalState.gasRefund, finalState.error, finalState.reverted ) } } } private def run[F[_]: Sync](state: ProgramState[F]): F[ProgramState[F]] = { val byte = state.program.getByte(state.pc) state.config.byteToOpCode.get(byte) match { case Some(opCode) => for { newState <- opCode.execute(state) _ <- Logger[F].trace( s"$opCode | pc: ${newState.pc} | depth: ${newState.env.callDepth} | gas: ${newState.gas} | stack: ${newState.stack}") s <- if (newState.halted || newState.reverted) newState.pure[F] else run(newState) } yield s case None => state.withError(InvalidOpCode(byte)).halt.pure[F] } } }
Example 31
Source File: Storage.scala From iotchain with MIT License | 5 votes |
package jbok.evm import cats.effect.Sync import cats.implicits._ import jbok.core.models.UInt256 import jbok.core.store.ColumnFamilies import jbok.persistent._ final case class Storage[F[_]: Sync](store: StageKVStore[F, UInt256, UInt256]) { def store(offset: UInt256, value: UInt256): F[Storage[F]] = Sync[F].pure { if (value == UInt256.zero) { this.copy(store = store.del(offset)) } else { this.copy(store = store.put(offset, value)) } } def load(offset: UInt256): F[UInt256] = store.get(offset).map(_.getOrElse(UInt256.zero)) def commit: F[Storage[F]] = store.commit.map(db2 => this.copy(store = db2)) def data: F[Map[UInt256, UInt256]] = store.toMap } object Storage { def empty[F[_]: Sync]: F[Storage[F]] = for { store <- MemoryKVStore[F] stage = StageKVStore(SingleColumnKVStore[F, UInt256, UInt256](ColumnFamilies.Node, store)) } yield Storage[F](stage) def fromMap[F[_]: Sync](kvs: Map[UInt256, UInt256]): F[Storage[F]] = for { storage <- empty[F] stored <- kvs.toList.foldLeftM(storage) { case (s, (k, v)) => s.store(k, v) } } yield stored def fromList[F[_]: Sync](words: List[UInt256]): F[Storage[F]] = for { storage <- empty[F] stored <- words.zipWithIndex.map { case (w, i) => UInt256(i) -> w }.foldLeftM(storage) { case (s, (k, v)) => s.store(k, v) } } yield stored }
Example 32
Source File: TxValidator.scala From iotchain with MIT License | 5 votes |
package jbok.core.validators import cats.effect.Sync import jbok.core.config.HistoryConfig import jbok.core.models._ import jbok.core.validators.TxInvalid._ import jbok.evm.EvmConfig import cats.implicits._ import jbok.common.math.N import jbok.common.math.implicits._ object TxInvalid { final case object TxSignatureInvalid extends Exception("SignedTransactionInvalid") final case class TxSyntaxInvalid(reason: String) extends Exception(s"TransactionSyntaxInvalid: ${reason}") final case class TxNonceTooHigh(txNonce: UInt256, senderNonce: UInt256) extends Exception( s"TxNonceTooHigh(got tx nonce $txNonce but sender nonce in mpt is: $senderNonce)" ) final case class TxNonceInvalid(txNonce: UInt256, senderNonce: UInt256) extends Exception( s"TxNonceInvalid(got tx nonce $txNonce but sender nonce in mpt is: $senderNonce)" ) final case class TxNotEnoughGasForIntrinsicInvalid(txGasLimit: N, txIntrinsicGas: N) extends Exception( s"TxNotEnoughGasForIntrinsicInvalid(xx gas limit ($txGasLimit) < tx intrinsic gas ($txIntrinsicGas))" ) final case class TxSenderCantPayUpfrontCostInvalid(upfrontCost: UInt256, senderBalance: UInt256) extends Exception( s"TxSenderCantPayUpfrontCostInvalid(upfrontcost ($upfrontCost) > sender balance ($senderBalance))" ) final case class TrxGasLimitTooBigInvalid(txGasLimit: N, accumGasUsed: N, blockGasLimit: N) extends Exception( s"TxGasLimitTooBigInvalid(tx gas limit ($txGasLimit) + acc gas ($accumGasUsed) > block gas limit ($blockGasLimit))" ) } final class TxValidator[F[_]](historyConfig: HistoryConfig)(implicit F: Sync[F], chainId: ChainId) { import TxValidator._ def validate( stx: SignedTransaction, senderAccount: Account, blockHeader: BlockHeader, upfrontGasCost: UInt256, accGasUsed: N ): F[Unit] = for { _ <- checkSyntacticValidity[F](stx, chainId) _ <- validateNonce(stx.nonce, senderAccount.nonce) _ <- validateGasLimitEnoughForIntrinsicGas(stx, blockHeader.number) _ <- validateAccountHasEnoughGasToPayUpfrontCost(senderAccount.balance, upfrontGasCost) _ <- validateBlockHasEnoughGasLimitForTx(stx.gasLimit, accGasUsed, blockHeader.gasLimit) } yield () def checkSyntacticValidity[F[_]](stx: SignedTransaction, chainId: ChainId)(implicit F: Sync[F]): F[Unit] = { import stx._ val validR = r > 0 && r < secp256k1n val validS = s > 0 && s < (secp256k1n / 2) + 1 if (nonce > maxNonceValue) F.raiseError(TxSyntaxInvalid(s"Invalid nonce: $nonce > $maxNonceValue")) else if (gasLimit > maxGasValue) F.raiseError(TxSyntaxInvalid(s"Invalid gasLimit: $gasLimit > $maxGasValue")) else if (gasPrice > maxGasValue) F.raiseError(TxSyntaxInvalid(s"Invalid gasPrice: $gasPrice > $maxGasValue")) else if (value > maxValue) F.raiseError(TxSyntaxInvalid(s"Invalid value: $value > $maxValue")) else if (!validR) F.raiseError(TxSyntaxInvalid(s"Invalid r: ${r}")) else if (!validS) F.raiseError(TxSyntaxInvalid(s"Invalid s: ${s}")) else if (stx.senderAddress.isEmpty || !stx.chainIdOpt.contains(chainId)) F.raiseError(TxSignatureInvalid) else F.unit } }
Example 33
Source File: BodyValidator.scala From iotchain with MIT License | 5 votes |
package jbok.core.validators import cats.effect.Sync import cats.implicits._ import jbok.core.models._ import jbok.core.validators.BodyInvalid._ import jbok.persistent.mpt.MerklePatriciaTrie object BodyInvalid { case object BodyTransactionsHashInvalid extends Exception("BlockTransactionsHashInvalid") } private[validators] object BodyValidator { def validate[F[_]: Sync](block: Block): F[Unit] = for { _ <- validateTransactionRoot(block) } yield () private def validateTransactionRoot[F[_]](block: Block)(implicit F: Sync[F]): F[Unit] = MerklePatriciaTrie.calcMerkleRoot[F, SignedTransaction](block.body.transactionList).flatMap { root => if (root == block.header.transactionsRoot) F.unit else F.raiseError(BodyTransactionsHashInvalid) } }
Example 34
Source File: Peer.scala From iotchain with MIT License | 5 votes |
package jbok.core.peer import cats.effect.concurrent.Ref import cats.effect.{Concurrent, Sync} import cats.implicits._ import fs2.concurrent.Queue import jbok.core.messages.{SignedTransactions, Status} import jbok.network.Message import scodec.bits.ByteVector import jbok.codec.rlp.implicits._ import jbok.common.log.Logger import jbok.common.math.N import jbok.crypto._ final case class Peer[F[_]]( uri: PeerUri, queue: Queue[F, Message[F]], status: Ref[F, Status], knownBlocks: Ref[F, Set[ByteVector]], knownTxs: Ref[F, Set[ByteVector]] )(implicit F: Sync[F]) { import Peer._ private[this] val log = Logger[F] def hasBlock(blockHash: ByteVector): F[Boolean] = knownBlocks.get.map(_.contains(blockHash)) def hasTxs(stxs: SignedTransactions): F[Boolean] = knownTxs.get.map(_.contains(stxs.encoded.bytes.kec256)) def markBlock(blockHash: ByteVector, number: N): F[Unit] = knownBlocks.update(s => s.take(MaxKnownBlocks - 1) + blockHash) >> status.update(s => s.copy(bestNumber = s.bestNumber.max(number))) def markTxs(stxs: SignedTransactions): F[Unit] = knownTxs.update(known => known.take(MaxKnownTxs - 1) + stxs.encoded.bytes.kec256) def markStatus(newStatus: Status): F[Unit] = status.update(s => if (newStatus.td > s.td) s.copy(bestNumber = newStatus.bestNumber, td = newStatus.td) else s) } object Peer { val MaxKnownTxs = 32768 val MaxKnownBlocks = 1024 def apply[F[_]: Concurrent](uri: PeerUri, status: Status): F[Peer[F]] = for { queue <- Queue.circularBuffer[F, Message[F]](100000) status <- Ref.of[F, Status](status) knownBlocks <- Ref.of[F, Set[ByteVector]](Set.empty) knownTxs <- Ref.of[F, Set[ByteVector]](Set.empty) } yield Peer[F](uri, queue, status, knownBlocks, knownTxs) }
Example 35
Source File: PeerSelector.scala From iotchain with MIT License | 5 votes |
package jbok.core.peer import cats.data.Kleisli import cats.effect.Sync import cats.implicits._ import jbok.common.math.N import jbok.core.messages.SignedTransactions import jbok.core.models.Block import scala.util.Random object PeerSelector { type PeerSelector[F[_]] = Kleisli[F, List[Peer[F]], List[Peer[F]]] def apply[F[_]](run: List[Peer[F]] => F[List[Peer[F]]]): PeerSelector[F] = Kleisli(run) def all[F[_]: Sync]: PeerSelector[F] = PeerSelector(Sync[F].pure) def except[F[_]: Sync](peer: Peer[F]): PeerSelector[F] = PeerSelector(_.filterNot(_ == peer).pure[F]) def one[F[_]: Sync](peer: Peer[F]): PeerSelector[F] = PeerSelector(_ => Sync[F].pure(List(peer))) def many[F[_]: Sync](list: List[Peer[F]]): PeerSelector[F] = PeerSelector(_ => Sync[F].pure(list)) def withoutBlock[F[_]: Sync](block: Block): PeerSelector[F] = PeerSelector { peers => peers .traverse[F, Option[Peer[F]]] { peer => peer.hasBlock(block.header.hash).map { case true => None case false => Some(peer) } } .map(_.flatten) } def withoutTxs[F[_]: Sync](stxs: SignedTransactions): PeerSelector[F] = PeerSelector { peers => peers .traverse[F, Option[Peer[F]]] { peer => peer.hasTxs(stxs).map { case true => None case false => Some(peer) } } .map(_.flatten) } def bestPeer[F[_]: Sync](minTD: N): PeerSelector[F] = PeerSelector { peers => peers .traverse(p => p.status.get.map(_.td).map(td => td -> p)) .map(_.filter(_._1 > minTD).sortBy(-_._1).map(_._2)) } def randomSelectSqrt[F[_]: Sync](min: Int): PeerSelector[F] = PeerSelector { peers => val numberOfPeersToSend = math.max(math.sqrt(peers.size).toInt, min) Sync[F].pure(Random.shuffle(peers).take(numberOfPeersToSend)) } }
Example 36
Source File: MiningConfig.scala From iotchain with MIT License | 5 votes |
package jbok.core.config import cats.effect.Sync import cats.implicits._ import io.circe.generic.extras.ConfiguredJsonCodec import jbok.core.keystore.KeyStore import jbok.core.models.Address import jbok.crypto.signature.KeyPair import jbok.codec.json.implicits._ import scala.concurrent.duration.FiniteDuration @ConfiguredJsonCodec final case class MiningConfig( enabled: Boolean, address: Address, passphrase: String, coinbase: Address, period: FiniteDuration, epoch: Int, minBroadcastPeers: Int ) object MiningConfig { def getKeyPair[F[_]](config: MiningConfig, keyStore: KeyStore[F])(implicit F: Sync[F]): F[Option[KeyPair]] = if (config.enabled) { keyStore.unlockAccount(config.coinbase, config.passphrase).map(_.keyPair.some) } else F.pure(None) }
Example 37
Source File: Wallet.scala From iotchain with MIT License | 5 votes |
package jbok.core.keystore import cats.effect.Sync import cats.implicits._ import jbok.core.models.{Address, ChainId, SignedTransaction, Transaction} import jbok.crypto.signature.{ECDSA, KeyPair, Signature} final case class Wallet(address: Address, keyPair: KeyPair) { def signTx[F[_]: Sync](tx: Transaction, chainId: ChainId): F[SignedTransaction] = SignedTransaction.sign[F](tx, keyPair, chainId) } object Wallet { def fromSecret[F[_]: Sync](secret: KeyPair.Secret): F[Wallet] = for { public <- Signature[ECDSA].generatePublicKey[F](secret) keyPair = KeyPair(public, secret) address = Address(keyPair) } yield Wallet(address, keyPair) }
Example 38
Source File: MockingKeyStore.scala From iotchain with MIT License | 5 votes |
package jbok.core.keystore import cats.effect.Sync import cats.implicits._ import cats.effect.concurrent.Ref import jbok.core.models.Address import jbok.crypto.signature.{ECDSA, KeyPair, Signature} import scodec.bits.ByteVector final class MockingKeyStore[F[_]](implicit F: Sync[F]) extends KeyStore[F] { private val m: Ref[F, Map[Address, KeyPair]] = Ref.unsafe(Map.empty) override def newAccount(passphrase: String): F[Address] = for { kp <- Signature[ECDSA].generateKeyPair[F]() _ <- m.update(_ + (Address(kp) -> kp)) } yield Address(kp) override def readPassphrase(prompt: String): F[String] = ??? override def importPrivateKey(key: ByteVector, passphrase: String): F[Address] = for { secret <- KeyPair.Secret(key).pure[F] public <- Signature[ECDSA].generatePublicKey[F](secret) kp = KeyPair(public, secret) address = Address(kp) _ <- m.update(_ + (address -> kp)) } yield address override def listAccounts: F[List[Address]] = m.get.map(_.keys.toList) override def unlockAccount(address: Address, passphrase: String): F[Wallet] = m.get.map(_(address)).map { kp => Wallet(Address(kp), kp) } override def deleteAccount(address: Address): F[Boolean] = m.update(_ - address).as(true) override def changePassphrase(address: Address, oldPassphrase: String, newPassphrase: String): F[Boolean] = F.pure(true) } object MockingKeyStore { def withInitKeys[F[_]: Sync](initKeys: List[KeyPair]): F[MockingKeyStore[F]] = { val keystore = new MockingKeyStore[F]() initKeys.traverse(kp => keystore.importPrivateKey(kp.secret.bytes, "")).as(keystore) } }
Example 39
Source File: FUUIDGen.scala From fuuid with MIT License | 5 votes |
package io.chrisdavenport.fuuid import java.util.UUID import cats.implicits._ import cats.effect.Sync def nameBased(namespace: FUUID, name: String): F[FUUID] } object FUUIDGen { def apply[F[_]](implicit ev: FUUIDGen[F]): FUUIDGen[F] = ev // Sync f => class FUUIDGen f implicit def instance[F[_]: Sync]: FUUIDGen[F] = new SyncFUUIDGen[F] private class SyncFUUIDGen[F[_]: Sync] extends FUUIDGen[F]{ def random: F[FUUID] = FUUID.randomFUUID[F] def fromString(s: String): F[FUUID] = FUUID.fromStringF[F](s) def fromUUID(uuid: UUID): F[FUUID] = FUUID.fromUUID(uuid).pure[F] def nameBased(namespace: FUUID, name: String): F[FUUID] = FUUID.nameBased[F](namespace, name) } }
Example 40
Source File: FUUID.scala From fuuid with MIT License | 5 votes |
package io.chrisdavenport.fuuid import cats._ import cats.implicits._ import cats.effect.Sync import java.util.UUID import scala.reflect.macros.blackbox final class FUUID private (private val uuid: UUID){ // Direct show method so people do not use toString def show: String = uuid.show // -1 less than, 0 equal to, 1 greater than def compare(that: FUUID): Int = this.uuid.compareTo(that.uuid) // Returns 0 when equal def eqv(that: FUUID): Boolean = compare(that) == 0 override def equals(obj: scala.Any): Boolean = obj match { case that: FUUID => eqv(that) case _ => false } override def hashCode: Int = uuid.hashCode override def toString: String = uuid.toString } object FUUID { implicit val instancesFUUID: Hash[FUUID] with Order[FUUID] with Show[FUUID] = new Hash[FUUID] with Order[FUUID] with Show[FUUID]{ override def show(t: FUUID): String = t.show override def eqv(x: FUUID, y: FUUID): Boolean = x.eqv(y) override def hash(x: FUUID): Int = x.hashCode override def compare(x: FUUID, y: FUUID): Int = x.compare(y) } def fromString(s: String): Either[Throwable, FUUID] = Either.catchNonFatal(new FUUID(UUID.fromString(s))) def fromStringOpt(s: String): Option[FUUID] = fromString(s).toOption def fromStringF[F[_]](s: String)(implicit AE: ApplicativeError[F, Throwable]): F[FUUID] = fromString(s).fold(AE.raiseError, AE.pure) def fromUUID(uuid: UUID): FUUID = new FUUID(uuid) def randomFUUID[F[_]: Sync]: F[FUUID] = Sync[F].delay( new FUUID(UUID.randomUUID) ) def fuuid(s: String): FUUID = macro Macros.fuuidLiteral private[FUUID] class Macros(val c: blackbox.Context) { import c.universe._ def fuuidLiteral(s: c.Expr[String]): c.Expr[FUUID] = s.tree match { case Literal(Constant(s: String))=> fromString(s) .fold( e => c.abort(c.enclosingPosition, e.getMessage.replace("UUID", "FUUID")), _ => c.Expr(q""" @SuppressWarnings(Array("org.wartremover.warts.Throw")) val fuuid = _root_.io.chrisdavenport.fuuid.FUUID.fromString($s).fold(throw _, _root_.scala.Predef.identity) fuuid """) ) case _ => c.abort( c.enclosingPosition, s"This method uses a macro to verify that a FUUID literal is valid. Use FUUID.fromString if you have a dynamic value you want to parse as an FUUID." ) } } object Unsafe { def toUUID(fuuid: FUUID): UUID = fuuid.uuid def withUUID[A](fuuid: FUUID)(f: UUID => A): A = f(fuuid.uuid) } }
Example 41
Source File: FTracing.scala From opencensus-scala with Apache License 2.0 | 5 votes |
package io.opencensus.scala.doobie import cats.effect.ExitCase.{Canceled, Completed, Error} import cats.effect.{Bracket, Sync} import doobie.free.connection.ConnectionIO import io.opencensus.scala.Tracing import io.opencensus.scala.doobie.FTracing.FBracket import io.opencensus.trace.{Span, Status} import cats.syntax.flatMap._ import cats.syntax.functor._ abstract class FTracing[F[_]: Sync: FBracket] { protected val tracing: Tracing private def fTrace(name: String, parentSpan: Option[Span]): F[Span] = Sync[F].delay( parentSpan.fold(tracing.startSpan(name))(span => tracing.startSpanWithParent(name, span) ) ) private def fStop(span: Span): F[Unit] = Sync[F].delay(tracing.endSpan(span, Status.OK)) private def fStopError(span: Span): F[Unit] = Sync[F].delay(tracing.endSpan(span, Status.INTERNAL)) private def fStopCanceled(span: Span): F[Unit] = Sync[F].delay(tracing.endSpan(span, Status.CANCELLED)) def traceF[A](co: F[A], name: String, parentSpan: Option[Span]): F[A] = for { startedSpan <- fTrace(name, parentSpan) result <- Bracket[F, Throwable].guaranteeCase(co) { case Completed => fStop(startedSpan) case Error(_) => fStopError(startedSpan) case Canceled => fStopCanceled(startedSpan) } } yield result } object FTracing { type FBracket[F[_]] = Bracket[F, Throwable] } object ConnectionIOTracing extends FTracing[ConnectionIO] { override protected val tracing: Tracing = Tracing }
Example 42
Source File: http4s.scala From sup with Apache License 2.0 | 5 votes |
package sup.modules import cats.effect.Sync import cats.Monad import cats.Reducible import org.http4s.dsl.Http4sDsl import org.http4s.EntityEncoder import org.http4s.HttpRoutes import org.http4s.Response import sup.HealthCheck import sup.HealthResult import cats.implicits._ object http4s { def healthCheckRoutes[F[_]: Sync, H[_]: Reducible]( healthCheck: HealthCheck[F, H], path: String = "health-check" )( implicit encoder: EntityEncoder[F, HealthResult[H]] ): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ HttpRoutes.of[F] { case GET -> Root / `path` => healthCheckResponse(healthCheck) } } def healthCheckResponse[F[_]: Monad, H[_]: Reducible]( healthCheck: HealthCheck[F, H] )( implicit encoder: EntityEncoder[F, HealthResult[H]] ): F[Response[F]] = { val dsl = new Http4sDsl[F] {} import dsl._ healthCheck.check.flatMap { check => if (check.value.reduce.isHealthy) Ok(check) else ServiceUnavailable(check) } } }
Example 43
Source File: sttp.scala From sup with Apache License 2.0 | 5 votes |
package sup.modules import cats.Functor import cats.effect.Sync import com.softwaremill.sttp.{Id, Request, SttpBackend} import sup.{HealthCheck, HealthResult} import cats.implicits._ object sttp { def remoteHealthCheck[F[_]: Sync, H[_]]( call: Request[HealthResult[H], Nothing] )( implicit backend: SttpBackend[F, Nothing] ): HealthCheck[F, H] = HealthCheck.liftF { backend.send(call).flatMap(response => Sync[F].delay(response.unsafeBody)) } }
Example 44
Source File: Github.scala From sonar-scala with GNU Lesser General Public License v3.0 | 5 votes |
package com.mwz.sonar.scala package pr package github import cats.effect.Sync import cats.syntax.flatMap._ import com.mwz.sonar.scala.pr.github.Codec._ import io.circe.generic.auto._ import mouse.boolean._ import org.http4s.client.Client import org.http4s.{Header, Headers, Method, Request, Uri} trait Github[F[_]] { def authenticatedUser: F[User] def pullRequest: F[PullRequest] def comments: F[List[Comment]] def createComment(comment: NewComment): F[Unit] def files: F[List[File]] def createStatus(sha: String, status: NewStatus): F[Unit] } object Github { def apply[F[_]: Sync](client: Client[F], pr: GlobalConfig.PullRequest): Github[F] = new Github[F] { val auth: Header = Header("Authorization", s"token ${pr.github.oauth}") val userUri: Uri = pr.github.apiuri / "user" val prUri: Uri = (pr.github.apiuri / "repos").addPath(pr.github.repository) / "pulls" / pr.prNumber val commentsUri: Uri = prUri / "comments" val filesUri: Uri = prUri / "files" def newStatusUri(sha: String): Uri = (pr.github.apiuri / "repos").addPath(pr.github.repository) / "statuses" / sha def request(uri: Uri): Request[F] = { Request[F]( uri = uri, headers = Headers.of(auth) ) } def authenticatedUser: F[User] = client.expect[User](request(userUri)) def pullRequest: F[PullRequest] = client.expect[PullRequest](request(prUri)) def comments: F[List[Comment]] = client.expect[List[Comment]](request(commentsUri)) def createComment(comment: NewComment): F[Unit] = { val request: F[Request[F]] = Sync[F].pure( Request(Method.POST, commentsUri, headers = Headers.of(auth)) .withEntity(comment) ) pr.dryRun.fold(Sync[F].unit, client.expect[Comment](request) >> Sync[F].unit) } def files: F[List[File]] = client.expect[List[File]](request(filesUri)) def createStatus(sha: String, status: NewStatus): F[Unit] = { val request: F[Request[F]] = Sync[F].pure( Request(Method.POST, newStatusUri(sha), headers = Headers.of(auth)) .withEntity(status) ) pr.dryRun.fold(Sync[F].unit, client.expect[Status](request) >> Sync[F].unit) } } }
Example 45
Source File: Logger.scala From sonar-scala with GNU Lesser General Public License v3.0 | 5 votes |
package com.mwz.sonar.scala package util import cats.effect.Sync import org.sonar.api.utils.log.{Logger => SonarLogger, Loggers => SonarLoggers} trait Logger[F[_]] { def debug(s: String): F[Unit] def info(s: String): F[Unit] def warn(s: String): F[Unit] def error(s: String): F[Unit] def error(s: String, e: Throwable): F[Unit] } object Logger { def apply[F[_]](implicit ev: Logger[F]): Logger[F] = ev def create[F[_]: Sync, T](clazz: Class[T], module: String): F[Logger[F]] = create(clazz, Some(module)) def create[F[_]: Sync, T](clazz: Class[T], module: Option[String] = None): F[Logger[F]] = Sync[F].delay { val log: SonarLogger = SonarLoggers.get(clazz) val prefix: String = "sonar-scala" + module.fold("")("-" + _) new Logger[F] { override def debug(s: String): F[Unit] = Sync[F].delay(log.debug(s"[$prefix] $s")) override def info(s: String): F[Unit] = Sync[F].delay(log.info(s"[$prefix] $s")) override def warn(s: String): F[Unit] = Sync[F].delay(log.warn(s"[$prefix] $s")) override def error(s: String): F[Unit] = Sync[F].delay(log.error(s"[$prefix] $s")) override def error(s: String, e: Throwable): F[Unit] = Sync[F].delay(log.error(s"[$prefix] $s", e)) } } }
Example 46
Source File: GcsStore.scala From fs2-blobstore with Apache License 2.0 | 5 votes |
package blobstore.gcs import java.nio.channels.Channels import java.time.Instant import java.util.Date import blobstore.{Path, Store} import cats.effect.{Blocker, ContextShift, Sync} import com.google.api.gax.paging.Page import com.google.cloud.storage.{Acl, Blob, BlobId, BlobInfo, Storage} import com.google.cloud.storage.Storage.{BlobListOption, CopyRequest} import fs2.{Chunk, Pipe, Stream} import scala.jdk.CollectionConverters._ final class GcsStore[F[_]](storage: Storage, blocker: Blocker, acls: List[Acl] = Nil)(implicit F: Sync[F], CS: ContextShift[F]) extends Store[F] { private def _chunk(pg: Page[Blob]): Chunk[Path] = { val (dirs, files) = pg.getValues.asScala.toSeq.partition(_.isDirectory) val dirPaths = Chunk.seq(dirs.map(b => Path(root = b.getBucket, key = b.getName.stripSuffix("/"), size = None, isDir = true, lastModified = None))) val filePaths = Chunk.seq(files.map{b => val size = Option(b.getSize: java.lang.Long).map(_.toLong) // Prevent throwing NPE (see https://github.com/scala/bug/issues/9634) val lastModified = Option(b.getUpdateTime: java.lang.Long).map(millis => Date.from(Instant.ofEpochMilli(millis))) // Prevent throwing NPE (see https://github.com/scala/bug/issues/9634) Path(b.getBucket, key = b.getName, size = size, isDir = false, lastModified = lastModified) }) Chunk.concat(List(dirPaths, filePaths)) } def list(path: Path): fs2.Stream[F, Path] = { Stream.unfoldChunkEval[F, () => Option[Page[Blob]], Path]{ () => Some(storage.list(path.root, BlobListOption.currentDirectory(), BlobListOption.prefix(path.key))) }{getPage => blocker.delay{ getPage().map{pg => if (pg.hasNextPage){ (_chunk(pg), () => Some(pg.getNextPage)) } else { (_chunk(pg), () => None) } } } } } def get(path: Path, chunkSize: Int): fs2.Stream[F, Byte] = { val is = blocker.delay(Channels.newInputStream(storage.get(path.root, path.key).reader())) fs2.io.readInputStream(is, chunkSize, blocker, closeAfterUse = true) } def put(path: Path): Pipe[F, Byte, Unit] = { val fos = Sync[F].delay{ val builder = { val b = BlobInfo.newBuilder(path.root, path.key) if (acls.nonEmpty) b.setAcl(acls.asJava) else b } val blobInfo = builder.build() val writer = storage.writer(blobInfo) Channels.newOutputStream(writer) } fs2.io.writeOutputStream(fos, blocker, closeAfterUse = true) } def move(src: Path, dst: Path): F[Unit] = F.productR(copy(src, dst))(remove(src)) def copy(src: Path, dst: Path): F[Unit] = { val req = CopyRequest.newBuilder().setSource(src.root, src.key).setTarget(BlobId.of(dst.root, dst.key)).build() F.void(blocker.delay(storage.copy(req).getResult)) } def remove(path: Path): F[Unit] = F.void(blocker.delay(storage.delete(path.root, path.key))) } object GcsStore{ def apply[F[_]]( storage: Storage, blocker: Blocker, acls: List[Acl] )(implicit F: Sync[F], CS: ContextShift[F]): GcsStore[F] = new GcsStore(storage, blocker, acls) }
Example 47
Source File: FileStore.scala From fs2-blobstore with Apache License 2.0 | 5 votes |
package blobstore package fs import java.nio.file.{Files, Paths, Path => NioPath} import java.util.Date import scala.jdk.CollectionConverters._ import cats.implicits._ import cats.effect.{Blocker, ContextShift, Sync} import fs2.{Pipe, Stream} final class FileStore[F[_]](fsroot: NioPath, blocker: Blocker)(implicit F: Sync[F], CS: ContextShift[F]) extends Store[F] { val absRoot: String = fsroot.toAbsolutePath.normalize.toString override def list(path: Path): fs2.Stream[F, Path] = { val isDir = Stream.eval(F.delay(Files.isDirectory(path))) val isFile = Stream.eval(F.delay(Files.exists(path))) val files = Stream.eval(F.delay(Files.list(path))) .flatMap(x => Stream.fromIterator(x.iterator.asScala)) .evalMap(x => F.delay( Path(x.toAbsolutePath.toString.replaceFirst(absRoot, "")).copy( size = Option(Files.size(x)), isDir = Files.isDirectory(x), lastModified = Option(new Date(Files.getLastModifiedTime(path).toMillis)) ) )) val file = fs2.Stream.eval { F.delay { path.copy( size = Option(Files.size(path)), lastModified = Option(new Date(Files.getLastModifiedTime(path).toMillis)) ) } } isDir.ifM(files, isFile.ifM(file, Stream.empty.covaryAll[F, Path])) } override def get(path: Path, chunkSize: Int): fs2.Stream[F, Byte] = fs2.io.file.readAll[F](path, blocker, chunkSize) override def put(path: Path): Pipe[F, Byte, Unit] = { in => val mkdir = Stream.eval(F.delay(Files.createDirectories(_toNioPath(path).getParent)).as(true)) mkdir.ifM( fs2.io.file.writeAll(path, blocker).apply(in), Stream.raiseError[F](new Exception(s"failed to create dir: $path")) ) } override def move(src: Path, dst: Path): F[Unit] = F.delay { Files.createDirectories(_toNioPath(dst).getParent) Files.move(src, dst) }.void override def copy(src: Path, dst: Path): F[Unit] = { F.delay { Files.createDirectories(_toNioPath(dst).getParent) Files.copy(src, dst) }.void } override def remove(path: Path): F[Unit] = F.delay({ Files.deleteIfExists(path) () }) implicit private def _toNioPath(path: Path): NioPath = Paths.get(absRoot, path.root, path.key) } object FileStore{ def apply[F[_]](fsroot: NioPath, blocker: Blocker)(implicit F: Sync[F], CS: ContextShift[F]): FileStore[F] = new FileStore(fsroot, blocker) }
Example 48
Source File: package.scala From fs2-blobstore with Apache License 2.0 | 5 votes |
import java.io.OutputStream import java.nio.file.Files import cats.effect.{ContextShift, Sync, Blocker} import fs2.{Pipe, Pull, Stream} import cats.implicits._ package object blobstore { protected[blobstore] def _writeAllToOutputStream1[F[_]](in: Stream[F, Byte], out: OutputStream, blocker: Blocker)( implicit F: Sync[F], CS: ContextShift[F]): Pull[F, Nothing, Unit] = { in.pull.uncons.flatMap { case None => Pull.done case Some((hd, tl)) => Pull.eval[F, Unit](blocker.delay(out.write(hd.toArray))) >> _writeAllToOutputStream1(tl, out, blocker) } } protected[blobstore] def bufferToDisk[F[_]](chunkSize: Int, blocker: Blocker)(implicit F: Sync[F], CS: ContextShift[F]) : Pipe[F, Byte, (Long, Stream[F, Byte])] = { in => Stream.bracket(F.delay(Files.createTempFile("bufferToDisk", ".bin")))( p => F.delay(p.toFile.delete).void).flatMap { p => in.through(fs2.io.file.writeAll(p, blocker)).drain ++ Stream.emit((p.toFile.length, fs2.io.file.readAll(p, blocker, chunkSize))) } } }
Example 49
Source File: Bootstrap.scala From hydra with Apache License 2.0 | 5 votes |
package hydra.ingest.modules import java.time.Instant import cats.data.NonEmptyList import cats.effect.Sync import cats.implicits._ import cats.{Monad, MonadError} import hydra.core.marshallers.History import hydra.ingest.app.AppConfig.V2MetadataTopicConfig import hydra.kafka.model._ import hydra.kafka.programs.CreateTopicProgram import hydra.kafka.util.KafkaUtils.TopicDetails final class Bootstrap[F[_]: MonadError[*[_], Throwable]] private ( createTopicProgram: CreateTopicProgram[F], cfg: V2MetadataTopicConfig ) { def bootstrapAll: F[Unit] = for { _ <- bootstrapMetadataTopic } yield () private def bootstrapMetadataTopic: F[Unit] = if (cfg.createOnStartup) { TopicMetadataV2.getSchemas[F].flatMap { schemas => createTopicProgram.createTopic( cfg.topicName, TopicMetadataV2Request( schemas, StreamTypeV2.Entity, false, InternalUseOnly, NonEmptyList.of(cfg.contactMethod), Instant.now, List.empty, Some( "This is the topic that Hydra uses to keep track of metadata for topics." ) ), TopicDetails(cfg.numPartitions, cfg.replicationFactor) ) } } else { Monad[F].unit } } object Bootstrap { def make[F[_]: Sync]( createTopicProgram: CreateTopicProgram[F], v2MetadataTopicConfig: V2MetadataTopicConfig ): F[Bootstrap[F]] = Sync[F].delay { new Bootstrap[F](createTopicProgram, v2MetadataTopicConfig) } }
Example 50
Source File: Routes.scala From hydra with Apache License 2.0 | 5 votes |
package hydra.ingest.modules import akka.actor.ActorSystem import akka.http.scaladsl.server.directives.RouteDirectives import akka.http.scaladsl.server.{Route, RouteConcatenation} import cats.effect.Sync import hydra.common.config.ConfigSupport import hydra.common.util.{ActorUtils, Futurable} import hydra.ingest.app.AppConfig.AppConfig import hydra.ingest.http._ import hydra.kafka.consumer.KafkaConsumerProxy import hydra.kafka.endpoints.{BootstrapEndpoint, BootstrapEndpointV2, TopicMetadataEndpoint, TopicsEndpoint} import hydra.kafka.util.KafkaUtils.TopicDetails import scala.concurrent.ExecutionContext final class Routes[F[_]: Sync: Futurable] private(programs: Programs[F], algebras: Algebras[F], cfg: AppConfig) (implicit system: ActorSystem) extends RouteConcatenation with ConfigSupport { private implicit val ec: ExecutionContext = system.dispatcher private val bootstrapEndpointV2 = if (cfg.v2MetadataTopicConfig.createV2TopicsEnabled) { val topicDetails = TopicDetails( cfg.createTopicConfig.defaultNumPartions, cfg.createTopicConfig.defaultReplicationFactor ) new BootstrapEndpointV2(programs.createTopic, topicDetails).route } else { RouteDirectives.reject } lazy val routes: F[Route] = Sync[F].delay { import ConfigSupport._ //TODO: remove this lookup val consumerPath = applicationConfig .getStringOpt("actors.kafka.consumer_proxy.path") .getOrElse( s"/user/service/${ActorUtils.actorName(classOf[KafkaConsumerProxy])}" ) val consumerProxy = system.actorSelection(consumerPath) new SchemasEndpoint().route ~ new BootstrapEndpoint(system).route ~ new TopicMetadataEndpoint(consumerProxy, algebras.metadata).route ~ new IngestorRegistryEndpoint().route ~ new IngestionWebSocketEndpoint().route ~ new IngestionEndpoint(cfg.ingestConfig.alternateIngestEnabled, programs.ingestionFlow, programs.ingestionFlowV2, cfg.ingestConfig.useOldIngestIfUAContains).route ~ new TopicsEndpoint(consumerProxy)(system.dispatcher).route ~ HealthEndpoint.route ~ bootstrapEndpointV2 } } object Routes { def make[F[_]: Sync: Futurable](programs: Programs[F], algebras: Algebras[F], config: AppConfig) (implicit system: ActorSystem): F[Routes[F]] = Sync[F].delay(new Routes[F](programs, algebras, config)) }
Example 51
Source File: KafkaAdminAlgebra.scala From hydra with Apache License 2.0 | 5 votes |
package hydra.kafka.algebras import cats.effect.concurrent.Ref import cats.effect.{Async, Concurrent, ContextShift, Resource, Sync} import cats.implicits._ import fs2.kafka._ import hydra.core.protocol._ import hydra.kafka.util.KafkaUtils.TopicDetails import org.apache.kafka.clients.admin.NewTopic import org.apache.kafka.common.errors.UnknownTopicOrPartitionException import scala.util.control.NoStackTrace def deleteTopic(name: String): F[Unit] } object KafkaAdminAlgebra { type TopicName = String final case class Topic(name: TopicName, numberPartitions: Int) def live[F[_]: Sync: Concurrent: ContextShift]( bootstrapServers: String, ): F[KafkaAdminAlgebra[F]] = Sync[F].delay { new KafkaAdminAlgebra[F] { override def describeTopic(name: TopicName): F[Option[Topic]] = { getAdminClientResource .use(_.describeTopics(name :: Nil)) .map(_.headOption.map(_._2).map { td => Topic(td.name(), td.partitions().size()) }) .recover { case _: UnknownTopicOrPartitionException => None } } override def getTopicNames: F[List[TopicName]] = getAdminClientResource.use(_.listTopics.names.map(_.toList)) override def createTopic(name: TopicName, d: TopicDetails): F[Unit] = { import scala.collection.JavaConverters._ val newTopic = new NewTopic(name, d.numPartitions, d.replicationFactor) .configs(d.configs.asJava) getAdminClientResource.use(_.createTopic(newTopic)) } override def deleteTopic(name: String): F[Unit] = getAdminClientResource.use(_.deleteTopic(name)) private def getAdminClientResource: Resource[F, KafkaAdminClient[F]] = { adminClientResource( AdminClientSettings.apply.withBootstrapServers(bootstrapServers) ) } } } def test[F[_]: Sync]: F[KafkaAdminAlgebra[F]] = Ref[F].of(Map[TopicName, Topic]()).flatMap(getTestKafkaClient[F]) private[this] def getTestKafkaClient[F[_]: Sync]( ref: Ref[F, Map[TopicName, Topic]] ): F[KafkaAdminAlgebra[F]] = Sync[F].delay { new KafkaAdminAlgebra[F] { override def describeTopic(name: TopicName): F[Option[Topic]] = ref.get.map(_.get(name)) override def getTopicNames: F[List[TopicName]] = ref.get.map(_.keys.toList) override def createTopic( name: TopicName, details: TopicDetails ): F[Unit] = { val entry = name -> Topic(name, details.numPartitions) ref.update(old => old + entry) } override def deleteTopic(name: String): F[Unit] = ref.update(_ - name) } } }
Example 52
Source File: MetadataAlgebraSpec.scala From hydra with Apache License 2.0 | 5 votes |
package hydra.kafka.algebras import java.time.Instant import cats.data.NonEmptyList import cats.effect.{Concurrent, ContextShift, IO, Sync, Timer} import cats.implicits._ import hydra.avro.registry.SchemaRegistry import hydra.core.marshallers.History import hydra.kafka.algebras.MetadataAlgebra.TopicMetadataContainer import hydra.kafka.model.ContactMethod.Slack import hydra.kafka.model.TopicMetadataV2Request.Subject import hydra.kafka.model.{Public, StreamTypeV2, TopicMetadataV2, TopicMetadataV2Key, TopicMetadataV2Request, TopicMetadataV2Value} import io.chrisdavenport.log4cats.SelfAwareStructuredLogger import io.chrisdavenport.log4cats.slf4j.Slf4jLogger import org.apache.avro.generic.GenericRecord import org.scalatest.Assertion import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike import retry.RetryPolicies._ import retry.syntax.all._ import retry.{RetryPolicy, _} import scala.concurrent.ExecutionContext import scala.concurrent.duration._ class MetadataAlgebraSpec extends AnyWordSpecLike with Matchers { implicit private val contextShift: ContextShift[IO] = IO.contextShift(ExecutionContext.global) private implicit val concurrentEffect: Concurrent[IO] = IO.ioConcurrentEffect private implicit val policy: RetryPolicy[IO] = limitRetries[IO](5) |+| exponentialBackoff[IO](500.milliseconds) private implicit val timer: Timer[IO] = IO.timer(ExecutionContext.global) private implicit def noop[A]: (A, RetryDetails) => IO[Unit] = retry.noop[IO, A] implicit private def unsafeLogger[F[_]: Sync]: SelfAwareStructuredLogger[F] = Slf4jLogger.getLogger[F] private implicit class RetryAndAssert[A](boolIO: IO[A]) { def retryIfFalse(check: A => Boolean): IO[Assertion] = boolIO.map(check).retryingM(identity, policy, noop).map(assert(_)) } private val metadataTopicName = "_internal.metadataTopic" private val consumerGroup = "Consumer Group" (for { kafkaClient <- KafkaClientAlgebra.test[IO] schemaRegistry <- SchemaRegistry.test[IO] metadata <- MetadataAlgebra.make(metadataTopicName, consumerGroup, kafkaClient, schemaRegistry, consumeMetadataEnabled = true) } yield { runTests(metadata, kafkaClient) }).unsafeRunSync() private def runTests(metadataAlgebra: MetadataAlgebra[IO], kafkaClientAlgebra: KafkaClientAlgebra[IO]): Unit = { "MetadataAlgebraSpec" should { "retrieve none for non-existant topic" in { val subject = Subject.createValidated("Non-existantTopic").get metadataAlgebra.getMetadataFor(subject).unsafeRunSync() shouldBe None } "retrieve metadata" in { val subject = Subject.createValidated("subject1").get val (genericRecordsIO, key, value) = getMetadataGenericRecords(subject) (for { record <- genericRecordsIO _ <- kafkaClientAlgebra.publishMessage(record, metadataTopicName) _ <- metadataAlgebra.getMetadataFor(subject).retryIfFalse(_.isDefined) metadata <- metadataAlgebra.getMetadataFor(subject) } yield metadata shouldBe Some(TopicMetadataContainer(key, value, None, None))).unsafeRunSync() } "retrieve all metadata" in { val subject = Subject.createValidated("subject2").get val (genericRecordsIO, key, value) = getMetadataGenericRecords(subject) (for { record <- genericRecordsIO _ <- kafkaClientAlgebra.publishMessage(record, metadataTopicName) _ <- metadataAlgebra.getMetadataFor(subject).retryIfFalse(_.isDefined) allMetadata <- metadataAlgebra.getAllMetadata } yield allMetadata should have length 2).unsafeRunSync() } } } private def getMetadataGenericRecords(subject: Subject): (IO[(GenericRecord, Option[GenericRecord])], TopicMetadataV2Key, TopicMetadataV2Value) = { val key = TopicMetadataV2Key(subject) val value = TopicMetadataV2Value( StreamTypeV2.Entity, deprecated = false, Public, NonEmptyList.one(Slack.create("#channel").get), Instant.now, List(), None) (TopicMetadataV2.encode[IO](key, Some(value)), key, value) } }
Example 53
Source File: OutWatch.scala From outwatch with Apache License 2.0 | 5 votes |
package outwatch import cats.effect.Sync import cats.implicits._ import org.scalajs.dom import org.scalajs.dom._ import outwatch.interpreter.SnabbdomOps import snabbdom.{VNodeProxy, patch} object OutWatch { def toSnabbdom[F[_]](vNode: VNode)(implicit F: Sync[F]): F[VNodeProxy] = F.delay { SnabbdomOps.toSnabbdom(vNode) } def renderInto[F[_]](element: dom.Element, vNode: VNode)(implicit F: Sync[F]): F[Unit] = toSnabbdom(vNode).map { node => val elem = dom.document.createElement("div") element.appendChild(elem) patch(elem, node) }.void def renderReplace[F[_]: Sync](element: dom.Element, vNode: VNode): F[Unit] = toSnabbdom(vNode).map { node => val elementNode = snabbdom.tovnode(element) patch(elementNode, node) }.void def renderInto[F[_]: Sync](querySelector: String, vNode: VNode): F[Unit] = renderInto(document.querySelector(querySelector), vNode) def renderReplace[F[_]: Sync](querySelector: String, vNode: VNode): F[Unit] = renderReplace(document.querySelector(querySelector), vNode) }
Example 54
Source File: HandlerFactory.scala From outwatch with Apache License 2.0 | 5 votes |
package outwatch.reactive import cats.effect.{Sync, SyncIO} import colibri._ @inline final class HandlerFactory[H[_] : CreateSubject] { // Create a Handler that keeps the last emitted value as State, typically a BehaviourSubject or ReplaySubject @inline def create[T]: SyncIO[H[T]] = SyncIO(unsafe[T]) @inline def create[T](seed: T): SyncIO[H[T]] = SyncIO(unsafe[T](seed)) @inline def createF[F[_]] = new CreatePartiallyApplied[F] @inline def createF[F[_], T](implicit F: Sync[F]): F[H[T]] = F.delay(unsafe[T]) @inline def createF[F[_], T](seed: T)(implicit F: Sync[F]): F[H[T]] = F.delay(unsafe[T](seed)) @inline def unsafe[T]: H[T] = CreateSubject[H].replay[T] @inline def unsafe[T](seed: T): H[T] = CreateSubject[H].behavior[T](seed) object publish { // Create a Handler that just publish to all subscribers but does not keep the latest value as State, typically a PublishSubject @inline def create[T]: SyncIO[H[T]] = SyncIO(unsafe[T]) @inline def createF[F[_], T](implicit F: Sync[F]): F[H[T]] = F.delay(unsafe[T]) @inline def unsafe[T]: H[T] = CreateSubject[H].publish[T] } @inline final class CreatePartiallyApplied[F[_]] { @inline def apply[T](seed: T)(implicit F: Sync[F]): F[H[T]] = createF[F, T](seed) } } @inline final class ProHandlerFactory[H[_,_] : CreateProSubject] { // Create a ProHandler that has different type parameters for the Observer[I] part and the Observable[O] part @inline def apply[SI[_] : Sink, SO[_] : Source, I,O](sink: SI[I], source: SO[O]): H[I, O] = CreateProSubject[H].from(sink, source) }
Example 55
Source File: LocalStorage.scala From outwatch with Apache License 2.0 | 5 votes |
package outwatch.util import cats.effect.Sync import cats.implicits._ import org.scalajs.dom import org.scalajs.dom.StorageEvent import org.scalajs.dom.window.{localStorage, sessionStorage} import outwatch.dsl.events import outwatch.reactive.handler._ import colibri._ class Storage(domStorage: dom.Storage) { private def handlerWithTransform[F[_]: Sync](key: String, transform: Observable[Option[String]] => Observable[Option[String]]): F[Handler[Option[String]]] = { val storage = new dom.ext.Storage(domStorage) for { h <- Handler.createF[F](storage(key)) } yield { // We execute the write-action to the storage // and pass the written value through to the underlying subject h h.transformSubject[Option[String]] { o => val c = o.redirect((o: Observable[Option[String]]) => transform(o).distinct) c.connect() c.sink } { input => input.doOnNext { case Some(data) => storage.update(key, data) case None => storage.remove(key) } } } } private def storageEventsForKey[F[_]: Sync](key: String): Observable[Option[String]] = // StorageEvents are only fired if the localStorage was changed in another window events.window.onStorage.collect { case e: StorageEvent if e.storageArea == domStorage && e.key == key => // newValue is either String or null if removed or cleared // Option() transformes this to Some(string) or None Option(e.newValue) case e: StorageEvent if e.storageArea == domStorage && e.key == null => // storage.clear() emits an event with key == null None } def handlerWithoutEvents[F[_]: Sync](key: String): F[Handler[Option[String]]] = { handlerWithTransform(key, identity) } def handlerWithEventsOnly[F[_]: Sync](key: String): F[Handler[Option[String]]] = { val storageEvents = storageEventsForKey(key) handlerWithTransform(key, _ => storageEvents) } def handler[F[_]: Sync](key: String): F[Handler[Option[String]]] = { val storageEvents = storageEventsForKey(key) handlerWithTransform(key, Observable.merge(_, storageEvents)) } } object LocalStorage extends Storage(localStorage) object SessionStorage extends Storage(sessionStorage)
Example 56
Source File: Store.scala From outwatch with Apache License 2.0 | 5 votes |
package outwatch.util import cats.effect.Sync import colibri._ object Store { @inline final class CreatePartiallyApplied[F[_]] { @inline def apply[A, M](initialAction: A, initialState: M, reducer: Reducer[A, M])(implicit F: Sync[F]) = create[F, A, M](initialAction, initialState, reducer) } def create[F[_]] = new CreatePartiallyApplied[F] def create[F[_], A, M]( initialAction: A, initialState: M, reducer: Reducer[A, M] )(implicit F: Sync[F]): F[ProSubject[A, (A, M)]] = F.delay { val subject = Subject.publish[A] val fold: ((A, M), A) => (A, M) = { case ((_, state), action) => { val (newState, effects) = reducer(state, action) effects.subscribe(Observer.create(subject.onNext)) action -> newState } } subject.transformSubjectSource(source => source .scan[(A, M)](initialAction -> initialState)(fold) .behavior(initialAction -> initialState).refCount .withDefaultSubscription[Observer](Observer.empty) ) } }
Example 57
Source File: UnverifiedJWTSig.scala From tsec with MIT License | 5 votes |
package tsec.jws.signature import java.time.Instant import cats.effect.Sync import tsec.jwt.JWTClaims import tsec.jwt.algorithms.JWTSigAlgo import tsec.signature.CryptoSignature import tsec.signature.jca.{SigCertificate, SigErrorM, SigPublicKey} import cats.syntax.flatMap._ import tsec.jws.JWSSerializer import tsec.common._ final case class UnverifiedJWTSig[A: JWTSigAlgo]( header: JWSSignedHeader[A], body: JWTClaims, signature: CryptoSignature[A] ) { def serialized(implicit hs: JWSSerializer[JWSSignedHeader[A]]): String = s"${hs.toB64URL(header)}.${JWTClaims.toB64URL(body)}.${signature.toB64UrlString}" } object UnverifiedJWTSig { def unverified[F[_], A: JWTSigAlgo](jwt: String)(implicit F: Sync[F], sigCV: JWSSigCV[F, A]): F[UnverifiedJWTSig[A]] = sigCV.extractRaw(jwt) def verifyK[F[_], A: JWTSigAlgo]( jwt: UnverifiedJWTSig[A], pubKey: SigPublicKey[A] )(implicit F: Sync[F], sigCV: JWSSigCV[F, A], hs: JWSSerializer[JWSSignedHeader[A]]): F[JWTSig[A]] = F.delay(Instant.now()).flatMap(sigCV.verify(jwt.serialized, pubKey, _)) def verifyC[F[_], A: JWTSigAlgo]( jwt: UnverifiedJWTSig[A], cert: SigCertificate[A] )(implicit F: Sync[F], sigCV: JWSSigCV[F, A], hs: JWSSerializer[JWSSignedHeader[A]]): F[JWTSig[A]] = F.delay(Instant.now()).flatMap(sigCV.verifyCert(jwt.serialized, cert, _)) } object UnverifiedJWTSigImpure { def unverified[A: JWTSigAlgo](jwt: String)(implicit sigCV: JWSSigCV[SigErrorM, A]): SigErrorM[UnverifiedJWTSig[A]] = sigCV.extractRaw(jwt) def verifyK[A: JWTSigAlgo]( jwt: UnverifiedJWTSig[A], pubKey: SigPublicKey[A] )(implicit sigCV: JWSSigCV[SigErrorM, A], hs: JWSSerializer[JWSSignedHeader[A]]): SigErrorM[JWTSig[A]] = sigCV.verify(jwt.serialized, pubKey, Instant.now()) def verifyC[A: JWTSigAlgo]( jwt: UnverifiedJWTSig[A], cert: SigCertificate[A] )(implicit sigCV: JWSSigCV[SigErrorM, A], hs: JWSSerializer[JWSSignedHeader[A]]): SigErrorM[JWTSig[A]] = sigCV.verifyCert(jwt.serialized, cert, Instant.now()) }
Example 58
Source File: StatefulJWTAuth.scala From tsec with MIT License | 5 votes |
package tsec.authentication.internal import java.time.Instant import cats.data.OptionT import cats.effect.Sync import cats.syntax.all._ import org.http4s._ import tsec.authentication._ import tsec.common._ import tsec.jws.mac._ import tsec.jwt._ import tsec.jwt.algorithms.JWTMacAlgo import tsec.mac.jca._ import scala.concurrent.duration.FiniteDuration private[tsec] abstract class StatefulJWTAuth[F[_], I, V, A: JWTMacAlgo]( val expiry: FiniteDuration, val maxIdle: Option[FiniteDuration], tokenStore: BackingStore[F, SecureRandomId, AugmentedJWT[A, I]], identityStore: IdentityStore[F, I, V], signingKey: MacSigningKey[A] )(implicit F: Sync[F], cv: JWSMacCV[F, A]) extends JWTAuthenticator[F, I, V, A] { private[tsec] def verifyAndRefresh( raw: String, retrieved: AugmentedJWT[A, I], now: Instant ): F[AugmentedJWT[A, I]] def parseRaw(raw: String, request: Request[F]): OptionT[F, SecuredRequest[F, V, AugmentedJWT[A, I]]] = OptionT( (for { now <- F.delay(Instant.now()) extracted <- cv.verifyAndParse(raw, signingKey, now) id <- cataOption(extracted.id) retrieved <- tokenStore.get(SecureRandomId(id)).orAuthFailure refreshed <- verifyAndRefresh(raw, retrieved, now) identity <- identityStore.get(retrieved.identity).orAuthFailure } yield SecuredRequest(request, identity, refreshed).some) .handleError(_ => None) ) def create(body: I): F[AugmentedJWT[A, I]] = for { cookieId <- F.delay(SecureRandomId.Interactive.generate) now <- F.delay(Instant.now()) newExpiry = now.plusSeconds(expiry.toSeconds) claims = JWTClaims( issuedAt = Some(now), jwtId = Some(cookieId), expiration = Some(newExpiry) ) signed <- JWTMac.build[F, A](claims, signingKey) created <- tokenStore.put(AugmentedJWT(cookieId, signed, body, newExpiry, touch(now))) } yield created def renew(authenticator: AugmentedJWT[A, I]): F[AugmentedJWT[A, I]] = F.delay(Instant.now()).flatMap { now => val updatedExpiry = now.plusSeconds(expiry.toSeconds) val newBody = authenticator.jwt.body.withExpiry(updatedExpiry) for { reSigned <- JWTMac.build[F, A](newBody, signingKey) updated <- tokenStore .update(authenticator.copy(jwt = reSigned, expiry = updatedExpiry, lastTouched = touch(now))) } yield updated } def update(authenticator: AugmentedJWT[A, I]): F[AugmentedJWT[A, I]] = tokenStore.update(authenticator) def discard(authenticator: AugmentedJWT[A, I]): F[AugmentedJWT[A, I]] = tokenStore.delete(SecureRandomId.coerce(authenticator.id)).map(_ => authenticator) def afterBlock(response: Response[F], authenticator: AugmentedJWT[A, I]): OptionT[F, Response[F]] = OptionT.pure[F](response) }
Example 59
Source File: StatelessJWTAuth.scala From tsec with MIT License | 5 votes |
package tsec.authentication.internal import java.time.Instant import cats.data.OptionT import cats.effect.Sync import cats.syntax.all._ import io.circe.syntax._ import io.circe.{Decoder, Encoder} import org.http4s._ import tsec.authentication._ import tsec.common._ import tsec.jws.mac._ import tsec.jwt.algorithms.JWTMacAlgo import tsec.jwt.JWTClaims import tsec.mac.MAC import tsec.mac.jca._ import scala.concurrent.duration._ private[tsec] abstract class StatelessJWTAuth[F[_], V: Decoder: Encoder.AsObject, A: JWTMacAlgo]( val expiry: FiniteDuration, val maxIdle: Option[FiniteDuration], signingKey: MacSigningKey[A] )(implicit F: Sync[F], cv: JWSMacCV[F, A]) extends JWTAuthenticator[F, V, V, A] { private[tsec] def verifyLastTouched(body: JWTMac[A], now: Instant): F[Option[Instant]] def parseRaw(raw: String, request: Request[F]): OptionT[F, SecuredRequest[F, V, AugmentedJWT[A, V]]] = OptionT( (for { now <- F.delay(Instant.now()) extracted <- cv.verifyAndParse(raw, signingKey, now) jwtid <- cataOption(extracted.id) body <- extracted.body.asF[F, V] expiry <- cataOption(extracted.body.expiration) lastTouched <- verifyLastTouched(extracted, now) augmented = AugmentedJWT( SecureRandomId.coerce(jwtid), extracted, body, expiry, lastTouched ) refreshed <- refresh(augmented) } yield SecuredRequest(request, body, refreshed).some) .handleError(_ => None) ) def create(body: V): F[AugmentedJWT[A, V]] = for { now <- F.delay(Instant.now()) jwtId <- SecureRandomId.Interactive.generateF[F] expiryTime = now.plusSeconds(expiry.toSeconds) lastTouched = touch(now) claims = JWTClaims( issuedAt = touch(now), jwtId = Some(jwtId), expiration = Some(expiryTime), customFields = body.asJsonObject.toList ) out <- JWTMac.build[F, A](claims, signingKey) } yield AugmentedJWT(jwtId, out, body, expiryTime, lastTouched) def update(authenticator: AugmentedJWT[A, V]): F[AugmentedJWT[A, V]] = F.pure(authenticator) def renew(authenticator: AugmentedJWT[A, V]): F[AugmentedJWT[A, V]] = for { now <- F.delay(Instant.now()) updatedExpiry = now.plusSeconds(expiry.toSeconds) authBody = authenticator.jwt.body lastTouched = touch(now) jwt <- JWTMac.build( authBody.withIATOption(lastTouched).withExpiry(updatedExpiry), signingKey ) } yield AugmentedJWT(authenticator.id, jwt, authenticator.identity, updatedExpiry, lastTouched) def discard(authenticator: AugmentedJWT[A, V]): F[AugmentedJWT[A, V]] = F.pure(authenticator.copy(jwt = JWTMac.buildToken[A](JWSMacHeader[A], JWTClaims(), MAC[A](Array.empty[Byte])))) def afterBlock(response: Response[F], authenticator: AugmentedJWT[A, V]): OptionT[F, Response[F]] = OptionT.pure[F](embed(response, authenticator)) }
Example 60
Source File: PartialStatelessJWTAuth.scala From tsec with MIT License | 5 votes |
package tsec.authentication.internal import java.time.Instant import cats.data.OptionT import cats.effect.Sync import cats.syntax.all._ import io.circe.parser.decode import io.circe.syntax._ import io.circe.{Decoder, Encoder} import org.http4s._ import tsec.authentication._ import tsec.common._ import tsec.jws.mac._ import tsec.jwt.algorithms.JWTMacAlgo import tsec.jwt.{JWTClaims, JWTPrinter} import tsec.mac.jca._ import scala.concurrent.duration._ def discard(authenticator: AugmentedJWT[A, I]): F[AugmentedJWT[A, I]] = for { now <- F.delay(Instant.now) jwt <- JWTMac .build[F, A]( authenticator.jwt.body .withExpiry(now) .withJwtID(SecureRandomId.Interactive.generate), signingKey ) } yield AugmentedJWT(authenticator.id, jwt, authenticator.identity, now, authenticator.lastTouched) }
Example 61
Source File: CredentialStore.scala From tsec with MIT License | 5 votes |
package tsec.authentication.credentials import cats.data.OptionT import cats.effect.Sync import cats.syntax.all._ import tsec.passwordhashers._ import tsec.passwordhashers.jca._ def updateCredentials(credentials: C, update: P => F[Unit]): F[Unit] = putCredentials(credentials, update) def isAuthenticated(credentials: C): F[Boolean] } abstract class PasswordStore[F[_], Id, P](implicit P: PasswordHasher[F, P], F: Sync[F]) extends CredentialStore[F, RawCredentials[Id], PasswordHash[P]] { def retrievePass(id: Id): OptionT[F, PasswordHash[P]] def putCredentials(credentials: RawCredentials[Id], put: PasswordHash[P] => F[Unit]): F[Unit] = for { hash <- P.hashpw(credentials.rawPassword) _ <- put(hash) } yield () def putCredentials(raw: Array[Byte], put: PasswordHash[P] => F[Unit]): F[Unit] = for { hash <- P.hashpw(raw) _ <- put(hash) } yield () def putCredentials(raw: Array[Char], put: PasswordHash[P] => F[Unit]): F[Unit] = for { hash <- P.hashpw(raw) _ <- put(hash) } yield () def isAuthenticated(credentials: RawCredentials[Id]): F[Boolean] = for { pass <- retrievePass(credentials.identity) .getOrElseF(F.raiseError(CredentialsError("No such user"))) check <- P.checkpwBool(credentials.rawPassword, pass) } yield check def isAuthenticated(id: Id, raw: Array[Byte]): F[Boolean] = for { pass <- retrievePass(id) .getOrElseF(F.raiseError(CredentialsError("No such user"))) check <- P.checkpwBool(raw, pass) } yield check def isAuthenticated(id: Id, raw: Array[Char]): F[Boolean] = for { pass <- retrievePass(id) .getOrElseF(F.raiseError(CredentialsError("No such user"))) check <- P.checkpwBool(raw, pass) } yield check } trait SCryptPasswordStore[F[_], Id] extends PasswordStore[F, Id, SCrypt] trait BCryptPasswordStore[F[_], Id] extends PasswordStore[F, Id, BCrypt]
Example 62
Source File: AEADCookieEncryptor.scala From tsec with MIT License | 5 votes |
package tsec.cookies import cats.effect.Sync import cats.syntax.all._ import tsec.cipher.common.padding.NoPadding import tsec.cipher.symmetric._ import tsec.cipher.symmetric.jca._ import tsec.common._ object AEADCookieEncryptor { def signAndEncrypt[F[_], A](message: String, aad: AAD, key: SecretKey[A])( implicit authEncryptor: JAuthEncryptor[F, A], ivStrat: IvGen[F, A], F: Sync[F] ): F[AEADCookie[A]] = if (message.isEmpty) F.raiseError(EncryptError("Cannot encrypt an empty string!")) else { val messageBytes = message.utf8Bytes for { iv <- ivStrat.genIv encrypted <- authEncryptor.encryptWithAAD(PlainText(messageBytes), key, iv, aad) } yield AEADCookie.fromEncrypted[A](encrypted, aad) } def retrieveFromSigned[F[_], A: AES](message: AEADCookie[A], key: SecretKey[A])( implicit authEncryptor: JAuthEncryptor[F, A], F: Sync[F], ivStrat: IvGen[F, A] ): F[String] = { val split = message.split("-") if (split.length != 2) F.raiseError(DecryptError("Could not decode cookie")) else { for { aad <- split(1).b64Bytes .fold[F[AAD]](F.raiseError(DecryptError("Could not decode cookie")))(arr => F.pure(AAD(arr))) rawCTBytes <- split(0).b64Bytes .fold[F[Array[Byte]]](F.raiseError(DecryptError("Could not decode cookie")))(F.pure) cipherText <- F.fromEither(CTOPS.ciphertextFromArray[A, GCM, NoPadding](rawCTBytes)) decrypted <- authEncryptor.decryptWithAAD(cipherText, key, aad) } yield decrypted.toUtf8String } } }
Example 63
Source File: JWTSignatureExamples.scala From tsec with MIT License | 5 votes |
object JWTSignatureExamples { import cats.effect.Sync import cats.syntax.all._ import tsec.jws.signature._ import tsec.jwt._ import tsec.signature.jca._ val claims = JWTClaims() def jwtStuffMonadic[F[_]](implicit F: Sync[F]): F[JWTSig[SHA256withECDSA]] = for { keyPair <- SHA256withECDSA.generateKeyPair[F] jwtSig <- JWTSig.signAndBuild[F, SHA256withECDSA](claims, keyPair.privateKey) //ToInstance jwtSigString <- JWTSig.signToString[F, SHA256withECDSA](claims, keyPair.privateKey) verified1 <- JWTSig.verifyK[F, SHA256withECDSA](jwtSigString, keyPair.publicKey) verified2 <- JWTSig.verifyKI[F, SHA256withECDSA](jwtSig, keyPair.publicKey) } yield verified2 val jwtStuff: Either[Throwable, JWTSig[SHA256withECDSA]] = for { keyPair <- SHA256withECDSA.generateKeyPair[SigErrorM] jwtSig <- JWTSigImpure.signAndBuild[SHA256withECDSA](claims, keyPair.privateKey) //ToInstance jwtSigString <- JWTSigImpure.signToString(claims, keyPair.privateKey) verified1 <- JWTSigImpure.verifyK(jwtSigString, keyPair.publicKey) verified2 <- JWTSigImpure.verifyKI(jwtSig, keyPair.publicKey) } yield verified2 }
Example 64
Source File: JWTMacExamples.scala From tsec with MIT License | 5 votes |
import java.time.Instant object JWTMacExamples { import cats.effect.Sync import cats.syntax.all._ import tsec.jws.mac._ import tsec.jwt._ import tsec.mac.jca._ import scala.concurrent.duration._ val impureClaims = JWTClaims(expiration = Some(Instant.now.plusSeconds(10.minutes.toSeconds))) val jwt: Either[Throwable, JWTMac[HMACSHA256]] = for { key <- HMACSHA256.generateKey[MacErrorM] jwt <- JWTMacImpure.build[HMACSHA256](impureClaims, key) //You can sign and build a jwt object directly verifiedFromObj <- JWTMacImpure.verifyFromInstance[HMACSHA256](jwt, key) stringjwt <- JWTMacImpure.buildToString[HMACSHA256](impureClaims, key) //Or build it straight to string isverified <- JWTMacImpure.verifyFromString[HMACSHA256](stringjwt, key) //You can verify straight from a string parsed <- JWTMacImpure.verifyAndParse[HMACSHA256](stringjwt, key) //Or verify and return the actual instance } yield parsed }
Example 65
Source File: BCrypt.scala From tsec with MIT License | 5 votes |
package tsec.passwordhashers.jca import java.nio.CharBuffer import cats.effect.Sync import tsec.common._ import tsec.passwordhashers._ import tsec.passwordhashers.jca.internal.JBCrypt sealed trait BCrypt object BCrypt extends JCAPasswordPlatform[BCrypt] { private[tsec] def unsafeHashpw(p: Array[Byte]): String = JBCrypt.hashpw(p, JBCryptUtil.genSalt(DefaultBcryptRounds)) private[tsec] def unsafeCheckpw(p: Array[Byte], hash: PasswordHash[BCrypt]): Boolean = JBCrypt.checkpw(p, hash) def hashpwWithRounds[F[_]](p: String, rounds: Int)(implicit F: Sync[F]): F[PasswordHash[BCrypt]] = hashpwWithRounds[F](p.asciiBytes, rounds) def hashpwWithRounds[F[_]](p: Array[Byte], rounds: Int)(implicit F: Sync[F]): F[PasswordHash[BCrypt]] = if (rounds < 10 || rounds > 30) F.raiseError(PasswordError("Invalid number of rounds")) else F.delay { val out = PasswordHash[BCrypt](JBCrypt.hashpw(p, JBCryptUtil.genSalt(rounds))) ByteUtils.zeroByteArray(p) out } def hashpwWithRounds[F[_]](p: Array[Char], rounds: Int)(implicit F: Sync[F]): F[PasswordHash[BCrypt]] = if (rounds < 10 || rounds > 30) F.raiseError(PasswordError("Invalid number of rounds")) else F.delay { val charbuffer = CharBuffer.wrap(p) val bytes = defaultCharset.encode(charbuffer).array() val out = PasswordHash[BCrypt](JBCrypt.hashpw(bytes, JBCryptUtil.genSalt(rounds))) //Clear pass ByteUtils.zeroCharArray(p) ByteUtils.zeroByteArray(bytes) out } }
Example 66
Source File: WithMacSigningKey.scala From tsec with MIT License | 5 votes |
package tsec.mac.jca import javax.crypto.{KeyGenerator, Mac, SecretKey} import javax.crypto.spec.SecretKeySpec import cats.Id import cats.effect.Sync import cats.instances.either._ import cats.syntax.either._ import tsec.keygen.symmetric.{IdKeyGen, SymmetricKeyGen} import tsec.mac.{MAC, MacAPI} protected[tsec] abstract class WithMacSigningKey[A](algo: String, keyLenBits: Int) extends MacKeyGenerator[A] with MacAPI[A, MacSigningKey] { implicit def syncMac[F[_]](implicit F: Sync[F]): JCAMessageAuth[F, A] = new JCAMessageAuth[F, A]() { def algorithm: String = algo protected[tsec] def genInstance: F[Mac] = F.delay(Mac.getInstance(algo)) protected[tsec] def signInternal(m: Mac, k: SecretKey, content: Array[Byte]): F[MAC[A]] = F.delay { m.init(k) MAC[A](m.doFinal(content)) } } implicit val macInstanceEither: JCAMessageAuth[MacErrorM, A] = new JCAMessageAuth[MacErrorM, A]() { def algorithm: String = algo protected[tsec] def genInstance: MacErrorM[Mac] = Either.catchNonFatal(Mac.getInstance(algo)) protected[tsec] def signInternal(m: Mac, k: SecretKey, content: Array[Byte]): MacErrorM[MAC[A]] = Either.catchNonFatal { m.init(k) MAC[A](m.doFinal(content)) } } implicit def genKeyMac[F[_]](implicit F: Sync[F]): MacKeyGen[F, A] = new SymmetricKeyGen[F, A, MacSigningKey] { def generateKey: F[MacSigningKey[A]] = F.delay(impl.generateKeyUnsafe()) def build(rawKey: Array[Byte]): F[MacSigningKey[A]] = F.delay(MacSigningKey[A](new SecretKeySpec(rawKey, algo))) } implicit def genKeyMacError: MacKeyGen[MacErrorM, A] = new MacKeyGen[MacErrorM, A] { def generateKey: MacErrorM[MacSigningKey[A]] = Either.catchNonFatal(impl.generateKeyUnsafe()) def build(rawKey: Array[Byte]): MacErrorM[MacSigningKey[A]] = Either.catchNonFatal(impl.buildKeyUnsafe(rawKey)) } implicit val idKeygenMac: IdKeyGen[A, MacSigningKey] = new IdKeyGen[A, MacSigningKey] { def generateKey: Id[MacSigningKey[A]] = impl.generateKeyUnsafe() def build(rawKey: Array[Byte]): Id[MacSigningKey[A]] = impl.buildKeyUnsafe(rawKey) } object impl { def generator: KeyGenerator = KeyGenerator.getInstance(algo) def generateKeyUnsafe(): MacSigningKey[A] = MacSigningKey.fromJavaKey[A](generator.generateKey()) def buildKeyUnsafe(key: Array[Byte]): MacSigningKey[A] = MacSigningKey.fromJavaKey[A](new SecretKeySpec(key, algo)) } implicit def keyGen: MacKeyGenerator[A] = this }
Example 67
Source File: SecureRandomIdGenerator.scala From tsec with MIT License | 5 votes |
package tsec.common import cats.effect.Sync import org.apache.commons.codec.binary.Hex case class SecureRandomIdGenerator(sizeInBytes: Int = 32) extends ManagedRandom { def generate: SecureRandomId = { val byteArray = new Array[Byte](sizeInBytes) nextBytes(byteArray) new String(Hex.encodeHex(byteArray)).asInstanceOf[SecureRandomId] } def generateF[F[_]](implicit F: Sync[F]): F[SecureRandomId] = F.delay(generate) } //Todo: Possible use case for refined? object SecureRandomId { lazy val Strong: SecureRandomIdGenerator = SecureRandomIdGenerator(32) lazy val Interactive: SecureRandomIdGenerator = SecureRandomIdGenerator(16) def apply(s: String): SecureRandomId = s.asInstanceOf[SecureRandomId] def coerce(s: String): SecureRandomId = s.asInstanceOf[SecureRandomId] }
Example 68
Source File: KeyDerivation.scala From tsec with MIT License | 5 votes |
package tsec.kdf.libsodium import cats.effect.Sync import tsec.common._ import tsec.libsodium.ScalaSodium sealed trait KeyDerivation object KeyDerivation { def generateKey[F[_]](implicit F: Sync[F], S: ScalaSodium): F[MasterKey] = F.delay { val masterKey = MasterKey(new Array[Byte](ScalaSodium.crypto_kdf_KEYBYTES)) S.crypto_kdf_keygen(masterKey) masterKey } def deriveKey[F[_]]( masterKey: MasterKey, keyLength: Int, id: Int, context: String )(implicit F: Sync[F], S: ScalaSodium): F[DerivedKey] = F.delay { if (ScalaSodium.crypto_kdf_BYTES_MIN > keyLength || keyLength > ScalaSodium.crypto_kdf_BYTES_MAX) throw KeyLengthError(keyLength) val ctx = context.utf8Bytes if (ctx.length != ScalaSodium.crypto_kdf_CONTEXTBYTES) throw ContextBytesError(ctx.length) val subKey = DerivedKey(new Array[Byte](keyLength)) S.crypto_kdf_derive_from_key(subKey, keyLength, id, ctx, masterKey) subKey } }
Example 69
Source File: SodiumHashPlatform.scala From tsec with MIT License | 5 votes |
package tsec.hashing.libsodium.internal import cats.Id import cats.effect.Sync import fs2._ import tsec.hashing.libsodium._ import tsec.libsodium.ScalaSodium import tsec.hashing._ abstract class SodiumHashPlatform[A](val algorithm: String) extends SodiumHash[A] with SodiumHashAPI[A] { self => implicit val sodiumHash: SodiumHash[A] = this implicit val sodiumHashAlgebra: SodiumHashAPI[A] = this implicit def hasher[F[_]](implicit F: Sync[F], S: ScalaSodium): CryptoHasher[F, A] = new CryptoHasher[F, A] { def algorithm: String = self.algorithm def hash(bytes: Array[Byte]): F[CryptoHash[A]] = F.delay(impl.unsafeHash(bytes)) def hashPipe: Pipe[F, Byte, Byte] = impl.hashPipe[F] } implicit def idHasher(implicit S: ScalaSodium): CryptoHasher[Id, A] = new CryptoHasher[Id, A] { def algorithm: String = self.algorithm def hash(bytes: Array[Byte]): Id[CryptoHash[A]] = impl.unsafeHash(bytes) def hashPipe: Pipe[Id, Byte, Byte] = in => Stream.suspend[Id, Byte] { for { rawState <- Stream.suspend(Stream.emit { val state = HashState[A](new Array[Byte](stateSize)) sodiumHashInit(state) state }) ast <- in.chunks.fold(rawState) { (st, in) => sodiumHashChunk(st, in.toBytes.toArray) st } out <- Stream.suspend(Stream.emit { val out = new Array[Byte](hashLen) sodiumHashFinal(ast, out) out }) c <- Stream.chunk(Chunk.bytes(out)).covary[Id] } yield c } } object impl { def unsafeHash(bytes: Array[Byte])(implicit S: ScalaSodium): CryptoHash[A] = { val out = new Array[Byte](hashLen) sodiumHash(bytes, out) CryptoHash[A](out) } final def hashPipe[F[_]](implicit F: Sync[F], S: ScalaSodium): Pipe[F, Byte, Byte] = { in => Stream.suspend[F, Byte] { for { rawState <- Stream.eval(F.delay { val state = HashState[A](new Array[Byte](stateSize)) sodiumHashInit(state) state }) ast <- in.chunks.fold(rawState) { (st, in) => sodiumHashChunk(st, in.toBytes.toArray) st } out <- Stream.eval(F.delay { val out = new Array[Byte](hashLen) sodiumHashFinal(ast, out) out }) c <- Stream.chunk(Chunk.bytes(out)).covary[F] } yield c } } } }
Example 70
Source File: Blake2b.scala From tsec with MIT License | 5 votes |
package tsec.hashing.libsodium import java.security.MessageDigest import cats.effect.Sync import tsec.hashing._ import tsec.hashing.libsodium.internal.SodiumHashPlatform import tsec.libsodium.ScalaSodium import tsec.libsodium.ScalaSodium.NullPtrBytes sealed trait Blake2b object Blake2b extends SodiumHashPlatform[Blake2b]("Blake2b") { val MinKeyLen = ScalaSodium.crypto_generichash_blake2b_KEYBYTES_MIN val DefaultKeyLen = ScalaSodium.crypto_generichash_blake2b_KEYBYTES val MaxKeyLen = ScalaSodium.crypto_generichash_blake2b_KEYBYTES_MAX val MinHashLen = ScalaSodium.crypto_generichash_blake2b_BYTES_MIN val MaxHashLen = ScalaSodium.crypto_generichash_blake2b_BYTES_MAX val hashLen: Int = ScalaSodium.crypto_generichash_blake2b_BYTES def generateKey[F[_]](implicit F: Sync[F], S: ScalaSodium): F[BlakeKey] = F.delay { BlakeKey(ScalaSodium.randomBytesUnsafe(DefaultKeyLen)) } def generateMinKey[F[_]](implicit F: Sync[F], S: ScalaSodium): F[BlakeKey] = F.delay { BlakeKey(ScalaSodium.randomBytesUnsafe(MinKeyLen)) } def generateMaxKey[F[_]](implicit F: Sync[F], S: ScalaSodium): F[BlakeKey] = F.delay { BlakeKey(ScalaSodium.randomBytesUnsafe(MaxKeyLen)) } def generateKeyVarLen[F[_]](len: Int)(implicit F: Sync[F], S: ScalaSodium): F[BlakeKey] = F.delay { val outLen = math.max(MinKeyLen, math.min(MaxKeyLen, len)) BlakeKey(ScalaSodium.randomBytesUnsafe(outLen)) } def hashVarLen[F[_]]( in: Array[Byte], len: Int = hashLen )(implicit F: Sync[F], S: ScalaSodium): F[CryptoHash[Blake2b]] = F.delay { val outLen = math.max(MinHashLen, math.min(MaxHashLen, len)) val out = new Array[Byte](outLen) S.crypto_generichash(out, outLen, in, in.length, NullPtrBytes, 0) CryptoHash[Blake2b](out) } def verify[F[_]](in: Array[Byte], compare: CryptoHash[Blake2b], key: BlakeKey)( implicit F: Sync[F], S: ScalaSodium ): F[Boolean] = F.delay { val out = new Array[Byte](compare.length) S.crypto_generichash(out, compare.length, in, in.length, key, key.length) MessageDigest.isEqual(out, compare) } def hashKeyed[F[_]](in: Array[Byte], key: BlakeKey)(implicit F: Sync[F], S: ScalaSodium): F[CryptoHash[Blake2b]] = F.delay { val out = new Array[Byte](hashLen) S.crypto_generichash(out, hashLen, in, in.length, key, key.length) CryptoHash[Blake2b](out) } def hashKeyedVarLen[F[_]](in: Array[Byte], key: BlakeKey, len: Int = hashLen)( implicit F: Sync[F], S: ScalaSodium ): F[CryptoHash[Blake2b]] = F.delay { val outLen = math.max(MinHashLen, math.min(MaxHashLen, len)) val out = new Array[Byte](outLen) S.crypto_generichash(out, outLen, in, in.length, key, key.length) CryptoHash[Blake2b](out) } def stateSize(implicit S: ScalaSodium): Int = S.crypto_generichash_statebytes def sodiumHash(in: Array[Byte], out: Array[Byte])(implicit S: ScalaSodium): Int = S.crypto_generichash(out, hashLen, in, in.length, NullPtrBytes, 0) def sodiumHashInit(state: HashState[Blake2b])(implicit S: ScalaSodium): Int = S.crypto_generichash_blake2b_init(state, NullPtrBytes, 0, hashLen) def sodiumHashChunk(state: HashState[Blake2b], in: Array[Byte])(implicit S: ScalaSodium): Int = S.crypto_generichash_update(state, in, in.length) def sodiumHashFinal(state: HashState[Blake2b], out: Array[Byte])(implicit S: ScalaSodium): Int = S.crypto_generichash_final(state, out, hashLen) }
Example 71
Source File: ScalaSodium.scala From tsec with MIT License | 5 votes |
package tsec.libsodium import cats.effect.Sync import org.log4s._ import tsec.internal._ import tsec.jni._ private def checkVersion(sodiumString: String): Unit = { val error = new SodiumLoadError(s"Unsupported libsodium version $sodiumString. Please upgrade to version 1.0.12+") sodiumString.trim.split("\\.") match { case Array(major, med, minor) => if (major.toInt < 1 || (minor.toInt < 12 && med.toInt == 0)) { logger.error(error)("Unsupported version") throw error } else logger.info("Loading libsodium jni... Hold tight Asznee") case _ => logger.error(error)("Unsupported version") throw error } } private[tsec] lazy val Sodium: ScalaSodium = { System.loadLibrary(libraryName) val sodium = new ScalaSodium() checkVersion(SodiumJNI.sodium_version_string.asInstanceOf[String]) if (sodium.sodium_init < 0) { val err = new SodiumLoadError("Has not been initialized properly") logger.error(err)("ScalaSodium has not been initialized properly") throw err } logger.info("Libsodium loaded properly") sodium } final def getSodiumUnsafe: ScalaSodium = Sodium final def getSodium[F[_]](implicit F: Sync[F]): F[ScalaSodium] = F.delay(Sodium) final def randomBytes[F[_]](len: Int)(implicit F: Sync[F], S: ScalaSodium): F[Array[Byte]] = F.delay { val bytes = new Array[Byte](len) S.randombytes_buf(bytes, len) bytes } final def randomBytesUnsafe(len: Int)(implicit S: ScalaSodium): Array[Byte] = { val bytes = new Array[Byte](len) S.randombytes_buf(bytes, len) bytes } private final class SodiumLoadError(reason: String) extends VirtualMachineError { override def getMessage: String = reason } }
Example 72
Source File: Argon2.scala From tsec with MIT License | 5 votes |
package tsec.passwordhashers.libsodium import cats.effect.Sync import tsec.common._ import tsec.libsodium.ScalaSodium import tsec.passwordhashers.libsodium.internal.SodiumPasswordHasher import tsec.passwordhashers.{PasswordHash, PasswordHasher} sealed trait Argon2 object Argon2 extends SodiumPasswordHasher[Argon2] { implicit val hasher: SodiumPasswordHasher[Argon2] = this val hashingAlgorithm: String = "Argon2id" val saltLen: Int = ScalaSodium.crypto_pwhash_argon2id_SALTBYTES val outLen: Int = ScalaSodium.crypto_pwhash_argon2id_STRBYTES implicit def passwordHasher[F[_]](implicit F: Sync[F], S: ScalaSodium): PasswordHasher[F, Argon2] = new PasswordHasher[F, Argon2] { def hashpw(p: Array[Char]): F[PasswordHash[Argon2]] = F.delay(hashpwUnsafe(p)) def hashpw(p: Array[Byte]): F[PasswordHash[Argon2]] = F.delay(hashpwUnsafe(p)) def checkpwBool(p: Array[Char], hash: PasswordHash[Argon2]): F[Boolean] = F.delay(checkpwUnsafe(p, hash)) def checkpwBool(p: Array[Byte], hash: PasswordHash[Argon2]): F[Boolean] = F.delay(checkpwUnsafe(p, hash)) private[tsec] def hashPassUnsafe(p: Array[Byte]): String = impl.unsafeHashpw(p, PasswordStrength.InteractiveStrength) private[tsec] def checkPassUnsafe(p: Array[Byte], hash: PasswordHash[Argon2]): Boolean = impl.unsafeCheckpw(p, hash) } def hashpwWithStrength[F[_], S]( p: String, strength: S )(implicit pws: PWStrengthParam[Argon2, S], F: Sync[F], S: ScalaSodium): F[PasswordHash[Argon2]] = F.delay(impl.unsafeHashpw(p.asciiBytes, strength)) def checkPass[F[_]](raw: String, hash: PasswordHash[Argon2])(implicit F: Sync[F], S: ScalaSodium): F[Boolean] = F.delay(impl.unsafeCheckpw(raw.asciiBytes, hash)) object impl { def unsafeHashpw[S]( passBytes: Array[Byte], strength: S )(implicit pws: PWStrengthParam[Argon2, S], S: ScalaSodium): PasswordHash[Argon2] = { val out = new Array[Byte](outLen) if (passBytes.isEmpty) throw SodiumPasswordError("Incorrect format") else if (S.crypto_pwhash_str(out, passBytes, passBytes.length, pws.opLimit, pws.memLimit) != 0) throw SodiumPasswordError("Could not hash password. Possibly out of memory") else PasswordHash[Argon2](out.toAsciiString) } def unsafeCheckpw(raw: Array[Byte], hash: PasswordHash[Argon2])(implicit S: ScalaSodium): Boolean = S.crypto_pwhash_str_verify(hash.asciiBytes, raw, raw.length) == 0 } }
Example 73
Source File: SodiumPasswordHasher.scala From tsec with MIT License | 5 votes |
package tsec.passwordhashers.libsodium.internal import cats.effect.Sync import cats.syntax.all._ import tsec.libsodium.ScalaSodium import tsec.passwordhashers._ import tsec.passwordhashers.libsodium._ trait SodiumPasswordHasher[P] extends PasswordHashAPI[P] { val hashingAlgorithm: String val saltLen: Int val outLen: Int def hashpwWithStrength[F[_], S]( p: String, strength: S )(implicit pws: PWStrengthParam[P, S], F: Sync[F], S: ScalaSodium): F[PasswordHash[P]] final def checkPassShortCircuit[F[_]]( raw: String, hash: PasswordHash[P] )(implicit F: Sync[F], S: ScalaSodium, P: PasswordHasher[F, P]): F[Unit] = checkpwBool[F](raw, hash).flatMap(res => if (res) F.unit else F.raiseError(SodiumPasswordError("Invalid password"))) }
Example 74
Source File: SodiumSCrypt.scala From tsec with MIT License | 5 votes |
package tsec.passwordhashers.libsodium import cats.effect.Sync import tsec.common._ import tsec.libsodium.ScalaSodium import tsec.passwordhashers.libsodium.internal.SodiumPasswordHasher import tsec.passwordhashers.{PasswordHasher, _} sealed trait SodiumSCrypt object SodiumSCrypt extends SodiumPasswordHasher[SodiumSCrypt] { implicit val hasher: SodiumPasswordHasher[SodiumSCrypt] = this val hashingAlgorithm: String = "SCrypt" val saltLen: Int = ScalaSodium.crypto_pwhash_scryptsalsa208sha256_SALTBYTES val outLen: Int = ScalaSodium.crypto_pwhash_scryptsalsa208sha256_STRBYTES def hashpwWithStrength[F[_], S]( p: String, strength: S )(implicit pws: PWStrengthParam[SodiumSCrypt, S], F: Sync[F], S: ScalaSodium): F[PasswordHash[SodiumSCrypt]] = F.delay(impl.unsafeHashpw(p.asciiBytes, strength)) implicit def genHasher[F[_]](implicit F: Sync[F], S: ScalaSodium): PasswordHasher[F, SodiumSCrypt] = new PasswordHasher[F, SodiumSCrypt] { def hashpw(p: Array[Char]): F[PasswordHash[SodiumSCrypt]] = F.delay(hashpwUnsafe(p)) def hashpw(p: Array[Byte]): F[PasswordHash[SodiumSCrypt]] = F.delay(hashpwUnsafe(p)) def checkpwBool(p: Array[Char], hash: PasswordHash[SodiumSCrypt]): F[Boolean] = F.delay(checkpwUnsafe(p, hash)) def checkpwBool(p: Array[Byte], hash: PasswordHash[SodiumSCrypt]): F[Boolean] = F.delay(checkpwUnsafe(p, hash)) private[tsec] def hashPassUnsafe(p: Array[Byte]): String = impl.unsafeHashpw(p, PasswordStrength.InteractiveStrength) private[tsec] def checkPassUnsafe(p: Array[Byte], hash: PasswordHash[SodiumSCrypt]): Boolean = impl.unsafeCheckpw(p, hash) } object impl { def unsafeHashpw[S]( passBytes: Array[Byte], strength: S )(implicit pws: PWStrengthParam[SodiumSCrypt, S], S: ScalaSodium): PasswordHash[SodiumSCrypt] = { val out = new Array[Byte](outLen) if (passBytes.isEmpty) throw SodiumPasswordError("Incorrect format") else if (S.crypto_pwhash_scryptsalsa208sha256_str(out, passBytes, passBytes.length, pws.opLimit, pws.memLimit) != 0) throw SodiumPasswordError("Could not hash password. Possibly out of memory") else PasswordHash[SodiumSCrypt](out.toAsciiString) } def unsafeCheckpw(rawBytes: Array[Byte], hash: PasswordHash[SodiumSCrypt])( implicit S: ScalaSodium ): Boolean = S.crypto_pwhash_scryptsalsa208sha256_str_verify(hash.asciiBytes, rawBytes, rawBytes.length) == 0 } }
Example 75
Source File: SodiumMacPlatform.scala From tsec with MIT License | 5 votes |
package tsec.mac.libsodium import cats.effect.Sync import tsec.keygen.symmetric.SymmetricKeyGen import tsec.libsodium.ScalaSodium import tsec.mac.{MessageAuth, _} private[tsec] abstract class SodiumMacPlatform[A](algo: String) extends SodiumMacAlgo[A] with SodiumMacAPI[A] { implicit val sm: SodiumMacAlgo[A] = this implicit val macAlgebra: SodiumMacAPI[A] = this implicit def symmGen[F[_]](implicit F: Sync[F], S: ScalaSodium): SymmetricKeyGen[F, A, SodiumMACKey] = new SymmetricKeyGen[F, A, SodiumMACKey] { def generateKey: F[SodiumMACKey[A]] = F.delay(impl.unsafeGenerateKey) def build(rawKey: Array[Byte]): F[SodiumMACKey[A]] = F.delay(impl.unsafeBuildKey(rawKey)) } implicit def authenticator[F[_]](implicit F: Sync[F], S: ScalaSodium): MessageAuth[F, A, SodiumMACKey] = new MessageAuth[F, A, SodiumMACKey] { def algorithm: String = algo def sign(in: Array[Byte], key: SodiumMACKey[A]): F[MAC[A]] = F.delay(impl.sign(in, key)) def verifyBool(in: Array[Byte], hashed: MAC[A], key: SodiumMACKey[A]): F[Boolean] = F.delay(impl.verify(in, hashed, key)) } object impl { final def sign(in: Array[Byte], key: SodiumMACKey[A])(implicit S: ScalaSodium): MAC[A] = { val out = new Array[Byte](macLen) sodiumSign(in, out, key) MAC[A](out) } final def verify(in: Array[Byte], hashed: MAC[A], key: SodiumMACKey[A])( implicit S: ScalaSodium ): Boolean = sodiumVerify(in, hashed, key) == 0 final def unsafeGenerateKey(implicit S: ScalaSodium): SodiumMACKey[A] = SodiumMACKey[A](ScalaSodium.randomBytesUnsafe(keyLen)) final def unsafeBuildKey(key: Array[Byte]): SodiumMACKey[A] = if (key.length != keyLen) throw new IllegalArgumentException("Invalid Key len ") //Better error type maybe? else SodiumMACKey[A](key) } }
Example 76
Source File: KeyExchange.scala From tsec with MIT License | 5 votes |
package tsec.kx.libsodium import cats.effect.Sync import tsec.cipher.symmetric.libsodium.SodiumKey import tsec.libsodium.ScalaSodium sealed trait KeyExchange object KeyExchange { def generateKeyPair[F[_]](implicit F: Sync[F], S: ScalaSodium): F[SodiumKeyPair[KeyExchange]] = F.delay { val pk = new Array[Byte](ScalaSodium.crypto_kx_PUBLICKEYBYTES) val sk = new Array[Byte](ScalaSodium.crypto_kx_SECRETKEYBYTES) S.crypto_kx_keypair(pk, sk) SodiumKeyPair(PublicKey[KeyExchange](pk), PrivateKey[KeyExchange](sk)) } def generateKeyPairSeed[F[_]](seed: Array[Byte])(implicit F: Sync[F], S: ScalaSodium): F[SodiumKeyPair[KeyExchange]] = F.delay { if (seed.length != ScalaSodium.crypto_kx_SEEDBYTES) throw KeySeedingError(seed.length) val pk = new Array[Byte](ScalaSodium.crypto_kx_PUBLICKEYBYTES) val sk = new Array[Byte](ScalaSodium.crypto_kx_SECRETKEYBYTES) S.crypto_kx_seed_keypair(pk, sk, seed) SodiumKeyPair(PublicKey[KeyExchange](pk), PrivateKey[KeyExchange](sk)) } def generateClientSessionKeys[F[_]]( keyPair: SodiumKeyPair[KeyExchange], server: PublicKey[KeyExchange] )(implicit F: Sync[F], S: ScalaSodium): F[SodiumSharedKeyPair[KeyExchange]] = F.delay { val rx = new Array[Byte](ScalaSodium.crypto_kx_SESSIONKEYBYTES) val tx = new Array[Byte](ScalaSodium.crypto_kx_SESSIONKEYBYTES) if (S.crypto_kx_client_session_keys(rx, tx, keyPair.pubKey, keyPair.privKey, server) != 0) throw KeySessionError SodiumSharedKeyPair[KeyExchange](SodiumKey(rx), SodiumKey(tx)) } def generateServerSessionKeys[F[_]]( keyPair: SodiumKeyPair[KeyExchange], client: PublicKey[KeyExchange] )(implicit F: Sync[F], S: ScalaSodium): F[SodiumSharedKeyPair[KeyExchange]] = F.delay { val rx = new Array[Byte](ScalaSodium.crypto_kx_SESSIONKEYBYTES) val tx = new Array[Byte](ScalaSodium.crypto_kx_SESSIONKEYBYTES) if (S.crypto_kx_server_session_keys(rx, tx, keyPair.pubKey, keyPair.privKey, client) != 0) throw KeySessionError SodiumSharedKeyPair[KeyExchange](SodiumKey(rx), SodiumKey(tx)) } }
Example 77
Source File: ProtectedResource.scala From tsec with MIT License | 5 votes |
package tsec.oauth2.provider import cats.implicits._ import cats.data.EitherT import cats.effect.Sync import tsec.oauth2.provider.AccessTokenFetcher._ object ProtectedResource { def apply[F[_], U](handler: ProtectedResourceHandler[F, U]): ProtectedResource[F, U] = new ProtectedResource[F, U](handler) } class ProtectedResource[F[_], U](handler: ProtectedResourceHandler[F, U]) { val fetchers = Set(RequestParameter, AuthHeader) def authorize( request: ProtectedResourceRequest )(implicit F: Sync[F]): EitherT[F, OAuthError, AuthInfo[U]] = for { result <- EitherT.fromEither[F]( fetchers .find { fetcher => fetcher.matches(request) } .toRight(InvalidRequest("Access token is not found")) .flatMap(x => x.fetch(request)) ) token <- EitherT[F, OAuthError, AccessToken]( handler.findAccessToken(result.token).map(_.toRight[OAuthError](InvalidToken("The access token is not found"))) ) _ <- EitherT(token.isExpired.map(expired => Either.cond(!expired, (), ExpiredToken))) authInfo <- EitherT[F, OAuthError, AuthInfo[U]]( handler.findAuthInfoByAccessToken(token).map(_.toRight[OAuthError](InvalidToken("The access token is invalid"))) ) } yield authInfo }
Example 78
Source File: AuthorizationCodeGrantHandler.scala From tsec with MIT License | 5 votes |
package tsec.oauth2.provider package grantHandler import cats.data.EitherT import cats.effect.Sync import cats.implicits._ import tsec.oauth2.provider.ValidatedRequest._ class AuthorizationCodeGrantHandler[F[_], U](handler: AuthorizationCodeHandler[F, U]) extends GrantHandler[F, U] { type A = ValidatedAuthorizationCode def handleRequest( req: ValidatedAuthorizationCode )(implicit F: Sync[F]): EitherT[F, OAuthError, GrantHandlerResult[U]] = for { _ <- EitherT( handler .validateClient(req) .map( isValid => Either.cond(isValid, (), InvalidClient("Invalid client or client is not authorized"): OAuthError) ) ) auth <- EitherT[F, OAuthError, AuthInfo[U]]( handler .findAuthInfoByCode(req.code) .map(_.toRight(InvalidGrant("Authorized information is not found by the code"))) ) _ <- EitherT .cond[F](auth.clientId.contains(req.clientCredential.clientId), (), InvalidClient("invalid clientId")) _ <- EitherT.cond[F]( auth.redirectUri.isEmpty || (auth.redirectUri.isDefined && auth.redirectUri == req.redirectUri), (), RedirectUriMismatch ) grantResult <- EitherT( issueAccessToken(handler, auth).attempt .map(_.leftMap(t => FailedToIssueAccessToken(t.getMessage): OAuthError)) ) _ <- EitherT( handler.deleteAuthCode(req.code).attempt.map(_.leftMap(t => FailedToDeleteAuthCode(t.getMessage): OAuthError)) ) } yield grantResult } trait AuthorizationCodeHandler[F[_], U] extends IssueAccessToken[F, U] { def deleteAuthCode(code: String): F[Unit] }
Example 79
Source File: ClientCredentialsGrantHandler.scala From tsec with MIT License | 5 votes |
package tsec.oauth2.provider package grantHandler import cats.data.EitherT import cats.effect.Sync import cats.implicits._ import tsec.oauth2.provider.ValidatedRequest._ class ClientCredentialsGrantHandler[F[_], U](handler: ClientCredentialsHandler[F, U]) extends GrantHandler[F, U] { type A = ValidatedClientCredentials def handleRequest( req: ValidatedClientCredentials )(implicit F: Sync[F]): EitherT[F, OAuthError, GrantHandlerResult[U]] = for { _ <- EitherT[F, OAuthError, Unit]( handler .validateClient(req) .map( isValid => Either.cond(isValid, (), InvalidClient("Invalid client or client is not authorized"): OAuthError) ) ) user <- EitherT[F, OAuthError, U]( handler .findUser(req) .map(_.toRight(InvalidGrant("client_id or client_secret or scope is incorrect"))) ) authInfo = AuthInfo(user, Some(req.clientCredential.clientId), req.scope, None) grantResult <- EitherT( issueAccessToken(handler, authInfo).attempt .map(_.leftMap(t => FailedToIssueAccessToken(t.getMessage): OAuthError)) ) } yield grantResult } trait ClientCredentialsHandler[F[_], U] extends IssueAccessToken[F, U] { def refreshAccessToken(authInfo: AuthInfo[U], refreshToken: String): F[AccessToken] }
Example 80
Source File: ImplicitGrantHandler.scala From tsec with MIT License | 5 votes |
package tsec.oauth2.provider package grantHandler import cats.implicits._ import cats.data.EitherT import cats.effect.Sync import tsec.oauth2.provider.ValidatedRequest._ class ImplicitGrantHandler[F[_], U](handler: ImplicitHandler[F, U]) extends GrantHandler[F, U] { type A = ValidatedImplicit def handleRequest( req: ValidatedImplicit )(implicit F: Sync[F]): EitherT[F, OAuthError, GrantHandlerResult[U]] = for { _ <- EitherT[F, OAuthError, Unit]( handler .validateClient(req) .map( isValid => Either.cond(isValid, (), InvalidClient("Invalid client or client is not authorized"): OAuthError) ) ) user <- EitherT[F, OAuthError, U]( handler.findUser(req).map(_.toRight(InvalidGrant("user cannot be authenticated"))) ) authInfo = AuthInfo(user, Some(req.clientCredential.clientId), req.scope, None) token = handler.getStoredAccessToken(authInfo).flatMap { token => val res = token match { case Some(token) => F.pure(token) case None => handler.createAccessToken(authInfo) } for { t <- res expiresIn <- t.expiresIn } yield GrantHandlerResult( authInfo, "Bearer", t.token, expiresIn, None, t.scope, t.params ) } grantResult <- EitherT( token.attempt .map(_.leftMap(t => FailedToIssueAccessToken(t.getMessage): OAuthError)) ) } yield grantResult } trait ImplicitHandler[F[_], U] { def getStoredAccessToken(authInfo: AuthInfo[U]): F[Option[AccessToken]] }
Example 81
Source File: RrefreshTokenHandler.scala From tsec with MIT License | 5 votes |
package tsec.oauth2.provider package grantHandler import cats.data.EitherT import cats.effect.Sync import cats.implicits._ import tsec.oauth2.provider.ValidatedRequest._ class RefreshTokenGrantHandler[F[_], U](handler: RefreshTokenHandler[F, U]) extends GrantHandler[F, U] { type A = ValidatedRefreshToken def handleRequest(req: ValidatedRefreshToken)(implicit F: Sync[F]): EitherT[F, OAuthError, GrantHandlerResult[U]] = for { _ <- EitherT[F, OAuthError, Unit]( handler .validateClient(req) .map( isValid => Either.cond(isValid, (), InvalidClient("Invalid client or client is not authorized"): OAuthError) ) ) auth <- EitherT[F, OAuthError, AuthInfo[U]]( handler .findAuthInfoByRefreshToken(req.refreshToken) .map(_.toRight(InvalidGrant("Authorized information is not found by the refresh token"))) ) _ <- EitherT .cond[F](auth.clientId.contains(req.clientCredential.clientId), (), InvalidClient("invalid clientId")) token <- EitherT( handler .refreshAccessToken(auth, req.refreshToken) .attempt .map(_.leftMap(t => RefreshTokenFailed(t.getMessage): OAuthError)) ) grantResult <- EitherT( token.expiresIn .map(GrantHandler.createGrantHandlerResult(auth, token, _)) .attempt .map(_.leftMap(t => RefreshTokenFailed(t.getMessage): OAuthError)) ) } yield grantResult } trait RefreshTokenHandler[F[_], U] { def findAuthInfoByRefreshToken(refreshToken: String): F[Option[AuthInfo[U]]] }
Example 82
Source File: PasswordNoClientCredGrantHandler.scala From tsec with MIT License | 5 votes |
package tsec.oauth2.provider package grantHandler import cats.data.EitherT import cats.effect.Sync import cats.implicits._ import tsec.oauth2.provider.ValidatedRequest._ class PasswordNoClientCredGrantHandler[F[_], U](handler: PasswordNoClientCredHandler[F, U]) extends GrantHandler[F, U] { type A = ValidatedPasswordNoClientCred def handleRequest( req: ValidatedPasswordNoClientCred )(implicit F: Sync[F]): EitherT[F, OAuthError, GrantHandlerResult[U]] = for { user <- EitherT[F, OAuthError, U]( handler.findUser(None, req).map(_.toRight(InvalidGrant("username or password is incorrect"))) ) authInfo = AuthInfo(user, None, req.scope, None) grantResult <- EitherT( issueAccessToken(handler, authInfo).attempt .map(_.leftMap(t => FailedToIssueAccessToken(t.getMessage): OAuthError)) ) } yield grantResult } trait PasswordNoClientCredHandler[F[_], U] extends IssueAccessToken[F, U] { def findUser(maybeCredential: Option[ClientCredential], request: ValidatedPasswordNoClientCred): F[Option[U]] }
Example 83
Source File: GrantHandler.scala From tsec with MIT License | 5 votes |
package tsec.oauth2.provider package grantHandler import cats.data.EitherT import cats.effect.Sync import cats.implicits._ import scala.concurrent.duration.FiniteDuration sealed abstract class GrantType extends Product with Serializable { def name: String } object GrantType { val header = "grant_type" case object AuthorizationCode extends GrantType { def name: String = "authorization_code" } case object RefreshToken extends GrantType { def name: String = "refresh_token" } case object ClientCrendentials extends GrantType { def name: String = "client_credentials" } case object Password extends GrantType { def name: String = "password" } case object Implicit extends GrantType { def name: String = "implicit" } val strToGrantType = Map( AuthorizationCode.name -> AuthorizationCode, RefreshToken.name -> RefreshToken, ClientCrendentials.name -> ClientCrendentials, Password.name -> Password, Implicit.name -> Implicit ) } final case class GrantHandlerResult[U]( authInfo: AuthInfo[U], tokenType: String, accessToken: String, expiresIn: Option[FiniteDuration], refreshToken: Option[String], scope: Option[String], params: Map[String, String] ) trait GrantHandler[F[_], U] { type A def handleRequest(req: A)(implicit F: Sync[F]): EitherT[F, OAuthError, GrantHandlerResult[U]] def refreshAccessToken(authInfo: AuthInfo[U], refreshToken: String): F[AccessToken] }
Example 84
Source File: JCAPrimitiveCipher.scala From tsec with MIT License | 5 votes |
package tsec.cipher.symmetric.jca.primitive import javax.crypto.{Cipher => JCipher} import cats.MonadError import cats.effect.Sync import cats.syntax.all._ import tsec.cipher.common.padding.SymmetricPadding import tsec.cipher.symmetric.{Encryptor, _} import tsec.cipher.symmetric.jca.{IvProcess, SecretKey} sealed abstract class JCAPrimitiveCipher[F[_], C, M, P]( implicit algoTag: BlockCipher[C], modeSpec: CipherMode[M], paddingTag: SymmetricPadding[P], private[tsec] val ivProcess: IvProcess[C, M, P] ) extends Encryptor[F, C, SecretKey] { private[tsec] def catchF[Y](a: => Y): F[Y] private def getInstance = JCAPrimitiveCipher.getJCipherUnsafe[C, M, P] def encrypt(plainText: PlainText, key: SecretKey[C], iv: Iv[C]): F[CipherText[C]] = catchF { val instance = getInstance ivProcess.encryptInit(instance, iv, key.toJavaKey) val encrypted = instance.doFinal(plainText) CipherText[C](RawCipherText(encrypted), iv) } def decrypt(cipherText: CipherText[C], key: SecretKey[C]): F[PlainText] = catchF { val instance = getInstance ivProcess.decryptInit(instance, cipherText.nonce, key.toJavaKey) val out = instance.doFinal(cipherText.content) PlainText(out) } } object JCAPrimitiveCipher { private[tsec] def getJCipherUnsafe[A, M, P]( implicit algoTag: BlockCipher[A], modeSpec: CipherMode[M], paddingTag: SymmetricPadding[P] ): JCipher = JCipher.getInstance(s"${algoTag.cipherName}/${modeSpec.mode}/${paddingTag.algorithm}") def sync[F[_], A: BlockCipher, M: CipherMode, P: SymmetricPadding]( implicit F: Sync[F], ivProcess: IvProcess[A, M, P] ): JCAPrimitiveCipher[F, A, M, P] = new JCAPrimitiveCipher[F, A, M, P] { private[tsec] def catchF[C](thunk: => C): F[C] = F.delay(thunk) } def monadError[F[_], A: BlockCipher, M: CipherMode, P: SymmetricPadding]( implicit F: MonadError[F, Throwable], ivProcess: IvProcess[A, M, P] ): JCAPrimitiveCipher[F, A, M, P] = new JCAPrimitiveCipher[F, A, M, P] { private[tsec] def catchF[C](thunk: => C): F[C] = F.catchNonFatal(thunk) } }
Example 85
Source File: IvStrategy.scala From tsec with MIT License | 5 votes |
package tsec.cipher.symmetric.jca import cats.Applicative import cats.effect.Sync import tsec.cipher.symmetric._ import tsec.common.ManagedRandom object JCAIvGen { def random[F[_], A](implicit C: BlockCipher[A], F: Sync[F]): IvGen[F, A] = new IvGen[F, A] with ManagedRandom { def genIv: F[Iv[A]] = F.delay(genIvUnsafe) def genIvUnsafe: Iv[A] = { val nonce = new Array[Byte](C.blockSizeBytes) nextBytes(nonce) Iv[A](nonce) } } def emptyIv[F[_], A](implicit F: Applicative[F]): IvGen[F, A] = new IvGen[F, A] { protected val cachedEmpty = Array.empty[Byte] def genIv: F[Iv[A]] = F.pure(Iv[A](cachedEmpty)) def genIvUnsafe: Iv[A] = Iv[A](cachedEmpty) } } trait CounterIvGen[F[_], A] extends IvGen[F, A] { def refresh: F[Unit] def counterState: F[Long] def unsafeCounterState: Long }
Example 86
Source File: AESCTR.scala From tsec with MIT License | 5 votes |
package tsec.cipher.symmetric.jca import java.util.concurrent.atomic.AtomicLong import cats.effect.Sync import tsec.cipher.common.padding.NoPadding import tsec.cipher.symmetric._ import tsec.cipher.symmetric.jca.primitive.JCAPrimitiveCipher sealed abstract class AESCTR[A] extends JCACipherAPI[A, CTR, NoPadding] with AES[A] with JCAKeyGen[A] { implicit val ae: AESCTR[A] = this implicit def genEncryptor[F[_]: Sync](implicit c: BlockCipher[A]): JCAPrimitiveCipher[F, A, CTR, NoPadding] = JCAPrimitiveCipher.sync[F, A, CTR, NoPadding] def incrementalIvStrategy[F[_]](implicit F: Sync[F]): CounterIvGen[F, A] = new CounterIvGen[F, A] { private val delta = 1000000L private val maxVal: Long = Long.MaxValue - delta private val fixedCounter: Array[Byte] = Array.fill[Byte](8)(0.toByte) private val atomicNonce: AtomicLong = new AtomicLong(Long.MinValue) def refresh: F[Unit] = F.delay(atomicNonce.set(Long.MinValue)) def counterState: F[Long] = F.delay(unsafeCounterState) def unsafeCounterState: Long = atomicNonce.get() def genIv: F[Iv[A]] = F.delay(genIvUnsafe) def genIvUnsafe: Iv[A] = if (atomicNonce.get() >= maxVal) { throw IvError("Maximum safe nonce number reached") } else { val nonce = atomicNonce.incrementAndGet() val iv = new Array[Byte](16) //AES block size iv(0) = (nonce >> 56).toByte iv(1) = (nonce >> 48).toByte iv(2) = (nonce >> 40).toByte iv(3) = (nonce >> 32).toByte iv(4) = (nonce >> 24).toByte iv(5) = (nonce >> 16).toByte iv(6) = (nonce >> 8).toByte iv(7) = nonce.toByte System.arraycopy(fixedCounter, 0, iv, 8, 8) Iv[A](iv) } } def ciphertextFromConcat(rawCT: Array[Byte]): Either[CipherTextError, CipherText[A]] = CTOPS.ciphertextFromArray[A, CTR, NoPadding](rawCT) } sealed trait AES128CTR object AES128CTR extends AESCTR[AES128CTR] with AES128[AES128CTR] sealed trait AES192CTR object AES192CTR extends AESCTR[AES192CTR] with AES192[AES192CTR] sealed trait AES256CTR object AES256CTR extends AESCTR[AES256CTR] with AES256[AES256CTR]
Example 87
Source File: AESGCM.scala From tsec with MIT License | 5 votes |
package tsec.cipher.symmetric.jca import java.util.concurrent.atomic.AtomicInteger import cats.effect.Sync import tsec.cipher.common.padding.NoPadding import tsec.cipher.symmetric._ import tsec.cipher.symmetric.jca.primitive.JCAAEADPrimitive sealed abstract class AESGCM[A] extends JCAAEAD[A, GCM, NoPadding] with AES[A] with JCAKeyGen[A] { implicit val ae: AESGCM[A] = this implicit def genEncryptor[F[_]: Sync](implicit c: AES[A]): AADEncryptor[F, A, SecretKey] = JCAAEADPrimitive.sync[F, A, GCM, NoPadding] def incrementalIvStrategy[F[_]](implicit F: Sync[F]): CounterIvGen[F, A] = new CounterIvGen[F, A] { private val delta = 1000000 private val maxVal: Int = Int.MaxValue - delta private val fixedCounter: Array[Byte] = Array.fill[Byte](8)(0.toByte) private val atomicNonce: AtomicInteger = new AtomicInteger(Int.MinValue) def refresh: F[Unit] = F.delay(atomicNonce.set(Int.MinValue)) def counterState: F[Long] = F.delay(unsafeCounterState) def unsafeCounterState: Long = atomicNonce.get().toLong def genIv: F[Iv[A]] = F.delay(genIvUnsafe) def genIvUnsafe: Iv[A] = if (atomicNonce.get() >= maxVal) throw IvError("Maximum safe nonce number reached") else { val nonce = atomicNonce.incrementAndGet() val iv = new Array[Byte](12) //GCM optimal iv len iv(0) = (nonce >> 24).toByte iv(1) = (nonce >> 16).toByte iv(2) = (nonce >> 8).toByte iv(3) = nonce.toByte System.arraycopy(fixedCounter, 0, iv, 4, 8) Iv[A](iv) } } def ciphertextFromConcat(rawCT: Array[Byte]): Either[CipherTextError, CipherText[A]] = CTOPS.ciphertextFromArray[A, GCM, NoPadding](rawCT) } sealed trait AES128GCM object AES128GCM extends AESGCM[AES128GCM] with AES128[AES128GCM] sealed trait AES192GCM object AES192GCM extends AESGCM[AES192GCM] with AES192[AES192GCM] sealed trait AES256GCM object AES256GCM extends AESGCM[AES256GCM] with AES256[AES256GCM]
Example 88
Source File: KamonSupport.scala From kamon-http4s with Apache License 2.0 | 5 votes |
package kamon.http4s package middleware.server import cats.data.{Kleisli, OptionT} import cats.effect.{Resource, Sync} import cats.implicits._ import kamon.Kamon import kamon.context.Storage import kamon.instrumentation.http.HttpServerInstrumentation.RequestHandler import kamon.instrumentation.http.HttpServerInstrumentation import org.http4s.{HttpRoutes, Request, Response} object KamonSupport { def apply[F[_]: Sync](service: HttpRoutes[F], interface: String, port: Int): HttpRoutes[F] = { val httpServerConfig = Kamon.config().getConfig("kamon.instrumentation.http4s.server") val instrumentation = HttpServerInstrumentation.from(httpServerConfig, "http4s.server", interface, port) Kleisli(kamonService[F](service, instrumentation)(_)) } private def kamonService[F[_]](service: HttpRoutes[F], instrumentation: HttpServerInstrumentation) (request: Request[F]) (implicit F: Sync[F]): OptionT[F, Response[F]] = OptionT { getHandler(instrumentation)(request).use { handler => for { resOrUnhandled <- service(request).value.attempt respWithContext <- kamonServiceHandler(handler, resOrUnhandled, instrumentation.settings) } yield respWithContext } } private def processRequest[F[_]](requestHandler: RequestHandler)(implicit F: Sync[F]): Resource[F, RequestHandler] = Resource.make(F.delay(requestHandler.requestReceived()))(h => F.delay(h.responseSent())) private def withContext[F[_]](requestHandler: RequestHandler)(implicit F: Sync[F]): Resource[F, Storage.Scope] = Resource.make(F.delay(Kamon.storeContext(requestHandler.context)))( scope => F.delay(scope.close())) private def getHandler[F[_]](instrumentation: HttpServerInstrumentation)(request: Request[F])(implicit F: Sync[F]): Resource[F, RequestHandler] = for { handler <- Resource.liftF(F.delay(instrumentation.createHandler(buildRequestMessage(request)))) _ <- processRequest(handler) _ <- withContext(handler) } yield handler private def kamonServiceHandler[F[_]](requestHandler: RequestHandler, e: Either[Throwable, Option[Response[F]]], settings: HttpServerInstrumentation.Settings) (implicit F: Sync[F]): F[Option[Response[F]]] = e match { case Left(e) => F.delay { requestHandler.span.fail(e.getMessage) Some(requestHandler.buildResponse(errorResponseBuilder, requestHandler.context)) } *> F.raiseError(e) case Right(None) => F.delay { requestHandler.span.name(settings.unhandledOperationName) val response: Response[F] = requestHandler.buildResponse[Response[F]]( notFoundResponseBuilder, requestHandler.context ) Some(response) } case Right(Some(response)) => F.delay { val a = requestHandler.buildResponse(getResponseBuilder(response), requestHandler.context) Some(a) } } }
Example 89
Source File: FileUtils.scala From skeuomorph with Apache License 2.0 | 5 votes |
package higherkindness.skeuomorph import java.io.{File, FileOutputStream, InputStream} import java.nio.file.{Files, Paths, StandardOpenOption} import cats.effect.{Resource, Sync} object FileUtils { def fileHandle[F[_]: Sync](name: String): Resource[F, File] = Resource.make( Sync[F].delay(new File(name)) )(file => Sync[F].delay(file.deleteOnExit())) def fileOutputStream[F[_]: Sync](file: File): Resource[F, FileOutputStream] = Resource.make( Sync[F].delay(new FileOutputStream(file)) )(fos => Sync[F].delay(fos.close())) def fileInputStream[F[_]: Sync](name: String): Resource[F, InputStream] = Resource.make( Sync[F].delay(Files.newInputStream(Paths.get(name), StandardOpenOption.DELETE_ON_CLOSE)) )(is => Sync[F].delay(is.close())) }
Example 90
Source File: ParseOpenApi.scala From skeuomorph with Apache License 2.0 | 5 votes |
package higherkindness.skeuomorph.openapi import java.io.File import higherkindness.droste._ import higherkindness.skeuomorph.Parser import schema.OpenApi import cats.effect.Sync import cats.syntax.flatMap._ import cats.syntax.functor._ import cats.syntax.either._ object ParseOpenApi { import JsonDecoders._ case class YamlSource(file: File) case class JsonSource(file: File) implicit def parseYamlOpenApi[F[_], T](implicit T: Embed[JsonSchemaF, T]): Parser[F, YamlSource, OpenApi[T]] = new Parser[F, YamlSource, OpenApi[T]] { import yaml.{Decoder => _, _} override def parse(input: YamlSource)(implicit S: Sync[F]): F[OpenApi[T]] = readContent(input.file).flatMap(x => S.fromEither( yaml .Decoder[OpenApi[T]] .apply(x) .left .map(_.valueOr(identity)) ) ) } implicit def parseJsonOpenApi[F[_], T](implicit T: Embed[JsonSchemaF, T]): Parser[F, JsonSource, OpenApi[T]] = new Parser[F, JsonSource, OpenApi[T]] { import io.circe.Decoder import io.circe.parser override def parse(input: JsonSource)(implicit S: Sync[F]): F[OpenApi[T]] = for { content <- readContent(input.file) json <- S.fromEither(parser.parse(content)) openApi <- S.fromEither(Decoder[OpenApi[T]].decodeJson(json)) } yield openApi } private def readContent[F[_]: Sync](file: File): F[String] = Sync[F].delay { scala.io.Source .fromFile(file) .getLines() .toList .mkString("\n") } }
Example 91
Source File: Http4sTelegramClient.scala From canoe with MIT License | 5 votes |
package canoe.api.clients import canoe.api.{FailedMethod, ResponseDecodingError, TelegramClient} import canoe.methods.Method import canoe.models.{InputFile, Response => TelegramResponse} import cats.effect.Sync import cats.syntax.all._ import fs2.Stream import io.chrisdavenport.log4cats.Logger import org.http4s._ import org.http4s.circe._ import org.http4s.client.Client import org.http4s.client.dsl.Http4sClientDsl._ import org.http4s.multipart.{Multipart, Part} private[api] class Http4sTelegramClient[F[_]: Sync: Logger](token: String, client: Client[F]) extends TelegramClient[F] { private val botApiUri: Uri = Uri.unsafeFromString("https://api.telegram.org") / s"bot$token" def execute[Req, Res](request: Req)(implicit M: Method[Req, Res]): F[Res] = { val req = prepareRequest(botApiUri / M.name, M, request) implicit val decoder: EntityDecoder[F, TelegramResponse[Res]] = jsonOf(Sync[F], TelegramResponse.decoder(M.decoder)) F.debug(s"Executing '${M.name}' Telegram method.") *> client .expect[TelegramResponse[Res]](req) .recoverWith { case error: InvalidMessageBodyFailure => handleUnknownEntity(M.name, request, error) } .flatMap(handleTelegramResponse(M, request)) } private def handleUnknownEntity[I, A](method: String, input: I, error: InvalidMessageBodyFailure): F[A] = F.error( s"Received unknown Telegram entity during execution of '$method' method. \nInput data: $input. \n${error.details}" ) *> ResponseDecodingError(error.details.dropWhile(_ != '{')).raiseError[F, A] private def prepareRequest[Req, Res](url: Uri, method: Method[Req, Res], action: Req): F[Request[F]] = { val uploads = method.attachments(action).collect { case (name, InputFile.Upload(filename, contents)) => Part.fileData(name, filename, Stream.emits(contents).covary[F]) } if (uploads.isEmpty) jsonRequest(url, method, action) else multipartRequest(url, method, action, uploads) } private def jsonRequest[Req, Res](url: Uri, method: Method[Req, Res], action: Req): F[Request[F]] = Method.POST(action, url)(F, jsonEncoderOf(method.encoder)) private def multipartRequest[Req, Res](url: Uri, method: Method[Req, Res], action: Req, parts: List[Part[F]]): F[Request[F]] = { val multipart = Multipart[F](parts.toVector) val params = method .encoder(action) .asObject .map( _.toIterable .filterNot(kv => kv._2.isNull || kv._2.isObject) .map { case (k, j) => k -> j.toString } .toMap ) .getOrElse(Map.empty) val urlWithQueryParams = params.foldLeft(url) { case (url, (key, value)) => url.withQueryParam(key, value) } Method.POST(multipart, urlWithQueryParams).map(_.withHeaders(multipart.headers)) } private def handleTelegramResponse[A, I, C](m: Method[I, A], input: I)(response: TelegramResponse[A]): F[A] = response match { case TelegramResponse(true, Some(result), _, _, _) => result.pure[F] case failed => F.error(s"Received failed response from Telegram: $failed. Method name: ${m.name}, input data: $input") *> FailedMethod(m, input, failed).raiseError[F, A] } }
Example 92
Source File: Http4sClientEndpointsJsonSchemaTest.scala From endpoints4s with MIT License | 5 votes |
package endpoints4s.http4s.client import endpoints4s.algebra import endpoints4s.algebra.client import cats.effect.Sync import org.http4s.client.Client import cats.effect.IO import scala.concurrent.Future import scala.concurrent.ExecutionContext.global import org.http4s.client.asynchttpclient.AsyncHttpClient import cats.effect.ContextShift import endpoints4s.algebra.circe import org.http4s.Uri class TestJsonSchemaClient[F[_]: Sync](host: Uri, client: Client[F]) extends Endpoints[F](host, client) with BasicAuthentication with JsonEntitiesFromCodecs with algebra.BasicAuthenticationTestApi with algebra.EndpointsTestApi with algebra.JsonFromCodecTestApi with algebra.SumTypedEntitiesTestApi with circe.JsonFromCirceCodecTestApi with circe.JsonEntitiesFromCodecs class Http4sClientEndpointsJsonSchemaTest extends client.EndpointsTestSuite[TestJsonSchemaClient[IO]] with client.BasicAuthTestSuite[TestJsonSchemaClient[IO]] with client.JsonFromCodecTestSuite[TestJsonSchemaClient[IO]] with client.SumTypedEntitiesTestSuite[TestJsonSchemaClient[IO]] { implicit val ctx: ContextShift[IO] = IO.contextShift(global) val (ahc, shutdown) = AsyncHttpClient.allocate[IO]().unsafeRunSync() val client = new TestJsonSchemaClient[IO]( Uri.unsafeFromString(s"http://localhost:$wiremockPort"), ahc ) def call[Req, Resp]( endpoint: client.Endpoint[Req, Resp], args: Req ): Future[Resp] = { Thread.sleep(50) val eventualResponse = endpoint(args) Thread.sleep(50) eventualResponse.unsafeToFuture() } def encodeUrl[A](url: client.Url[A])(a: A): String = url.encodeUrl(a).toOption.get.renderString clientTestSuite() basicAuthSuite() jsonFromCodecTestSuite() override def afterAll(): Unit = { shutdown.unsafeRunSync() super.afterAll() } }
Example 93
Source File: RerunnableContextShiftSuite.scala From catbird with Apache License 2.0 | 5 votes |
package io.catbird.util.effect import cats.effect.{ ContextShift, IO, Sync } import com.twitter.util.{ Await, Future, FuturePool } import io.catbird.util.Rerunnable import org.scalatest.Outcome import org.scalatest.funsuite.FixtureAnyFunSuite class RerunnableContextShiftSuite extends FixtureAnyFunSuite with ThreadPoolNamingSupport { protected final class FixtureParam { val futurePoolName = "future-pool" val otherPoolName = "other-pool" val ioPoolName = "io-pool" val futurePool = FuturePool.interruptible(newNamedThreadPool(futurePoolName)) val otherPool = newNamedThreadPool(otherPoolName) val ioPool = newNamedThreadPool(ioPoolName) def newIO: IO[String] = IO(currentThreadName()) def newFuture: Future[String] = futurePool(currentThreadName()) def newRerunnable: Rerunnable[String] = Rerunnable(currentThreadName()) } test("ContextShift[Rerunnable].shift shifts to the pool of the instance") { f => implicit val cs: ContextShift[Rerunnable] = RerunnableContextShift.fromExecutionContext(f.ioPool) val (poolName1, poolName2, poolName3) = (for { poolName1 <- Rerunnable.fromFuture(f.newFuture) _ <- ContextShift[Rerunnable](cs).shift poolName2 <- Sync[Rerunnable].delay(currentThreadName()) poolName3 <- Rerunnable.fromFuture(f.newFuture) } yield (poolName1, poolName2, poolName3)).run.await assert(poolName1 == f.futurePoolName) assert(poolName2 == f.ioPoolName) assert(poolName2 == f.ioPoolName) } test("ContextShift[Rerunnable].evalOn executes on correct pool and shifts back to previous pool") { f => implicit val cs: ContextShift[Rerunnable] = RerunnableContextShift.fromExecutionContext(f.ioPool) val (poolName1, poolName2, poolName3) = (for { poolName1 <- f.newRerunnable poolName2 <- ContextShift[Rerunnable].evalOn(f.otherPool)(f.newRerunnable) poolName3 <- f.newRerunnable } yield (poolName1, poolName2, poolName3)).run.await assert(poolName1 == currentThreadName()) // The first rerunnable is not explicitly evaluated on a dedicated pool assert(poolName2 == f.otherPoolName) assert(poolName3 == f.ioPoolName) } test("ContextShift[Rerunnable].evalOn executes on correct pool and shifts back to future pool") { f => implicit val cs: ContextShift[Rerunnable] = RerunnableContextShift.fromExecutionContext(f.ioPool) val (poolName1, poolName2, poolName3) = (for { poolName1 <- Rerunnable.fromFuture(f.newFuture) // The future was started on a dedicated pool (e.g. netty) poolName2 <- ContextShift[Rerunnable].evalOn(f.otherPool)(f.newRerunnable) poolName3 <- Rerunnable.fromFuture(f.newFuture) } yield (poolName1, poolName2, poolName3)).run.await assert(poolName1 == f.futurePoolName) assert(poolName2 == f.otherPoolName) assert(poolName3 == f.futurePoolName) } implicit private class FutureAwaitOps[A](future: Future[A]) { def await: A = Await.result(future) } override protected def withFixture(test: OneArgTest): Outcome = withFixture(test.toNoArgTest(new FixtureParam)) }
Example 94
Source File: package.scala From fs2-blobstore with Apache License 2.0 | 5 votes |
import java.io.OutputStream import java.nio.file.Files import cats.effect.{Blocker, Concurrent, ContextShift, Resource, Sync} import fs2.{Chunk, Hotswap, Pipe, Pull, RaiseThrowable, Stream} import cats.implicits._ package object blobstore { protected[blobstore] def _writeAllToOutputStream1[F[_]](in: Stream[F, Byte], out: OutputStream, blocker: Blocker)( implicit F: Sync[F], CS: ContextShift[F] ): Pull[F, Nothing, Unit] = { in.pull.uncons.flatMap { case None => Pull.done case Some((hd, tl)) => Pull.eval[F, Unit](blocker.delay(out.write(hd.toArray))) >> _writeAllToOutputStream1(tl, out, blocker) } } protected[blobstore] def bufferToDisk[F[_]]( chunkSize: Int, blocker: Blocker )(implicit F: Sync[F], CS: ContextShift[F]): Pipe[F, Byte, (Long, Stream[F, Byte])] = { in => Stream.bracket(F.delay(Files.createTempFile("bufferToDisk", ".bin")))(p => F.delay(p.toFile.delete).void).flatMap { p => in.through(fs2.io.file.writeAll(p, blocker)).drain ++ Stream.emit((p.toFile.length, fs2.io.file.readAll(p, blocker, chunkSize))) } } private[blobstore] def putRotateBase[F[_]: Concurrent, T]( limit: Long, openNewFile: Resource[F, T] )(consume: T => Chunk[Byte] => F[Unit]): Pipe[F, Byte, Unit] = { in => Stream .resource(Hotswap(openNewFile)) .flatMap { case (hotswap, newFile) => goRotate(limit, 0L, in, newFile, hotswap, openNewFile)( consume = consumer => bytes => Pull.eval(consume(consumer)(bytes)).as(consumer), extract = Stream.emit ).stream } } private[blobstore] def goRotate[F[_]: RaiseThrowable, A, B]( limit: Long, acc: Long, s: Stream[F, Byte], consumer: B, hotswap: Hotswap[F, A], resource: Resource[F, A] )( consume: B => Chunk[Byte] => Pull[F, Unit, B], extract: A => Stream[F, B] ): Pull[F, Unit, Unit] = { val toWrite = (limit - acc).min(Int.MaxValue.toLong).toInt s.pull.unconsLimit(toWrite).flatMap { case Some((hd, tl)) => val newAcc = acc + hd.size consume(consumer)(hd).flatMap { consumer => if (newAcc >= limit) { Pull .eval(hotswap.swap(resource)) .flatMap(a => extract(a).pull.headOrError) .flatMap(nc => goRotate(limit, 0L, tl, nc, hotswap, resource)(consume, extract)) } else { goRotate(limit, newAcc, tl, consumer, hotswap, resource)(consume, extract) } } case None => Pull.done } } }
Example 95
Source File: Slf4jLogger.scala From log4cats with Apache License 2.0 | 5 votes |
package io.chrisdavenport.log4cats.slf4j import cats.effect.Sync import io.chrisdavenport.log4cats.SelfAwareStructuredLogger import io.chrisdavenport.log4cats.slf4j.internal._ import org.slf4j.{Logger => JLogger} import language.experimental.macros object Slf4jLogger { def getLogger[F[_]: Sync]: SelfAwareStructuredLogger[F] = macro GetLoggerMacros.unsafeCreateImpl[F[_]] @deprecated("0.3.0", "Use getLogger instead") def unsafeCreate[F[_]: Sync]: SelfAwareStructuredLogger[F] = macro GetLoggerMacros.unsafeCreateImpl[F[_]] def getLoggerFromName[F[_]: Sync](name: String): SelfAwareStructuredLogger[F] = getLoggerFromSlf4j(org.slf4j.LoggerFactory.getLogger(name)) @deprecated("0.3.0", "Use getLoggerFromName") def unsafeFromName[F[_]: Sync](name: String): SelfAwareStructuredLogger[F] = getLoggerFromName[F](name) def getLoggerFromClass[F[_]: Sync](clazz: Class[_]): SelfAwareStructuredLogger[F] = getLoggerFromSlf4j[F](org.slf4j.LoggerFactory.getLogger(clazz)) @deprecated("0.3.0", "Use getLoggerFromClass") def unsafeFromClass[F[_]: Sync](clazz: Class[_]): SelfAwareStructuredLogger[F] = getLoggerFromClass[F](clazz) def getLoggerFromSlf4j[F[_]: Sync](logger: JLogger): SelfAwareStructuredLogger[F] = new Slf4jLoggerInternal.Slf4jLogger(logger) @deprecated("0.3.0", "Use getLoggerFromSlf4J instead") def unsafeFromSlf4j[F[_]: Sync](logger: JLogger): SelfAwareStructuredLogger[F] = getLoggerFromSlf4j[F](logger) def create[F[_]: Sync]: F[SelfAwareStructuredLogger[F]] = macro GetLoggerMacros.safeCreateImpl[F[_]] def fromName[F[_]: Sync](name: String): F[SelfAwareStructuredLogger[F]] = Sync[F].delay(getLoggerFromName(name)) def fromClass[F[_]: Sync](clazz: Class[_]): F[SelfAwareStructuredLogger[F]] = Sync[F].delay(getLoggerFromClass(clazz)) def fromSlf4j[F[_]: Sync](logger: JLogger): F[SelfAwareStructuredLogger[F]] = Sync[F].delay(getLoggerFromSlf4j[F](logger)) }
Example 96
Source File: TestingLogger.scala From log4cats with Apache License 2.0 | 5 votes |
package io.chrisdavenport.log4cats.testing import io.chrisdavenport.log4cats.{SelfAwareLogger} import cats.effect.Sync import cats.implicits._ import java.util.concurrent.atomic.AtomicReference import scala.annotation.tailrec trait TestingLogger[F[_]] extends SelfAwareLogger[F] { import TestingLogger.LogMessage def logged: F[Vector[LogMessage]] } object TestingLogger { sealed trait LogMessage { def message: String def throwOpt: Option[Throwable] } final case class TRACE(message: String, throwOpt: Option[Throwable]) extends LogMessage final case class DEBUG(message: String, throwOpt: Option[Throwable]) extends LogMessage final case class INFO(message: String, throwOpt: Option[Throwable]) extends LogMessage final case class WARN(message: String, throwOpt: Option[Throwable]) extends LogMessage final case class ERROR(message: String, throwOpt: Option[Throwable]) extends LogMessage def impl[F[_]: Sync]( traceEnabled: Boolean = true, debugEnabled: Boolean = true, infoEnabled: Boolean = true, warnEnabled: Boolean = true, errorEnabled: Boolean = true ): TestingLogger[F] = { val ar = new AtomicReference(Vector.empty[LogMessage]) def appendLogMessage(m: LogMessage): F[Unit] = Sync[F].delay { @tailrec def mod(): Unit = { val c = ar.get val u = c :+ m if (!ar.compareAndSet(c, u)) mod else () } mod() } new TestingLogger[F] { def logged: F[Vector[LogMessage]] = Sync[F].delay(ar.get) def isTraceEnabled: F[Boolean] = Sync[F].pure(traceEnabled) def isDebugEnabled: F[Boolean] = Sync[F].pure(debugEnabled) def isInfoEnabled: F[Boolean] = Sync[F].pure(infoEnabled) def isWarnEnabled: F[Boolean] = Sync[F].pure(warnEnabled) def isErrorEnabled: F[Boolean] = Sync[F].pure(errorEnabled) def error(message: => String): F[Unit] = if (errorEnabled) appendLogMessage(ERROR(message, None)) else Sync[F].pure(()) def error(t: Throwable)(message: => String): F[Unit] = if (errorEnabled) appendLogMessage(ERROR(message, t.some)) else Sync[F].pure(()) def warn(message: => String): F[Unit] = if (warnEnabled) appendLogMessage(WARN(message, None)) else Sync[F].pure(()) def warn(t: Throwable)(message: => String): F[Unit] = if (warnEnabled) appendLogMessage(WARN(message, t.some)) else Sync[F].pure(()) def info(message: => String): F[Unit] = if (infoEnabled) appendLogMessage(INFO(message, None)) else Sync[F].pure(()) def info(t: Throwable)(message: => String): F[Unit] = if (infoEnabled) appendLogMessage(INFO(message, t.some)) else Sync[F].pure(()) def debug(message: => String): F[Unit] = if (debugEnabled) appendLogMessage(DEBUG(message, None)) else Sync[F].pure(()) def debug(t: Throwable)(message: => String): F[Unit] = if (debugEnabled) appendLogMessage(DEBUG(message, t.some)) else Sync[F].pure(()) def trace(message: => String): F[Unit] = if (traceEnabled) appendLogMessage(TRACE(message, None)) else Sync[F].pure(()) def trace(t: Throwable)(message: => String): F[Unit] = if (traceEnabled) appendLogMessage(TRACE(message, t.some)) else Sync[F].pure(()) } } }
Example 97
Source File: marshalling.scala From hammock with MIT License | 5 votes |
package hammock import cats._ import cats.free._ import cats.effect.Sync object marshalling { sealed trait MarshallF[A] { def dec: Decoder[A] // } object MarshallF { def unmarshall[A: Decoder](entity: Entity): MarshallF[A] = Unmarshall(entity) private[marshalling] final case class Unmarshall[A](entity: Entity)(implicit D: Decoder[A]) extends MarshallF[A] { def dec = D } } object Ops { def unmarshall[A: Decoder](entity: Entity): Free[MarshallF, A] = Free.liftF(MarshallF.unmarshall(entity)) } class MarshallC[F[_]](implicit I: MarshallF :<: F) { def unmarshall[A: Decoder](entity: Entity): Free[F, A] = Ops.unmarshall(entity).inject } implicit def marshallC[F[_]](implicit I: InjectK[MarshallF, F]): MarshallC[F] = new MarshallC[F] implicit def marshallNT[F[_]: Sync]: MarshallF ~> F = λ[MarshallF ~> F] { case [email protected](entity) => um.dec .decode(entity) .fold(Sync[F].raiseError, Sync[F].pure) } }
Example 98
Source File: package.scala From hammock with MIT License | 5 votes |
import cats._ import cats.data.{EitherK, NonEmptyList} import cats.free.Free import cats.effect.Sync import contextual._ package object hammock { import hammock.marshalling._ import hammock.InterpTrans type HammockF[A] = EitherK[HttpF, MarshallF, A] implicit class HttpRequestIOSyntax[A](fa: Free[HttpF, A]) { def exec[F[_]: Sync](implicit interp: InterpTrans[F]): F[A] = fa foldMap interp.trans } implicit class HammockFSyntax[A](fa: Free[HammockF, A]) { def exec[F[_]: Sync](implicit NT: HammockF ~> F): F[A] = fa foldMap NT } implicit class AsSyntaxOnHttpF[F[_], A](fa: Free[F, HttpResponse])( implicit H: InjectK[HttpF, F]) { def as[B](implicit D: Decoder[B], M: MarshallC[EitherK[F, MarshallF, *]]): Free[EitherK[F, MarshallF, *], B] = fa.inject[EitherK[F, MarshallF, *]] flatMap { response => M.unmarshall(response.entity) } } implicit def hammockNT[F[_]: Sync]( implicit H: InterpTrans[F], M: MarshallF ~> F ): HammockF ~> F = H.trans or M object UriContext extends Context object UriInterpolator extends Interpolator { type Output = Uri type ContextType = UriContext.type type Input = String def contextualize(interpolation: StaticInterpolation) = { interpolation.parts.foldLeft(List.empty[ContextType]) { case (contexts, Hole(_, _)) => UriContext :: contexts case (contexts, _) => contexts } } def evaluate(interpolation: RuntimeInterpolation): Uri = { val substituted = interpolation.literals .zipAll(interpolation.substitutions, "", "") .flatMap(x => List(x._1, x._2)) .mkString("") Uri.fromString(substituted).right.get } } implicit val embedString = UriInterpolator.embed[String](Case(UriContext, UriContext) { x => x }) implicit class UriQueryParamsBuilder(val self: NonEmptyList[(String, String)]) extends AnyVal { def &(param: (String, String)): NonEmptyList[(String, String)] = param :: self } implicit class UriQueryInitBuilder(val self: (String, String)) extends AnyVal { def &(param: (String, String)): NonEmptyList[(String, String)] = NonEmptyList(self, param :: Nil) } }
Example 99
Source File: codecs.scala From freestyle with Apache License 2.0 | 5 votes |
package examples.todolist package http import cats.Applicative import cats.effect.Sync import io.circe.generic.auto._ import org.http4s._ import org.http4s.circe._ object codecs { implicit def tagEncoder[F[_]: Applicative]: EntityEncoder[F, Tag] = jsonEncoderOf[F, Tag] implicit def tagDecoder[F[_]: Sync]: EntityDecoder[F, Tag] = jsonOf[F, Tag] implicit def todoItemEncoder[F[_]: Applicative]: EntityEncoder[F, TodoItem] = jsonEncoderOf[F, TodoItem] implicit def todoItemDecoder[F[_]: Sync]: EntityDecoder[F, TodoItem] = jsonOf[F, TodoItem] implicit def todoListEncoder[F[_]: Applicative]: EntityEncoder[F, TodoList] = jsonEncoderOf[F, TodoList] implicit def todoListDecoder[F[_]: Sync]: EntityDecoder[F, TodoList] = jsonOf[F, TodoList] implicit def todoFormEncoder[F[_]: Applicative]: EntityEncoder[F, TodoForm] = jsonEncoderOf[F, TodoForm] implicit def todoFormDecoder[F[_]: Sync]: EntityDecoder[F, TodoForm] = jsonOf[F, TodoForm] }
Example 100
Source File: free.scala From freestyle with Apache License 2.0 | 5 votes |
package freestyle.free package http import _root_.hammock._ import cats.{MonadError, ~>} import cats.effect.Sync import cats.free.Free object client { import freestyle.free._ import freestyle.free.implicits._ @free sealed trait HammockM { def options(uri: Uri, headers: Map[String, String]): FS[HttpResponse] def get(uri: Uri, headers: Map[String, String]): FS[HttpResponse] def head(uri: Uri, headers: Map[String, String]): FS[HttpResponse] def post(uri: Uri, headers: Map[String, String], body: Option[Entity]): FS[HttpResponse] def put(uri: Uri, headers: Map[String, String], body: Option[Entity]): FS[HttpResponse] def delete(uri: Uri, headers: Map[String, String]): FS[HttpResponse] def trace(uri: Uri, headers: Map[String, String]): FS[HttpResponse] def run[A](req: Free[HttpF, A]): FS[A] } trait Implicits { implicit def freeStyleHammockHandler[M[_] : MonadError[?[_], Throwable]](implicit I: InterpTrans[M], S: Sync[M]): HammockM.Handler[M] = new HammockM.Handler[M] { def options(uri: Uri, headers: Map[String, String]): M[HttpResponse] = Ops.options(uri, headers) foldMap I.trans def get(uri: Uri, headers: Map[String, String]): M[HttpResponse] = Ops.get(uri, headers) foldMap I.trans def head(uri: Uri, headers: Map[String, String]): M[HttpResponse] = Ops.head(uri, headers) foldMap I.trans def post(uri: Uri, headers: Map[String, String], body: Option[Entity]): M[HttpResponse] = Ops.post(uri, headers, body) foldMap I.trans def put(uri: Uri, headers: Map[String, String], body: Option[Entity]): M[HttpResponse] = Ops.put(uri, headers, body) foldMap I.trans def delete(uri: Uri, headers: Map[String, String]): M[HttpResponse] = Ops.delete(uri, headers) foldMap I.trans def trace(uri: Uri, headers: Map[String, String]): M[HttpResponse] = Ops.trace(uri, headers) foldMap I.trans def run[A](req: Free[HttpF, A]): M[A] = req foldMap I.trans } implicit def freeSLiftHammock[F[_]: HammockM]: FreeSLift[F, Free[HttpF, ?]] = new FreeSLift[F, Free[HttpF, ?]] { def liftFSPar[A](hio: Free[HttpF, A]): FreeS.Par[F, A] = HammockM[F].run(hio) } } object implicits extends Implicits }
Example 101
Source File: Config.scala From scala-steward with Apache License 2.0 | 5 votes |
package org.scalasteward.core.application import better.files._ import cats.effect.Sync import org.http4s.Uri import org.http4s.Uri.UserInfo import org.scalasteward.core.application.Cli.EnvVar import org.scalasteward.core.git.Author import org.scalasteward.core.util import org.scalasteward.core.vcs.data.AuthenticatedUser import scala.concurrent.duration.FiniteDuration import scala.sys.process.Process final case class Config( workspace: File, reposFile: File, defaultRepoConfigFile: Option[File], gitAuthor: Author, vcsType: SupportedVCS, vcsApiHost: Uri, vcsLogin: String, gitAskPass: File, signCommits: Boolean, whitelistedDirectories: List[String], readOnlyDirectories: List[String], disableSandbox: Boolean, doNotFork: Boolean, ignoreOptsFiles: Boolean, envVars: List[EnvVar], processTimeout: FiniteDuration, scalafixMigrations: Option[File], groupMigrations: Option[File], cacheTtl: FiniteDuration, cacheMissDelay: FiniteDuration, bitbucketServerUseDefaultReviewers: Boolean ) { def vcsUser[F[_]](implicit F: Sync[F]): F[AuthenticatedUser] = { val urlWithUser = util.uri.withUserInfo.set(UserInfo(vcsLogin, None))(vcsApiHost).renderString val prompt = s"Password for '$urlWithUser': " F.delay { val password = Process(List(gitAskPass.pathAsString, prompt)).!!.trim AuthenticatedUser(vcsLogin, password) } } } object Config { def create[F[_]](args: Cli.Args)(implicit F: Sync[F]): F[Config] = F.delay { Config( workspace = args.workspace.toFile, reposFile = args.reposFile.toFile, defaultRepoConfigFile = args.defaultRepoConf.map(_.toFile), gitAuthor = Author(args.gitAuthorName, args.gitAuthorEmail), vcsType = args.vcsType, vcsApiHost = args.vcsApiHost, vcsLogin = args.vcsLogin, gitAskPass = args.gitAskPass.toFile, signCommits = args.signCommits, whitelistedDirectories = args.whitelist, readOnlyDirectories = args.readOnly, disableSandbox = args.disableSandbox, doNotFork = args.doNotFork, ignoreOptsFiles = args.ignoreOptsFiles, envVars = args.envVar, processTimeout = args.processTimeout, scalafixMigrations = args.scalafixMigrations.map(_.toFile), groupMigrations = args.groupMigrations.map(_.toFile), cacheTtl = args.cacheTtl, cacheMissDelay = args.cacheMissDelay, bitbucketServerUseDefaultReviewers = args.bitbucketServerUseDefaultReviewers ) } }
Example 102
Source File: VCSSelection.scala From scala-steward with Apache License 2.0 | 5 votes |
package org.scalasteward.core.vcs import cats.effect.Sync import org.scalasteward.core.application.Config import org.scalasteward.core.application.SupportedVCS.{Bitbucket, BitbucketServer, GitHub, Gitlab} import org.scalasteward.core.bitbucket.http4s.Http4sBitbucketApiAlg import org.scalasteward.core.bitbucketserver.http4s.Http4sBitbucketServerApiAlg import org.scalasteward.core.github.http4s.Http4sGitHubApiAlg import org.scalasteward.core.gitlab.http4s.Http4sGitLabApiAlg import org.scalasteward.core.util.HttpJsonClient import org.scalasteward.core.vcs.data.AuthenticatedUser class VCSSelection[F[_]: Sync](implicit client: HttpJsonClient[F], user: AuthenticatedUser) { private def github(config: Config): Http4sGitHubApiAlg[F] = { import org.scalasteward.core.github.http4s.authentication.addCredentials new Http4sGitHubApiAlg[F](config.vcsApiHost, _ => addCredentials(user)) } private def gitlab(config: Config): Http4sGitLabApiAlg[F] = { import org.scalasteward.core.gitlab.http4s.authentication.addCredentials new Http4sGitLabApiAlg[F](config.vcsApiHost, user, _ => addCredentials(user), config.doNotFork) } private def bitbucket(config: Config): Http4sBitbucketApiAlg[F] = { import org.scalasteward.core.bitbucket.http4s.authentication.addCredentials new Http4sBitbucketApiAlg(config.vcsApiHost, user, _ => addCredentials(user), config.doNotFork) } private def bitbucketServer(config: Config): Http4sBitbucketServerApiAlg[F] = { import org.scalasteward.core.bitbucket.http4s.authentication.addCredentials new Http4sBitbucketServerApiAlg[F]( config.vcsApiHost, _ => addCredentials(user), config.bitbucketServerUseDefaultReviewers ) } def getAlg(config: Config): VCSApiAlg[F] = config.vcsType match { case GitHub => github(config) case Gitlab => gitlab(config) case Bitbucket => bitbucket(config) case BitbucketServer => bitbucketServer(config) } }
Example 103
Source File: Http4sBitbucketApiAlg.scala From scala-steward with Apache License 2.0 | 5 votes |
package org.scalasteward.core.bitbucket.http4s import cats.effect.Sync import cats.implicits._ import org.http4s.{Request, Status, Uri} import org.scalasteward.core.bitbucket.Url import org.scalasteward.core.bitbucket.http4s.json._ import org.scalasteward.core.git.Branch import org.scalasteward.core.util.{HttpJsonClient, UnexpectedResponse} import org.scalasteward.core.vcs.VCSApiAlg import org.scalasteward.core.vcs.data._ class Http4sBitbucketApiAlg[F[_]: Sync]( bitbucketApiHost: Uri, user: AuthenticatedUser, modify: Repo => Request[F] => F[Request[F]], doNotFork: Boolean )(implicit client: HttpJsonClient[F]) extends VCSApiAlg[F] { private val url = new Url(bitbucketApiHost) override def createFork(repo: Repo): F[RepoOut] = for { fork <- client.post[RepositoryResponse](url.forks(repo), modify(repo)).recoverWith { case UnexpectedResponse(_, _, _, Status.BadRequest, _) => client.get(url.repo(repo.copy(owner = user.login)), modify(repo)) } maybeParent <- fork.parent .map(n => client.get[RepositoryResponse](url.repo(n), modify(n))) .sequence[F, RepositoryResponse] } yield mapToRepoOut(fork, maybeParent) private def mapToRepoOut( repo: RepositoryResponse, maybeParent: Option[RepositoryResponse] ): RepoOut = RepoOut( repo.name, repo.owner, maybeParent.map(p => mapToRepoOut(p, None)), repo.httpsCloneUrl, repo.mainBranch ) override def createPullRequest(repo: Repo, data: NewPullRequestData): F[PullRequestOut] = { val sourceBranchOwner = if (doNotFork) repo.owner else user.login val payload = CreatePullRequestRequest( data.title, Branch(data.head), Repo(sourceBranchOwner, repo.repo), data.base, data.body ) client.postWithBody(url.pullRequests(repo), payload, modify(repo)) } override def getBranch(repo: Repo, branch: Branch): F[BranchOut] = client.get(url.branch(repo, branch), modify(repo)) override def getRepo(repo: Repo): F[RepoOut] = for { repo <- client.get[RepositoryResponse](url.repo(repo), modify(repo)) maybeParent <- repo.parent .map(n => client.get[RepositoryResponse](url.repo(n), modify(n))) .sequence[F, RepositoryResponse] } yield mapToRepoOut(repo, maybeParent) override def listPullRequests(repo: Repo, head: String, base: Branch): F[List[PullRequestOut]] = client .get[Page[PullRequestOut]](url.listPullRequests(repo, head), modify(repo)) .map(_.values) }
Example 104
Source File: DateTimeAlg.scala From scala-steward with Apache License 2.0 | 5 votes |
package org.scalasteward.core.util import cats.effect.Sync import cats.implicits._ import cats.{Functor, Monad} import java.util.concurrent.TimeUnit import scala.concurrent.duration.FiniteDuration trait DateTimeAlg[F[_]] { def currentTimeMillis: F[Long] final def currentTimestamp(implicit F: Functor[F]): F[Timestamp] = currentTimeMillis.map(Timestamp.apply) final def timed[A](fa: F[A])(implicit F: Monad[F]): F[(A, FiniteDuration)] = for { start <- currentTimeMillis a <- fa end <- currentTimeMillis duration = FiniteDuration(end - start, TimeUnit.MILLISECONDS) } yield (a, duration) } object DateTimeAlg { def create[F[_]](implicit F: Sync[F]): DateTimeAlg[F] = new DateTimeAlg[F] { override def currentTimeMillis: F[Long] = F.delay(System.currentTimeMillis()) } }
Example 105
Source File: HttpJsonClient.scala From scala-steward with Apache License 2.0 | 5 votes |
package org.scalasteward.core.util import cats.effect.Sync import cats.implicits._ import io.circe.{Decoder, Encoder} import org.http4s.Method.{GET, POST} import org.http4s.circe.{jsonEncoderOf, jsonOf} import org.http4s.client.Client import org.http4s._ import scala.util.control.NoStackTrace final class HttpJsonClient[F[_]: Sync](implicit client: Client[F] ) { type ModReq = Request[F] => F[Request[F]] def get[A: Decoder](uri: Uri, modify: ModReq): F[A] = request[A](GET, uri, modify) def post[A: Decoder](uri: Uri, modify: ModReq): F[A] = request[A](POST, uri, modify) def postWithBody[A: Decoder, B: Encoder](uri: Uri, body: B, modify: ModReq): F[A] = post[A](uri, modify.compose(_.withEntity(body)(jsonEncoderOf[F, B]))) private def request[A: Decoder](method: Method, uri: Uri, modify: ModReq): F[A] = client.expectOr[A](modify(Request[F](method, uri)))(resp => toUnexpectedResponse(uri, method, resp) )(jsonOf[F, A].transform(_.leftMap(failure => JsonParseError(uri, method, failure)))) private def toUnexpectedResponse( uri: Uri, method: Method, response: Response[F] ): F[Throwable] = { val body = response.body.through(fs2.text.utf8Decode).compile.string body.map(UnexpectedResponse(uri, method, response.headers, response.status, _)) } } final case class JsonParseError( uri: Uri, method: Method, underlying: DecodeFailure ) extends DecodeFailure { val message = s"uri: $uri\nmethod: $method\nmessage: ${underlying.message}" override def cause: Option[Throwable] = underlying.some override def toHttpResponse[F[_]](httpVersion: HttpVersion): Response[F] = underlying.toHttpResponse(httpVersion) } final case class UnexpectedResponse( uri: Uri, method: Method, headers: Headers, status: Status, body: String ) extends RuntimeException with NoStackTrace { override def getMessage: String = s"uri: $uri\nmethod: $method\nstatus: $status\nheaders: $headers\nbody: $body" }
Example 106
Source File: MillAlg.scala From scala-steward with Apache License 2.0 | 5 votes |
package org.scalasteward.core.buildtool.mill import cats.implicits._ import cats.effect.Sync import org.scalasteward.core.BuildInfo import org.scalasteward.core.buildtool.BuildToolAlg import org.scalasteward.core.data.Scope import org.scalasteward.core.data.Scope.Dependencies import org.scalasteward.core.io.{FileAlg, ProcessAlg, WorkspaceAlg} import org.scalasteward.core.scalafix.Migration import org.scalasteward.core.util.Nel import org.scalasteward.core.vcs.data.Repo trait MillAlg[F[_]] extends BuildToolAlg[F] object MillAlg { private val content = s"""|import coursierapi.MavenRepository | |interp.repositories() ++= Seq( | MavenRepository.of("https://oss.sonatype.org/content/repositories/snapshots/") |) |interp.load.ivy("${BuildInfo.organization}" %% "${BuildInfo.millPluginModuleName}" % "${BuildInfo.version}") |""".stripMargin def create[F[_]](implicit fileAlg: FileAlg[F], processAlg: ProcessAlg[F], workspaceAlg: WorkspaceAlg[F], F: Sync[F] ): MillAlg[F] = new MillAlg[F] { override def containsBuild(repo: Repo): F[Boolean] = workspaceAlg.repoDir(repo).flatMap(repoDir => fileAlg.isRegularFile(repoDir / "build.sc")) override def getDependencies(repo: Repo): F[List[Dependencies]] = for { repoDir <- workspaceAlg.repoDir(repo) predef = repoDir / "scala-steward.sc" _ <- fileAlg.writeFile(predef, content) millcmd = if ((repoDir / "mill").exists) (repoDir / "mill").toString() else "mill" extracted <- processAlg.exec( Nel( millcmd, List( "-i", "-p", predef.toString(), "show", s"${BuildInfo.millPluginModuleRootPkg}.StewardPlugin/extractDeps" ) ), repoDir ) parsed <- F.fromEither( parser.parseModules(extracted.dropWhile(!_.startsWith("{")).mkString("\n")) ) _ <- fileAlg.deleteForce(predef) } yield parsed.map(module => Scope(module.dependencies, module.repositories)) override def runMigrations(repo: Repo, migrations: Nel[Migration]): F[Unit] = F.unit } }
Example 107
Source File: MigrationAlg.scala From scala-steward with Apache License 2.0 | 5 votes |
package org.scalasteward.core.scalafix import better.files.File import cats.data.OptionT import cats.effect.Sync import cats.implicits._ import io.circe.config.parser.decode import org.scalasteward.core.data.{Update, Version} import org.scalasteward.core.io.FileAlg import org.scalasteward.core.util.{ApplicativeThrowable, MonadThrowable} trait MigrationAlg { def findMigrations(update: Update): List[Migration] } object MigrationAlg { def create[F[_]](extraMigrations: Option[File])(implicit fileAlg: FileAlg[F], F: Sync[F] ): F[MigrationAlg] = loadMigrations(extraMigrations).map { migrations => new MigrationAlg { override def findMigrations(update: Update): List[Migration] = findMigrationsImpl(migrations, update) } } def loadMigrations[F[_]]( extraMigrations: Option[File] )(implicit fileAlg: FileAlg[F], F: MonadThrowable[F]): F[List[Migration]] = for { default <- fileAlg .readResource("scalafix-migrations.conf") .flatMap(decodeMigrations[F](_, "default")) maybeExtra <- OptionT(extraMigrations.flatTraverse(fileAlg.readFile)) .semiflatMap(decodeMigrations[F](_, "extra")) .value migrations = maybeExtra match { case Some(extra) if extra.disableDefaults => extra.migrations case Some(extra) => default.migrations ++ extra.migrations case None => default.migrations } } yield migrations private def decodeMigrations[F[_]](content: String, tpe: String)(implicit F: ApplicativeThrowable[F] ): F[ScalafixMigrations] = F.fromEither(decode[ScalafixMigrations](content)) .adaptErr(new Throwable(s"Failed to load $tpe Scalafix migrations", _)) private def findMigrationsImpl( givenMigrations: List[Migration], update: Update ): List[Migration] = givenMigrations.filter { migration => update.groupId === migration.groupId && migration.artifactIds.exists(re => update.artifactIds.exists(artifactId => re.r.findFirstIn(artifactId.name).isDefined) ) && Version(update.currentVersion) < migration.newVersion && Version(update.newerVersions.head) >= migration.newVersion } }
Example 108
Source File: MockContext.scala From scala-steward with Apache License 2.0 | 5 votes |
package org.scalasteward.core.mock import better.files.File import cats.Parallel import cats.effect.Sync import org.http4s.Uri import org.scalasteward.core.TestInstances.ioContextShift import org.scalasteward.core.application.Cli.EnvVar import org.scalasteward.core.application.{Config, SupportedVCS} import org.scalasteward.core.buildtool.BuildToolDispatcher import org.scalasteward.core.buildtool.maven.MavenAlg import org.scalasteward.core.buildtool.mill.MillAlg import org.scalasteward.core.buildtool.sbt.SbtAlg import org.scalasteward.core.coursier.{CoursierAlg, VersionsCache} import org.scalasteward.core.edit.EditAlg import org.scalasteward.core.git.{Author, GitAlg} import org.scalasteward.core.io.{MockFileAlg, MockProcessAlg, MockWorkspaceAlg} import org.scalasteward.core.nurture.PullRequestRepository import org.scalasteward.core.persistence.JsonKeyValueStore import org.scalasteward.core.repocache.RepoCacheRepository import org.scalasteward.core.repoconfig.RepoConfigAlg import org.scalasteward.core.scalafix.MigrationAlg import org.scalasteward.core.scalafmt.ScalafmtAlg import org.scalasteward.core.update.{FilterAlg, GroupMigrations, PruningAlg, UpdateAlg} import org.scalasteward.core.util.uri._ import org.scalasteward.core.util.{BracketThrowable, DateTimeAlg} import org.scalasteward.core.vcs.VCSRepoAlg import org.scalasteward.core.vcs.data.AuthenticatedUser import scala.concurrent.duration._ object MockContext { implicit val config: Config = Config( workspace = File.temp / "ws", reposFile = File.temp / "repos.md", defaultRepoConfigFile = Some(File.temp / "default.scala-steward.conf"), gitAuthor = Author("Bot Doe", "[email protected]"), vcsType = SupportedVCS.GitHub, vcsApiHost = Uri(), vcsLogin = "bot-doe", gitAskPass = File.temp / "askpass.sh", signCommits = false, whitelistedDirectories = Nil, readOnlyDirectories = Nil, disableSandbox = false, doNotFork = false, ignoreOptsFiles = false, envVars = List( EnvVar("TEST_VAR", "GREAT"), EnvVar("ANOTHER_TEST_VAR", "ALSO_GREAT") ), processTimeout = 10.minutes, scalafixMigrations = None, groupMigrations = None, cacheTtl = 1.hour, cacheMissDelay = 0.milliseconds, bitbucketServerUseDefaultReviewers = false ) implicit val mockEffBracketThrowable: BracketThrowable[MockEff] = Sync[MockEff] implicit val mockEffParallel: Parallel[MockEff] = Parallel.identity implicit val fileAlg: MockFileAlg = new MockFileAlg implicit val mockLogger: MockLogger = new MockLogger implicit val processAlg: MockProcessAlg = new MockProcessAlg implicit val workspaceAlg: MockWorkspaceAlg = new MockWorkspaceAlg implicit val coursierAlg: CoursierAlg[MockEff] = CoursierAlg.create implicit val dateTimeAlg: DateTimeAlg[MockEff] = DateTimeAlg.create implicit val gitAlg: GitAlg[MockEff] = GitAlg.create implicit val user: AuthenticatedUser = AuthenticatedUser("scala-steward", "token") implicit val vcsRepoAlg: VCSRepoAlg[MockEff] = VCSRepoAlg.create(config, gitAlg) implicit val scalafmtAlg: ScalafmtAlg[MockEff] = ScalafmtAlg.create implicit val migrationAlg: MigrationAlg = MigrationAlg.create[MockEff](config.scalafixMigrations).runA(MockState.empty).unsafeRunSync() implicit val cacheRepository: RepoCacheRepository[MockEff] = new RepoCacheRepository[MockEff](new JsonKeyValueStore("repo_cache", "1")) implicit val filterAlg: FilterAlg[MockEff] = new FilterAlg[MockEff] implicit val versionsCache: VersionsCache[MockEff] = new VersionsCache[MockEff](config.cacheTtl, new JsonKeyValueStore("versions", "1")) implicit val groupMigrations: GroupMigrations = GroupMigrations.create[MockEff].runA(MockState.empty).unsafeRunSync() implicit val updateAlg: UpdateAlg[MockEff] = new UpdateAlg[MockEff] implicit val mavenAlg: MavenAlg[MockEff] = MavenAlg.create implicit val sbtAlg: SbtAlg[MockEff] = SbtAlg.create implicit val millAlg: MillAlg[MockEff] = MillAlg.create implicit val buildToolDispatcher: BuildToolDispatcher[MockEff] = BuildToolDispatcher.create implicit val editAlg: EditAlg[MockEff] = new EditAlg[MockEff] implicit val repoConfigAlg: RepoConfigAlg[MockEff] = new RepoConfigAlg[MockEff] implicit val pullRequestRepository: PullRequestRepository[MockEff] = new PullRequestRepository[MockEff](new JsonKeyValueStore("pull_requests", "1")) implicit val pruningAlg: PruningAlg[MockEff] = new PruningAlg[MockEff] }
Example 109
Source File: loggerTest.scala From scala-steward with Apache License 2.0 | 5 votes |
package org.scalasteward.core.util import cats.effect.Sync import org.scalasteward.core.mock.MockContext._ import org.scalasteward.core.mock.{MockEff, MockState} import org.scalasteward.core.util.logger.LoggerOps import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers class loggerTest extends AnyFunSuite with Matchers { test("attemptLog_") { final case class Err(msg: String) extends Throwable(msg) val err = Err("hmm?") val state = mockLogger .attemptLog_("run")(Sync[MockEff].raiseError(err)) .runS(MockState.empty) .unsafeRunSync() state.logs shouldBe Vector((None, "run"), (Some(err), "run failed")) } test("infoTimed") { val state = mockLogger .infoTimed(_ => "timed")(mockLogger.info("inner")) .runS(MockState.empty) .unsafeRunSync() state.logs shouldBe Vector((None, "inner"), (None, "timed")) } }
Example 110
Source File: ElasticClient.scala From fs2-elastic with MIT License | 5 votes |
package com.alessandromarrella.fs2_elastic import org.elasticsearch.client.{ RestClient, RestClientBuilder, RestHighLevelClient } import fs2._ import cats.effect.Sync import org.apache.http.HttpHost object Client { def fromHosts[F[_]](hosts: HttpHost*)( implicit F: Sync[F]): Stream[F, RestHighLevelClient] = Stream.bracket( F.delay(new RestHighLevelClient(RestClient.builder(hosts: _*))))( c => F.delay(c.close()) ) def fromClientBuilder[F[_]](restClientBuilder: RestClientBuilder)( implicit F: Sync[F]): Stream[F, RestHighLevelClient] = Stream.bracket(F.delay(new RestHighLevelClient(restClientBuilder)))( c => F.delay(c.close()) ) }
Example 111
Source File: CassandraSync.scala From kafka-journal with MIT License | 5 votes |
package com.evolutiongaming.kafka.journal.eventual.cassandra import cats.arrow.FunctionK import cats.effect.concurrent.Semaphore import cats.effect.{Concurrent, Sync, Timer} import cats.implicits._ import cats.~> import com.evolutiongaming.cassandra import com.evolutiongaming.cassandra.sync.AutoCreate import com.evolutiongaming.kafka.journal.Origin trait CassandraSync[F[_]] { def apply[A](fa: F[A]): F[A] } object CassandraSync { def empty[F[_]]: CassandraSync[F] = new CassandraSync[F] { def apply[A](fa: F[A]) = fa } def apply[F[_]](implicit F: CassandraSync[F]): CassandraSync[F] = F def apply[F[_] : Sync : Timer : CassandraSession]( config: SchemaConfig, origin: Option[Origin], ): CassandraSync[F] = { val keyspace = config.keyspace val autoCreate = if (keyspace.autoCreate) AutoCreate.Table else AutoCreate.None apply( keyspace = keyspace.name, table = config.locksTable, autoCreate = autoCreate, metadata = origin.map(_.value)) } def apply[F[_] : Sync : Timer : CassandraSession]( keyspace: String, table: String, autoCreate: AutoCreate, metadata: Option[String], ): CassandraSync[F] = { new CassandraSync[F] { def apply[A](fa: F[A]) = { val cassandraSync = cassandra.sync.CassandraSync.of[F]( session = CassandraSession[F].unsafe, keyspace = keyspace, table = table, autoCreate = autoCreate) for { cassandraSync <- cassandraSync result <- cassandraSync(id = "kafka-journal", metadata = metadata)(fa) } yield result } } } def of[F[_] : Concurrent : Timer : CassandraSession]( config: SchemaConfig, origin: Option[Origin] ): F[CassandraSync[F]] = { for { semaphore <- Semaphore[F](1) } yield { val cassandraSync = apply[F](config, origin) val serial = new (F ~> F) { def apply[A](fa: F[A]) = semaphore.withPermit(fa) } cassandraSync.mapK(serial, FunctionK.id) } } implicit class CassandraSyncOps[F[_]](val self: CassandraSync[F]) extends AnyVal { def mapK[G[_]](fg: F ~> G, gf: G ~> F): CassandraSync[G] = new CassandraSync[G] { def apply[A](fa: G[A]) = fg(self(gf(fa))) } } }
Example 112
Source File: ResultSet.scala From kafka-journal with MIT License | 5 votes |
package com.evolutiongaming.kafka.journal.eventual.cassandra import cats.effect.{Concurrent, Sync} import cats.effect.implicits._ import cats.implicits._ import com.datastax.driver.core.{Row, ResultSet => ResultSetJ} import com.evolutiongaming.scassandra.util.FromGFuture import com.evolutiongaming.sstream.Stream import com.evolutiongaming.sstream.FoldWhile._ object ResultSet { def apply[F[_] : Concurrent : FromGFuture](resultSet: ResultSetJ): Stream[F, Row] = { val iterator = resultSet.iterator() val fetch = FromGFuture[F].apply { resultSet.fetchMoreResults() }.void val fetched = Sync[F].delay { resultSet.isFullyFetched } val next = Sync[F].delay { List.fill(resultSet.getAvailableWithoutFetching)(iterator.next()) } apply[F, Row](fetch, fetched, next) } def apply[F[_] : Concurrent, A]( fetch: F[Unit], fetched: F[Boolean], next: F[List[A]] ): Stream[F, A] = new Stream[F, A] { def foldWhileM[L, R](l: L)(f: (L, A) => F[Either[L, R]]) = { l.tailRecM[F, Either[L, R]] { l => def apply(rows: List[A]) = { for { result <- rows.foldWhileM(l)(f) } yield { result.asRight[L] } } def fetchAndApply(rows: List[A]) = { for { fetching <- fetch.start result <- rows.foldWhileM(l)(f) result <- result match { case l: Left[L, R] => fetching.join as l.rightCast[Either[L, R]] case r: Right[L, R] => r.leftCast[L].asRight[L].pure[F] } } yield result } for { fetched <- fetched rows <- next result <- if (fetched) apply(rows) else fetchAndApply(rows) } yield result } } } }
Example 113
Source File: TopicCommit.scala From kafka-journal with MIT License | 5 votes |
package com.evolutiongaming.kafka.journal.replicator import java.time.Instant import cats.Applicative import cats.data.{NonEmptyMap => Nem} import cats.effect.concurrent.Ref import cats.effect.{Clock, Sync} import cats.implicits._ import com.evolutiongaming.catshelper.ClockHelper._ import com.evolutiongaming.catshelper.DataHelper._ import com.evolutiongaming.kafka.journal.util.TemporalHelper._ import com.evolutiongaming.kafka.journal.KafkaConsumer import com.evolutiongaming.skafka._ import scala.collection.immutable.SortedMap import scala.concurrent.duration._ trait TopicCommit[F[_]] { def apply(offsets: Nem[Partition, Offset]): F[Unit] } object TopicCommit { def empty[F[_] : Applicative]: TopicCommit[F] = (_: Nem[Partition, Offset]) => ().pure[F] def apply[F[_]]( topic: Topic, metadata: String, consumer: KafkaConsumer[F, _, _], ): TopicCommit[F] = { offsets: Nem[Partition, Offset] => { val offsets1 = offsets.mapKV { (partition, offset) => val offset1 = OffsetAndMetadata(offset, metadata) val partition1 = TopicPartition(topic, partition) (partition1, offset1) } consumer.commit(offsets1) } } def delayed[F[_] : Sync : Clock]( delay: FiniteDuration, commit: TopicCommit[F] ): F[TopicCommit[F]] = { case class State(until: Instant, offsets: SortedMap[Partition, Offset] = SortedMap.empty) for { timestamp <- Clock[F].instant stateRef <- Ref[F].of(State(timestamp + delay)) } yield { new TopicCommit[F] { def apply(offsets: Nem[Partition, Offset]) = { def apply(state: State, timestamp: Instant) = { val offsets1 = state.offsets ++ offsets.toSortedMap if (state.until <= timestamp) { offsets1 .toNem .foldMapM { offsets => commit(offsets) } .as(State(timestamp + delay)) } else { state .copy(offsets = offsets1) .pure[F] } } for { timestamp <- Clock[F].instant state <- stateRef.get state <- apply(state, timestamp) _ <- stateRef.set(state) } yield {} } } } } }
Example 114
Source File: LogFromAkka.scala From kafka-journal with MIT License | 5 votes |
package com.evolutiongaming.kafka.journal import akka.event.LoggingAdapter import cats.effect.Sync import com.evolutiongaming.catshelper.Log object LogFromAkka { def apply[F[_] : Sync](log: LoggingAdapter): Log[F] = new Log[F] { def debug(msg: => String) = { Sync[F].delay { if (log.isDebugEnabled) log.debug(msg) } } def info(msg: => String) = { Sync[F].delay { if (log.isInfoEnabled) log.info(msg) } } def warn(msg: => String) = { Sync[F].delay { if (log.isWarningEnabled) log.warning(msg) } } def warn(msg: => String, cause: Throwable) = { Sync[F].delay { if (log.isWarningEnabled) log.warning(s"$msg: $cause") } } def error(msg: => String) = { Sync[F].delay { if (log.isErrorEnabled) log.error(msg) } } def error(msg: => String, cause: Throwable) = { Sync[F].delay { if (log.isErrorEnabled) log.error(cause, msg) } } } }
Example 115
Source File: ThreadFactoryOf.scala From kafka-journal with MIT License | 5 votes |
package com.evolutiongaming.kafka.journal.execution import java.util.concurrent.{ThreadFactory, Executors => ExecutorsJ} import cats.effect.Sync import cats.implicits._ object ThreadFactoryOf { def apply[F[_] : Sync]( prefix: String, uncaughtExceptionHandler: Thread.UncaughtExceptionHandler = UncaughtExceptionHandler.default ): F[ThreadFactory] = { for { factory <- Sync[F].delay { ExecutorsJ.defaultThreadFactory() } } yield { new ThreadFactory { def newThread(runnable: Runnable) = { val thread = factory.newThread(runnable) val threadId = thread.getId thread.setName(s"$prefix-$threadId") thread.setUncaughtExceptionHandler(uncaughtExceptionHandler) thread } } } } }
Example 116
Source File: ThreadPoolOf.scala From kafka-journal with MIT License | 5 votes |
package com.evolutiongaming.kafka.journal.execution import java.util.concurrent.{SynchronousQueue, ThreadFactory, ThreadPoolExecutor} import cats.effect.{Resource, Sync} import cats.implicits._ import scala.concurrent.duration._ object ThreadPoolOf { def apply[F[_] : Sync]( minSize: Int, maxSize: Int, threadFactory: ThreadFactory, keepAlive: FiniteDuration = 1.minute, ): Resource[F, ThreadPoolExecutor] = { val result = for { result <- Sync[F].delay { new ThreadPoolExecutor( minSize, maxSize, keepAlive.length, keepAlive.unit, new SynchronousQueue[Runnable], threadFactory) } } yield { val release = Sync[F].delay { result.shutdown() } (result, release) } Resource(result) } }
Example 117
Source File: ForkJoinPoolOf.scala From kafka-journal with MIT License | 5 votes |
package com.evolutiongaming.kafka.journal.execution import java.util.concurrent.ForkJoinPool import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory import cats.effect.{Resource, Sync} import cats.implicits._ object ForkJoinPoolOf { def apply[F[_] : Sync]( name: String, parallelism: Int ): Resource[F, ForkJoinPool] = { val threadFactory = ForkJoinPool.defaultForkJoinWorkerThreadFactory.withPrefix(name) val threadPool = Sync[F].delay { new ForkJoinPool( parallelism, threadFactory, UncaughtExceptionHandler.default, true) } val result = for { threadPool <- threadPool } yield { val release = Sync[F].delay { threadPool.shutdown() } (threadPool, release) } Resource(result) } implicit class ForkJoinWorkerThreadFactoryOps(val self: ForkJoinWorkerThreadFactory) extends AnyVal { def withPrefix(prefix: String): ForkJoinWorkerThreadFactory = new ForkJoinWorkerThreadFactory { def newThread(pool: ForkJoinPool) = { val thread = self.newThread(pool) val threadId = thread.getId thread.setName(s"$prefix-$threadId") thread } } } }
Example 118
Source File: ScheduledExecutorServiceOf.scala From kafka-journal with MIT License | 5 votes |
package com.evolutiongaming.kafka.journal.execution import java.util.concurrent.{ScheduledExecutorService, ThreadFactory, Executors => ExecutorsJ} import cats.effect.{Resource, Sync} import cats.implicits._ object ScheduledExecutorServiceOf { def apply[F[_] : Sync]( parallelism: Int, threadFactory: ThreadFactory ): Resource[F, ScheduledExecutorService] = { val result = for { threadPool <- Sync[F].delay { ExecutorsJ.newScheduledThreadPool(parallelism, threadFactory) } } yield { val release = Sync[F].delay { threadPool.shutdown() } (threadPool, release) } Resource(result) } }
Example 119
Source File: HostName.scala From kafka-journal with MIT License | 5 votes |
package com.evolutiongaming.kafka.journal import cats.effect.Sync final case class HostName(value: String) { override def toString: String = value } object HostName { def of[F[_] : Sync](): F[Option[HostName]] = { Sync[F].delay { for { a <- com.evolutiongaming.hostname.HostName() } yield { HostName(a) } } } }
Example 120
Source File: ResourceRef.scala From kafka-journal with MIT License | 5 votes |
package com.evolutiongaming.kafka.journal.util import cats.effect.concurrent.Ref import cats.effect.implicits._ import cats.effect.{Resource, Sync} import cats.implicits._ import scala.util.control.NoStackTrace trait ResourceRef[F[_], A] { def get: F[A] def set(a: A, release: F[Unit]): F[Unit] def set(a: Resource[F, A]): F[Unit] } object ResourceRef { def of[F[_] : Sync, A](resource: Resource[F, A]): Resource[F, ResourceRef[F, A]] = { case class State(a: A, release: F[Unit]) Resource .make { for { ab <- resource.allocated (a, release) = ab ref <- Ref[F].of(State(a, release).some) } yield ref } { ref => ref .getAndSet(none) .flatMap { _.foldMapM { _.release } } } .map { ref => new ResourceRef[F, A] { def get = { ref .get .flatMap { case Some(state) => state.a.pure[F] case None => ResourceReleasedError.raiseError[F, A] } } def set(a: A, release: F[Unit]) = { ref .modify { case Some(state) => (State(a, release).some, state.release ) case None => (none, ResourceReleasedError.raiseError[F, Unit]) } .flatten .uncancelable } def set(a: Resource[F, A]) = { a .allocated .flatMap { case (a, release) => set(a, release) } } } } } } case object ResourceReleasedError extends RuntimeException("Resource released") with NoStackTrace
Example 121
Source File: ActorSystemOf.scala From kafka-journal with MIT License | 5 votes |
package com.evolutiongaming.kafka.journal.util import akka.actor.ActorSystem import cats.effect.{Resource, Sync} import cats.implicits._ import com.evolutiongaming.catshelper.FromFuture import com.typesafe.config.Config object ActorSystemOf { def apply[F[_] : Sync : FromFuture]( name: String, config: Option[Config] = None): Resource[F, ActorSystem] = { val system = Sync[F].delay { config.fold(ActorSystem(name)) { config => ActorSystem(name, config) } } for { system <- Resource.liftF(system) result <- apply(system) } yield result } def apply[F[_] : Sync : FromFuture](system: ActorSystem): Resource[F, ActorSystem] = { val release = FromFuture[F].apply { system.terminate() }.void val result = (system, release).pure[F] Resource(result) } }
Example 122
Source File: Executors.scala From kafka-journal with MIT License | 5 votes |
package com.evolutiongaming.kafka.journal.util import java.util.concurrent.ScheduledExecutorService import cats.effect.{Resource, Sync} import com.evolutiongaming.catshelper.Runtime import com.evolutiongaming.kafka.journal.execution.{ForkJoinPoolOf, ScheduledExecutorServiceOf, ThreadFactoryOf, ThreadPoolOf} import scala.concurrent.{ExecutionContext, ExecutionContextExecutorService} object Executors { def blocking[F[_] : Sync]( name: String, ): Resource[F, ExecutionContextExecutorService] = { for { threadFactory <- Resource.liftF(ThreadFactoryOf[F](name)) threadPool <- ThreadPoolOf[F](2, Int.MaxValue, threadFactory) } yield { ExecutionContext.fromExecutorService(threadPool) } } def nonBlocking[F[_] : Sync]( name: String, ): Resource[F, ExecutionContextExecutorService] = { for { cores <- Resource.liftF(Runtime[F].availableCores) parallelism = cores + 1 forkJoinPool <- ForkJoinPoolOf[F](name, parallelism) } yield { ExecutionContext.fromExecutorService(forkJoinPool) } } def scheduled[F[_] : Sync]( name: String, parallelism: Int ): Resource[F, ScheduledExecutorService] = { for { threadFactory <- Resource.liftF(ThreadFactoryOf[F](name)) result <- ScheduledExecutorServiceOf[F](parallelism, threadFactory) } yield result } }
Example 123
Source File: LogOfFromAkka.scala From kafka-journal with MIT License | 5 votes |
package com.evolutiongaming.kafka.journal import akka.actor.ActorSystem import akka.event.LogSource import cats.effect.Sync import cats.implicits._ import com.evolutiongaming.catshelper.LogOf object LogOfFromAkka { def apply[F[_] : Sync](system: ActorSystem): LogOf[F] = { def log[A: LogSource](source: A) = { for { log <- Sync[F].delay { akka.event.Logging(system, source) } } yield { LogFromAkka[F](log) } } new LogOf[F] { def apply(source: String) = log(source) def apply(source: Class[_]) = log(source) } } }
Example 124
Source File: TestSync.scala From kafka-journal with MIT License | 5 votes |
package com.evolutiongaming.kafka.journal.util import cats.Monad import cats.effect.{ExitCase, Sync} import scala.util.control.NonFatal object TestSync { def apply[F[_]](implicit F: Monad[F]): Sync[F] = new Sync[F] { def suspend[A](thunk: => F[A]) = thunk def bracketCase[A, B](acquire: F[A])(use: A => F[B])(release: (A, ExitCase[Throwable]) => F[Unit]) = { flatMap(acquire) { a => try { val b = use(a) try release(a, ExitCase.Completed) catch { case NonFatal(_) => } b } catch { case NonFatal(e) => release(a, ExitCase.Error(e)) raiseError(e) } } } def raiseError[A](e: Throwable) = throw e def handleErrorWith[A](fa: F[A])(f: Throwable => F[A]) = try fa catch { case NonFatal(e) => f(e) } def flatMap[A, B](fa: F[A])(f: A => F[B]) = F.flatMap(fa)(f) def tailRecM[A, B](a: A)(f: A => F[Either[A, B]]) = F.tailRecM(a)(f) def pure[A](a: A) = F.pure(a) } }
Example 125
Source File: SerializedMsgSerializer.scala From kafka-journal with MIT License | 5 votes |
package akka.persistence.kafka.journal import akka.actor.ActorSystem import cats.effect.Sync import cats.implicits._ import cats.~> import com.evolutiongaming.serialization.{SerializedMsg, SerializedMsgConverter, SerializedMsgExt} trait SerializedMsgSerializer[F[_]] { def toMsg(a: AnyRef): F[SerializedMsg] def fromMsg(a: SerializedMsg): F[AnyRef] } object SerializedMsgSerializer { def of[F[_] : Sync](actorSystem: ActorSystem): F[SerializedMsgSerializer[F]] = { for { converter <- Sync[F].delay { SerializedMsgExt(actorSystem) } } yield { apply(converter) } } def apply[F[_] : Sync](converter: SerializedMsgConverter): SerializedMsgSerializer[F] = { new SerializedMsgSerializer[F] { def toMsg(a: AnyRef) = { Sync[F].delay { converter.toMsg(a) } } def fromMsg(a: SerializedMsg) = { for { a <- Sync[F].delay { converter.fromMsg(a) } a <- Sync[F].fromTry(a) } yield a } } } implicit class SerializedMsgSerializerOps[F[_]](val self: SerializedMsgSerializer[F]) extends AnyVal { def mapK[G[_]](f: F ~> G): SerializedMsgSerializer[G] = new SerializedMsgSerializer[G] { def toMsg(a: AnyRef) = f(self.toMsg(a)) def fromMsg(a: SerializedMsg) = f(self.fromMsg(a)) } } }
Example 126
Source File: EventSerializerSpec.scala From kafka-journal with MIT License | 5 votes |
package akka.persistence.kafka.journal import java.io.FileOutputStream import akka.persistence.PersistentRepr import akka.persistence.serialization.Snapshot import cats.effect.{IO, Sync} import com.evolutiongaming.kafka.journal.FromBytes.implicits._ import com.evolutiongaming.kafka.journal.IOSuite._ import com.evolutiongaming.kafka.journal._ import com.evolutiongaming.kafka.journal.util.CatsHelper._ import org.scalatest.funsuite.AsyncFunSuite import org.scalatest.matchers.should.Matchers import play.api.libs.json.JsString import scodec.bits.ByteVector import TestJsonCodec.instance import cats.implicits._ import scala.util.Try class EventSerializerSpec extends AsyncFunSuite with ActorSuite with Matchers { for { (name, payloadType, payload) <- List( ("PersistentRepr.bin", PayloadType.Binary, Snapshot("binary")), ("PersistentRepr.text.json", PayloadType.Json, "text"), ("PersistentRepr.json", PayloadType.Json, JsString("json"))) } { test(s"toEvent & toPersistentRepr, payload: $payload") { val persistenceId = "persistenceId" val persistentRepr = PersistentRepr( payload = payload, sequenceNr = 1, persistenceId = persistenceId, manifest = "manifest", writerUuid = "writerUuid") val fa = for { serializer <- EventSerializer.of[IO](actorSystem) event <- serializer.toEvent(persistentRepr) actual <- serializer.toPersistentRepr(persistenceId, event) _ <- Sync[IO].delay { actual shouldEqual persistentRepr } payload <- event.payload.getOrError[IO]("Event.payload is not defined") _ = payload.payloadType shouldEqual payloadType bytes <- ByteVectorOf[IO](getClass, name) } yield { payload match { case payload: Payload.Binary => payload.value shouldEqual bytes case payload: Payload.Text => payload.value shouldEqual bytes.fromBytes[Try, String].get case payload: Payload.Json => payload.value shouldEqual JsonCodec.summon[Try].decode.fromBytes(bytes).get } } fa.run() } } def writeToFile[F[_] : Sync](bytes: ByteVector, path: String): F[Unit] = { Sync[F].delay { val os = new FileOutputStream(path) os.write(bytes.toArray) os.close() } } }
Example 127
Source File: ActorSystemRefTest.scala From kafka-journal with MIT License | 5 votes |
package akka.persistence.kafka.journal import cats.arrow.FunctionK import cats.effect.{IO, Sync} import cats.implicits._ import com.evolutiongaming.kafka.journal.ActorSuite import com.evolutiongaming.kafka.journal.IOSuite._ import org.scalatest.funsuite.AsyncFunSuite import org.scalatest.matchers.should.Matchers class ActorSystemRefTest extends AsyncFunSuite with ActorSuite with Matchers { import ActorSystemRefTest._ test("Extension") { val result = for { ref <- Sync[IO].delay { Extension(actorSystem) } ref <- ref.fromFuture[IO].mapK(FunctionK.id).pure[IO] a <- ref.get.start _ <- ref.set(0) a <- a.join _ = a shouldEqual 0 a <- ref.get _ = a shouldEqual 0 a <- ref.set(0).attempt _ = a.isLeft shouldEqual true } yield {} result.run() } } object ActorSystemRefTest { object Extension extends ActorSystemRef.ExtensionId[Int] }
Example 128
Source File: data.scala From redis4cats with Apache License 2.0 | 5 votes |
package dev.profunktor.redis4cats import cats.effect.Sync import cats.syntax.functor._ import dev.profunktor.redis4cats.JavaConversions._ import io.lettuce.core.{ ReadFrom => JReadFrom } import io.lettuce.core.codec.{ ByteArrayCodec, CipherCodec, CompressionCodec, RedisCodec => JRedisCodec, StringCodec } import io.lettuce.core.{ KeyScanCursor => JKeyScanCursor } import javax.crypto.Cipher import javax.crypto.spec.SecretKeySpec object data { final case class RedisChannel[K](underlying: K) extends AnyVal final case class RedisCodec[K, V](underlying: JRedisCodec[K, V]) extends AnyVal final case class NodeId(value: String) extends AnyVal final case class KeyScanCursor[K](underlying: JKeyScanCursor[K]) extends AnyVal { def keys: List[K] = underlying.getKeys.asScala.toList def cursor: String = underlying.getCursor } object RedisCodec { val Ascii: RedisCodec[String, String] = RedisCodec(StringCodec.ASCII) val Utf8: RedisCodec[String, String] = RedisCodec(StringCodec.UTF8) val Bytes: RedisCodec[Array[Byte], Array[Byte]] = RedisCodec(ByteArrayCodec.INSTANCE) def decryptSupplier[F[_]: Sync](key: SecretKeySpec): F[CipherCodec.CipherSupplier] = cipherSupplier[F](key, Cipher.DECRYPT_MODE) private def cipherSupplier[F[_]: Sync](key: SecretKeySpec, mode: Int): F[CipherCodec.CipherSupplier] = { val mkCipher = F.delay { val cipher: Cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") cipher.init(mode, key) cipher } mkCipher.map { cipher => new CipherCodec.CipherSupplier { override def get(kd: CipherCodec.KeyDescriptor): Cipher = cipher } } } } object ReadFrom { val Master = JReadFrom.MASTER val MasterPreferred = JReadFrom.MASTER_PREFERRED val Nearest = JReadFrom.NEAREST val Replica = JReadFrom.REPLICA val ReplicaPreferred = JReadFrom.REPLICA_PREFERRED } }
Example 129
Source File: Log.scala From redis4cats with Apache License 2.0 | 5 votes |
package dev.profunktor.redis4cats.effect import cats.Applicative import cats.effect.Sync trait Log[F[_]] { def debug(msg: => String): F[Unit] def error(msg: => String): F[Unit] def info(msg: => String): F[Unit] } object Log { def apply[F[_]](implicit ev: Log[F]): Log[F] = ev object NoOp { implicit def instance[F[_]: Applicative]: Log[F] = new Log[F] { def debug(msg: => String): F[Unit] = F.unit def error(msg: => String): F[Unit] = F.unit def info(msg: => String): F[Unit] = F.unit } } object Stdout { implicit def instance[F[_]: Sync]: Log[F] = new Log[F] { def debug(msg: => String): F[Unit] = F.delay(Console.out.println(msg)) def error(msg: => String): F[Unit] = F.delay(Console.err.println(msg)) def info(msg: => String): F[Unit] = F.delay(Console.out.println(msg)) } } }
Example 130
Source File: ResilientStream.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.resiliency import cats.effect.{Sync, Timer} import cats.syntax.apply._ import dev.profunktor.fs2rabbit.effects.Log import fs2.Stream import scala.concurrent.duration._ import scala.util.control.NonFatal object ResilientStream { def runF[F[_]: Log: Sync: Timer](program: F[Unit], retry: FiniteDuration = 5.seconds): F[Unit] = run(Stream.eval(program), retry) def run[F[_]: Log: Sync: Timer]( program: Stream[F, Unit], retry: FiniteDuration = 5.seconds ): F[Unit] = loop(program, retry, 1).compile.drain private def loop[F[_]: Log: Sync: Timer]( program: Stream[F, Unit], retry: FiniteDuration, count: Int ): Stream[F, Unit] = program.handleErrorWith { case NonFatal(err) => Stream.eval(Log[F].error(err.getMessage) *> Log[F].info(s"Restarting in ${retry.toSeconds * count}...")) >> loop[F](Stream.sleep(retry) >> program, retry, count + 1) } }
Example 131
Source File: Deletion.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.algebra import cats.effect.Sync import cats.syntax.functor._ import dev.profunktor.fs2rabbit.config.deletion import dev.profunktor.fs2rabbit.config.deletion.{DeletionExchangeConfig, DeletionQueueConfig} import dev.profunktor.fs2rabbit.effects.BoolValue.syntax._ import dev.profunktor.fs2rabbit.model.AMQPChannel object Deletion { def make[F[_]: Sync]: Deletion[F] = new Deletion[F] { override def deleteQueue(channel: AMQPChannel, config: DeletionQueueConfig): F[Unit] = Sync[F].delay { channel.value.queueDelete( config.queueName.value, config.ifUnused.isTrue, config.ifEmpty.isTrue ) }.void override def deleteQueueNoWait(channel: AMQPChannel, config: DeletionQueueConfig): F[Unit] = Sync[F].delay { channel.value.queueDeleteNoWait( config.queueName.value, config.ifUnused.isTrue, config.ifEmpty.isTrue ) }.void override def deleteExchange( channel: AMQPChannel, config: deletion.DeletionExchangeConfig ): F[Unit] = Sync[F].delay { channel.value.exchangeDelete(config.exchangeName.value, config.ifUnused.isTrue) }.void override def deleteExchangeNoWait( channel: AMQPChannel, config: deletion.DeletionExchangeConfig ): F[Unit] = Sync[F].delay { channel.value.exchangeDeleteNoWait( config.exchangeName.value, config.ifUnused.isTrue ) }.void } } trait Deletion[F[_]] { def deleteQueue(channel: AMQPChannel, config: DeletionQueueConfig): F[Unit] def deleteQueueNoWait(channel: AMQPChannel, config: DeletionQueueConfig): F[Unit] def deleteExchange(channel: AMQPChannel, config: DeletionExchangeConfig): F[Unit] def deleteExchangeNoWait(channel: AMQPChannel, config: DeletionExchangeConfig): F[Unit] }
Example 132
Source File: Connection.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.algebra import cats.data.NonEmptyList import cats.effect.{Resource, Sync} import cats.implicits._ import com.rabbitmq.client.{Address, ConnectionFactory, DefaultSaslConfig, SaslConfig} import dev.profunktor.fs2rabbit.config.Fs2RabbitConfig import dev.profunktor.fs2rabbit.effects.Log import dev.profunktor.fs2rabbit.javaConversion._ import dev.profunktor.fs2rabbit.model.{AMQPChannel, AMQPConnection, RabbitChannel, RabbitConnection} import javax.net.ssl.SSLContext object ConnectionResource { type ConnectionResource[F[_]] = Connection[Resource[F, ?]] def make[F[_]: Sync: Log]( conf: Fs2RabbitConfig, sslCtx: Option[SSLContext] = None, // Unlike SSLContext, SaslConfig is not optional because it is always set // by the underlying Java library, even if the user doesn't set it. saslConf: SaslConfig = DefaultSaslConfig.PLAIN ): F[Connection[Resource[F, ?]]] = Sync[F].delay { new Connection[Resource[F, ?]] { private[fs2rabbit] def mkConnectionFactory: F[(ConnectionFactory, NonEmptyList[Address])] = Sync[F].delay { val factory = new ConnectionFactory() val firstNode = conf.nodes.head factory.setHost(firstNode.host) factory.setPort(firstNode.port) factory.setVirtualHost(conf.virtualHost) factory.setConnectionTimeout(conf.connectionTimeout) factory.setAutomaticRecoveryEnabled(conf.automaticRecovery) if (conf.ssl) { sslCtx.fold(factory.useSslProtocol())(factory.useSslProtocol) } factory.setSaslConfig(saslConf) conf.username.foreach(factory.setUsername) conf.password.foreach(factory.setPassword) val addresses = conf.nodes.map(node => new Address(node.host, node.port)) (factory, addresses) } private[fs2rabbit] def acquireChannel(connection: AMQPConnection): F[AMQPChannel] = Sync[F] .delay(connection.value.createChannel) .flatTap(c => Log[F].info(s"Acquired channel: $c")) .map(RabbitChannel) private[fs2rabbit] val acquireConnection: F[AMQPConnection] = mkConnectionFactory.flatMap { case (factory, addresses) => Sync[F] .delay(factory.newConnection(addresses.toList.asJava)) .flatTap(c => Log[F].info(s"Acquired connection: $c")) .map(RabbitConnection) } override def createConnection: Resource[F, AMQPConnection] = Resource.make(acquireConnection) { case RabbitConnection(conn) => Log[F].info(s"Releasing connection: $conn previously acquired.") *> Sync[F].delay { if (conn.isOpen) conn.close() } } override def createChannel(connection: AMQPConnection): Resource[F, AMQPChannel] = Resource.make(acquireChannel(connection)) { case RabbitChannel(channel) => Sync[F].delay { if (channel.isOpen) channel.close() } } } } } trait Connection[F[_]] { def createConnection: F[AMQPConnection] def createChannel(connection: AMQPConnection): F[AMQPChannel] }
Example 133
Source File: Publish.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.algebra import cats.effect.syntax.effect._ import cats.effect.{Blocker, ContextShift, Effect, Sync} import cats.syntax.functor._ import com.rabbitmq.client.{AMQP, ReturnListener} import dev.profunktor.fs2rabbit.model._ object Publish { def make[F[_]: Effect: ContextShift]( blocker: Blocker ): Publish[F] = new Publish[F] { override def basicPublish(channel: AMQPChannel, exchangeName: ExchangeName, routingKey: RoutingKey, msg: AmqpMessage[Array[Byte]]): F[Unit] = blocker.delay { channel.value.basicPublish( exchangeName.value, routingKey.value, msg.properties.asBasicProps, msg.payload ) } override def basicPublishWithFlag(channel: AMQPChannel, exchangeName: ExchangeName, routingKey: RoutingKey, flag: PublishingFlag, msg: AmqpMessage[Array[Byte]]): F[Unit] = blocker.delay { channel.value.basicPublish( exchangeName.value, routingKey.value, flag.mandatory, msg.properties.asBasicProps, msg.payload ) } override def addPublishingListener( channel: AMQPChannel, listener: PublishReturn => F[Unit] ): F[Unit] = Sync[F].delay { val returnListener = new ReturnListener { override def handleReturn(replyCode: Int, replyText: String, exchange: String, routingKey: String, properties: AMQP.BasicProperties, body: Array[Byte]): Unit = { val publishReturn = PublishReturn( ReplyCode(replyCode), ReplyText(replyText), ExchangeName(exchange), RoutingKey(routingKey), AmqpProperties.unsafeFrom(properties), AmqpBody(body) ) listener(publishReturn).toIO.unsafeRunAsync(_ => ()) } } channel.value.addReturnListener(returnListener) }.void override def clearPublishingListeners(channel: AMQPChannel): F[Unit] = Sync[F].delay { channel.value.clearReturnListeners() }.void } } trait Publish[F[_]] { def basicPublish(channel: AMQPChannel, exchangeName: ExchangeName, routingKey: RoutingKey, msg: AmqpMessage[Array[Byte]]): F[Unit] def basicPublishWithFlag(channel: AMQPChannel, exchangeName: ExchangeName, routingKey: RoutingKey, flag: PublishingFlag, msg: AmqpMessage[Array[Byte]]): F[Unit] def addPublishingListener(channel: AMQPChannel, listener: PublishReturn => F[Unit]): F[Unit] def clearPublishingListeners(channel: AMQPChannel): F[Unit] }
Example 134
Source File: Declaration.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.algebra import cats.effect.Sync import cats.syntax.functor._ import dev.profunktor.fs2rabbit.arguments._ import dev.profunktor.fs2rabbit.config.declaration.{DeclarationExchangeConfig, DeclarationQueueConfig} import dev.profunktor.fs2rabbit.effects.BoolValue.syntax._ import dev.profunktor.fs2rabbit.model.{AMQPChannel, ExchangeName, QueueName} object Declaration { def make[F[_]: Sync]: Declaration[F] = new Declaration[F] { override def declareExchange(channel: AMQPChannel, config: DeclarationExchangeConfig): F[Unit] = Sync[F].delay { channel.value.exchangeDeclare( config.exchangeName.value, config.exchangeType.toString.toLowerCase, config.durable.isTrue, config.autoDelete.isTrue, config.internal.isTrue, config.arguments ) }.void override def declareExchangeNoWait( channel: AMQPChannel, config: DeclarationExchangeConfig ): F[Unit] = Sync[F].delay { channel.value.exchangeDeclareNoWait( config.exchangeName.value, config.exchangeType.toString.toLowerCase, config.durable.isTrue, config.autoDelete.isTrue, config.internal.isTrue, config.arguments ) }.void override def declareExchangePassive(channel: AMQPChannel, exchangeName: ExchangeName): F[Unit] = Sync[F].delay { channel.value.exchangeDeclarePassive(exchangeName.value) }.void override def declareQueue(channel: AMQPChannel): F[QueueName] = Sync[F].delay { QueueName(channel.value.queueDeclare().getQueue) } override def declareQueue(channel: AMQPChannel, config: DeclarationQueueConfig): F[Unit] = Sync[F].delay { channel.value.queueDeclare( config.queueName.value, config.durable.isTrue, config.exclusive.isTrue, config.autoDelete.isTrue, config.arguments ) }.void override def declareQueueNoWait(channel: AMQPChannel, config: DeclarationQueueConfig): F[Unit] = Sync[F].delay { channel.value.queueDeclareNoWait( config.queueName.value, config.durable.isTrue, config.exclusive.isTrue, config.autoDelete.isTrue, config.arguments ) }.void override def declareQueuePassive(channel: AMQPChannel, queueName: QueueName): F[Unit] = Sync[F].delay { channel.value.queueDeclarePassive(queueName.value) }.void } } trait Declaration[F[_]] { def declareExchange(channel: AMQPChannel, exchangeConfig: DeclarationExchangeConfig): F[Unit] def declareExchangeNoWait(value: AMQPChannel, exchangeConfig: DeclarationExchangeConfig): F[Unit] def declareExchangePassive(channel: AMQPChannel, exchangeName: ExchangeName): F[Unit] def declareQueue(channel: AMQPChannel): F[QueueName] def declareQueue(channel: AMQPChannel, queueConfig: DeclarationQueueConfig): F[Unit] def declareQueueNoWait(channel: AMQPChannel, queueConfig: DeclarationQueueConfig): F[Unit] def declareQueuePassive(channel: AMQPChannel, queueName: QueueName): F[Unit] }
Example 135
Source File: AckingProgram.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.program import cats.Applicative import cats.effect.{Effect, Sync} import dev.profunktor.fs2rabbit.algebra.{AMQPInternals, Acking, Consume} import dev.profunktor.fs2rabbit.arguments.Arguments import dev.profunktor.fs2rabbit.config.Fs2RabbitConfig import dev.profunktor.fs2rabbit.model.AckResult.{Ack, NAck, Reject} import dev.profunktor.fs2rabbit.model._ object AckingProgram { def make[F[_]: Effect](config: Fs2RabbitConfig): F[AckingProgram[F]] = Sync[F].delay { WrapperAckingProgram(config, Consume.make) } } trait AckingProgram[F[_]] extends Acking[F] with Consume[F] case class WrapperAckingProgram[F[_]: Effect] private ( config: Fs2RabbitConfig, consume: Consume[F] ) extends AckingProgram[F] { override def createAcker(channel: AMQPChannel): F[AckResult => F[Unit]] = Applicative[F].pure { case Ack(tag) => consume.basicAck(channel, tag, multiple = false) case NAck(tag) => consume.basicNack(channel, tag, multiple = false, config.requeueOnNack) case Reject(tag) => consume.basicReject(channel, tag, config.requeueOnReject) } override def basicAck(channel: AMQPChannel, tag: DeliveryTag, multiple: Boolean): F[Unit] = consume.basicAck(channel, tag, multiple) override def basicNack(channel: AMQPChannel, tag: DeliveryTag, multiple: Boolean, requeue: Boolean): F[Unit] = consume.basicNack(channel, tag, multiple, requeue) override def basicReject(channel: AMQPChannel, tag: DeliveryTag, requeue: Boolean): F[Unit] = consume.basicReject(channel, tag, requeue) override def basicQos(channel: AMQPChannel, basicQos: BasicQos): F[Unit] = consume.basicQos(channel, basicQos) override def basicConsume[A](channel: AMQPChannel, queueName: QueueName, autoAck: Boolean, consumerTag: ConsumerTag, noLocal: Boolean, exclusive: Boolean, args: Arguments)(internals: AMQPInternals[F]): F[ConsumerTag] = consume.basicConsume(channel, queueName, autoAck, consumerTag, noLocal, exclusive, args)(internals) override def basicCancel(channel: AMQPChannel, consumerTag: ConsumerTag): F[Unit] = consume.basicCancel(channel, consumerTag) }
Example 136
Source File: ConsumingProgram.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.program import cats.effect.{Effect, Sync} import cats.implicits._ import dev.profunktor.fs2rabbit.algebra.ConsumingStream._ import dev.profunktor.fs2rabbit.algebra.{AMQPInternals, Consume, InternalQueue} import dev.profunktor.fs2rabbit.arguments.Arguments import dev.profunktor.fs2rabbit.effects.EnvelopeDecoder import dev.profunktor.fs2rabbit.model._ import fs2.Stream object ConsumingProgram { def make[F[_]: Effect](internalQueue: InternalQueue[F]): F[ConsumingProgram[F]] = Sync[F].delay { WrapperConsumingProgram(internalQueue, Consume.make) } } trait ConsumingProgram[F[_]] extends ConsumingStream[F] with Consume[F] case class WrapperConsumingProgram[F[_]: Effect] private ( internalQueue: InternalQueue[F], consume: Consume[F] ) extends ConsumingProgram[F] { override def createConsumer[A]( queueName: QueueName, channel: AMQPChannel, basicQos: BasicQos, autoAck: Boolean = false, noLocal: Boolean = false, exclusive: Boolean = false, consumerTag: ConsumerTag = ConsumerTag(""), args: Arguments = Map.empty )(implicit decoder: EnvelopeDecoder[F, A]): F[Stream[F, AmqpEnvelope[A]]] = { val setup = for { internalQ <- internalQueue.create internals = AMQPInternals[F](Some(internalQ)) _ <- consume.basicQos(channel, basicQos) consumerTag <- consume.basicConsume( channel, queueName, autoAck, consumerTag, noLocal, exclusive, args )(internals) } yield (consumerTag, internalQ) Stream .bracket(setup) { case (tag, _) => consume.basicCancel(channel, tag) } .flatMap { case (_, queue) => queue.dequeue.rethrow .evalMap(env => decoder(env).map(a => env.copy(payload = a))) } .pure[F] } override def basicAck(channel: AMQPChannel, tag: DeliveryTag, multiple: Boolean): F[Unit] = consume.basicAck(channel, tag, multiple) override def basicNack(channel: AMQPChannel, tag: DeliveryTag, multiple: Boolean, requeue: Boolean): F[Unit] = consume.basicNack(channel, tag, multiple, requeue) override def basicReject(channel: AMQPChannel, tag: DeliveryTag, requeue: Boolean): F[Unit] = consume.basicReject(channel, tag, requeue) override def basicQos(channel: AMQPChannel, basicQos: BasicQos): F[Unit] = consume.basicQos(channel, basicQos) override def basicConsume[A]( channel: AMQPChannel, queueName: QueueName, autoAck: Boolean, consumerTag: ConsumerTag, noLocal: Boolean, exclusive: Boolean, args: Arguments )(internals: AMQPInternals[F]): F[ConsumerTag] = consume.basicConsume(channel, queueName, autoAck, consumerTag, noLocal, exclusive, args)(internals) override def basicCancel(channel: AMQPChannel, consumerTag: ConsumerTag): F[Unit] = consume.basicCancel(channel, consumerTag) }
Example 137
Source File: StreamEval.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.effects import cats.effect.Sync import cats.syntax.functor._ import fs2.{Pipe, Stream} trait StreamEval[F[_]] { def pure[A](body: A): Stream[F, A] def evalF[A](body: => A): Stream[F, A] def evalDiscard[A](body: => A): Stream[F, Unit] def liftSink[A](f: A => F[Unit]): Pipe[F, A, Unit] def liftPipe[A, B](f: A => F[B]): Pipe[F, A, B] } object StreamEval { implicit def syncStreamEvalInstance[F[_]: Sync]: StreamEval[F] = new StreamEval[F] { override def pure[A](body: A): Stream[F, A] = Stream(body).covary[F] override def evalF[A](body: => A): Stream[F, A] = Stream.eval(Sync[F].delay(body)) override def evalDiscard[A](body: => A): Stream[F, Unit] = Stream.eval(Sync[F].delay(body).void) override def liftSink[A](f: A => F[Unit]): Pipe[F, A, Unit] = liftPipe[A, Unit](f) override def liftPipe[A, B](f: A => F[B]): Pipe[F, A, B] = _.evalMap(f) } }
Example 138
Source File: Log.scala From fs2-rabbit with Apache License 2.0 | 5 votes |
package dev.profunktor.fs2rabbit.effects import cats.effect.Sync import org.slf4j.LoggerFactory trait Log[F[_]] { def info(value: => String): F[Unit] def error(value: => String): F[Unit] } object Log { private[fs2rabbit] val logger = LoggerFactory.getLogger(this.getClass) def apply[F[_]](implicit ev: Log[F]): Log[F] = ev implicit def syncLogInstance[F[_]](implicit F: Sync[F]): Log[F] = new Log[F] { override def error(value: => String): F[Unit] = F.delay(logger.error(value)) override def info(value: => String): F[Unit] = F.delay(logger.info(value)) } }
Example 139
Source File: Markdown.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.convert.flexmark import java.io.{InputStream, InputStreamReader} import java.nio.charset.Charset import java.util import scala.util.Try import cats.effect.Sync import cats.implicits._ import fs2.Stream import docspell.common._ import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension import com.vladsch.flexmark.ext.tables.TablesExtension import com.vladsch.flexmark.html.HtmlRenderer import com.vladsch.flexmark.parser.Parser import com.vladsch.flexmark.util.data.{DataKey, MutableDataSet} object Markdown { def toHtml( is: InputStream, cfg: MarkdownConfig, cs: Charset ): Either[Throwable, String] = { val p = createParser() val r = createRenderer() Try { val reader = new InputStreamReader(is, cs) val doc = p.parseReader(reader) wrapHtml(r.render(doc), cfg) }.toEither } def toHtml(md: String, cfg: MarkdownConfig): String = { val p = createParser() val r = createRenderer() val doc = p.parse(md) wrapHtml(r.render(doc), cfg) } def toHtml[F[_]: Sync]( data: Stream[F, Byte], cfg: MarkdownConfig, cs: Charset ): F[String] = data.through(Binary.decode(cs)).compile.foldMonoid.map(str => toHtml(str, cfg)) private def wrapHtml(body: String, cfg: MarkdownConfig): String = s"""<!DOCTYPE html> |<html> |<head> |<meta charset="utf-8"/> |<style> |${cfg.internalCss} |</style> |</head> |<body> |$body |</body> |</html> |""".stripMargin private def createParser(): Parser = { val opts = new MutableDataSet() opts.set( Parser.EXTENSIONS.asInstanceOf[DataKey[util.Collection[_]]], util.Arrays.asList(TablesExtension.create(), StrikethroughExtension.create()) ); Parser.builder(opts).build() } private def createRenderer(): HtmlRenderer = { val opts = new MutableDataSet() HtmlRenderer.builder(opts).build() } }
Example 140
Source File: InfoRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.joex.routes import cats.effect.Sync import docspell.joex.BuildInfo import docspell.joexapi.model.VersionInfo import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object InfoRoutes { def apply[F[_]: Sync](): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ HttpRoutes.of[F] { case GET -> (Root / "version") => Ok( VersionInfo( BuildInfo.version, BuildInfo.builtAtMillis, BuildInfo.builtAtString, BuildInfo.gitHeadCommit.getOrElse(""), BuildInfo.gitDescribedVersion.getOrElse("") ) ) } } }
Example 141
Source File: EvalProposals.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.joex.process import java.time.{LocalDate, Period} import cats.effect.Sync import cats.implicits._ import docspell.common._ import docspell.joex.scheduler.Task import docspell.store.records.RAttachmentMeta object EvalProposals { def apply[F[_]: Sync](data: ItemData): Task[F, ProcessItemArgs, ItemData] = Task { _ => Timestamp .current[F] .map { now => val metas = data.metas.map(calcCandidateWeight(now.toUtcDate)) data.copy(metas = metas) } } def calcCandidateWeight(now: LocalDate)(rm: RAttachmentMeta): RAttachmentMeta = { val list = rm.proposals.change(mp => mp.addWeights(weight(rm, mp, now))) rm.copy(proposals = list.sortByWeights) } def weight(rm: RAttachmentMeta, mp: MetaProposal, ref: LocalDate)( cand: MetaProposal.Candidate ): Double = mp.proposalType match { case MetaProposalType.DueDate => //for due dates, sort earliest on top MetaProposal .parseDate(cand) .map { ld => val p = Period.between(ref, ld) // conversion only for sorting val d = p.getYears * 365 + p.getMonths * 31 + p.getDays d.toDouble } .getOrElse(2000.0) case _ => val textLen = rm.content.map(_.length).getOrElse(0) val tagCount = cand.origin.size.toDouble val pos = cand.origin.map(_.startPosition).min val words = cand.origin.map(_.label.split(' ').length).max.toDouble val nerFac = cand.origin.map(label => nerTagFactor(label.tag, mp.proposalType)).min (1 / words) * (1 / tagCount) * positionWeight(pos, textLen) * nerFac } def positionWeight(pos: Int, total: Int): Double = if (total <= 0) 1 else { val p = math.abs(pos.toDouble / total.toDouble) if (p < 0.7) p / 2 else p } def nerTagFactor(tag: NerTag, mt: MetaProposalType): Double = tag match { case NerTag.Date => 1.0 case NerTag.Email => 0.5 case NerTag.Location => 1.0 case NerTag.Misc => 1.0 case NerTag.Organization => if (mt == MetaProposalType.CorrOrg) 0.8 else 1.0 case NerTag.Person => if ( mt == MetaProposalType.CorrPerson || mt == MetaProposalType.ConcPerson ) 0.8 else 1.0 case NerTag.Website => 0.5 } }
Example 142
Source File: TextAnalysis.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.joex.process import cats.effect.Sync import cats.implicits._ import docspell.analysis.{TextAnalyser, TextAnalysisConfig} import docspell.common._ import docspell.joex.process.ItemData.AttachmentDates import docspell.joex.scheduler.Task import docspell.store.records.RAttachmentMeta object TextAnalysis { def apply[F[_]: Sync]( cfg: TextAnalysisConfig )(item: ItemData): Task[F, ProcessItemArgs, ItemData] = Task { ctx => TextAnalyser.create[F](cfg).use { analyser => for { _ <- ctx.logger.info("Starting text analysis") s <- Duration.stopTime[F] t <- item.metas.toList .traverse( annotateAttachment[F](ctx.args.meta.language, ctx.logger, analyser) ) _ <- ctx.logger.debug(s"Storing tags: ${t.map(_._1.copy(content = None))}") _ <- t.traverse(m => ctx.store.transact(RAttachmentMeta.updateLabels(m._1.id, m._1.nerlabels)) ) e <- s _ <- ctx.logger.info(s"Text-Analysis finished in ${e.formatExact}") v = t.toVector } yield item.copy(metas = v.map(_._1), dateLabels = v.map(_._2)) } } def annotateAttachment[F[_]: Sync]( lang: Language, logger: Logger[F], analyser: TextAnalyser[F] )(rm: RAttachmentMeta): F[(RAttachmentMeta, AttachmentDates)] = for { labels <- analyser.annotate(logger, lang, rm.content.getOrElse("")) } yield (rm.copy(nerlabels = labels.all.toList), AttachmentDates(rm, labels.dates)) }
Example 143
Source File: TestTasks.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.joex.process import cats.effect.Sync import cats.implicits._ import docspell.common.ProcessItemArgs import docspell.common.syntax.all._ import docspell.joex.scheduler.Task import org.log4s._ object TestTasks { private[this] val logger = getLogger def success[F[_]]: Task[F, ProcessItemArgs, Unit] = Task(ctx => ctx.logger.info(s"Running task now: ${ctx.args}")) def failing[F[_]: Sync]: Task[F, ProcessItemArgs, Unit] = Task { ctx => ctx.logger .info(s"Failing the task run :(") .map(_ => sys.error("Oh, cannot extract gold from this document")) } def longRunning[F[_]: Sync]: Task[F, ProcessItemArgs, Unit] = Task { ctx => logger.fwarn(s"${Thread.currentThread()} From executing long running task") >> ctx.logger.info(s"${Thread.currentThread()} Running task now: ${ctx.args}") >> sleep(2400) >> ctx.logger.debug("doing things") >> sleep(2400) >> ctx.logger.debug("doing more things") >> sleep(2400) >> ctx.logger.info("doing more things") } private def sleep[F[_]: Sync](ms: Long): F[Unit] = Sync[F].delay(Thread.sleep(ms)) }
Example 144
Source File: SaveProposals.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.joex.process import cats.effect.Sync import cats.implicits._ import docspell.common._ import docspell.joex.scheduler.Task import docspell.store.records._ object SaveProposals { def apply[F[_]: Sync](data: ItemData): Task[F, ProcessItemArgs, ItemData] = Task { ctx => ctx.logger.info("Storing proposals") *> data.metas .traverse(rm => ctx.logger.debug(s"Storing attachment proposals: ${rm.proposals}") *> ctx.store.transact(RAttachmentMeta.updateProposals(rm.id, rm.proposals)) ) .map(_ => data) } }
Example 145
Source File: QueueLogger.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.joex.scheduler import cats.effect.{Concurrent, Sync} import cats.implicits._ import fs2.concurrent.Queue import docspell.common._ object QueueLogger { def create[F[_]: Sync]( jobId: Ident, jobInfo: String, q: Queue[F, LogEvent] ): Logger[F] = new Logger[F] { def trace(msg: => String): F[Unit] = LogEvent.create[F](jobId, jobInfo, LogLevel.Debug, msg).flatMap(q.enqueue1) def debug(msg: => String): F[Unit] = LogEvent.create[F](jobId, jobInfo, LogLevel.Debug, msg).flatMap(q.enqueue1) def info(msg: => String): F[Unit] = LogEvent.create[F](jobId, jobInfo, LogLevel.Info, msg).flatMap(q.enqueue1) def warn(msg: => String): F[Unit] = LogEvent.create[F](jobId, jobInfo, LogLevel.Warn, msg).flatMap(q.enqueue1) def error(ex: Throwable)(msg: => String): F[Unit] = LogEvent .create[F](jobId, jobInfo, LogLevel.Error, msg) .map(le => le.copy(ex = Some(ex))) .flatMap(q.enqueue1) def error(msg: => String): F[Unit] = LogEvent.create[F](jobId, jobInfo, LogLevel.Error, msg).flatMap(q.enqueue1) } def apply[F[_]: Concurrent]( jobId: Ident, jobInfo: String, bufferSize: Int, sink: LogSink[F] ): F[Logger[F]] = for { q <- Queue.circularBuffer[F, LogEvent](bufferSize) log = create(jobId, jobInfo, q) _ <- Concurrent[F].start(q.dequeue.through(sink.receive).compile.drain) } yield log }
Example 146
Source File: LogSink.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.joex.scheduler import cats.effect.{Concurrent, Sync} import cats.implicits._ import fs2.{Pipe, Stream} import docspell.common._ import docspell.common.syntax.all._ import docspell.store.Store import docspell.store.records.RJobLog import org.log4s.{LogLevel => _, _} trait LogSink[F[_]] { def receive: Pipe[F, LogEvent, Unit] } object LogSink { private[this] val logger = getLogger def apply[F[_]](sink: Pipe[F, LogEvent, Unit]): LogSink[F] = new LogSink[F] { val receive = sink } def logInternal[F[_]: Sync](e: LogEvent): F[Unit] = e.level match { case LogLevel.Info => logger.finfo(e.logLine) case LogLevel.Debug => logger.fdebug(e.logLine) case LogLevel.Warn => logger.fwarn(e.logLine) case LogLevel.Error => e.ex match { case Some(exc) => logger.ferror(exc)(e.logLine) case None => logger.ferror(e.logLine) } } def printer[F[_]: Sync]: LogSink[F] = LogSink(_.evalMap(e => logInternal(e))) def db[F[_]: Sync](store: Store[F]): LogSink[F] = LogSink( _.evalMap(ev => for { id <- Ident.randomId[F] joblog = RJobLog( id, ev.jobId, ev.level, ev.time, ev.msg + ev.ex.map(th => ": " + th.getMessage).getOrElse("") ) _ <- logInternal(ev) _ <- store.transact(RJobLog.insert(joblog)) } yield () ) ) def dbAndLog[F[_]: Concurrent](store: Store[F]): LogSink[F] = { val s: Stream[F, Pipe[F, LogEvent, Unit]] = Stream.emits(Seq(printer[F].receive, db[F](store).receive)) LogSink(Pipe.join(s)) } }
Example 147
Source File: LogEvent.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.joex.scheduler import cats.effect.Sync import cats.implicits._ import docspell.common._ case class LogEvent( jobId: Ident, jobInfo: String, time: Timestamp, level: LogLevel, msg: String, ex: Option[Throwable] = None ) { def logLine: String = s">>> ${time.asString} $level $jobInfo: $msg" } object LogEvent { def create[F[_]: Sync]( jobId: Ident, jobInfo: String, level: LogLevel, msg: String ): F[LogEvent] = Timestamp.current[F].map(now => LogEvent(jobId, jobInfo, now, level, msg)) }
Example 148
Source File: JobTask.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.joex.scheduler import cats.effect.Sync import cats.implicits._ import docspell.common.Ident import docspell.common.syntax.all._ import io.circe.Decoder case class JobTask[F[_]]( name: Ident, task: Task[F, String, Unit], onCancel: Task[F, String, Unit] ) object JobTask { def json[F[_]: Sync, A]( name: Ident, task: Task[F, A, Unit], onCancel: Task[F, A, Unit] )(implicit D: Decoder[A] ): JobTask[F] = { val convert: String => F[A] = str => str.parseJsonAs[A] match { case Right(a) => a.pure[F] case Left(ex) => Sync[F].raiseError(new Exception(s"Cannot parse task arguments: $str", ex)) } JobTask(name, task.contramap(convert), onCancel.contramap(convert)) } }
Example 149
Source File: TextExtract.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.extract.ocr import cats.effect.{Blocker, ContextShift, Sync} import fs2.Stream import docspell.common._ import docspell.extract.internal.Text import docspell.files._ object TextExtract { def extract[F[_]: Sync: ContextShift]( in: Stream[F, Byte], blocker: Blocker, logger: Logger[F], lang: String, config: OcrConfig ): Stream[F, Text] = extractOCR(in, blocker, logger, lang, config) def extractOCR[F[_]: Sync: ContextShift]( in: Stream[F, Byte], blocker: Blocker, logger: Logger[F], lang: String, config: OcrConfig ): Stream[F, Text] = Stream .eval(TikaMimetype.detect(in, MimeTypeHint.none)) .flatMap({ case MimeType.pdf => Stream.eval(Ocr.extractPdf(in, blocker, logger, lang, config)).unNoneTerminate case mt if mt.primary == "image" => Ocr.extractImage(in, blocker, logger, lang, config) case mt => raiseError(s"File `$mt` not supported") }) .map(Text.apply) private def raiseError[F[_]: Sync](msg: String): Stream[F, Nothing] = Stream.raiseError[F](new Exception(msg)) }
Example 150
Source File: PdfboxExtract.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.extract.pdfbox import java.io.InputStream import java.nio.file.Path import scala.util.{Try, Using} import cats.effect.Sync import cats.implicits._ import fs2.Stream import docspell.extract.internal.Text import org.apache.pdfbox.pdmodel.PDDocument import org.apache.pdfbox.text.PDFTextStripper object PdfboxExtract { def get[F[_]: Sync](data: Stream[F, Byte]): F[Either[Throwable, Text]] = data.compile .to(Array) .map(bytes => Using(PDDocument.load(bytes))(readText).toEither.flatten) def get(is: InputStream): Either[Throwable, Text] = Using(PDDocument.load(is))(readText).toEither.flatten def get(inFile: Path): Either[Throwable, Text] = Using(PDDocument.load(inFile.toFile))(readText).toEither.flatten private def readText(doc: PDDocument): Either[Throwable, Text] = Try { val stripper = new PDFTextStripper() stripper.setAddMoreFormatting(true) stripper.setLineSeparator("\n") Text(Option(stripper.getText(doc))) }.toEither }
Example 151
Source File: RtfExtract.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.extract.rtf import java.io.{ByteArrayInputStream, InputStream} import javax.swing.text.rtf.RTFEditorKit import scala.util.Try import cats.effect.Sync import cats.implicits._ import fs2.Stream import docspell.common.MimeType import docspell.extract.internal.Text object RtfExtract { val rtfType = MimeType.application("rtf") def get(is: InputStream): Either[Throwable, Text] = Try { val kit = new RTFEditorKit() val doc = kit.createDefaultDocument() kit.read(is, doc, 0) Text(doc.getText(0, doc.getLength)) }.toEither def get[F[_]: Sync](data: Stream[F, Byte]): F[Either[Throwable, Text]] = data.compile.to(Array).map(new ByteArrayInputStream(_)).map(get) }
Example 152
Source File: PoiExtract.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.extract.poi import java.io.{ByteArrayInputStream, InputStream} import scala.util.Try import cats.data.EitherT import cats.effect.Sync import cats.implicits._ import fs2.Stream import docspell.common._ import docspell.extract.internal.Text import docspell.files.TikaMimetype import org.apache.poi.hssf.extractor.ExcelExtractor import org.apache.poi.hssf.usermodel.HSSFWorkbook import org.apache.poi.hwpf.extractor.WordExtractor import org.apache.poi.xssf.extractor.XSSFExcelExtractor import org.apache.poi.xssf.usermodel.XSSFWorkbook import org.apache.poi.xwpf.extractor.XWPFWordExtractor import org.apache.poi.xwpf.usermodel.XWPFDocument object PoiExtract { def get[F[_]: Sync]( data: Stream[F, Byte], hint: MimeTypeHint ): F[Either[Throwable, Text]] = TikaMimetype.detect(data, hint).flatMap(mt => get(data, mt)) def get[F[_]: Sync]( data: Stream[F, Byte], mime: MimeType ): F[Either[Throwable, Text]] = mime match { case PoiType.doc => getDoc(data) case PoiType.xls => getXls(data) case PoiType.xlsx => getXlsx(data) case PoiType.docx => getDocx(data) case PoiType.msoffice => EitherT(getDoc[F](data)) .recoverWith({ case _ => EitherT(getXls[F](data)) }) .value case PoiType.ooxml => EitherT(getDocx[F](data)) .recoverWith({ case _ => EitherT(getXlsx[F](data)) }) .value case mt => Sync[F].pure(Left(new Exception(s"Unsupported content: ${mt.asString}"))) } def getDocx(is: InputStream): Either[Throwable, Text] = Try { val xt = new XWPFWordExtractor(new XWPFDocument(is)) Text(Option(xt.getText)) }.toEither def getDoc(is: InputStream): Either[Throwable, Text] = Try { val xt = new WordExtractor(is) Text(Option(xt.getText)) }.toEither def getXlsx(is: InputStream): Either[Throwable, Text] = Try { val xt = new XSSFExcelExtractor(new XSSFWorkbook(is)) Text(Option(xt.getText)) }.toEither def getXls(is: InputStream): Either[Throwable, Text] = Try { val xt = new ExcelExtractor(new HSSFWorkbook(is)) Text(Option(xt.getText)) }.toEither def getDocx[F[_]: Sync](data: Stream[F, Byte]): F[Either[Throwable, Text]] = data.compile.to(Array).map(new ByteArrayInputStream(_)).map(getDocx) def getDoc[F[_]: Sync](data: Stream[F, Byte]): F[Either[Throwable, Text]] = data.compile.to(Array).map(new ByteArrayInputStream(_)).map(getDoc) def getXlsx[F[_]: Sync](data: Stream[F, Byte]): F[Either[Throwable, Text]] = data.compile.to(Array).map(new ByteArrayInputStream(_)).map(getXlsx) def getXls[F[_]: Sync](data: Stream[F, Byte]): F[Either[Throwable, Text]] = data.compile.to(Array).map(new ByteArrayInputStream(_)).map(getXls) }
Example 153
Source File: StreamSyntax.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.common.syntax import cats.effect.Sync import cats.implicits._ import fs2.Stream import io.circe._ import io.circe.parser._ trait StreamSyntax { implicit class StringStreamOps[F[_]](s: Stream[F, String]) { def parseJsonAs[A](implicit d: Decoder[A], F: Sync[F]): F[Either[Throwable, A]] = s.fold("")(_ + _) .compile .last .map(optStr => for { str <- optStr .map(_.trim) .toRight(new Exception("Empty string cannot be parsed into a value")) json <- parse(str).leftMap(_.underlying) value <- json.as[A] } yield value ) } }
Example 154
Source File: Ident.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.common import java.security.SecureRandom import java.util.UUID import cats.Eq import cats.effect.Sync import cats.implicits._ import io.circe.{Decoder, Encoder} import scodec.bits.ByteVector case class Ident(id: String) { def isEmpty: Boolean = id.trim.isEmpty def nonEmpty: Boolean = !isEmpty def /(next: Ident): Ident = new Ident(id + "." + next.id) } object Ident { implicit val identEq: Eq[Ident] = Eq.by(_.id) val chars: Set[Char] = (('A' to 'Z') ++ ('a' to 'z') ++ ('0' to '9') ++ "-_.").toSet def randomUUID[F[_]: Sync]: F[Ident] = Sync[F].delay(unsafe(UUID.randomUUID.toString)) def randomId[F[_]: Sync]: F[Ident] = Sync[F].delay { val random = new SecureRandom() val buffer = new Array[Byte](32) random.nextBytes(buffer) unsafe(ByteVector.view(buffer).toBase58.grouped(11).mkString("-")) } def apply(str: String): Either[String, Ident] = fromString(str) def fromString(s: String): Either[String, Ident] = if (s.forall(chars.contains)) Right(new Ident(s)) else Left(s"Invalid identifier: '$s'. Allowed chars: ${chars.toList.sorted.mkString}") def fromBytes(bytes: ByteVector): Ident = unsafe(bytes.toBase58) def fromByteArray(bytes: Array[Byte]): Ident = fromBytes(ByteVector.view(bytes)) def unsafe(s: String): Ident = fromString(s) match { case Right(id) => id case Left(err) => sys.error(err) } def unapply(arg: String): Option[Ident] = fromString(arg).toOption implicit val encodeIdent: Encoder[Ident] = Encoder.encodeString.contramap(_.id) implicit val decodeIdent: Decoder[Ident] = Decoder.decodeString.emap(Ident.fromString) }
Example 155
Source File: InfoRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect.Sync import docspell.restapi.model.VersionInfo import docspell.restserver.BuildInfo import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object InfoRoutes { def apply[F[_]: Sync](): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ HttpRoutes.of[F] { case GET -> (Root / "version") => Ok( VersionInfo( BuildInfo.version, BuildInfo.builtAtMillis, BuildInfo.builtAtString, BuildInfo.gitHeadCommit.getOrElse(""), BuildInfo.gitDescribedVersion.getOrElse("") ) ) } } }
Example 156
Source File: RNode.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.store.records import cats.effect.Sync import cats.implicits._ import docspell.common._ import docspell.store.impl.Column import docspell.store.impl.Implicits._ import doobie._ import doobie.implicits._ case class RNode( id: Ident, nodeType: NodeType, url: LenientUri, updated: Timestamp, created: Timestamp ) {} object RNode { def apply[F[_]: Sync](id: Ident, nodeType: NodeType, uri: LenientUri): F[RNode] = Timestamp.current[F].map(now => RNode(id, nodeType, uri, now, now)) val table = fr"node" object Columns { val id = Column("id") val nodeType = Column("type") val url = Column("url") val updated = Column("updated") val created = Column("created") val all = List(id, nodeType, url, updated, created) } import Columns._ def insert(v: RNode): ConnectionIO[Int] = insertRow( table, all, fr"${v.id},${v.nodeType},${v.url},${v.updated},${v.created}" ).update.run def update(v: RNode): ConnectionIO[Int] = updateRow( table, id.is(v.id), commas( nodeType.setTo(v.nodeType), url.setTo(v.url), updated.setTo(v.updated) ) ).update.run def set(v: RNode): ConnectionIO[Int] = for { n <- update(v) k <- if (n == 0) insert(v) else 0.pure[ConnectionIO] } yield n + k def delete(appId: Ident): ConnectionIO[Int] = (fr"DELETE FROM" ++ table ++ where(id.is(appId))).update.run def findAll(nt: NodeType): ConnectionIO[Vector[RNode]] = selectSimple(all, table, nodeType.is(nt)).query[RNode].to[Vector] def findById(nodeId: Ident): ConnectionIO[Option[RNode]] = selectSimple(all, table, id.is(nodeId)).query[RNode].option }
Example 157
Source File: RInvitation.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.store.records import cats.effect.Sync import cats.implicits._ import docspell.common._ import docspell.store.impl.Implicits._ import docspell.store.impl._ import doobie._ import doobie.implicits._ case class RInvitation(id: Ident, created: Timestamp) {} object RInvitation { val table = fr"invitation" object Columns { val id = Column("id") val created = Column("created") val all = List(id, created) } import Columns._ def generate[F[_]: Sync]: F[RInvitation] = for { c <- Timestamp.current[F] i <- Ident.randomId[F] } yield RInvitation(i, c) def insert(v: RInvitation): ConnectionIO[Int] = insertRow(table, all, fr"${v.id},${v.created}").update.run def insertNew: ConnectionIO[RInvitation] = generate[ConnectionIO].flatMap(v => insert(v).map(_ => v)) def findById(invite: Ident): ConnectionIO[Option[RInvitation]] = selectSimple(all, table, id.is(invite)).query[RInvitation].option def delete(invite: Ident): ConnectionIO[Int] = deleteFrom(table, id.is(invite)).update.run def useInvite(invite: Ident, minCreated: Timestamp): ConnectionIO[Boolean] = { val get = selectCount(id, table, and(id.is(invite), created.isGt(minCreated))) .query[Int] .unique for { inv <- get _ <- delete(invite) } yield inv > 0 } def deleteOlderThan(ts: Timestamp): ConnectionIO[Int] = deleteFrom(table, created.isLt(ts)).update.run }
Example 158
Source File: FlywayMigrate.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.store.migrate import cats.effect.Sync import docspell.store.JdbcConfig import org.flywaydb.core.Flyway import org.log4s._ object FlywayMigrate { private[this] val logger = getLogger def run[F[_]: Sync](jdbc: JdbcConfig): F[Int] = Sync[F].delay { logger.info("Running db migrations...") val locations = jdbc.dbmsName match { case Some(dbtype) => val name = if (dbtype == "h2") "postgresql" else dbtype List(s"classpath:db/migration/${name}") case None => logger.warn( s"Cannot read database name from jdbc url: ${jdbc.url}. Go with PostgreSQL" ) List("classpath:db/postgresql") } logger.info(s"Using migration locations: $locations") val fw = Flyway .configure() .cleanDisabled(true) .dataSource(jdbc.url.asString, jdbc.user, jdbc.password) .locations(locations: _*) .load() fw.repair() fw.migrate() } }
Example 159
Source File: TestSupport.scala From cedi-dtrace with Apache License 2.0 | 5 votes |
package com.ccadllc.cedi.dtrace package logging import cats.effect.{ IO, Sync } import io.circe._ import io.circe.syntax._ import org.scalacheck.Arbitrary import org.scalatest.Suite import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import shapeless.Lazy trait TestSupport extends AnyWordSpecLike with Matchers with ScalaCheckPropertyChecks with TraceGenerators with TestData { self: Suite => override def testEmitter[F[_]: Sync]: F[TraceSystem.Emitter[F]] = Sync[F].pure(LogEmitter.apply) val salesManagementSystem = TraceSystem(testSystemData, testEmitter[IO].unsafeRunSync, TraceSystem.realTimeTimer[IO]) val calculateQuarterlySalesTraceContext = TraceContext(quarterlySalesCalculationSpan, true, salesManagementSystem) def encodeGeneratedJson[A: Arbitrary](implicit encoder: Lazy[Encoder[A]]): Unit = { implicit val e = encoder.value "encode arbitrary instances to JSON" in { forAll { (msg: A) => msg.asJson.noSpaces should not be (None) } } } def encodeSpecificJson[A](a: A, json: Json)(implicit encoder: Lazy[Encoder[A]]): Unit = { implicit val e = encoder.value "encode specific instance to JSON and ensure it matches expected" in { a.asJson shouldBe json } } }
Example 160
Source File: LogstashLogbackEmitter.scala From cedi-dtrace with Apache License 2.0 | 5 votes |
package com.ccadllc.cedi.dtrace package logstash import cats.effect.Sync import cats.implicits._ import net.logstash.logback.marker.LogstashMarker import net.logstash.logback.marker.Markers._ import org.slf4j.LoggerFactory import scala.collection.JavaConverters._ @deprecated("use EcsLogstashLogbackEmitter", "2.0.0") final class LogstashLogbackEmitter[F[_]](implicit F: Sync[F]) extends TraceSystem.Emitter[F] { private val logger = LoggerFactory.getLogger("distributed-trace.logstash") final val description: String = "Logstash Logback Emitter" final def emit(tc: TraceContext[F]): F[Unit] = F.delay { if (logger.isDebugEnabled) { val s = tc.currentSpan val marker: LogstashMarker = append("where", tc.system.data.allValues.asJava). and[LogstashMarker](append("root", s.root)). and[LogstashMarker](append("trace-id", s.spanId.traceId.toString)). and[LogstashMarker](append("span-id", s.spanId.spanId)). and[LogstashMarker](append("parent-id", s.spanId.parentSpanId)). and[LogstashMarker](append("span-name", s.spanName.value)). and[LogstashMarker](append("start-time", s.startTime.show)). and[LogstashMarker](append("span-success", s.failure.isEmpty)). and[LogstashMarker](append("failure-detail", s.failure.map(_.render).orNull)). and[LogstashMarker](append("span-duration", s.duration.toMicros)). and[LogstashMarker](append("notes", s.notes.map(n => n.name.value -> n.value).collect { case (name, Some(value)) => name -> value.toString }.toMap.asJava)) logger.debug(marker, "Span {} {} after {} microseconds", s.spanName.value, if (s.failure.isEmpty) "succeeded" else "failed", s.duration.toMicros.toString) } } }
Example 161
Source File: EcsLogstashLogbackEmitter.scala From cedi-dtrace with Apache License 2.0 | 5 votes |
package com.ccadllc.cedi.dtrace package logstash import cats.effect.Sync import cats.implicits._ import net.logstash.logback.marker.LogstashMarker import net.logstash.logback.marker.Markers._ import org.slf4j.LoggerFactory import scala.collection.JavaConverters._ final class EcsLogstashLogbackEmitter[F[_]](implicit F: Sync[F]) extends TraceSystem.Emitter[F] { object ecs { object field { val kind: String = "event.kind" val module: String = "event.module" val root: String = "dtrace.root" val traceId: String = "dtrace.trace_id" val parentId: String = "dtrace.parent_id" val spanId: String = "event.id" val spanName: String = "event.action" val spanStart: String = "event.start" val spanOutcome: String = "event.outcome" val spanDuration: String = "event.duration" val spanFailureDetail: String = "error.message" val spanMetadata: String = "labels" } } private val logger = LoggerFactory.getLogger("distributed-trace.ecs.logstash") final val description: String = "ECS-Compliant Logstash Logback Emitter" final def emit(tc: TraceContext[F]): F[Unit] = F.delay { if (logger.isDebugEnabled) { val s = tc.currentSpan val marker: LogstashMarker = { val m = append(ecs.field.kind, "event"). and[LogstashMarker](append(ecs.field.module, "dtrace")). and[LogstashMarker](append(ecs.field.root, s.root)). and[LogstashMarker](append(ecs.field.traceId, s.spanId.traceId.toString)). and[LogstashMarker](append(ecs.field.parentId, s.spanId.parentSpanId)). and[LogstashMarker](append(ecs.field.spanId, s.spanId.spanId)). and[LogstashMarker](append(ecs.field.spanName, s.spanName.value)). and[LogstashMarker](append(ecs.field.spanStart, s.startTime.show)). and[LogstashMarker](append(ecs.field.spanOutcome, if (s.failure.isEmpty) "success" else "failure")). and[LogstashMarker](append(ecs.field.spanDuration, s.duration.toUnit(tc.system.timer.unit))). and[LogstashMarker](append(ecs.field.spanFailureDetail, s.failure.map(_.render).orNull)). and[LogstashMarker](append( ecs.field.spanMetadata, (tc.system.data.meta.values ++ s.notes.map( n => n.name.value -> n.value).collect { case (name, Some(value)) => name -> value.toString }.toMap).asJava)) tc.system.data.identity.values.foldLeft(m) { case (acc, (k, v)) => acc.and[LogstashMarker](append(k, v)) } } logger.debug(marker, s"Span {} {} after {} ${tc.system.timer.unit.toString.toLowerCase}s", s.spanName.value, if (s.failure.isEmpty) "succeeded" else "failed", s.duration.toUnit(tc.system.timer.unit).toString) } } }
Example 162
Source File: TestEmitter.scala From cedi-dtrace with Apache License 2.0 | 5 votes |
package com.ccadllc.cedi.dtrace import cats.effect.Sync class TestEmitter[F[_]](implicit F: Sync[F]) extends TraceSystem.Emitter[F] { class EmitterTestCache { case class EmitterTestEntry(msg: String, tc: TraceContext[F]) private var emitterLogCache: Vector[EmitterTestEntry] = Vector.empty def put(msg: String, tc: TraceContext[F]): Unit = synchronized { emitterLogCache = emitterLogCache :+ EmitterTestEntry(msg.toLowerCase, tc) } def all: Vector[EmitterTestEntry] = emitterLogCache def containingAll(substrings: String*): Vector[EmitterTestEntry] = { def containing(substrings: Seq[String])(predicate: (EmitterTestEntry, Seq[String]) => Boolean): Vector[EmitterTestEntry] = { require(!substrings.isEmpty) val lowerSubstrings = substrings map { _.toLowerCase } emitterLogCache filter { predicate(_, lowerSubstrings) } } containing(substrings) { (e, strings) => strings forall { e.msg.contains } } } } val cache = new EmitterTestCache override def description: String = "Test Emitter" override def emit(tc: TraceContext[F]): F[Unit] = { def formatText(context: TraceContext[F]) = { s"Span: [ span-id=${context.currentSpan.spanId.spanId} ] [ trace-id=${context.currentSpan.spanId.traceId} ] [ parent-id=${context.currentSpan.spanId.parentSpanId} ] [ span-name=${context.currentSpan.spanName} ] [ system-data=${context.system.data.description} ] [ start-time=${context.currentSpan.startTime} ] [ span-duration=${context.currentSpan.duration} ] [ span-success=${context.currentSpan.failure.isEmpty} ] [ failure-detail=${context.currentSpan.failure.fold("N/A")(_.render)} ][ notes=[${context.currentSpan.notes.mkString("] [")}] ]" } F.delay(cache.put(formatText(tc), tc)) } }
Example 163
Source File: TestClient.scala From franklin with Apache License 2.0 | 5 votes |
package com.azavea.franklin.api import cats.effect.Resource import cats.effect.Sync import cats.implicits._ import com.azavea.franklin.api.services.{CollectionItemsService, CollectionsService} import com.azavea.stac4s.{StacCollection, StacItem} import eu.timepit.refined.auto._ import io.circe.syntax._ import org.http4s.circe.CirceEntityDecoder._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.implicits._ import org.http4s.{Method, Request, Uri} import java.net.URLEncoder import java.nio.charset.StandardCharsets class TestClient[F[_]: Sync]( collectionsService: CollectionsService[F], collectionItemsService: CollectionItemsService[F] ) { private def createCollection(collection: StacCollection): F[StacCollection] = collectionsService.routes.orNotFound.run( Request( method = Method.POST, uri = Uri.unsafeFromString("/collections") ).withEntity(collection.asJson) ) flatMap { _.as[StacCollection] } private def deleteCollection(collection: StacCollection): F[Unit] = { val encodedCollectionId = URLEncoder.encode(collection.id, StandardCharsets.UTF_8.toString) collectionsService.routes.orNotFound .run( Request( method = Method.DELETE, uri = Uri.unsafeFromString(s"/collections/$encodedCollectionId") ) ) .void } private def createItemInCollection(collection: StacCollection, item: StacItem): F[StacItem] = { val encodedCollectionId = URLEncoder.encode(collection.id, StandardCharsets.UTF_8.toString) collectionItemsService.routes.orNotFound.run( Request( method = Method.POST, uri = Uri.unsafeFromString(s"/collections/$encodedCollectionId/items") ).withEntity(item) ) flatMap { _.as[StacItem] } } private def deleteItemInCollection(collection: StacCollection, item: StacItem): F[Unit] = { val encodedCollectionId = URLEncoder.encode(collection.id, StandardCharsets.UTF_8.toString) val encodedItemId = URLEncoder.encode(item.id, StandardCharsets.UTF_8.toString) collectionItemsService.routes.orNotFound .run( Request( method = Method.DELETE, uri = Uri.unsafeFromString(s"/collections/$encodedCollectionId/items/$encodedItemId") ) ) .void } def getItemResource(collection: StacCollection, item: StacItem): Resource[F, StacItem] = Resource.make(createItemInCollection(collection, item.copy(collection = Some(collection.id))))( item => deleteItemInCollection(collection, item) ) def getCollectionResource(collection: StacCollection): Resource[F, StacCollection] = Resource.make(createCollection(collection))(collection => deleteCollection(collection)) def getCollectionItemResource( item: StacItem, collection: StacCollection ): Resource[F, (StacItem, StacCollection)] = (getItemResource(collection, item), getCollectionResource(collection)).tupled }
Example 164
Source File: TestServices.scala From franklin with Apache License 2.0 | 5 votes |
package com.azavea.franklin.api import cats.effect.{ContextShift, Sync} import com.azavea.franklin.api.commands.ApiConfig import com.azavea.franklin.api.services.{CollectionItemsService, CollectionsService, SearchService} import doobie.Transactor import eu.timepit.refined.types.numeric.{NonNegInt, PosInt} class TestServices[F[_]: Sync](xa: Transactor[F])(implicit cs: ContextShift[F]) { val apiConfig: ApiConfig = ApiConfig(PosInt(9090), PosInt(9090), "localhost", "http", NonNegInt(30), true, false) val searchService: SearchService[F] = new SearchService[F](apiConfig.apiHost, NonNegInt(30), apiConfig.enableTiles, xa) val collectionsService: CollectionsService[F] = new CollectionsService[F]( xa, apiConfig ) val collectionItemsService: CollectionItemsService[F] = new CollectionItemsService[F]( xa, apiConfig ) }
Example 165
Source File: TestConsole.scala From console4cats with Apache License 2.0 | 5 votes |
package cats.effect.test import cats._ import cats.data.Chain import cats.effect.concurrent.Ref import cats.effect.{ Console, Sync } import cats.syntax.functor._ import cats.syntax.show._ private class TestConsole[F[_]: Applicative]( outLines: Ref[F, Chain[String]], outWords: Ref[F, Chain[String]], outErrors: Ref[F, Chain[String]], val readLn: F[String] ) extends Console[F] { override def putStrLn[A: Show](a: A): F[Unit] = outLines.update(_.append(a.show)) override def putStr[A: Show](a: A): F[Unit] = outWords.update(_.append(a.show)) override def putError[A: Show](a: A): F[Unit] = outErrors.update(_.append(a.show)) } object TestConsole { def sequenceAndDefault[F[_]: Sync]( inputs: Chain[String], default: String ): F[F[String]] = Ref[F].of(inputs).map { _.modify { _.uncons match { case Some((head, tail)) => (tail, head) case None => (Chain.nil, default) } } } } }
Example 166
Source File: TracedPrograms.scala From http4s-tracer with Apache License 2.0 | 5 votes |
package dev.profunktor.tracer.module.tracer import cats.Parallel import cats.effect.Sync import cats.syntax.apply._ import dev.profunktor.tracer.Trace.Trace import dev.profunktor.tracer.TracerLog import dev.profunktor.tracer.algebra.UserAlgebra import dev.profunktor.tracer.model.user.{User, Username} import dev.profunktor.tracer.module.{LivePrograms, Programs} case class TracedPrograms[F[_]: Parallel: Sync: λ[T[_] => TracerLog[Trace[T, ?]]]]( repos: TracedRepositories[F], clients: TracedHttpClients[F] ) extends Programs[Trace[F, ?]] { private val programs = LivePrograms[Trace[F, ?]](repos, clients) override val users: UserAlgebra[Trace[F, ?]] = new UserTracer[F](programs.users) } private[tracer] final class UserTracer[F[_]: Sync]( users: UserAlgebra[Trace[F, ?]] )(implicit L: TracerLog[Trace[F, ?]]) extends UserAlgebra[Trace[F, ?]] { override def find(username: Username): Trace[F, User] = L.info[UserAlgebra[F]](s"Find user by username: ${username.value}") *> users.find(username) override def persist(user: User): Trace[F, Unit] = L.info[UserAlgebra[F]](s"About to persist user: ${user.username.value}") *> users.persist(user) }
Example 167
Source File: TracedHttpClients.scala From http4s-tracer with Apache License 2.0 | 5 votes |
package dev.profunktor.tracer.module.tracer import cats.effect.Sync import cats.syntax.apply._ import dev.profunktor.tracer.Trace.Trace import dev.profunktor.tracer.http.client.UserRegistry import dev.profunktor.tracer.model.user.User import dev.profunktor.tracer.module.{HttpClients, LiveHttpClients} import dev.profunktor.tracer.{Trace, TracerLog} import org.http4s.client.Client case class TracedHttpClients[F[_]: Sync: λ[T[_] => TracerLog[Trace[T, ?]]]] private ( client: Client[F] ) extends HttpClients[Trace[F, ?]] { private val clients = LiveHttpClients[F](client) override val userRegistry: UserRegistry[Trace[F, ?]] = new TracedUserRegistry[F](clients.userRegistry) } private[tracer] final class TracedUserRegistry[F[_]: Sync]( registry: UserRegistry[F] )(implicit L: TracerLog[Trace[F, ?]]) extends UserRegistry[Trace[F, ?]] { override def register(user: User): Trace[F, Unit] = L.info[UserRegistry[F]](s"Registering user: ${user.username.value}") *> Trace(_ => registry.register(user)) }
Example 168
Source File: Repositories.scala From http4s-tracer with Apache License 2.0 | 5 votes |
package dev.profunktor.tracer.module import cats.effect.Sync import cats.syntax.functor._ import dev.profunktor.tracer.repository.algebra.UserRepository import dev.profunktor.tracer.repository.interpreter.MemUserRepository private[module] trait Repositories[F[_]] { def users: UserRepository[F] } object LiveRepositories { def apply[F[_]: Sync]: F[Repositories[F]] = MemUserRepository.create[F].map(new LiveRepositories[F](_)) } final class LiveRepositories[F[_]](usersRepo: UserRepository[F]) extends Repositories[F] { val users: UserRepository[F] = usersRepo }
Example 169
Source File: MemUserRepository.scala From http4s-tracer with Apache License 2.0 | 5 votes |
package dev.profunktor.tracer.repository.interpreter import cats.effect.Sync import cats.effect.concurrent.Ref import cats.syntax.all._ import dev.profunktor.tracer.model.user.{User, Username} import dev.profunktor.tracer.repository.algebra.UserRepository object MemUserRepository { def create[F[_]: Sync]: F[UserRepository[F]] = Ref.of[F, Map[Username, User]](Map.empty).map(new MemUserRepository[F](_)) } class MemUserRepository[F[_]: Sync] private ( state: Ref[F, Map[Username, User]] ) extends UserRepository[F] { def find(username: Username): F[Option[User]] = state.get.map(_.get(username)) def persist(user: User): F[Unit] = state.update(_.updated(user.username, user)) }
Example 170
Source File: UserRoutes.scala From http4s-tracer with Apache License 2.0 | 5 votes |
package dev.profunktor.tracer.http import cats.effect.Sync import cats.syntax.all._ import dev.profunktor.tracer.Trace._ import dev.profunktor.tracer.algebra.UserAlgebra import dev.profunktor.tracer.model.user.{User, Username} import dev.profunktor.tracer.model.errors.UserError._ import dev.profunktor.tracer.{Http4sTracerDsl, TracedHttpRoute, Tracer} import org.http4s._ import org.http4s.server.Router class UserRoutes[F[_]: Sync: Tracer](users: UserAlgebra[Trace[F, ?]]) extends Http4sTracerDsl[F] { private[http] val PathPrefix = "/users" private val httpRoutes: HttpRoutes[F] = TracedHttpRoute[F] { case GET -> Root / username using traceId => users .find(Username(username)) .run(traceId) .flatMap(user => Ok(user)) .handleErrorWith { case UserNotFound(u) => NotFound(u.value) } case tr @ POST -> Root using traceId => tr.request.decode[User] { user => users .persist(user) .run(traceId) .flatMap(_ => Created()) .handleErrorWith { case UserAlreadyExists(u) => Conflict(u.value) } } } val routes: HttpRoutes[F] = Router( PathPrefix -> httpRoutes ) }
Example 171
Source File: UserRegistry.scala From http4s-tracer with Apache License 2.0 | 5 votes |
package dev.profunktor.tracer.http package client import cats.effect.Sync import cats.syntax.functor._ import dev.profunktor.tracer.model.user.User import io.circe.syntax._ import org.http4s.Method._ import org.http4s.Uri import org.http4s.client.Client import org.http4s.client.dsl.Http4sClientDsl trait UserRegistry[F[_]] { def register(user: User): F[Unit] } final case class LiveUserRegistry[F[_]: Sync]( client: Client[F] ) extends UserRegistry[F] with Http4sClientDsl[F] { private val uri = Uri.uri("https://jsonplaceholder.typicode.com/posts") def register(user: User): F[Unit] = client.successful(POST(user.asJson, uri)).void }
Example 172
Source File: AuthRoutes.scala From http4s-tracer with Apache License 2.0 | 5 votes |
package dev.profunktor.tracer.http import cats.effect.Sync import cats.syntax.flatMap._ import dev.profunktor.tracer.Trace._ import dev.profunktor.tracer.Tracer import dev.profunktor.tracer.algebra.UserAlgebra import dev.profunktor.tracer.auth.{AuthTracedHttpRoute, Http4sAuthTracerDsl} import dev.profunktor.tracer.model.user.Username import io.circe.generic.auto._ import org.http4s._ import org.http4s.server.{AuthMiddleware, Router} class AuthRoutes[F[_]: Sync: Tracer](users: UserAlgebra[Trace[F, ?]]) extends Http4sAuthTracerDsl[F] { private[http] val PathPrefix = "/auth" private val httpRoutes: AuthedRoutes[String, F] = AuthTracedHttpRoute[String, F] { case GET -> Root as user using traceId => users.find(Username(user)).run(traceId) >> Ok(user -> traceId) case POST -> Root as user using traceId => Created(user -> traceId) } lazy val authMiddleware: AuthMiddleware[F, String] = null lazy val routes: HttpRoutes[F] = Router( PathPrefix -> authMiddleware(httpRoutes) ) }
Example 173
Source File: Tracer.scala From http4s-tracer with Apache License 2.0 | 5 votes |
package dev.profunktor.tracer import cats.Applicative import cats.data.Kleisli import cats.effect.Sync import cats.syntax.all._ import org.http4s.syntax.StringSyntax import org.http4s.{Header, HttpApp, Request} object Tracer extends StringSyntax { private[tracer] val DefaultTraceIdHeader = "Trace-Id" final case class TraceId(value: String) extends AnyVal { override def toString = s"[Trace-Id] - [$value]" } def apply[F[_]](implicit ev: Tracer[F]): Tracer[F] = ev def create[F[_]](headerName: String = DefaultTraceIdHeader): Tracer[F] = new Tracer[F](headerName) } class Tracer[F[_]] private (headerName: String) { import Trace._, Tracer._ def middleware( http: HttpApp[F], logRequest: Boolean = false, logResponse: Boolean = false )(implicit F: Sync[F], L: TracerLog[Trace[F, ?]]): HttpApp[F] = Kleisli { req => val createId: F[(Request[F], TraceId)] = for { id <- GenUUID.make[F] tr <- F.delay(req.putHeaders(Header(headerName, id.value))) } yield (tr, id) for { mi <- getTraceId(req) (tr, id) <- mi.fold(createId)(id => (req, id).pure[F]) _ <- if (logRequest) L.info[Tracer[F]](s"$req").run(id) else F.unit rs <- http(tr).map(_.putHeaders(Header(headerName, id.value))) _ <- if (logResponse) L.info[Tracer[F]](s"$rs").run(id) else F.unit } yield rs } def loggingMiddleware( http: HttpApp[F] )(implicit F: Sync[F], L: TracerLog[Trace[F, ?]]): HttpApp[F] = middleware(http, logRequest = true, logResponse = true) def getTraceId(request: Request[F])(implicit F: Applicative[F]): F[Option[TraceId]] = F.pure(request.headers.get(headerName.ci).map(h => TraceId(h.value))) }
Example 174
Source File: tracerlog.scala From http4s-tracer with Apache License 2.0 | 5 votes |
package dev.profunktor.tracer.instances import cats.effect.Sync import cats.syntax.flatMap._ import dev.profunktor.tracer.Trace import dev.profunktor.tracer.Trace._ import dev.profunktor.tracer.TracerLog import org.slf4j.{Logger, LoggerFactory} import scala.reflect.ClassTag object tracerlog { implicit def defaultLog[F[_]](implicit F: Sync[F]): TracerLog[Trace[F, ?]] = new TracerLog[Trace[F, ?]] { def logger[A](implicit ct: ClassTag[A]): F[Logger] = F.delay(LoggerFactory.getLogger(ct.runtimeClass)) override def info[A: ClassTag](value: => String): Trace[F, Unit] = Trace { id => logger[A].flatMap { log => if (log.isInfoEnabled) F.delay(log.info(s"$id - $value")) else F.unit } } override def error[A: ClassTag](value: => String): Trace[F, Unit] = Trace { id => logger[A].flatMap { log => if (log.isErrorEnabled) F.delay(log.error(s"$id - $value")) else F.unit } } override def warn[A: ClassTag](value: => String): Trace[F, Unit] = Trace { id => logger[A].flatMap { log => if (log.isWarnEnabled) F.delay(log.warn(s"$id - $value")) else F.unit } } } }
Example 175
Source File: Fixture.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.sourcing.projections import akka.persistence.journal.{Tagged, WriteEventAdapter} import cats.effect.{IO, Sync} import cats.effect.concurrent.Ref import scala.annotation.nowarn object Fixture { sealed trait Event final case object Executed extends Event final case object OtherExecuted extends Event final case object AnotherExecuted extends Event final case object YetAnotherExecuted extends Event final case object RetryExecuted extends Event final case object IgnoreExecuted extends Event final case object NotDiscarded extends Event final case object Discarded extends Event sealed trait EventTransform final case object ExecutedTransform extends EventTransform final case object OtherExecutedTransform extends EventTransform final case object AnotherExecutedTransform extends EventTransform final case object YetAnotherExecutedTransform extends EventTransform final case object RetryExecutedTransform extends EventTransform final case object IgnoreExecutedTransform extends EventTransform final case object NotDiscardedTransform extends EventTransform final case object DiscardedTransform extends EventTransform sealed trait Cmd final case object Execute extends Cmd final case object ExecuteOther extends Cmd final case object ExecuteAnother extends Cmd final case object ExecuteYetAnother extends Cmd final case object ExecuteRetry extends Cmd final case object ExecuteIgnore extends Cmd sealed trait State final case object Perpetual extends State sealed trait Rejection final case object Reject extends Rejection class TaggingAdapter extends WriteEventAdapter { override def manifest(event: Any): String = "" override def toJournal(event: Any): Any = event match { case Executed => Tagged(event, Set("executed")) case OtherExecuted => Tagged(event, Set("other")) case AnotherExecuted => Tagged(event, Set("another")) case YetAnotherExecuted => Tagged(event, Set("yetanother")) case RetryExecuted => Tagged(event, Set("retry")) case IgnoreExecuted => Tagged(event, Set("ignore")) case NotDiscarded => Tagged(event, Set("discard")) case Discarded => Tagged(event, Set("discard")) } } val initial: State = Perpetual @nowarn("cat=unused") def next(state: State, event: Event): State = Perpetual @nowarn("cat=unused") def eval(state: State, cmd: Cmd): IO[Either[Rejection, Event]] = cmd match { case Execute => IO.pure(Right(Executed)) case ExecuteOther => IO.pure(Right(OtherExecuted)) case ExecuteAnother => IO.pure(Right(AnotherExecuted)) case ExecuteYetAnother => IO.pure(Right(YetAnotherExecuted)) case ExecuteRetry => IO.pure(Right(RetryExecuted)) case ExecuteIgnore => IO.pure(Right(IgnoreExecuted)) } def memoize[F[_], A](fa: F[A])(implicit F: Sync[F]): F[F[A]] = { import cats.implicits._ for { ref <- Ref[F].of(fa.attempt) _ <- ref.update(_.flatTap(a => ref.set(a.pure[F]))) } yield ref.get.flatten.rethrow } }
Example 176
Source File: AbstractHttpClient.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli.clients import cats.effect.{Sync, Timer} import cats.implicits._ import ch.epfl.bluebrain.nexus.cli.CliError.ClientError import ch.epfl.bluebrain.nexus.cli.CliError.ClientError.{SerializationError, Unexpected} import ch.epfl.bluebrain.nexus.cli.config.EnvConfig import ch.epfl.bluebrain.nexus.cli.{logRetryErrors, ClientErrOr, Console} import io.circe.Decoder import org.http4s.circe.CirceEntityDecoder._ import org.http4s.client.Client import org.http4s.{Request, Response} import retry.CatsEffect._ import retry.RetryPolicy import retry.syntax.all._ import scala.reflect.ClassTag import scala.util.control.NonFatal class AbstractHttpClient[F[_]: Timer](client: Client[F], env: EnvConfig)(implicit protected val F: Sync[F], protected val console: Console[F] ) { protected val retry = env.httpClient.retry protected def successCondition[A] = retry.condition.notRetryFromEither[A] _ implicit protected val retryPolicy: RetryPolicy[F] = retry.retryPolicy implicit protected def logOnError[A] = logRetryErrors[F, A]("interacting with an HTTP API") protected def executeDiscard[A](req: Request[F], returnValue: => A): F[ClientErrOr[A]] = execute(req, _.body.compile.drain.as(Right(returnValue))) protected def executeParse[A: Decoder](req: Request[F])(implicit A: ClassTag[A]): F[ClientErrOr[A]] = execute( req, _.attemptAs[A].value.map( _.leftMap(err => SerializationError(err.message, s"The response payload was not of type '${A.runtimeClass.getSimpleName}'") ) ) ) private def execute[A](req: Request[F], f: Response[F] => F[ClientErrOr[A]]): F[ClientErrOr[A]] = client .fetch(req)(ClientError.errorOr[F, A](r => f(r))) .recoverWith { case NonFatal(err) => F.delay(Left(Unexpected(Option(err.getMessage).getOrElse("").take(30)))) } .retryingM(successCondition[A]) }
Example 177
Source File: SparqlClient.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli.clients import cats.effect.{Sync, Timer} import ch.epfl.bluebrain.nexus.cli.config.EnvConfig import ch.epfl.bluebrain.nexus.cli.sse.{OrgLabel, ProjectLabel} import ch.epfl.bluebrain.nexus.cli.{ClientErrOr, Console} import org.http4s._ import org.http4s.client.Client import org.http4s.headers.`Content-Type` trait SparqlClient[F[_]] { final def apply[F[_]: Sync: Timer](client: Client[F], env: EnvConfig, console: Console[F]): SparqlClient[F] = { implicit val c: Console[F] = console new LiveSparqlClient[F](client, env) } final val `application/sparql-query`: MediaType = new MediaType("application", "sparql-query") final private class LiveSparqlClient[F[_]: Timer: Console: Sync](client: Client[F], env: EnvConfig) extends AbstractHttpClient(client, env) with SparqlClient[F] { override def query( org: OrgLabel, proj: ProjectLabel, view: Option[Uri], queryStr: String ): F[ClientErrOr[SparqlResults]] = { val uri = env.sparql(org, proj, view.getOrElse(env.defaultSparqlView)) val headers = Headers(env.authorizationHeader.toList) val req = Request[F](method = Method.POST, uri = uri, headers = headers) .withEntity(queryStr) .withContentType(`Content-Type`(`application/sparql-query`)) executeParse[SparqlResults](req) } } }
Example 178
Source File: ProjectClient.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli.clients import cats.effect.concurrent.Ref import cats.effect.{Sync, Timer} import cats.implicits._ import ch.epfl.bluebrain.nexus.cli.config.EnvConfig import ch.epfl.bluebrain.nexus.cli.sse.{OrgLabel, OrgUuid, ProjectLabel, ProjectUuid} import ch.epfl.bluebrain.nexus.cli.{ClientErrOr, Console} import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder import org.http4s.client.Client import org.http4s.{Headers, Request} trait ProjectClient[F[_]] { final def apply[F[_]: Sync: Timer]( client: Client[F], env: EnvConfig, cache: Ref[F, Map[(OrgUuid, ProjectUuid), (OrgLabel, ProjectLabel)]], console: Console[F] ): ProjectClient[F] = { implicit val c: Console[F] = console new LiveProjectClient[F](client, env, cache) } private class LiveProjectClient[F[_]: Timer: Console: Sync]( client: Client[F], env: EnvConfig, cache: Ref[F, Map[(OrgUuid, ProjectUuid), (OrgLabel, ProjectLabel)]] ) extends AbstractHttpClient[F](client, env) with ProjectClient[F] { override def labels(org: OrgUuid, proj: ProjectUuid): F[ClientErrOr[(OrgLabel, ProjectLabel)]] = cache.get.flatMap { map => map.get((org, proj)) match { // value in cache, return case Some(value) => F.pure(Right(value)) // value not in cache, fetch, update and return case None => get(org, proj).flatMap { // propagate error case l @ Left(_) => F.pure(l) // success, update cache and return case r @ Right(value) => cache.modify(m => (m.updated((org, proj), value), value)) *> F.pure(r) } } } private def get(org: OrgUuid, proj: ProjectUuid): F[ClientErrOr[(OrgLabel, ProjectLabel)]] = { val uri = env.project(org, proj) val req = Request[F](uri = uri, headers = Headers(env.authorizationHeader.toList)) executeParse[NexusAPIProject](req).map { case Right(NexusAPIProject(orgLabel, projectLabel)) => Right((orgLabel, projectLabel)) case Left(err) => Left(err) } } } final private[ProjectClient] case class NexusAPIProject(`_organizationLabel`: OrgLabel, `_label`: ProjectLabel) private[ProjectClient] object NexusAPIProject { implicit val nexusAPIProjectDecoder: Decoder[NexusAPIProject] = deriveDecoder[NexusAPIProject] } }
Example 179
Source File: InfluxClient.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli.clients import cats.effect.{Sync, Timer} import cats.implicits._ import ch.epfl.bluebrain.nexus.cli._ import ch.epfl.bluebrain.nexus.cli.config.influx.InfluxConfig import ch.epfl.bluebrain.nexus.cli.config.{AppConfig, EnvConfig} import io.circe.Json import org.http4s.client.Client import org.http4s.{Method, Request, UrlForm} trait InfluxClient[F[_]] { final def apply[F[_]: Sync: Timer]( client: Client[F], config: AppConfig, console: Console[F] ): InfluxClient[F] = { implicit val c: Console[F] = console new LiveInfluxDbClient[F](client, config.influx, config.env) } }
Example 180
Source File: TestEventStreamClient.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli.dummies import java.util.UUID import cats.effect.Sync import cats.effect.concurrent.Ref import cats.implicits._ import ch.epfl.bluebrain.nexus.cli.clients.{EventStreamClient, ProjectClient} import ch.epfl.bluebrain.nexus.cli.sse._ import ch.epfl.bluebrain.nexus.cli.{ClientErrOr, LabeledEvent} import fs2.{Pipe, Stream} class TestEventStreamClient[F[_]](events: List[Event], projectClient: ProjectClient[F])(implicit F: Sync[F]) extends EventStreamClient[F] { private val noOffset: Offset = Offset(new UUID(0L, 0L)) private val offsetEvents: Seq[(Offset, Event)] = events.map { ev => (Offset(new UUID(ev.instant.toEpochMilli, 0L)), ev) } private def saveOffset(lastEventIdCache: Ref[F, Option[Offset]]): Pipe[F, (Offset, Event), Event] = _.evalMap { case (offset, event) => lastEventIdCache.update(_ => Some(offset)) >> F.pure(event) } private def eventsFrom(lastEventIdCache: Ref[F, Option[Offset]]): F[Seq[(Offset, Event)]] = lastEventIdCache.get.map(lastEventId => offsetEvents.dropWhile { case (offset, _) => offset.value.getMostSignificantBits <= lastEventId.getOrElse(noOffset).value.getMostSignificantBits } ) private def eventAndLabels(event: Event): F[ClientErrOr[LabeledEvent]] = projectClient.labels(event.organization, event.project).map(_.map { case (org, proj) => (event, org, proj) }) override def apply(lastEventId: Option[Offset]): F[EventStream[F]] = Ref.of(lastEventId).flatMap { ref => val stream = eventsFrom(ref).map { events => Stream.fromIterator[F](events.iterator).through(saveOffset(ref)).evalMap(eventAndLabels) } F.delay(EventStream(stream, ref)) } override def apply(organization: OrgLabel, lastEventId: Option[Offset]): F[EventStream[F]] = Ref.of(lastEventId).flatMap { ref => val stream = eventsFrom(ref).map { events => Stream.fromIterator[F](events.iterator).through(saveOffset(ref)).evalMap(eventAndLabels).filter { case Right((_, org, _)) => org == organization case Left(_) => true } } F.delay(EventStream(stream, ref)) } override def apply(organization: OrgLabel, project: ProjectLabel, lastEventId: Option[Offset]): F[EventStream[F]] = Ref.of(lastEventId).flatMap { ref => val stream = eventsFrom(ref).map { events => Stream.fromIterator[F](events.iterator).through(saveOffset(ref)).evalMap(eventAndLabels).filter { case Right((_, org, proj)) => org == organization && proj == project case Left(_) => true } } F.delay(EventStream(stream, ref)) } }
Example 181
Source File: TestSparqlClient.scala From nexus with Apache License 2.0 | 5 votes |
package ch.epfl.bluebrain.nexus.cli.dummies import java.io.ByteArrayOutputStream import cats.effect.Sync import cats.implicits._ import ch.epfl.bluebrain.nexus.cli.CliError.ClientError.SerializationError import ch.epfl.bluebrain.nexus.cli.ClientErrOr import ch.epfl.bluebrain.nexus.cli.clients.{SparqlClient, SparqlResults} import ch.epfl.bluebrain.nexus.cli.sse.{Event, OrgLabel, ProjectLabel} import io.circe.Json import org.http4s.Uri class TestSparqlClient[F[_]](events: List[Event])(implicit F: Sync[F]) extends SparqlClient[F] { import io.circe.parser._ import org.apache.jena.query.{Dataset, DatasetFactory, QueryFactory, ReadWrite, ResultSetFormatter, _} import org.apache.jena.rdf.model.{Model, ModelFactory} import org.apache.jena.riot.system.StreamRDFLib import org.apache.jena.riot.{Lang, RDFParser} private def toJenaModel(j: Json): Model = { val model = ModelFactory.createDefaultModel() val stream = StreamRDFLib.graph(model.getGraph) RDFParser.create.fromString(j.noSpaces).lang(Lang.JSONLD).parse(stream) model } val ds: Dataset = DatasetFactory.createTxnMem() events.foreach { event => val jsonGraph = event.raw.hcursor.get[Json]("_source").getOrElse(Json.obj()) val graphUri = event.resourceId.addSegment("graph").renderString val model = toJenaModel(jsonGraph) ds.begin(ReadWrite.WRITE) try { ds.removeNamedModel(graphUri) ds.commit() } finally { ds.end() } ds.begin(ReadWrite.WRITE) try { ds.addNamedModel(graphUri, model) ds.commit() } finally { ds.end() } } ds.setDefaultModel(ds.getUnionModel) override def query( org: OrgLabel, proj: ProjectLabel, view: Option[Uri], queryStr: String ): F[ClientErrOr[SparqlResults]] = { F.delay { ds.begin(ReadWrite.READ) try { val query = QueryFactory.create(queryStr) val qexec = QueryExecutionFactory.create(query, ds.asDatasetGraph()) val results = qexec.execSelect val outputStream = new ByteArrayOutputStream() ResultSetFormatter.outputAsJSON(outputStream, results) val json = new String(outputStream.toByteArray) decode[SparqlResults](json).leftMap(_ => SerializationError("Unable to decode sparql results", classOf[SparqlResults].getSimpleName, Some(json)) ) } finally { ds.end() } } } } object TestSparqlClient { final def apply[F[_]](events: List[Event])(implicit F: Sync[F]): F[TestSparqlClient[F]] = F.delay(new TestSparqlClient[F](events)) }
Example 182
Source File: package.scala From pureconfig with Mozilla Public License 2.0 | 5 votes |
package pureconfig.module.catseffect import scala.language.higherKinds import scala.reflect.ClassTag import cats.effect.{ Blocker, ContextShift, Sync } import pureconfig.{ ConfigReader, ConfigSource, Derivation } import pureconfig.module.catseffect package object syntax { implicit class CatsEffectConfigSource(private val cs: ConfigSource) extends AnyVal { @inline final def loadF[F[_], A](blocker: Blocker)(implicit F: Sync[F], csf: ContextShift[F], reader: Derivation[ConfigReader[A]], ct: ClassTag[A]): F[A] = catseffect.loadF(cs, blocker) @deprecated("Use `cs.loadF[F, A](blocker)` instead", "0.12.3") def loadF[F[_], A](implicit F: Sync[F], reader: Derivation[ConfigReader[A]], ct: ClassTag[A]): F[A] = catseffect.loadF(cs) } }
Example 183
Source File: TestRoutes.scala From scala-server-lambda with MIT License | 5 votes |
package io.github.howardjohn.lambda.http4s import cats.{Applicative, MonadError} import cats.effect.Sync import cats.implicits._ import io.github.howardjohn.lambda.LambdaHandlerBehavior import io.github.howardjohn.lambda.LambdaHandlerBehavior._ import org.http4s.dsl.Http4sDsl import org.http4s.{EntityDecoder, Header, HttpRoutes} import org.http4s.circe._ import io.circe.generic.auto._ import io.circe.syntax._ import org.http4s.dsl.impl.OptionalQueryParamDecoderMatcher class TestRoutes[F[_]] { object TimesQueryMatcher extends OptionalQueryParamDecoderMatcher[Int]("times") val dsl = Http4sDsl[F] import dsl._ def routes(implicit sync: Sync[F], jsonDecoder: EntityDecoder[F, JsonBody], me: MonadError[F, Throwable], stringDecoder: EntityDecoder[F, String], ap: Applicative[F]): HttpRoutes[F] = HttpRoutes.of[F] { case GET -> Root / "hello" :? TimesQueryMatcher(times) => Ok { Seq .fill(times.getOrElse(1))("Hello World!") .mkString(" ") } case GET -> Root / "long" => Applicative[F].pure(Thread.sleep(1000)).flatMap(_ => Ok("Hello World!")) case GET -> Root / "exception" => throw RouteException() case GET -> Root / "error" => InternalServerError() case req@GET -> Root / "header" => val header = req.headers.find(h => h.name.value == inputHeader).map(_.value).getOrElse("Header Not Found") Ok(header, Header(outputHeader, outputHeaderValue)) case req@POST -> Root / "post" => req.as[String].flatMap(s => Ok(s)) case req@POST -> Root / "json" => req.as[JsonBody].flatMap(s => Ok(LambdaHandlerBehavior.jsonReturn.asJson)) } }
Example 184
Source File: MongoClient.scala From fs2-mongodb with MIT License | 5 votes |
package org.lyranthe.fs2_mongodb import com.mongodb.async.client.{MongoClient, MongoClients} import com.mongodb.MongoClientSettings import cats.effect.{Resource, Sync} object Mongo { def fromUrl[F[_]](url: String)(implicit F: Sync[F]): Resource[F, MongoClient] = Resource.make(F.delay(MongoClients.create(url))){ client => F.delay(client.close()) } def fromSettings[F[_]](settings: MongoClientSettings)( implicit F: Sync[F]): Resource[F, MongoClient] = { Resource.make(F.delay(MongoClients.create(settings)))(client => F.delay(client.close())) } }
Example 185
Source File: ProjectionFlow.scala From ticket-booking-aecor with Apache License 2.0 | 5 votes |
package ru.pavkin.booking.common.view import aecor.data.{Committable, EntityEvent} import cats.effect.Sync import io.chrisdavenport.log4cats.Logger import cats.implicits._ object ProjectionFlow { def apply[F[_], K, E, S](log: Logger[F], aggregateProjection: Projection[F, EntityEvent[K, E], S], )(implicit F: Sync[F]): fs2.Pipe[F, Committable[F, EntityEvent[K, E]], Unit] = { def foldEvent(event: EntityEvent[K, E], state: Option[S]): F[Option[S]] = { val newVersion = aggregateProjection.applyEvent(state)(event) log.debug(s"New version [$newVersion]") >> newVersion .fold( F.raiseError[Option[S]]( new IllegalStateException(s"Projection failed for state = [$state], event = [$event]") ) )(_.pure[F]) } def runProjection(event: EntityEvent[K, E]): F[Unit] = for { (currentVersion, currentState) <- aggregateProjection.fetchVersionAndState(event) _ <- log.debug(s"Current $currentVersion [$currentState]") _ <- F.whenA(currentVersion.value < event.sequenceNr) { foldEvent(event, currentState).flatMap { case None => F.unit case Some(state) => aggregateProjection.saveNewVersion(state, currentVersion.next) } } } yield () _.evalMap(_.traverse(runProjection)).evalMap(_.commit) } }
Example 186
Source File: StubConfirmationService.scala From ticket-booking-aecor with Apache License 2.0 | 5 votes |
package ru.pavkin.booking.booking.service import java.time.temporal.ChronoUnit import java.time.{ Duration, Instant } import java.util.concurrent.TimeUnit import cats.Monad import cats.data.NonEmptyList import cats.effect.{ Clock, Sync } import cats.effect.concurrent.Ref import cats.implicits._ import ru.pavkin.booking.booking.service.TicketReservationService._ import ru.pavkin.booking.booking.service.StubConfirmationService.ConcertState import ru.pavkin.booking.common.models._ class StubConfirmationService[F[_]: Monad](clock: Clock[F], state: Ref[F, Map[ConcertId, ConcertState]]) extends TicketReservationService[F] { val expireAfter: Duration = Duration.of(6, ChronoUnit.HOURS) def reserve(bookingId: BookingKey, concertId: ConcertId, seats: NonEmptyList[Seat]): F[Either[ReservationFailure, Reservation]] = clock .realTime(TimeUnit.MILLISECONDS) .map(Instant.ofEpochMilli) .flatMap( now => state.modify[Either[ReservationFailure, Reservation]]( concerts => concerts.get(concertId) match { case None => concerts -> Left(UnknownSeats) case Some(concertState) => concertState .book(bookingId, seats) .fold(e => concerts -> Left(e), { case (c, t) => concerts.updated(concertId, c) -> Right( Reservation(t, Some(now.plus(expireAfter))) ) }) } ) ) def release(bookingId: BookingKey): F[Either[ReleaseFailure, Unit]] = state.modify[Either[ReleaseFailure, Unit]]( concerts => Either .fromOption(concerts.find(_._2.bookedSeats.contains(bookingId)), UnknownBooking) .flatMap { case (concertId, concertState) => concertState.release(bookingId).map(concertId -> _) } match { case Left(value) => concerts -> Left(value) case Right((concertId, newState)) => concerts.updated(concertId, newState) -> Right(()) } ) } object StubConfirmationService { def apply[F[_]: Sync](clock: Clock[F], initial: Map[ConcertId, ConcertState]): F[StubConfirmationService[F]] = Ref.of(initial).map(new StubConfirmationService(clock, _)) case class ConcertState(prices: Map[Seat, Money], availableSeats: Set[Seat], bookedSeats: Map[BookingKey, NonEmptyList[Seat]]) { def book( bookingId: BookingKey, seats: NonEmptyList[Seat] ): Either[ReservationFailure, (ConcertState, NonEmptyList[Ticket])] = if (bookedSeats.contains(bookingId)) Left(SeatsAlreadyBooked) else if (!seats.forall(availableSeats)) Left(SeatsAlreadyBooked) else if (!seats.forall(prices.contains)) Left(UnknownSeats) else Right( copy( availableSeats = availableSeats.diff(seats.toList.toSet), bookedSeats = bookedSeats.updated(bookingId, seats) ) -> seats.map(s => Ticket(s, prices(s))) ) def release(bookingId: BookingKey): Either[ReleaseFailure, ConcertState] = bookedSeats.get(bookingId) match { case Some(booked) => Right( copy( availableSeats = availableSeats ++ booked.toList.toSet, bookedSeats = bookedSeats - bookingId ) ) case None => Left(UnknownBooking) } } }
Example 187
Source File: BookingExpirationProcess.scala From ticket-booking-aecor with Apache License 2.0 | 5 votes |
package ru.pavkin.booking.booking.process import java.time.Instant import cats.effect.Sync import cats.implicits._ import ru.pavkin.booking.booking.booking.Bookings import ru.pavkin.booking.booking.view.BookingViewRepository class BookingExpirationProcess[F[_]: Sync](bookings: Bookings[F], bookingView: BookingViewRepository[F]) extends (Instant => F[Unit]) { def apply(now: Instant): F[Unit] = bookingView .expired(now) .evalMap(k => bookings(k).expire.void) .compile .drain }
Example 188
Source File: BookingEndpoint.scala From ticket-booking-aecor with Apache License 2.0 | 5 votes |
package ru.pavkin.booking.booking.endpoint import java.util.UUID import cats.data.NonEmptyList import cats.effect.Sync import cats.implicits._ import ru.pavkin.booking.booking.booking.Bookings import ru.pavkin.booking.booking.entity.{ BookingCommandRejection, BookingNotFound } import ru.pavkin.booking.booking.view.{ BookingView, BookingViewRepository } import ru.pavkin.booking.common.models.{ BookingKey, ClientId, ConcertId, Seat } trait BookingEndpoint[F[_]] { def placeBooking(client: ClientId, concertId: ConcertId, seats: NonEmptyList[Seat]): F[Either[BookingCommandRejection, Unit]] def cancelBooking(clientId: ClientId, bookingId: BookingKey, reason: String): F[Either[BookingCommandRejection, Unit]] def clientBookings(client: ClientId): F[List[BookingView]] } final class DefaultBookingEndpoint[F[_]]( bookings: Bookings[F], bookingsView: BookingViewRepository[F] )(implicit F: Sync[F]) extends BookingEndpoint[F] { def placeBooking(client: ClientId, concertId: ConcertId, seats: NonEmptyList[Seat]): F[Either[BookingCommandRejection, Unit]] = for { id <- Sync[F].delay(UUID.randomUUID()) result <- bookings(BookingKey(id.toString)).place(client, concertId, seats) } yield result def cancelBooking(clientId: ClientId, bookingId: BookingKey, reason: String): F[Either[BookingCommandRejection, Unit]] = bookingsView.get(bookingId).flatMap { case None => F.pure(Left(BookingNotFound)) case Some(b) if b.clientId =!= clientId => F.pure(Left(BookingNotFound)) case Some(_) => bookings(bookingId).cancel(reason) } def clientBookings(client: ClientId): F[List[BookingView]] = bookingsView.byClient(client) }
Example 189
Source File: ConditionalLoggerSpec.scala From odin with Apache License 2.0 | 5 votes |
package io.odin.extras.loggers import cats.data.Kleisli import cats.effect.Sync import cats.effect.concurrent.Ref import cats.mtl.instances.all._ import cats.syntax.applicativeError._ import cats.syntax.flatMap._ import cats.syntax.order._ import io.odin.loggers.{DefaultLogger, HasContext} import io.odin.syntax._ import io.odin.extras.syntax._ import io.odin.{Level, LoggerMessage, OdinSpec} import monix.eval.Task import monix.execution.schedulers.TestScheduler class ConditionalLoggerSpec extends OdinSpec { implicit private val scheduler: TestScheduler = TestScheduler() type F[A] = Kleisli[Task, Map[String, String], A] case class RefLogger(ref: Ref[F, List[LoggerMessage]]) extends DefaultLogger[F] { def log(msg: LoggerMessage): F[Unit] = ref.update(_ :+ msg) } implicit private val hasContext: HasContext[Map[String, String]] = (env: Map[String, String]) => env it should "use log level of the inner logger in case of success" in { forAll { (messages: List[LoggerMessage], ctx: Map[String, String]) => val fa = for { ref <- Ref.of[F, List[LoggerMessage]](List.empty) _ <- RefLogger(ref) .withMinimalLevel(Level.Info) .withContext .withErrorLevel(Level.Debug)(logger => logger.log(messages)) written <- ref.get } yield written val written = fa.run(ctx).runSyncUnsafe() val expected = messages.filter(_.level >= Level.Info).map(m => m.copy(context = m.context ++ ctx)) written shouldBe expected } } it should "use log level of the conditional logger in case of error" in { forAll { (messages: List[LoggerMessage], ctx: Map[String, String]) => val error = new RuntimeException("Boom") val fa = for { ref <- Ref.of[F, List[LoggerMessage]](List.empty) attempt <- RefLogger(ref) .withMinimalLevel(Level.Info) .withContext .withErrorLevel(Level.Debug)(logger => logger.log(messages) >> Sync[F].raiseError[Unit](error)) .attempt written <- ref.get } yield (attempt, written) val (attempt, written) = fa.run(ctx).runSyncUnsafe() val expected = messages.filter(_.level >= Level.Debug).map(m => m.copy(context = m.context ++ ctx)) attempt shouldBe Left(error) written shouldBe expected } } }
Example 190
Source File: ConsoleLogger.scala From odin with Apache License 2.0 | 5 votes |
package io.odin.loggers import java.io.PrintStream import cats.effect.{Sync, Timer} import cats.syntax.all._ import io.odin.formatter.Formatter import io.odin.{Level, Logger, LoggerMessage} case class ConsoleLogger[F[_]: Timer]( formatter: Formatter, out: PrintStream, err: PrintStream, override val minLevel: Level )(implicit F: Sync[F]) extends DefaultLogger[F](minLevel) { private def println(out: PrintStream, msg: LoggerMessage, formatter: Formatter): F[Unit] = F.delay(out.println(formatter.format(msg))) def log(msg: LoggerMessage): F[Unit] = if (msg.level < Level.Warn) { println(out, msg, formatter) } else { println(err, msg, formatter) } } object ConsoleLogger { def apply[F[_]: Timer: Sync](formatter: Formatter, minLevel: Level): Logger[F] = ConsoleLogger(formatter, scala.Console.out, scala.Console.err, minLevel) }
Example 191
Source File: FileLogger.scala From odin with Apache License 2.0 | 5 votes |
package io.odin.loggers import java.io.BufferedWriter import java.nio.file.{Files, Paths} import cats.effect.syntax.all._ import cats.effect.{Resource, Sync, Timer} import cats.instances.list._ import cats.syntax.all._ import io.odin.formatter.Formatter import io.odin.{Level, Logger, LoggerMessage} case class FileLogger[F[_]: Timer](buffer: BufferedWriter, formatter: Formatter, override val minLevel: Level)( implicit F: Sync[F] ) extends DefaultLogger[F](minLevel) { def log(msg: LoggerMessage): F[Unit] = write(msg, formatter).guarantee(flush) override def log(msgs: List[LoggerMessage]): F[Unit] = msgs.traverse(write(_, formatter)).void.guarantee(flush) private def write(msg: LoggerMessage, formatter: Formatter): F[Unit] = F.delay { buffer.write(formatter.format(msg) + System.lineSeparator()) } private def flush: F[Unit] = F.delay(buffer.flush()).handleErrorWith(_ => F.unit) } object FileLogger { def apply[F[_]: Timer](fileName: String, formatter: Formatter, minLevel: Level)( implicit F: Sync[F] ): Resource[F, Logger[F]] = { def mkBuffer: F[BufferedWriter] = F.delay(Files.newBufferedWriter(Paths.get(fileName))) def closeBuffer(buffer: BufferedWriter): F[Unit] = F.delay(buffer.close()).handleErrorWith(_ => F.unit) Resource.make(mkBuffer)(closeBuffer).map { buffer => FileLogger(buffer, formatter, minLevel) } } }
Example 192
Source File: ProducerRecord.scala From skafka with MIT License | 5 votes |
package com.evolutiongaming.skafka.producer import java.time.Instant import cats.effect.Sync import cats.implicits._ import com.evolutiongaming.skafka._ final case class ProducerRecord[+K, +V]( topic: Topic, value: Option[V] = None, key: Option[K] = None, partition: Option[Partition] = None, timestamp: Option[Instant] = None, headers: List[Header] = Nil) object ProducerRecord { def apply[K, V](topic: Topic, value: V, key: K): ProducerRecord[K, V] = { ProducerRecord(topic = topic, value = Some(value), key = Some(key)) } implicit class ProducerRecordOps[K, V](val self: ProducerRecord[K, V]) extends AnyVal { def toBytes[F[_] : Sync](implicit toBytesK: ToBytes[F, K], toBytesV: ToBytes[F, V] ): F[ProducerRecord[Bytes, Bytes]] = { val topic = self.topic for { k <- self.key.traverse { toBytesK(_, topic) } v <- self.value.traverse { toBytesV(_, topic) } } yield { self.copy(value = v, key = k) } } } }
Example 193
Source File: AccountRepositoryInMemory.scala From frdomain-extras with Apache License 2.0 | 5 votes |
package frdomain.ch6 package domain package repository package interpreter import java.time.LocalDateTime import scala.collection.immutable.Map import cats._ import cats.data._ import cats.implicits._ import cats.instances.all._ import cats.effect.concurrent.Ref import cats.effect.Sync import common._ import model.account._ // Constructor private for the interpreter to prevent the Ref from leaking // access through smart constructor below final class AccountRepositoryInMemory[M[_]: Monad] private (repo: Ref[M, Map[AccountNo, Account]]) extends AccountRepository[M] { def query(no: AccountNo): M[Option[Account]] = repo.get.map(_.get(no)) def store(a: Account): M[Account] = repo.update(_ + ((a.no, a))).map(_ => a) def query(openedOn: LocalDateTime): M[List[Account]] = repo.get.map(_.values.filter(_.dateOfOpen.getOrElse(today) == openedOn).toList) def all: M[List[Account]] = repo.get.map(_.values.toList) def balance(no: AccountNo): M[Option[Balance]] = query(no).map(_.map(_.balance)) } // Smart constructor object AccountRepositoryInMemory { def make[M[_]: Sync]: M[AccountRepositoryInMemory[M]] = Ref.of[M, Map[AccountNo, Account]](Map.empty).map(new AccountRepositoryInMemory(_)) }
Example 194
Source File: HostnamePlatform.scala From ip4s with Apache License 2.0 | 5 votes |
package com.comcast.ip4s import java.net.{InetAddress, UnknownHostException} import cats.data.NonEmptyList import cats.effect.Sync private[ip4s] trait HostnamePlatform { self: Hostname => def resolveAll[F[_]: Sync]: F[Option[NonEmptyList[IpAddress]]] = Sync[F].delay { try { val addrs = InetAddress.getAllByName(self.toString) NonEmptyList.fromList(addrs.toList.flatMap(addr => IpAddress.fromBytes(addr.getAddress))) } catch { case _: UnknownHostException => None } } }
Example 195
Source File: CatsEffect.scala From cats-effect-testing with Apache License 2.0 | 5 votes |
package cats.effect.testing.specs2 import cats.effect.{Effect, Resource, Sync} import cats.effect.syntax.effect._ import org.specs2.execute.{AsResult, Failure, Result} import scala.concurrent.duration._ import scala.language.higherKinds trait CatsEffect { protected val Timeout: Duration = 10.seconds implicit def effectAsResult[F[_]: Effect, R](implicit R: AsResult[R]): AsResult[F[R]] = new AsResult[F[R]] { def asResult(t: => F[R]): Result = t.toIO.unsafeRunTimed(Timeout) .map(R.asResult(_)) .getOrElse(Failure(s"expectation timed out after $Timeout")) } implicit def resourceAsResult[F[_]: Effect, R](implicit R: AsResult[R]): AsResult[Resource[F,R]] = new AsResult[Resource[F,R]]{ def asResult(t: => Resource[F, R]): Result = t.use(r => Sync[F].delay(R.asResult(r))) .toIO .unsafeRunTimed(Timeout) .getOrElse(Failure(s"expectation timed out after $Timeout")) } }
Example 196
Source File: IOTest.scala From cats-effect-testing with Apache License 2.0 | 5 votes |
package cats.effect.testing.scalatest.scalacheck import cats.data.EitherT import cats.effect.testing.scalatest.AsyncIOSpec import cats.effect.{IO, Sync} import org.scalatest.matchers.should.Matchers import org.scalatest.freespec.AsyncFreeSpec import org.scalatestplus.scalacheck.{CheckerAsserting, ScalaCheckPropertyChecks} class IOTest extends AsyncFreeSpec with AsyncIOSpec with Matchers with ScalaCheckPropertyChecks { "Scalacheck IO assertions" - { "Assert success" in { forAll { (l1: List[Int], l2: List[Int]) => IO.delay(l1.size + l2.size shouldBe (l1 ::: l2).size) } } "Assert exception" in { val check: IO[Unit] = forAll { (l1: List[Int], l2: List[Int]) => IO.delay(l1.size + l2.size shouldBe -1) } check.assertThrows[Exception] } implicit def ioCheckingAsserting[A]: CheckerAsserting[IO[A]] { type Result = IO[Unit] } = new EffectCheckerAsserting } "Scalacheck EitherT[IO, Throwable, A] assertions" - { type Eff[A] = EitherT[IO, Throwable, A] "Assert success" in { val check = forAll { (l1: List[Int], l2: List[Int]) => Sync[Eff].delay(l1.size + l2.size shouldBe (l1 ::: l2).size) } check.leftSemiflatMap[Unit](IO.raiseError).merge.assertNoException } "Assert exception" in { val check = forAll { (l1: List[Int], l2: List[Int]) => Sync[Eff].delay(l1.size + l2.size shouldBe -1) } check.leftSemiflatMap[Unit](IO.raiseError[Unit]).merge.assertThrows[Exception] } implicit def checkingAsserting[A]: CheckerAsserting[Eff[A]] { type Result = Eff[Unit] } = new EffectCheckerAsserting } }
Example 197
Source File: AssertingSyntax.scala From cats-effect-testing with Apache License 2.0 | 5 votes |
package cats.effect.testing.scalatest import cats.Functor import cats.effect.Sync import org.scalatest.{Assertion, Assertions, Succeeded} import cats.implicits._ def assertThrows[E <: Throwable](implicit F: Sync[F], ct: reflect.ClassTag[E]): F[Assertion] = self.attempt.flatMap { case Left(t: E) => F.pure(Succeeded: Assertion) case Left(t) => F.delay( fail( s"Expected an exception of type ${ct.runtimeClass.getName} but got an exception: $t" ) ) case Right(a) => F.delay( fail(s"Expected an exception of type ${ct.runtimeClass.getName} but got a result: $a") ) } } }
Example 198
Source File: TransactionRoute.scala From aecor with MIT License | 5 votes |
package aecor.example.transaction import java.util.UUID import aecor.example.account import aecor.example.account.AccountId import aecor.example.common.Amount import cats.effect.{Effect, Sync} import cats.implicits._ import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityDecoder import org.http4s.dsl.Http4sDsl import io.circe.generic.auto._ trait TransactionService[F[_]] { def authorizePayment(transactionId: TransactionId, from: From[AccountId], to: To[AccountId], amount: Amount): F[TransactionRoute.ApiResult] } object TransactionRoute { sealed trait ApiResult object ApiResult { case object Authorized extends ApiResult case class Declined(reason: String) extends ApiResult } final case class CreateTransactionRequest(from: From[AccountId], to: To[AccountId], amount: Amount) object TransactionIdVar { def unapply(arg: String): Option[TransactionId] = TransactionId(arg).some } private final class Builder[F[_]: Sync](service: TransactionService[F]) extends Http4sDsl[F] with CirceEntityDecoder { def routes: HttpRoutes[F] = HttpRoutes.of[F] { case req @ PUT -> Root / "transactions" / TransactionIdVar(transactionId) => for { body <- req.as[CreateTransactionRequest] CreateTransactionRequest(from, to, amount) = body resp <- service.authorizePayment(transactionId, from, to, amount).flatMap { case ApiResult.Authorized => Ok("Authorized") case ApiResult.Declined(reason) => BadRequest(s"Declined: $reason") } } yield resp case POST -> Root / "test" => service .authorizePayment( TransactionId(UUID.randomUUID.toString), From(account.EventsourcedAlgebra.rootAccountId), To(AccountId("foo")), Amount(1) ) .flatMap { case ApiResult.Authorized => Ok("Authorized") case ApiResult.Declined(reason) => BadRequest(s"Declined: $reason") } } } def apply[F[_]: Effect](api: TransactionService[F]): HttpRoutes[F] = new Builder(api).routes }
Example 199
Source File: Supervision.scala From aecor with MIT License | 5 votes |
package aecor.kafkadistributedprocessing import cats.effect.{ Sync, Timer } import fs2.Stream.retry import scala.concurrent.duration._ object Supervision { type Supervision[F[_]] = F[Unit] => F[Unit] def exponentialBackoff[F[_]: Timer: Sync](minBackoff: FiniteDuration = 2.seconds, maxBackoff: FiniteDuration = 10.seconds, randomFactor: Double = 0.2, maxAttempts: Int = Int.MaxValue): Supervision[F] = { def nextDelay(in: FiniteDuration): FiniteDuration = FiniteDuration((in.toMillis * (1 + randomFactor)).toLong, MILLISECONDS).min(maxBackoff) fa => retry(fa, minBackoff, nextDelay, maxAttempts, Function.const(true)).compile.drain } def noop[F[_]]: Supervision[F] = identity }
Example 200
Source File: E2eSupport.scala From aecor with MIT License | 5 votes |
package aecor.testkit import aecor.data.{ EventsourcedBehavior, _ } import aecor.runtime.{ EventJournal, Eventsourced } import cats.data.StateT import cats.effect.{ IO, Sync } import cats.implicits._ import cats.mtl.MonadState import cats.tagless.FunctorK import cats.tagless.syntax.functorK._ import cats.~> import fs2.Stream import monocle.Lens import scala.collection.immutable._ object E2eSupport { final class Runtime[F[_]] { def deploy[M[_[_]]: FunctorK, S, E, K]( behavior: EventsourcedBehavior[M, F, S, E], journal: EventJournal[F, K, E] )(implicit F: Sync[F]): K => M[F] = Eventsourced[M, F, S, E, K](behavior, journal) } abstract class Processes[F[_]](items: Vector[F[Unit]]) { protected type S protected implicit def F: MonadState[F, S] final private implicit val monad = F.monad final def runProcesses: F[Unit] = for { stateBefore <- F.get _ <- items.sequence stateAfter <- F.get _ <- if (stateAfter == stateBefore) { ().pure[F] } else { runProcesses } } yield () final def wireK[I, M[_[_]]: FunctorK](behavior: I => M[F]): I => M[F] = i => behavior(i).mapK(new (F ~> F) { override def apply[A](fa: F[A]): F[A] = fa <* runProcesses }) final def wire[A, B](f: F[B]): F[B] = f <* runProcesses } object Processes { def apply[F[_], S0](items: F[Unit]*)(implicit F0: MonadState[F, S0]): Processes[F] = new Processes[F](items.toVector) { final override type S = S0 override implicit def F: MonadState[F, S] = F0 } } } trait E2eSupport { import cats.mtl.instances.state._ type SpecState type F[A] = StateT[IO, SpecState, A] final def mkJournal[I, E](lens: Lens[SpecState, StateEventJournal.State[I, E]], tagging: Tagging[I]): StateEventJournal[F, I, SpecState, E] = StateEventJournal[F, I, SpecState, E](lens, tagging) final def wireProcess[In](process: In => F[Unit], source: Stream[F, Committable[F, In]], sources: Stream[F, Committable[F, In]]*)(implicit F: Sync[F]): F[Unit] = sources .fold(source)(_ ++ _) .evalMap(_.process(process)) .compile .drain val runtime = new E2eSupport.Runtime[F] }