Cтриминг видео на Kotlin

Пишу бэкенд приложение на Kotlin+Ktor. Задача состоит в том что с html формы пользователь отправляет видео, которое необходимо сохранить в MinIO. Затем по запросу от пользователя необходимо достать это видео из хранилище и запустить его стрим на хтмл страничке. Но столкнулся с проблемой при получении видео из хранилища (видео беру чанками). Вылетает следующая ошибка:

DEBUG Application - 206 Partial Content: GET - /video/21e57ab6-3275-47e0-9e27-8b522d7f21a9. Exception class io.ktor.util.cio.ChannelWriteException: Cannot write to a channel
Caused by: [CIRCULAR REFERENCE: io.ktor.util.cio.ChannelWriteException: Cannot write to a channel]Caused by: java.io.IOException: Broken pipe

Код контроллера

   get("/{uuid}") {
                val uuid = UUID.fromString(call.parameters["uuid"])
                val range = call.request.headers["Range"]
    
                val parsedRange = Range.parseHttpRangeString(range, defaultChunkSize)
                val chunkWithMetadata = videoService.fetchChunk(uuid, parsedRange)
    
                call.response.header("Content-Type", chunkWithMetadata.metadata.`httpContentType`)
                call.response.header("Accept-Ranges", "bytes")
                call.response.header(
                    "Content-Length",
                    calculateContentLengthHeader(parsedRange, chunkWithMetadata.metadata.size)
                )
                call.response.header(
                    "Content-Range",
                    constructContentRangeHeader(parsedRange, chunkWithMetadata.metadata.size)
                )
    
                call.respondOutputStream(
                    status = HttpStatusCode.PartialContent,
                    contentType = ContentType(
                        contentType = chunkWithMetadata.metadata.httpContentType,
                        contentSubtype = chunkWithMetadata.metadata.httpContentType
                    ),
                    введите сюда кодcontentLength = calculateContentLengthHeader(parsedRange, chunkWithMetadata.metadata.size).toLong(),
                ) {
                    val output = this
                    output.write(chunkWithMetadata.chunk)
                }
            }

Код сервиса:

override suspend fun fetchChunk(uuid: UUID, range: Range): ChunkWithMetadata {
        val fileMetadata = fileMetadataDAOFacade.findById(uuid)
        return ChunkWithMetadata(fileMetadata!!, readChunk(uuid, range, fileMetadata.size))
    }

    private fun readChunk(uuid: UUID, range: Range, fileSize: Long): ByteArray {
        val startPosition = range.getRangeStart()
        val endPosition = range.getRangeEnd(fileSize)
        val chunkSize = (endPosition - startPosition + 1)

        try {
            storageService.getInputStream(uuid, startPosition, chunkSize).use { inputStream ->
                return inputStream.readAllBytes()
            }
        } catch (exception: Exception) {
            throw StorageException(exception)
        }
    }

    data class ChunkWithMetadata(
        val metadata: FileMetadataEntity,
        val chunk: ByteArray
    )

Подскажите, пожалуйста, с чем может быть проблема


Ответы (0 шт):