All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fireflysource.net.http.server.impl.CompressedServerOutputChannel.kt Maven / Gradle / Ivy

There is a newer version: 5.0.2
Show newest version
package com.fireflysource.net.http.server.impl

import com.fireflysource.common.io.BufferUtils
import com.fireflysource.common.io.flipToFill
import com.fireflysource.common.io.flipToFlush
import com.fireflysource.net.http.common.codec.ContentEncoded
import com.fireflysource.net.http.common.model.ContentEncoding
import com.fireflysource.net.http.server.HttpServerOutputChannel
import java.io.OutputStream
import java.nio.ByteBuffer
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets
import java.util.concurrent.CompletableFuture

class CompressedServerOutputChannel(
    private val outputChannel: HttpServerOutputChannel,
    private val contentEncoding: ContentEncoding,
    private val bufferSize: Int = 512
) : HttpServerOutputChannel {

    private var compressedOutputStream: OutputStream? = null
    private var outputStreamAdapter: ServerOutputStreamAdapter? = null

    private inner class ServerOutputStreamAdapter : OutputStream() {

        override fun write(b: Int) {
            val buffer = BufferUtils.allocate(1)
            val pos = buffer.flipToFill()
            buffer.put(b.toByte())
            buffer.flipToFlush(pos)
            outputChannel.write(buffer)
        }

        override fun write(b: ByteArray) {
            outputChannel.write(ByteBuffer.wrap(b))
        }

        override fun write(b: ByteArray, off: Int, len: Int) {
            outputChannel.write(ByteBuffer.wrap(b, off, len))
        }

    }

    override fun isCommitted(): Boolean = outputChannel.isCommitted

    override fun commit(): CompletableFuture {
        return outputChannel.commit().thenAccept {
            val adapter = ServerOutputStreamAdapter()
            compressedOutputStream = ContentEncoded.createEncodingOutputStream(adapter, contentEncoding, bufferSize)
        }
    }

    override fun write(byteBuffer: ByteBuffer): CompletableFuture {
        val bytes = BufferUtils.toArray(byteBuffer)
        getOutput().write(bytes)
        val future = CompletableFuture()
        future.complete(bytes.size)
        return future
    }

    override fun write(byteBuffers: Array, offset: Int, length: Int): CompletableFuture {
        val last = offset + length - 1
        val buffer = BufferUtils.merge((offset..last).map { byteBuffers[it].duplicate() })
        val bytes = BufferUtils.toArray(buffer)
        getOutput().write(bytes)
        val future = CompletableFuture()
        future.complete(bytes.size.toLong())
        return future
    }

    override fun write(byteBufferList: List, offset: Int, length: Int): CompletableFuture {
        return write(byteBufferList.toTypedArray(), offset, length)
    }

    override fun write(string: String): CompletableFuture {
        return write(string, StandardCharsets.UTF_8)
    }

    override fun write(string: String, charset: Charset): CompletableFuture {
        val buffer = BufferUtils.toBuffer(string, charset)
        return write(buffer)
    }

    private fun getOutput(): OutputStream {
        val output = compressedOutputStream
        requireNotNull(output) { "The compressed output stream not create" }
        return output
    }

    override fun closeAsync(): CompletableFuture {
        compressedOutputStream?.close()
        outputStreamAdapter?.close()
        return outputChannel.closeAsync()
    }

    override fun close() {
        closeAsync()
    }

    override fun isOpen(): Boolean = outputChannel.isOpen
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy