From 1f0ccd53b633cb20b1c54b9dbd058cc300829442 Mon Sep 17 00:00:00 2001 From: Artur Albov Date: Fri, 8 Jun 2018 16:19:29 +0300 Subject: [PATCH] #178 Refactoring of search API. Not found items handling. Reactive search controller. --- .../contract/common/CommonConfiguration.kt | 19 ++----- ...dateEthereumContractSummaryApplication.kt} | 4 +- .../ethereum/EthereumConsumerConfiguration.kt | 10 ++-- docs/api/search.v1.yaml | 25 ++++++++- .../fund/cyber/api/bitcoin/dto/Contract.kt | 9 ++-- .../fund/cyber/api/bitcoin/handlers/Block.kt | 9 ++-- .../cyber/api/bitcoin/handlers/Contract.kt | 4 +- .../cyber/api/bitcoin/handlers/Transaction.kt | 5 +- .../cyber/api/common/CommonConfiguration.kt | 6 +++ .../fund/cyber/api/ethereum/dto/Contract.kt | 13 ++--- .../fund/cyber/api/ethereum/handlers/Block.kt | 5 +- .../cyber/api/ethereum/handlers/Contract.kt | 4 +- .../api/ethereum/handlers/Transaction.kt | 5 +- .../fund/cyber/api/ethereum/handlers/Uncle.kt | 5 +- .../fund/cyber/api/search/ElasticResponse.kt | 49 +++++++++++++++++ .../fund/cyber/api/search/SearchController.kt | 53 ++++++++----------- search-api/src/main/resources/application.yml | 6 ++- 17 files changed, 145 insertions(+), 86 deletions(-) rename contract-summary/ethereum/src/main/kotlin/fund/cyber/{ApplicationConfiguration.kt => UpdateEthereumContractSummaryApplication.kt} (78%) create mode 100644 search-api/src/main/kotlin/fund/cyber/api/search/ElasticResponse.kt diff --git a/contract-summary/common/src/main/kotlin/fund/cyber/contract/common/CommonConfiguration.kt b/contract-summary/common/src/main/kotlin/fund/cyber/contract/common/CommonConfiguration.kt index ddbdddb8..46581b31 100644 --- a/contract-summary/common/src/main/kotlin/fund/cyber/contract/common/CommonConfiguration.kt +++ b/contract-summary/common/src/main/kotlin/fund/cyber/contract/common/CommonConfiguration.kt @@ -1,11 +1,8 @@ package fund.cyber.contract.common -import fund.cyber.search.configuration.CHAIN_FAMILY -import fund.cyber.search.configuration.CHAIN_NAME -import fund.cyber.search.model.chains.ChainFamily -import fund.cyber.search.model.chains.ChainInfo +import fund.cyber.search.model.chains.Chain import io.micrometer.core.instrument.MeterRegistry -import org.springframework.beans.factory.annotation.Value +import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -15,17 +12,11 @@ import org.springframework.scheduling.annotation.EnableScheduling @Configuration class CommonConfiguration { - @Value("\${$CHAIN_FAMILY:}") - private lateinit var chainFamily: String - - @Value("\${$CHAIN_NAME:}") - private lateinit var chainName: String - - @Bean - fun chainInfo() = ChainInfo(ChainFamily.valueOf(chainFamily), chainName) + @Autowired + private lateinit var chain: Chain @Bean fun metricsCommonTags(): MeterRegistryCustomizer { - return MeterRegistryCustomizer { registry -> registry.config().commonTags("chain", chainInfo().fullName) } + return MeterRegistryCustomizer { registry -> registry.config().commonTags("chain", chain.name) } } } diff --git a/contract-summary/ethereum/src/main/kotlin/fund/cyber/ApplicationConfiguration.kt b/contract-summary/ethereum/src/main/kotlin/fund/cyber/UpdateEthereumContractSummaryApplication.kt similarity index 78% rename from contract-summary/ethereum/src/main/kotlin/fund/cyber/ApplicationConfiguration.kt rename to contract-summary/ethereum/src/main/kotlin/fund/cyber/UpdateEthereumContractSummaryApplication.kt index 8300b03f..a84c87b9 100644 --- a/contract-summary/ethereum/src/main/kotlin/fund/cyber/ApplicationConfiguration.kt +++ b/contract-summary/ethereum/src/main/kotlin/fund/cyber/UpdateEthereumContractSummaryApplication.kt @@ -7,12 +7,12 @@ import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration @SpringBootApplication(exclude = [CassandraDataAutoConfiguration::class, KafkaAutoConfiguration::class]) -class ApplicationConfiguration { +class UpdateEthereumContractSummaryApplication { companion object { @JvmStatic fun main(args: Array) { - SpringApplication.run(ApplicationConfiguration::class.java, *args) + SpringApplication.run(UpdateEthereumContractSummaryApplication::class.java, *args) } } } diff --git a/contract-summary/ethereum/src/main/kotlin/fund/cyber/contract/ethereum/EthereumConsumerConfiguration.kt b/contract-summary/ethereum/src/main/kotlin/fund/cyber/contract/ethereum/EthereumConsumerConfiguration.kt index 735be2fc..4a14bb91 100644 --- a/contract-summary/ethereum/src/main/kotlin/fund/cyber/contract/ethereum/EthereumConsumerConfiguration.kt +++ b/contract-summary/ethereum/src/main/kotlin/fund/cyber/contract/ethereum/EthereumConsumerConfiguration.kt @@ -10,7 +10,7 @@ import fund.cyber.contract.ethereum.delta.EthereumTxDeltaProcessor import fund.cyber.contract.ethereum.delta.EthereumUncleDeltaProcessor import fund.cyber.search.configuration.KAFKA_BROKERS import fund.cyber.search.configuration.KAFKA_BROKERS_DEFAULT -import fund.cyber.search.model.chains.ChainInfo +import fund.cyber.search.model.chains.Chain import fund.cyber.search.model.ethereum.EthereumBlock import fund.cyber.search.model.ethereum.EthereumTx import fund.cyber.search.model.ethereum.EthereumUncle @@ -62,7 +62,7 @@ class EthereumTxConsumerConfiguration { private lateinit var monitoring: MeterRegistry @Autowired - private lateinit var chainInfo: ChainInfo + private lateinit var chain: Chain //todo generate containers on the fly from DeltaProcessor information @@ -73,7 +73,7 @@ class EthereumTxConsumerConfiguration { consumerConfigs(), JsonDeserializer(PumpEvent::class.java), JsonDeserializer(EthereumTx::class.java) ) - val containerProperties = ContainerProperties(chainInfo.txPumpTopic).apply { + val containerProperties = ContainerProperties(chain.txPumpTopic).apply { setBatchErrorHandler(SeekToCurrentBatchErrorHandler()) messageListener = UpdateContractSummaryProcess(contractSummaryStorage, txDeltaProcessor, deltaMerger, monitoring, kafkaBrokers) @@ -93,7 +93,7 @@ class EthereumTxConsumerConfiguration { consumerConfigs(), JsonDeserializer(PumpEvent::class.java), JsonDeserializer(EthereumBlock::class.java) ) - val containerProperties = ContainerProperties(chainInfo.blockPumpTopic).apply { + val containerProperties = ContainerProperties(chain.blockPumpTopic).apply { setBatchErrorHandler(SeekToCurrentBatchErrorHandler()) messageListener = UpdateContractSummaryProcess(contractSummaryStorage, blockDeltaProcessor, deltaMerger, monitoring, kafkaBrokers) @@ -113,7 +113,7 @@ class EthereumTxConsumerConfiguration { consumerConfigs(), JsonDeserializer(PumpEvent::class.java), JsonDeserializer(EthereumUncle::class.java) ) - val containerProperties = ContainerProperties(chainInfo.unclePumpTopic).apply { + val containerProperties = ContainerProperties(chain.unclePumpTopic).apply { setBatchErrorHandler(SeekToCurrentBatchErrorHandler()) messageListener = UpdateContractSummaryProcess(contractSummaryStorage, uncleDeltaProcessor, deltaMerger, monitoring, kafkaBrokers) diff --git a/docs/api/search.v1.yaml b/docs/api/search.v1.yaml index c994ac84..7a459be3 100644 --- a/docs/api/search.v1.yaml +++ b/docs/api/search.v1.yaml @@ -87,12 +87,28 @@ paths: operationId: search-stats responses: '200': - description: 'Successful statistics' + description: 'Successful request' content: application/json: schema: $ref: '#/components/schemas/SearchStatsResponse' + + /search/chains: + get: + tags: + - search + summary: Search API available chains and their entities + description: 'Endpoint to obtain search chains and their entities' + operationId: search-chains + responses: + '200': + description: 'Successful request' + content: + application/json: + schema: + $ref: '#/components/schemas/SearchChainsResponse' + components: schemas: @@ -143,3 +159,10 @@ components: indexSizeBytes: type: integer format: int64 + + SearchChainsResponse: + type: object + additionalProperties: + type: array + items: + type: string diff --git a/search-api/src/main/kotlin/fund/cyber/api/bitcoin/dto/Contract.kt b/search-api/src/main/kotlin/fund/cyber/api/bitcoin/dto/Contract.kt index ea120d7b..c9b474ee 100644 --- a/search-api/src/main/kotlin/fund/cyber/api/bitcoin/dto/Contract.kt +++ b/search-api/src/main/kotlin/fund/cyber/api/bitcoin/dto/Contract.kt @@ -20,8 +20,8 @@ data class ContractTxSummaryDto( data class ContractSummaryDto( val hash: String, - val confirmedBalance: String, - val confirmedTotalReceived: String, + val confirmedBalance: BigDecimal, + val confirmedTotalReceived: BigDecimal, val confirmedTxNumber: Int, val firstActivityDate: Instant, val lastActivityDate: Instant, @@ -29,8 +29,9 @@ data class ContractSummaryDto( ) { constructor(contract: CqlBitcoinContractSummary, txes: List) : this( - hash = contract.hash, confirmedBalance = contract.confirmedBalance, - confirmedTotalReceived = contract.confirmedTotalReceived, confirmedTxNumber = contract.confirmedTxNumber, + hash = contract.hash, confirmedBalance = BigDecimal(contract.confirmedBalance), + confirmedTotalReceived = BigDecimal(contract.confirmedTotalReceived), + confirmedTxNumber = contract.confirmedTxNumber, firstActivityDate = contract.firstActivityDate, lastActivityDate = contract.lastActivityDate, unconfirmedTxValues = txes.map { contractTx -> contractTx.hash to ContractTxSummaryDto(contractTx) }.toMap() ) diff --git a/search-api/src/main/kotlin/fund/cyber/api/bitcoin/handlers/Block.kt b/search-api/src/main/kotlin/fund/cyber/api/bitcoin/handlers/Block.kt index 9062aafb..6d0ae01a 100644 --- a/search-api/src/main/kotlin/fund/cyber/api/bitcoin/handlers/Block.kt +++ b/search-api/src/main/kotlin/fund/cyber/api/bitcoin/handlers/Block.kt @@ -1,14 +1,13 @@ package fund.cyber.api.bitcoin.handlers import fund.cyber.api.common.SingleRepositoryItemRequestHandler +import fund.cyber.api.common.asServerResponse import fund.cyber.api.common.toPageableResponse -import fund.cyber.cassandra.bitcoin.model.CqlBitcoinBlock import fund.cyber.cassandra.bitcoin.repository.BitcoinBlockRepository import fund.cyber.cassandra.bitcoin.repository.PageableBitcoinBlockTxRepository import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.DependsOn -import org.springframework.web.reactive.function.server.ServerResponse @Configuration @DependsOn("bitcoin-search-repositories") @@ -20,9 +19,9 @@ class BitcoinBlockHandlersConfiguration { BitcoinBlockRepository::class.java ) { request, repository -> - val blockNumber = request.pathVariable("blockNumber").toLong() - val block = repository.findById(blockNumber) - ServerResponse.ok().body(block, CqlBitcoinBlock::class.java) + val blockNumber = request.pathVariable("blockNumber").toLong() + val block = repository.findById(blockNumber) + block.asServerResponse() } @Bean diff --git a/search-api/src/main/kotlin/fund/cyber/api/bitcoin/handlers/Contract.kt b/search-api/src/main/kotlin/fund/cyber/api/bitcoin/handlers/Contract.kt index bcd8f045..60b58a80 100644 --- a/search-api/src/main/kotlin/fund/cyber/api/bitcoin/handlers/Contract.kt +++ b/search-api/src/main/kotlin/fund/cyber/api/bitcoin/handlers/Contract.kt @@ -3,6 +3,7 @@ package fund.cyber.api.bitcoin.handlers import fund.cyber.api.bitcoin.dto.ContractSummaryDto import fund.cyber.api.common.BiRepositoryItemRequestHandler import fund.cyber.api.common.SingleRepositoryItemRequestHandler +import fund.cyber.api.common.asServerResponse import fund.cyber.api.common.toPageableResponse import fund.cyber.cassandra.bitcoin.repository.BitcoinContractSummaryRepository import fund.cyber.cassandra.bitcoin.repository.BitcoinContractTxRepository @@ -11,7 +12,6 @@ import fund.cyber.cassandra.bitcoin.repository.PageableBitcoinContractTxReposito import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.DependsOn -import org.springframework.web.reactive.function.server.ServerResponse @Configuration @DependsOn("bitcoin-search-repositories") @@ -32,7 +32,7 @@ class BitcoinContractHandlersConfiguration { val result = contract.zipWith(contractUnconfirmedTxes.collectList()) { contr, txes -> ContractSummaryDto(contr, txes) } - ServerResponse.ok().body(result, ContractSummaryDto::class.java) + result.asServerResponse() } @Bean diff --git a/search-api/src/main/kotlin/fund/cyber/api/bitcoin/handlers/Transaction.kt b/search-api/src/main/kotlin/fund/cyber/api/bitcoin/handlers/Transaction.kt index 0499a390..19483a17 100644 --- a/search-api/src/main/kotlin/fund/cyber/api/bitcoin/handlers/Transaction.kt +++ b/search-api/src/main/kotlin/fund/cyber/api/bitcoin/handlers/Transaction.kt @@ -1,12 +1,11 @@ package fund.cyber.api.bitcoin.handlers import fund.cyber.api.common.SingleRepositoryItemRequestHandler -import fund.cyber.cassandra.bitcoin.model.CqlBitcoinTx +import fund.cyber.api.common.asServerResponse import fund.cyber.cassandra.bitcoin.repository.BitcoinTxRepository import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.DependsOn -import org.springframework.web.reactive.function.server.ServerResponse @Configuration @DependsOn("bitcoin-search-repositories") @@ -20,7 +19,7 @@ class BitcoinTxHandlersConfiguration { val hash = request.pathVariable("hash") val tx = repository.findById(hash) - ServerResponse.ok().body(tx, CqlBitcoinTx::class.java) + tx.asServerResponse() } } diff --git a/search-api/src/main/kotlin/fund/cyber/api/common/CommonConfiguration.kt b/search-api/src/main/kotlin/fund/cyber/api/common/CommonConfiguration.kt index 0b6077e5..ab9bd227 100644 --- a/search-api/src/main/kotlin/fund/cyber/api/common/CommonConfiguration.kt +++ b/search-api/src/main/kotlin/fund/cyber/api/common/CommonConfiguration.kt @@ -21,16 +21,22 @@ import org.springframework.context.support.GenericApplicationContext import org.springframework.web.cors.CorsConfiguration import org.springframework.web.cors.reactive.CorsWebFilter import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource +import org.springframework.web.reactive.function.BodyInserters import org.springframework.web.reactive.function.server.HandlerFunction import org.springframework.web.reactive.function.server.RequestPredicates.path import org.springframework.web.reactive.function.server.RouterFunction import org.springframework.web.reactive.function.server.RouterFunctions import org.springframework.web.reactive.function.server.ServerResponse +import org.springframework.web.reactive.function.server.ServerResponse.notFound +import org.springframework.web.reactive.function.server.ServerResponse.ok import org.springframework.web.util.pattern.PathPatternParser import reactor.core.publisher.Mono import java.net.InetAddress +fun Mono.asServerResponse() = this.flatMap { obj -> ok().body(BodyInserters.fromObject(obj)) } + .switchIfEmpty(notFound().build()) + fun List>.asSingleRouterFunction(): RouterFunction { return if (isEmpty()) { RouterFunctions.route(path("/ping"), HandlerFunction { _ -> ServerResponse.ok().build() as Mono }) diff --git a/search-api/src/main/kotlin/fund/cyber/api/ethereum/dto/Contract.kt b/search-api/src/main/kotlin/fund/cyber/api/ethereum/dto/Contract.kt index 8264dc28..8c6d95ed 100644 --- a/search-api/src/main/kotlin/fund/cyber/api/ethereum/dto/Contract.kt +++ b/search-api/src/main/kotlin/fund/cyber/api/ethereum/dto/Contract.kt @@ -7,9 +7,9 @@ import java.time.Instant data class ContractSummaryDto( val hash: String, - val confirmedBalance: String, + val confirmedBalance: BigDecimal, val smartContract: Boolean, - val confirmedTotalReceived: String, + val confirmedTotalReceived: BigDecimal, val txNumber: Int, val minedUncleNumber: Int, val minedBlockNumber: Int, @@ -19,10 +19,11 @@ data class ContractSummaryDto( ) { constructor(contract: CqlEthereumContractSummary, txes: List) : this( - hash = contract.hash, confirmedBalance = contract.confirmedBalance, smartContract = contract.smartContract, - confirmedTotalReceived = contract.confirmedTotalReceived, txNumber = contract.txNumber, - minedUncleNumber = contract.minedUncleNumber, minedBlockNumber = contract.minedBlockNumber, - firstActivityDate = contract.firstActivityDate, lastActivityDate = contract.lastActivityDate, + hash = contract.hash, confirmedBalance = BigDecimal(contract.confirmedBalance), + smartContract = contract.smartContract, confirmedTotalReceived = BigDecimal(contract.confirmedTotalReceived), + txNumber = contract.txNumber, minedUncleNumber = contract.minedUncleNumber, + minedBlockNumber = contract.minedBlockNumber, firstActivityDate = contract.firstActivityDate, + lastActivityDate = contract.lastActivityDate, unconfirmedTxValues = txes.map { contractTx -> contractTx.hash to BigDecimal(contractTx.value) }.toMap() ) } diff --git a/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Block.kt b/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Block.kt index ca3bf003..93309831 100644 --- a/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Block.kt +++ b/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Block.kt @@ -1,14 +1,13 @@ package fund.cyber.api.ethereum.handlers import fund.cyber.api.common.SingleRepositoryItemRequestHandler +import fund.cyber.api.common.asServerResponse import fund.cyber.api.common.toPageableResponse -import fund.cyber.cassandra.ethereum.model.CqlEthereumBlock import fund.cyber.cassandra.ethereum.repository.EthereumBlockRepository import fund.cyber.cassandra.ethereum.repository.PageableEthereumBlockTxRepository import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.DependsOn -import org.springframework.web.reactive.function.server.ServerResponse @Configuration @DependsOn("ethereum-search-repositories") @@ -22,7 +21,7 @@ class EthereumBlockHandlersConfiguration { val blockNumber = request.pathVariable("blockNumber").toLong() val block = repository.findById(blockNumber) - ServerResponse.ok().body(block, CqlEthereumBlock::class.java) + block.asServerResponse() } @Bean diff --git a/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Contract.kt b/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Contract.kt index b6cdc9ec..f97fad70 100644 --- a/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Contract.kt +++ b/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Contract.kt @@ -2,6 +2,7 @@ package fund.cyber.api.ethereum.handlers import fund.cyber.api.common.BiRepositoryItemRequestHandler import fund.cyber.api.common.SingleRepositoryItemRequestHandler +import fund.cyber.api.common.asServerResponse import fund.cyber.api.common.toPageableResponse import fund.cyber.api.ethereum.dto.ContractSummaryDto import fund.cyber.cassandra.ethereum.repository.EthereumContractRepository @@ -13,7 +14,6 @@ import fund.cyber.common.toSearchHashFormat import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.DependsOn -import org.springframework.web.reactive.function.server.ServerResponse @Configuration @DependsOn("ethereum-search-repositories") @@ -34,7 +34,7 @@ class EthereumContractHandlersConfiguration { val result = contract.zipWith(contractUnconfirmedTxes.collectList()) { contr, txes -> ContractSummaryDto(contr, txes) } - ServerResponse.ok().body(result, ContractSummaryDto::class.java) + result.asServerResponse() } @Bean diff --git a/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Transaction.kt b/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Transaction.kt index f8580be3..d0c50e6c 100644 --- a/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Transaction.kt +++ b/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Transaction.kt @@ -1,13 +1,12 @@ package fund.cyber.api.ethereum.handlers import fund.cyber.api.common.SingleRepositoryItemRequestHandler -import fund.cyber.cassandra.ethereum.model.CqlEthereumTx +import fund.cyber.api.common.asServerResponse import fund.cyber.cassandra.ethereum.repository.EthereumTxRepository import fund.cyber.common.toSearchHashFormat import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.DependsOn -import org.springframework.web.reactive.function.server.ServerResponse @Configuration @DependsOn("ethereum-search-repositories") @@ -21,7 +20,7 @@ class EthereumTxHandlersConfiguration { val hash = request.pathVariable("hash") val tx = repository.findById(hash.toSearchHashFormat()) - ServerResponse.ok().body(tx, CqlEthereumTx::class.java).switchIfEmpty(ServerResponse.notFound().build()) + tx.asServerResponse() } } diff --git a/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Uncle.kt b/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Uncle.kt index d884fad1..9a8eafcb 100644 --- a/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Uncle.kt +++ b/search-api/src/main/kotlin/fund/cyber/api/ethereum/handlers/Uncle.kt @@ -1,13 +1,12 @@ package fund.cyber.api.ethereum.handlers import fund.cyber.api.common.SingleRepositoryItemRequestHandler -import fund.cyber.cassandra.ethereum.model.CqlEthereumUncle +import fund.cyber.api.common.asServerResponse import fund.cyber.cassandra.ethereum.repository.EthereumUncleRepository import fund.cyber.common.toSearchHashFormat import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.DependsOn -import org.springframework.web.reactive.function.server.ServerResponse @Configuration @DependsOn("ethereum-search-repositories") @@ -21,7 +20,7 @@ class EthereumUncleHandlersConfiguration { val hash = request.pathVariable("hash") val uncle = repository.findById(hash.toSearchHashFormat()) - ServerResponse.ok().body(uncle, CqlEthereumUncle::class.java) + uncle.asServerResponse() } } diff --git a/search-api/src/main/kotlin/fund/cyber/api/search/ElasticResponse.kt b/search-api/src/main/kotlin/fund/cyber/api/search/ElasticResponse.kt new file mode 100644 index 00000000..3c135cf6 --- /dev/null +++ b/search-api/src/main/kotlin/fund/cyber/api/search/ElasticResponse.kt @@ -0,0 +1,49 @@ +package fund.cyber.api.search + +import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse +import org.elasticsearch.action.search.SearchResponse + +fun SearchResponse.toCyberSearchResponse(query: String, page: Int, pageSize: Int) + : fund.cyber.api.search.SearchResponse { + + val responseItems = this.hits.map { hit -> + val chain = hit.index.substringBefore(".") + val entity = hit.index.substringAfter(".") + ItemPreview(chain, entity, hit.sourceAsString) + } + return SearchResponse( + query = query, page = page, pageSize = pageSize, totalHits = this.hits.totalHits, + items = responseItems, searchTime = this.tookInMillis + ) +} + +fun IndicesStatsResponse.searchStats(): SearchStatsResponse { + + val indexSizeBytes = this.total.store.sizeInBytes + + val transactionsCount = this.indices + .filterKeys { indexName -> indexName.endsWith("tx", true) } + .values.map { txIndexStat -> txIndexStat.primaries.docs.count }.sum() + + val chains = this.indices.keys.map { indexName -> indexName.substringBefore(".") }.toSet() + + return SearchStatsResponse(chains.size, transactionsCount, indexSizeBytes) +} + +fun IndicesStatsResponse.chainEntities(): Map> { + + val chainsEntities = mutableMapOf>() + + this.indices.keys.forEach { indexName -> + + val chainName = indexName.substringBefore(".") + val entityName = indexName.substringAfter(".") + + if (chainsEntities.containsKey(chainName)) { + chainsEntities[chainName]!!.add(entityName) + } else { + chainsEntities[chainName] = mutableListOf(entityName) + } + } + return chainsEntities +} diff --git a/search-api/src/main/kotlin/fund/cyber/api/search/SearchController.kt b/search-api/src/main/kotlin/fund/cyber/api/search/SearchController.kt index f814e4aa..40fbe381 100644 --- a/search-api/src/main/kotlin/fund/cyber/api/search/SearchController.kt +++ b/search-api/src/main/kotlin/fund/cyber/api/search/SearchController.kt @@ -11,60 +11,49 @@ import reactor.core.publisher.Mono @RestController class SearchController( - private val elasticClient: TransportClient + private val elasticClient: TransportClient ) { //todo slice caching, general web caching @GetMapping("/search") fun search( - @RequestParam query: String, - @RequestParam(required = false, defaultValue = "0") page: Int, - @RequestParam(required = false, defaultValue = "10") pageSize: Int, - @RequestParam(required = false, defaultValue = "") chains: Array, - @RequestParam(required = false, defaultValue = "") types: Array + @RequestParam query: String, + @RequestParam(required = false, defaultValue = "0") page: Int, + @RequestParam(required = false, defaultValue = "10") pageSize: Int, + @RequestParam(required = false, defaultValue = "") chains: Array, + @RequestParam(required = false, defaultValue = "") types: Array ): Mono { - val elasticQuery = QueryBuilders.matchQuery("_all", query) - .fuzziness(Fuzziness.ZERO) + val elasticQuery = QueryBuilders.matchQuery("_all", query).fuzziness(Fuzziness.ZERO) - val elasticResponse = elasticClient.prepareSearch(*prepareIndices(chains, types)) + return Mono.fromCallable { + elasticClient.prepareSearch(*prepareIndices(chains, types)) .setIndicesOptions(IndicesOptions.lenientExpandOpen()) .setTypes() .setQuery(elasticQuery) .setFrom(page * pageSize).setSize(pageSize).setExplain(true) .get() - - val responseItems = elasticResponse.hits.map { hit -> - val chain = hit.index.substringBefore(".") - val entity = hit.index.substringAfter(".") - ItemPreview(chain, entity, hit.sourceAsString) - } - - return Mono.just( - SearchResponse( - query = query, page = page, pageSize = pageSize, totalHits = elasticResponse.hits.totalHits, - items = responseItems, searchTime = elasticResponse.tookInMillis - ) - ) + }.map { elasticResponse -> elasticResponse.toCyberSearchResponse(query, page, pageSize) } } @GetMapping("/search/stats") - fun searchStats() : Mono { - - val indicesStats = elasticClient.admin().indices().prepareStats().setStore(true).setDocs(true).execute().get() + fun searchStats(): Mono { - val indexSizeBytes = indicesStats.total.store.sizeInBytes - - val transactionsCount = indicesStats.indices - .filterKeys { indexName -> indexName.endsWith("tx", true)} - .values.map { txIndexStat -> txIndexStat.primaries.docs.count }.sum() + return Mono.fromCallable { + elasticClient.admin().indices().prepareStats().setStore(true).setDocs(true).execute().get() + }.map { indicesStats -> indicesStats.searchStats() } + } - val chains = indicesStats.indices.keys.map { indexName -> indexName.substringBefore(".") }.toSet() + @GetMapping("/search/chains") + fun searchChains(): Mono>> { - return Mono.just(SearchStatsResponse(chains.size, transactionsCount, indexSizeBytes)) + return Mono + .fromCallable { elasticClient.admin().indices().prepareStats().execute().get() } + .map { indicesStats -> indicesStats.chainEntities() } } private fun prepareIndices(chains: Array, types: Array): Array { + val chainsToFilter = if (chains.isEmpty()) arrayOf("*") else chains val typesToFilter = if (types.isEmpty()) arrayOf("*") else types diff --git a/search-api/src/main/resources/application.yml b/search-api/src/main/resources/application.yml index 7ab88f6a..43312d90 100644 --- a/search-api/src/main/resources/application.yml +++ b/search-api/src/main/resources/application.yml @@ -15,4 +15,8 @@ management: uptime: enabled: true processor: - enabled: false \ No newline at end of file + enabled: false +server: + error: + whitelabel: + enabled: false \ No newline at end of file