Compare commits
7 Commits
master
...
feature/pm
| Author | SHA1 | Date |
|---|---|---|
|
|
e1a10dd039 | |
|
|
7f8c17a938 | |
|
|
a7146ad28f | |
|
|
6617d1c5c0 | |
|
|
8289858818 | |
|
|
2a557de252 | |
|
|
b33082e1fe |
|
|
@ -6,7 +6,7 @@ import org.springframework.stereotype.Component
|
||||||
import ru.touchin.push.message.provider.dto.request.PushTokenCheck
|
import ru.touchin.push.message.provider.dto.request.PushTokenCheck
|
||||||
import ru.touchin.push.message.provider.dto.request.PushTokenMessage
|
import ru.touchin.push.message.provider.dto.request.PushTokenMessage
|
||||||
import ru.touchin.push.message.provider.dto.result.SendPushResult
|
import ru.touchin.push.message.provider.dto.result.SendPushResult
|
||||||
import ru.touchin.push.message.provider.dto.result.SendPushTokenMessageResult
|
import ru.touchin.push.message.provider.dto.result.SendPushTokenMessageTraceableResult
|
||||||
import ru.touchin.push.message.provider.enums.PushTokenStatus
|
import ru.touchin.push.message.provider.enums.PushTokenStatus
|
||||||
import ru.touchin.push.message.provider.exceptions.InvalidPushTokenException
|
import ru.touchin.push.message.provider.exceptions.InvalidPushTokenException
|
||||||
import ru.touchin.push.message.provider.exceptions.PushMessageProviderException
|
import ru.touchin.push.message.provider.exceptions.PushMessageProviderException
|
||||||
|
|
@ -32,7 +32,7 @@ class FcmClient(
|
||||||
fun check(request: PushTokenCheck): PushTokenStatus {
|
fun check(request: PushTokenCheck): PushTokenStatus {
|
||||||
val validationRequest = PushTokenMessage(
|
val validationRequest = PushTokenMessage(
|
||||||
token = request.pushToken,
|
token = request.pushToken,
|
||||||
notification = null,
|
pushMessageNotification = null,
|
||||||
data = emptyMap()
|
data = emptyMap()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ class FcmClient(
|
||||||
return try {
|
return try {
|
||||||
val messageId = firebaseMessaging.send(message, dryRun)
|
val messageId = firebaseMessaging.send(message, dryRun)
|
||||||
|
|
||||||
SendPushTokenMessageResult(messageId)
|
SendPushTokenMessageTraceableResult(messageId)
|
||||||
} catch (e: FirebaseMessagingException) {
|
} catch (e: FirebaseMessagingException) {
|
||||||
throw firebaseMessagingExceptionConverter(e)
|
throw firebaseMessagingExceptionConverter(e)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package ru.touchin.push.message.provider.fcm.converters
|
|
||||||
|
|
||||||
import com.google.firebase.messaging.Notification as FcmNotification
|
|
||||||
import org.springframework.stereotype.Component
|
|
||||||
import ru.touchin.push.message.provider.dto.Notification
|
|
||||||
|
|
||||||
@Component
|
|
||||||
class NotificationConverter {
|
|
||||||
|
|
||||||
operator fun invoke(notification: Notification): FcmNotification {
|
|
||||||
return FcmNotification.builder()
|
|
||||||
.setTitle(notification.title)
|
|
||||||
.setBody(notification.description)
|
|
||||||
.setImage(notification.imageUrl)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package ru.touchin.push.message.provider.fcm.converters
|
||||||
|
|
||||||
|
import com.google.firebase.messaging.Notification as FcmNotification
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
import ru.touchin.push.message.provider.dto.PushMessageNotification
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class PushMessageNotificationConverter {
|
||||||
|
|
||||||
|
operator fun invoke(pushMessageNotification: PushMessageNotification): FcmNotification {
|
||||||
|
return FcmNotification.builder()
|
||||||
|
.setTitle(pushMessageNotification.title)
|
||||||
|
.setBody(pushMessageNotification.description)
|
||||||
|
.setImage(pushMessageNotification.imageUrl)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -6,12 +6,12 @@ import com.google.firebase.messaging.ApnsConfig
|
||||||
import com.google.firebase.messaging.Aps
|
import com.google.firebase.messaging.Aps
|
||||||
import com.google.firebase.messaging.Message
|
import com.google.firebase.messaging.Message
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import ru.touchin.push.message.provider.dto.Notification
|
import ru.touchin.push.message.provider.dto.PushMessageNotification
|
||||||
import ru.touchin.push.message.provider.dto.request.PushTokenMessage
|
import ru.touchin.push.message.provider.dto.request.PushTokenMessage
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class PushTokenMessageConverter(
|
class PushTokenMessageConverter(
|
||||||
private val notificationConverter: NotificationConverter
|
private val pushMessageNotificationConverter: PushMessageNotificationConverter
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
|
@ -26,14 +26,14 @@ class PushTokenMessageConverter(
|
||||||
.setToken(request.token)
|
.setToken(request.token)
|
||||||
.setupApns()
|
.setupApns()
|
||||||
.setupAndroid()
|
.setupAndroid()
|
||||||
.setIfExists(request.notification)
|
.setIfExists(request.pushMessageNotification)
|
||||||
.putAllData(request.data)
|
.putAllData(request.data)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Message.Builder.setIfExists(notification: Notification?): Message.Builder {
|
private fun Message.Builder.setIfExists(pushMessageNotification: PushMessageNotification?): Message.Builder {
|
||||||
return if (notification != null) {
|
return if (pushMessageNotification != null) {
|
||||||
setNotification(notificationConverter(notification))
|
setNotification(pushMessageNotificationConverter(pushMessageNotification))
|
||||||
} else {
|
} else {
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,15 @@ import org.junit.Assert
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.boot.test.context.SpringBootTest
|
import org.springframework.boot.test.context.SpringBootTest
|
||||||
import ru.touchin.push.message.provider.dto.Notification
|
import ru.touchin.push.message.provider.dto.PushMessageNotification
|
||||||
import com.google.firebase.messaging.Notification as FcmNotification
|
import com.google.firebase.messaging.Notification as FcmNotification
|
||||||
import org.junit.jupiter.api.DisplayName
|
import org.junit.jupiter.api.DisplayName
|
||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
class NotificationConverterTest {
|
class PushMessageNotificationConverterTest {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
lateinit var notificationConverter: NotificationConverter
|
lateinit var pushMessageNotificationConverter: PushMessageNotificationConverter
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
lateinit var objectMapper: ObjectMapper
|
lateinit var objectMapper: ObjectMapper
|
||||||
|
|
@ -21,19 +21,19 @@ class NotificationConverterTest {
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("Конвертация уведомления происходит корректно")
|
@DisplayName("Конвертация уведомления происходит корректно")
|
||||||
fun invoke_basic() {
|
fun invoke_basic() {
|
||||||
val notification = Notification(
|
val pushMessageNotification = PushMessageNotification(
|
||||||
title = "title",
|
title = "title",
|
||||||
description = "description",
|
description = "description",
|
||||||
imageUrl = "imageUrl"
|
imageUrl = "imageUrl"
|
||||||
)
|
)
|
||||||
|
|
||||||
val realResult = notificationConverter(notification)
|
val realResult = pushMessageNotificationConverter(pushMessageNotification)
|
||||||
val realResultJson = objectMapper.writeValueAsString(realResult)
|
val realResultJson = objectMapper.writeValueAsString(realResult)
|
||||||
|
|
||||||
val expectedResult = FcmNotification.builder()
|
val expectedResult = FcmNotification.builder()
|
||||||
.setTitle(notification.title)
|
.setTitle(pushMessageNotification.title)
|
||||||
.setBody(notification.description)
|
.setBody(pushMessageNotification.description)
|
||||||
.setImage(notification.imageUrl)
|
.setImage(pushMessageNotification.imageUrl)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val expectedResultJson = objectMapper.writeValueAsString(expectedResult)
|
val expectedResultJson = objectMapper.writeValueAsString(expectedResult)
|
||||||
|
|
@ -11,7 +11,7 @@ import org.junit.jupiter.api.DisplayName
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.boot.test.context.SpringBootTest
|
import org.springframework.boot.test.context.SpringBootTest
|
||||||
import ru.touchin.push.message.provider.dto.Notification
|
import ru.touchin.push.message.provider.dto.PushMessageNotification
|
||||||
import ru.touchin.push.message.provider.dto.request.PushTokenMessage
|
import ru.touchin.push.message.provider.dto.request.PushTokenMessage
|
||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
|
|
@ -21,7 +21,7 @@ class PushTokenMessageConverterTest {
|
||||||
lateinit var pushTokenMessageConverter: PushTokenMessageConverter
|
lateinit var pushTokenMessageConverter: PushTokenMessageConverter
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
lateinit var notificationConverter: NotificationConverter
|
lateinit var pushMessageNotificationConverter: PushMessageNotificationConverter
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
lateinit var objectMapper: ObjectMapper
|
lateinit var objectMapper: ObjectMapper
|
||||||
|
|
@ -29,14 +29,14 @@ class PushTokenMessageConverterTest {
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("Конвертация сообщения с уведомлением происходит корректно")
|
@DisplayName("Конвертация сообщения с уведомлением происходит корректно")
|
||||||
fun invoke_withNotification() {
|
fun invoke_withNotification() {
|
||||||
val notification = Notification(
|
val pushMessageNotification = PushMessageNotification(
|
||||||
title = "title",
|
title = "title",
|
||||||
description = "description",
|
description = "description",
|
||||||
imageUrl = "imageUrl"
|
imageUrl = "imageUrl"
|
||||||
)
|
)
|
||||||
val pushTokenMessage = PushTokenMessage(
|
val pushTokenMessage = PushTokenMessage(
|
||||||
token = "token",
|
token = "token",
|
||||||
notification = notification,
|
pushMessageNotification = pushMessageNotification,
|
||||||
data = mapOf("testKey" to "testvalue")
|
data = mapOf("testKey" to "testvalue")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -45,7 +45,7 @@ class PushTokenMessageConverterTest {
|
||||||
|
|
||||||
val expectedResult = Message.builder()
|
val expectedResult = Message.builder()
|
||||||
.setToken(pushTokenMessage.token)
|
.setToken(pushTokenMessage.token)
|
||||||
.setNotification(notificationConverter(notification))
|
.setNotification(pushMessageNotificationConverter(pushMessageNotification))
|
||||||
.putAllData(pushTokenMessage.data)
|
.putAllData(pushTokenMessage.data)
|
||||||
.setupApns()
|
.setupApns()
|
||||||
.setupAndroid()
|
.setupAndroid()
|
||||||
|
|
@ -65,7 +65,7 @@ class PushTokenMessageConverterTest {
|
||||||
fun invoke_withoutNotification() {
|
fun invoke_withoutNotification() {
|
||||||
val pushTokenMessage = PushTokenMessage(
|
val pushTokenMessage = PushTokenMessage(
|
||||||
token = "token",
|
token = "token",
|
||||||
notification = null,
|
pushMessageNotification = null,
|
||||||
data = mapOf("testKey" to "testvalue")
|
data = mapOf("testKey" to "testvalue")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import org.springframework.boot.test.mock.mockito.MockBean
|
||||||
import ru.touchin.push.message.provider.dto.request.PushTokenCheck
|
import ru.touchin.push.message.provider.dto.request.PushTokenCheck
|
||||||
import ru.touchin.push.message.provider.dto.request.PushTokenMessage
|
import ru.touchin.push.message.provider.dto.request.PushTokenMessage
|
||||||
import ru.touchin.push.message.provider.dto.result.CheckPushTokenResult
|
import ru.touchin.push.message.provider.dto.result.CheckPushTokenResult
|
||||||
import ru.touchin.push.message.provider.dto.result.SendPushTokenMessageResult
|
import ru.touchin.push.message.provider.dto.result.SendPushTokenMessageTraceableResult
|
||||||
import ru.touchin.push.message.provider.enums.PushTokenStatus
|
import ru.touchin.push.message.provider.enums.PushTokenStatus
|
||||||
import ru.touchin.push.message.provider.fcm.clients.FcmClient
|
import ru.touchin.push.message.provider.fcm.clients.FcmClient
|
||||||
import ru.touchin.push.message.provider.services.PushMessageProviderService
|
import ru.touchin.push.message.provider.services.PushMessageProviderService
|
||||||
|
|
@ -29,11 +29,11 @@ class PushMessageProviderFcmServiceTest {
|
||||||
fun send_basic() {
|
fun send_basic() {
|
||||||
val request = PushTokenMessage(
|
val request = PushTokenMessage(
|
||||||
token = "testToken",
|
token = "testToken",
|
||||||
notification = null,
|
pushMessageNotification = null,
|
||||||
data = emptyMap()
|
data = emptyMap()
|
||||||
)
|
)
|
||||||
|
|
||||||
val expectedResult = SendPushTokenMessageResult("testMessageId")
|
val expectedResult = SendPushTokenMessageTraceableResult("testMessageId")
|
||||||
|
|
||||||
Mockito.`when`(
|
Mockito.`when`(
|
||||||
fcmClient.sendPushTokenMessage(request)
|
fcmClient.sendPushTokenMessage(request)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
plugins {
|
||||||
|
id("kotlin")
|
||||||
|
id("kotlin-spring")
|
||||||
|
id("maven-publish")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||||
|
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
||||||
|
|
||||||
|
implementation(project(":logger-spring"))
|
||||||
|
implementation(project(":common-spring-web"))
|
||||||
|
implementation(project(":push-message-provider"))
|
||||||
|
|
||||||
|
testImplementation(project(":logger-spring-web"))
|
||||||
|
|
||||||
|
testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin")
|
||||||
|
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||||
|
testImplementation("org.testcontainers:junit-jupiter")
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ru.touchin.push.message.provider.hpk
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Import
|
||||||
|
import ru.touchin.push.message.provider.hpk.configurations.PushMessageProviderHpkConfiguration
|
||||||
|
|
||||||
|
@Import(value = [PushMessageProviderHpkConfiguration::class])
|
||||||
|
annotation class EnablePushMessageProviderHpk
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
package ru.touchin.push.message.provider.hpk.base.builders
|
||||||
|
|
||||||
|
internal interface Buildable
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
package ru.touchin.push.message.provider.hpk.base.clients
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import org.springframework.web.reactive.function.client.ClientResponse
|
||||||
|
import ru.touchin.push.message.provider.hpk.base.clients.dto.ConditionalResponse
|
||||||
|
|
||||||
|
internal open class ConditionalWebClientParser(
|
||||||
|
private val objectMapper: ObjectMapper,
|
||||||
|
) {
|
||||||
|
|
||||||
|
open fun isOkResponse(clientResponse: ClientResponse): Boolean {
|
||||||
|
return clientResponse.statusCode().is2xxSuccessful
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(Exception::class)
|
||||||
|
inline fun <reified S, reified F> parse(
|
||||||
|
clientResponse: ClientResponse,
|
||||||
|
body: String,
|
||||||
|
): ConditionalResponse<S, F> {
|
||||||
|
return if (isOkResponse(clientResponse)) {
|
||||||
|
ConditionalResponse<S, F>(
|
||||||
|
success = parseValue(body, S::class.java),
|
||||||
|
failure = null
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
ConditionalResponse(
|
||||||
|
success = null,
|
||||||
|
failure = parseValue(body, F::class.java)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> parseValue(source: String?, clazz: Class<T>): T {
|
||||||
|
return if (clazz.canonicalName != String::class.java.canonicalName) {
|
||||||
|
objectMapper.readValue(source, clazz)
|
||||||
|
} else {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
source as T // T is String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
package ru.touchin.push.message.provider.hpk.base.clients
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelOption
|
||||||
|
import io.netty.handler.ssl.SslContextBuilder
|
||||||
|
import io.netty.handler.timeout.ReadTimeoutHandler
|
||||||
|
import io.netty.handler.timeout.WriteTimeoutHandler
|
||||||
|
import org.springframework.http.client.reactive.ReactorClientHttpConnector
|
||||||
|
import org.springframework.web.reactive.function.client.ClientResponse
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient
|
||||||
|
import reactor.core.publisher.Mono
|
||||||
|
import reactor.core.scheduler.Schedulers
|
||||||
|
import reactor.netty.http.client.HttpClient
|
||||||
|
import ru.touchin.common.spring.web.webclient.BaseLogWebClient
|
||||||
|
import ru.touchin.common.spring.web.webclient.dto.RequestLogData
|
||||||
|
import ru.touchin.common.spring.web.webclient.logger.WebClientLogger
|
||||||
|
import ru.touchin.push.message.provider.hpk.base.clients.dto.ConditionalResponse
|
||||||
|
import ru.touchin.push.message.provider.hpk.properties.HpkProperties
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
abstract class ConfigurableWebClient(
|
||||||
|
webClientLogger: WebClientLogger,
|
||||||
|
webClientBuilder: WebClient.Builder,
|
||||||
|
protected val webService: HpkProperties.WebService,
|
||||||
|
) : BaseLogWebClient(webClientLogger, webClientBuilder) {
|
||||||
|
|
||||||
|
private val conditionalWebClientParser: Lazy<ConditionalWebClientParser> = lazy {
|
||||||
|
ConditionalWebClientParser(
|
||||||
|
objectMapper = getObjectMapper(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun WebClient.Builder.setTimeouts(): WebClient.Builder {
|
||||||
|
val httpClient: HttpClient = HttpClient.create()
|
||||||
|
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, webService.http.connectionTimeout.toMillis().toInt())
|
||||||
|
.doOnConnected { setup ->
|
||||||
|
setup.addHandlerLast(ReadTimeoutHandler(webService.http.readTimeout.toMillis(), TimeUnit.MILLISECONDS))
|
||||||
|
setup.addHandlerLast(WriteTimeoutHandler(webService.http.writeTimeout.toMillis(), TimeUnit.MILLISECONDS))
|
||||||
|
}
|
||||||
|
.let { httpClient ->
|
||||||
|
webService.ssl?.let { ssl ->
|
||||||
|
httpClient.secure { builder ->
|
||||||
|
builder
|
||||||
|
.sslContext(SslContextBuilder.forClient().build())
|
||||||
|
.handshakeTimeout(ssl.handshakeTimeout)
|
||||||
|
.closeNotifyFlushTimeout(ssl.notifyFlushTimeout)
|
||||||
|
.closeNotifyReadTimeout(ssl.notifyReadTimeout)
|
||||||
|
}
|
||||||
|
} ?: httpClient
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientConnector(ReactorClientHttpConnector(httpClient))
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline fun <reified S, reified F> WebClient.RequestHeadersSpec<*>.exchangeWithWrap(
|
||||||
|
requestLogData: RequestLogData,
|
||||||
|
): Mono<ConditionalResponse<S, F>> {
|
||||||
|
return exchangeToMono { clientResponse ->
|
||||||
|
parse<S, F>(clientResponse)
|
||||||
|
}.doOnNext { responseWrapper ->
|
||||||
|
getLogger().log(
|
||||||
|
requestLogData.copy(
|
||||||
|
responseBody = responseWrapper.success ?: responseWrapper.failure
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline fun <reified S, reified F> parse(
|
||||||
|
clientResponse: ClientResponse,
|
||||||
|
): Mono<ConditionalResponse<S, F>> {
|
||||||
|
val responseBody = clientResponse
|
||||||
|
.bodyToMono(String::class.java)
|
||||||
|
.defaultIfEmpty(String())
|
||||||
|
.publishOn(Schedulers.parallel())
|
||||||
|
|
||||||
|
return responseBody
|
||||||
|
.map { body ->
|
||||||
|
conditionalWebClientParser.value.parse(
|
||||||
|
clientResponse = clientResponse,
|
||||||
|
body = body,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package ru.touchin.push.message.provider.hpk.base.clients.dto
|
||||||
|
|
||||||
|
internal open class ConditionalResponse<S, F>(
|
||||||
|
val success: S?,
|
||||||
|
val failure: F?,
|
||||||
|
) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
// Only one value should be present
|
||||||
|
check((success == null) != (failure == null))
|
||||||
|
}
|
||||||
|
|
||||||
|
val isSuccess: Boolean = success != null
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package ru.touchin.push.message.provider.hpk.base.enums
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonValue
|
||||||
|
|
||||||
|
internal interface ValueableSerializableEnum<T> {
|
||||||
|
|
||||||
|
val value: T
|
||||||
|
|
||||||
|
@JsonValue
|
||||||
|
fun toValue(): T = value
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ru.touchin.push.message.provider.hpk.base.extensions
|
||||||
|
|
||||||
|
import ru.touchin.push.message.provider.hpk.base.builders.Buildable
|
||||||
|
|
||||||
|
fun <V, B : Buildable> B.ifNotNull(value: V?, setter: B.(V) -> B): B {
|
||||||
|
return value?.let { setter(it) } ?: this
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
package ru.touchin.push.message.provider.hpk.configurations
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import com.fasterxml.jackson.databind.PropertyNamingStrategies
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
|
||||||
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
|
||||||
|
import org.springframework.cache.CacheManager
|
||||||
|
import org.springframework.cache.concurrent.ConcurrentMapCache
|
||||||
|
import org.springframework.cache.support.SimpleCacheManager
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.ComponentScan
|
||||||
|
import org.springframework.context.annotation.Import
|
||||||
|
import ru.touchin.push.message.provider.configurations.PushMessageProviderConfiguration
|
||||||
|
import ru.touchin.push.message.provider.hpk.services.HmsOauthAccessTokenCacheServiceImpl.Companion.HMS_CLIENT_SERVICE_CACHE_KEY
|
||||||
|
|
||||||
|
@ComponentScan("ru.touchin.push.message.provider.hpk")
|
||||||
|
@ConfigurationPropertiesScan(basePackages = ["ru.touchin.push.message.provider.hpk"])
|
||||||
|
@Import(value = [PushMessageProviderConfiguration::class])
|
||||||
|
class PushMessageProviderHpkConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Qualifier("push-message-provider.hpk.webclient-objectmapper")
|
||||||
|
fun webclientObjectMapper(): ObjectMapper {
|
||||||
|
return jacksonObjectMapper()
|
||||||
|
.registerModule(JavaTimeModule())
|
||||||
|
.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
|
||||||
|
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
|
||||||
|
.setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
|
||||||
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Qualifier("push-message-provider.hpk.client-objectmapper")
|
||||||
|
fun clientObjectMapper(): ObjectMapper {
|
||||||
|
return jacksonObjectMapper()
|
||||||
|
.registerModule(JavaTimeModule())
|
||||||
|
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
|
||||||
|
.setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
@Qualifier("push-message-provider.hpk.webclient-cachemanager")
|
||||||
|
fun cacheManager(): CacheManager {
|
||||||
|
return SimpleCacheManager().also {
|
||||||
|
it.setCaches(
|
||||||
|
listOf(
|
||||||
|
ConcurrentMapCache(HMS_CLIENT_SERVICE_CACHE_KEY)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
package ru.touchin.push.message.provider.hpk.properties
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||||
|
import org.springframework.boot.context.properties.ConstructorBinding
|
||||||
|
import java.net.URL
|
||||||
|
import java.time.Duration
|
||||||
|
|
||||||
|
@ConstructorBinding
|
||||||
|
@ConfigurationProperties(prefix = "push-message-provider.hpk")
|
||||||
|
data class HpkProperties(
|
||||||
|
val webServices: WebServices,
|
||||||
|
) {
|
||||||
|
|
||||||
|
class WebServices(
|
||||||
|
val clientId: String,
|
||||||
|
val oauth: Oauth,
|
||||||
|
val hpk: Hpk,
|
||||||
|
)
|
||||||
|
|
||||||
|
class Oauth(
|
||||||
|
val clientSecret: String,
|
||||||
|
url: URL,
|
||||||
|
http: Http,
|
||||||
|
ssl: Ssl?,
|
||||||
|
) : WebService(
|
||||||
|
url = url,
|
||||||
|
http = http,
|
||||||
|
ssl = ssl,
|
||||||
|
)
|
||||||
|
|
||||||
|
class Hpk(
|
||||||
|
url: URL,
|
||||||
|
http: Http,
|
||||||
|
ssl: Ssl?,
|
||||||
|
) : WebService(
|
||||||
|
url = url,
|
||||||
|
http = http,
|
||||||
|
ssl = ssl,
|
||||||
|
)
|
||||||
|
|
||||||
|
open class WebService(
|
||||||
|
val url: URL,
|
||||||
|
val http: Http,
|
||||||
|
val ssl: Ssl?,
|
||||||
|
)
|
||||||
|
|
||||||
|
class Http(
|
||||||
|
val readTimeout: Duration,
|
||||||
|
val writeTimeout: Duration,
|
||||||
|
val connectionTimeout: Duration,
|
||||||
|
)
|
||||||
|
|
||||||
|
class Ssl(
|
||||||
|
val handshakeTimeout: Duration,
|
||||||
|
val notifyFlushTimeout: Duration,
|
||||||
|
val notifyReadTimeout: Duration,
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package ru.touchin.push.message.provider.dto
|
package ru.touchin.push.message.provider.dto
|
||||||
|
|
||||||
class Notification(
|
class PushMessageNotification(
|
||||||
val title: String?,
|
val title: String?,
|
||||||
val description: String?,
|
val description: String?,
|
||||||
val imageUrl: String?
|
val imageUrl: String?
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package ru.touchin.push.message.provider.dto.request
|
package ru.touchin.push.message.provider.dto.request
|
||||||
|
|
||||||
import ru.touchin.push.message.provider.dto.Notification
|
import ru.touchin.push.message.provider.dto.PushMessageNotification
|
||||||
|
|
||||||
class PushTokenMessage(
|
class PushTokenMessage(
|
||||||
val token: String,
|
val token: String,
|
||||||
override val notification: Notification?,
|
override val pushMessageNotification: PushMessageNotification?,
|
||||||
override val data: Map<String, String>
|
override val data: Map<String, String>
|
||||||
) : SendPushRequest
|
) : SendPushRequest
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
package ru.touchin.push.message.provider.dto.request
|
package ru.touchin.push.message.provider.dto.request
|
||||||
|
|
||||||
import ru.touchin.push.message.provider.dto.Notification
|
import ru.touchin.push.message.provider.dto.PushMessageNotification
|
||||||
|
|
||||||
sealed interface SendPushRequest {
|
sealed interface SendPushRequest {
|
||||||
|
|
||||||
val notification: Notification?
|
val pushMessageNotification: PushMessageNotification?
|
||||||
val data: Map<String, String>
|
val data: Map<String, String>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@ package ru.touchin.push.message.provider.dto.result
|
||||||
import ru.touchin.push.message.provider.enums.PushTokenStatus
|
import ru.touchin.push.message.provider.enums.PushTokenStatus
|
||||||
|
|
||||||
data class CheckPushTokenResult(
|
data class CheckPushTokenResult(
|
||||||
val status: PushTokenStatus
|
val status: PushTokenStatus,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
package ru.touchin.push.message.provider.dto.result
|
package ru.touchin.push.message.provider.dto.result
|
||||||
|
|
||||||
class SendPushTokenMessageResult(
|
object SendPushTokenMessageResult : SendPushResult
|
||||||
val messageId: String
|
|
||||||
) : SendPushResult
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package ru.touchin.push.message.provider.dto.result
|
||||||
|
|
||||||
|
data class SendPushTokenMessageTraceableResult(
|
||||||
|
val messageId: String
|
||||||
|
) : SendPushResult
|
||||||
|
|
@ -3,6 +3,7 @@ package ru.touchin.push.message.provider.enums
|
||||||
enum class PlatformType {
|
enum class PlatformType {
|
||||||
|
|
||||||
ANDROID_GOOGLE,
|
ANDROID_GOOGLE,
|
||||||
|
ANDROID_HUAWEI,
|
||||||
IOS
|
IOS
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package ru.touchin.push.message.provider.enums
|
||||||
|
|
||||||
enum class PushMessageProviderType {
|
enum class PushMessageProviderType {
|
||||||
|
|
||||||
FCM
|
FCM,
|
||||||
|
HPK,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ include("validation-spring")
|
||||||
include("version-spring-web")
|
include("version-spring-web")
|
||||||
include("push-message-provider")
|
include("push-message-provider")
|
||||||
include("push-message-provider-fcm")
|
include("push-message-provider-fcm")
|
||||||
|
include("push-message-provider-hpk")
|
||||||
include("response-wrapper-spring-web")
|
include("response-wrapper-spring-web")
|
||||||
include("settings-spring-jpa")
|
include("settings-spring-jpa")
|
||||||
include("security-authorization-server-core")
|
include("security-authorization-server-core")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue