У меня есть очень простой образ докера Kotlin/Ktor, который делает следующее:
import com.google.events.cloud.firestore.v1.DocumentEventData
fun Application.configureRouting() {
val logger = LoggerFactory.getLogger(javaClass)
routing {
post("/debugfirestore") {
val message = call.receive<ByteArray>()
val data = DocumentEventData.parseFrom(message)
logger.info("documentEventData: $data")
return@post
}
}
}
fun Application.configureSerialization() {
install(ContentNegotiation) {
json()
@OptIn(ExperimentalSerializationApi::class)
protobuf()
}
}
У меня также есть Eventarc и Firestore, настроенные следующим образом:
% gcloud eventarc triggers update my-firestore-update \
--location=nam5 \
--service-account=... \
--destination-run-service=my-prototype \
--destination-run-region=us-central1 \
--destination-run-path = "/debugfirestore" \
--event-filters = "database=(default)" \
--event-filters-path-pattern = "entity=test-collection/**" \
--event-filters = "type=google.cloud.datastore.entity.v1.written"
Я запускаю свое приложение в Google Cloud Run. Я могу успешно запустить и получить событие, но не могу проанализировать полезную нагрузку protobuf (думаю, это protobuf?).
com.google.protobuf.InvalidProtocolBufferException: Protocol message had invalid UTF-8.
at com.google.protobuf.InvalidProtocolBufferException.invalidUtf8(InvalidProtocolBufferException.java:149)
at com.google.protobuf.Utf8$UnsafeProcessor.decodeUtf8(Utf8.java:1365)
at com.google.protobuf.Utf8.decodeUtf8(Utf8.java:318)
at com.google.protobuf.CodedInputStream$ArrayDecoder.readStringRequireUtf8(CodedInputStream.java:788)
at com.google.events.cloud.firestore.v1.Document$Builder.mergeFrom(Document.java:854)
at com.google.events.cloud.firestore.v1.Document$Builder.mergeFrom(Document.java:655)
at com.google.protobuf.CodedInputStream$ArrayDecoder.readMessage(CodedInputStream.java:844)
at com.google.events.cloud.firestore.v1.DocumentEventData$Builder.mergeFrom(DocumentEventData.java:615)
at com.google.events.cloud.firestore.v1.DocumentEventData$1.parsePartialFrom(DocumentEventData.java:1290)
at com.google.events.cloud.firestore.v1.DocumentEventData$1.parsePartialFrom(DocumentEventData.java:1282)
at com.google.protobuf.AbstractParser.parsePartialFrom(AbstractParser.java:135)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:168)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:180)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:185)
at com.google.protobuf.AbstractParser.parseFrom(AbstractParser.java:25)
at com.google.events.cloud.firestore.v1.DocumentEventData.parseFrom(DocumentEventData.java:360)
Данные, которые я пишу в Firestore, представляют собой простой объект JSON без каких-либо сумасшедших символов (AFAICT). Почему он жалуется на UTF8? Я предполагаю, что проблема связана с тем, как я пытаюсь проанализировать полезную нагрузку запроса ИЛИ ответ не в том формате (ByteArray), который я думаю. Где я ошибаюсь?
изменить: я также попробовал это:
post("/debugfirestore") {
logger.info("Content-Type = ${call.request.contentType()}")
val data = call.receive<DocumentEventData>()
logger.info("documentEventData: $data")
call.respond("$data")
return@post
}
Я думал, что это может сработать, поскольку у меня есть плагин protobuf(), но он не говорит:
Вызвано: kotlinx.serialization.SerializationException: сериализатор для класса DocumentEventData не найден.
Дальше я вижу журналы, в которых говорится:
Убедитесь, что класс помечен как «@Serializable» и что применен плагин компилятора сериализации.
Кстати, я попробовал добавить это: logger.info("Content-Type = ${call.request.contentType()}")
и он распечатывает application/protobuf.
Знакомы ли вы с protoc
? Вы можете попробовать захватить message
из своего кода и использовать онлайн-декодер или, что более полезно, protoc --decode
со схемой, чтобы попытаться воспроизвести десериализацию и убедиться, что вы получаете то, что, по вашему мнению, получаете.
Я написал это, чтобы показать, как декодировать сообщения EventArc с помощью protoc --decode
Ваше сообщение в блоге заставило меня понять, что я пытаюсь десериализовать неправильный тип; Мне нужно было использовать EntityEventData
, а не DocumentEventData
! Кстати, я знаком с протоколом, но благодарен, что в итоге он мне не понадобился для такой простой задачи. ;)
Проблема в том, что мне нужно было использовать EntityEventData
вместо DocumentEventData
.
Спасибо DazWilkin за ответ.
Примечание: использование сериализации Kotlinx, похоже, мне здесь не подходит, потому что, я думаю, ни EntityEventData
, ни DocumentEventData
не являются @Serializable
.
Я сделал это с помощью GKE и Go(lang). Типом контента по умолчанию является JSON, а не Protobuf, поэтому вам может потребоваться пересмотреть свой
gcloud eventarc trigger
, включив в него --event-data-content-type = "application/protobuf"