
com.bybutter.sisyphus.starter.grpc.transcoding.GrpcTranscodingConfig.kt Maven / Gradle / Ivy
package com.bybutter.sisyphus.starter.grpc.transcoding
import com.bybutter.sisyphus.spring.BeanUtils
import com.bybutter.sisyphus.starter.grpc.LocalClientRepository
import com.bybutter.sisyphus.starter.grpc.ServiceRegistrar
import io.grpc.Channel
import io.grpc.Server
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
import org.springframework.beans.factory.support.BeanDefinitionBuilder
import org.springframework.beans.factory.support.BeanDefinitionRegistry
import org.springframework.context.EnvironmentAware
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar
import org.springframework.core.env.Environment
import org.springframework.core.type.AnnotationMetadata
import org.springframework.web.cors.reactive.CorsConfigurationSource
import org.springframework.web.cors.reactive.CorsWebFilter
import org.springframework.web.reactive.function.server.RouterFunction
/**
* Config of gRPC transcoding, it will register webflux router and CORS filter based on the gRPC server.
*
* It imported by [EnableHttpToGrpcTranscoding] annotation, and it will found all services registered by
* [ServiceRegistrar], create [TranscodingRouterFunction] and register into spring context for handling
* HTTP requests.
*
* Also, CORS requests have been supported too, it will analyze service and register [CorsWebFilter] based
* on [TranscodingCorsConfigurationSource] into spring context.
*/
class GrpcTranscodingConfig : ImportBeanDefinitionRegistrar, EnvironmentAware {
private lateinit var environment: Environment
override fun setEnvironment(environment: Environment) {
this.environment = environment
}
override fun registerBeanDefinitions(
importingClassMetadata: AnnotationMetadata,
registry: BeanDefinitionRegistry,
) {
// Find the [EnableHttpToGrpcTranscoding] annotation.
val enableAnnotation =
importingClassMetadata.getAnnotationAttributes(EnableHttpToGrpcTranscoding::class.java.name)
?: return
// Get the enabled transcoding service in [EnableHttpToGrpcTranscoding] annotation.
val enableServices =
(enableAnnotation[EnableHttpToGrpcTranscoding::services.name] as? Array)?.asList()
?: listOf()
registerRouterFunction(registry, enableServices)
registerTranscodingCorsConfigSource(registry, enableServices)
}
/**
* Register router function bean definition to spring context.
*
* @param registry BeanDefinitionRegistry the [BeanDefinitionRegistry] for registering.
* @param enableServices Collection the name of services which need to enable gRPC transcoding.
* Empty list for all supported services.
*/
private fun registerRouterFunction(
registry: BeanDefinitionRegistry,
enableServices: Collection,
) {
val definitionBuilder =
BeanDefinitionBuilder.genericBeanDefinition(RouterFunction::class.java) {
val server =
(registry as ConfigurableListableBeanFactory).getBean(ServiceRegistrar.QUALIFIER_AUTO_CONFIGURED_GRPC_SERVER) as Server
val channel =
(registry as ConfigurableListableBeanFactory).getBean(
LocalClientRepository.QUALIFIER_AUTO_CONFIGURED_GRPC_IN_PROCESS_CHANNEL,
) as Channel
val rules =
exportTranscodingRules(
BeanUtils.getSortedBeans(registry, TranscodingRouterRuleExporter::class.java).values,
server,
enableServices,
)
TranscodingRouterFunction(rules, channel)
}
definitionBuilder.addDependsOn(LocalClientRepository.QUALIFIER_AUTO_CONFIGURED_GRPC_IN_PROCESS_CHANNEL)
registry.registerBeanDefinition(
QUALIFIER_AUTO_CONFIGURED_GRPC_TRANSCODING_ROUTER_FUNCTION,
definitionBuilder.beanDefinition,
)
}
/**
* Register gRPC transcoding CORS config source bean definition to spring context.
*
* @param enableServices Collection the name of services which need to enable CORS in transcoding.
* Empty list for all supported services.
*/
private fun registerTranscodingCorsConfigSource(
registry: BeanDefinitionRegistry,
enableServices: Collection,
) {
val definitionBuilder =
BeanDefinitionBuilder.genericBeanDefinition(CorsConfigurationSource::class.java) {
val server =
(registry as ConfigurableListableBeanFactory).getBean(ServiceRegistrar.QUALIFIER_AUTO_CONFIGURED_GRPC_SERVER) as Server
val rules =
exportTranscodingRules(
BeanUtils.getSortedBeans(registry, TranscodingRouterRuleExporter::class.java).values,
server,
enableServices,
)
// Create CORS config source for transcoding.
TranscodingCorsConfigurationSource(
rules,
// Try to get the default transcoding cors configuration factory form spring application context
BeanUtils.getSortedBeans(registry, TranscodingCorsConfigurationInterceptor::class.java).values,
)
}
registry.registerBeanDefinition(
QUALIFIER_AUTO_CONFIGURED_GRPC_TRANSCODING_CORS_CONFIG,
definitionBuilder.beanDefinition,
)
}
private fun exportTranscodingRules(
exporters: Collection,
server: Server,
enableServices: Collection,
): List {
val enableServices = enableServices.toSet()
val rules = mutableListOf()
for (exporter in exporters) {
exporter.export(server, enableServices, rules)
}
return rules
}
companion object {
/**
* Bean name for registered transcoding router function, you can use it to refer it.
*/
const val QUALIFIER_AUTO_CONFIGURED_GRPC_TRANSCODING_ROUTER_FUNCTION = "sisyphus:grpc:transcoding-router"
/**
* Bean name for registered transcoding CORS filter, you can use it to refer it.
*/
const val QUALIFIER_AUTO_CONFIGURED_GRPC_TRANSCODING_CORS_CONFIG = "sisyphus:grpc:transcoding-cors"
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy