Allow client configuration of hosts binding

This commit is contained in:
Amos Ng 2020-06-14 23:47:57 +00:00 committed by carbotaniuman
parent 41d06a2646
commit aa60500fb0
5 changed files with 75 additions and 7 deletions

View file

@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
### Added ### Added
- [2020-06-14] Added new `client_hostname` selector to allow for custom address binding for Netty by [@lflare].
- [2020-06-14] Added new `ui_hostname` selector to allow for custom address binding for WebUiNetty by [@lflare].
### Changed ### Changed

View file

@ -102,7 +102,7 @@ class Netty(private val tls: ServerSettings.TlsCert, private val clientSettings:
.option(ChannelOption.SO_BACKLOG, 1000) .option(ChannelOption.SO_BACKLOG, 1000)
.childOption(ChannelOption.SO_KEEPALIVE, true) .childOption(ChannelOption.SO_KEEPALIVE, true)
val channel = bootstrap.bind(clientSettings.clientPort).sync().channel() val channel = bootstrap.bind(InetSocketAddress(clientSettings.clientHostname, clientSettings.clientPort)).sync().channel()
address = channel.localAddress() as InetSocketAddress address = channel.localAddress() as InetSocketAddress
closeFuture = channel.closeFuture() closeFuture = channel.closeFuture()
} }

View file

@ -0,0 +1,62 @@
package mdnet.base
import io.netty.bootstrap.ServerBootstrap
import io.netty.channel.ChannelFactory
import io.netty.channel.ChannelFuture
import io.netty.channel.ChannelInitializer
import io.netty.channel.ChannelOption
import io.netty.channel.ServerChannel
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.SocketChannel
import io.netty.channel.socket.nio.NioServerSocketChannel
import io.netty.handler.codec.http.HttpObjectAggregator
import io.netty.handler.codec.http.HttpServerCodec
import io.netty.handler.codec.http.HttpServerKeepAliveHandler
import io.netty.handler.stream.ChunkedWriteHandler
import java.net.InetSocketAddress
import java.util.concurrent.TimeUnit
import org.http4k.core.HttpHandler
import org.http4k.server.Http4kChannelHandler
import org.http4k.server.Http4kServer
import org.http4k.server.ServerConfig
import org.slf4j.LoggerFactory
private val LOGGER = LoggerFactory.getLogger(WebUiNetty::class.java)
class WebUiNetty(private val hostname: String, private val port: Int) : ServerConfig {
override fun toServer(httpHandler: HttpHandler): Http4kServer = object : Http4kServer {
private val masterGroup = NioEventLoopGroup()
private val workerGroup = NioEventLoopGroup()
private lateinit var closeFuture: ChannelFuture
private lateinit var address: InetSocketAddress
override fun start(): Http4kServer = apply {
val bootstrap = ServerBootstrap()
bootstrap.group(masterGroup, workerGroup)
.channelFactory(ChannelFactory<ServerChannel> { NioServerSocketChannel() })
.childHandler(object : ChannelInitializer<SocketChannel>() {
public override fun initChannel(ch: SocketChannel) {
ch.pipeline().addLast("codec", HttpServerCodec())
ch.pipeline().addLast("keepAlive", HttpServerKeepAliveHandler())
ch.pipeline().addLast("aggregator", HttpObjectAggregator(Int.MAX_VALUE))
ch.pipeline().addLast("streamer", ChunkedWriteHandler())
ch.pipeline().addLast("handler", Http4kChannelHandler(httpHandler))
}
})
.option(ChannelOption.SO_BACKLOG, 1000)
.childOption(ChannelOption.SO_KEEPALIVE, true)
val channel = bootstrap.bind(InetSocketAddress(hostname, port)).sync().channel()
address = channel.localAddress() as InetSocketAddress
closeFuture = channel.closeFuture()
}
override fun stop() = apply {
masterGroup.shutdownGracefully(5, 15, TimeUnit.SECONDS).sync()
workerGroup.shutdownGracefully(5, 15, TimeUnit.SECONDS).sync()
closeFuture.sync()
}
override fun port(): Int = address.port
}
}

View file

@ -1,7 +1,10 @@
/* ktlint-disable no-wildcard-imports */ /* ktlint-disable no-wildcard-imports */
package mdnet.base.server package mdnet.base.server
import java.time.Instant
import java.util.concurrent.atomic.AtomicReference
import mdnet.base.Statistics import mdnet.base.Statistics
import mdnet.base.WebUiNetty
import mdnet.base.settings.WebSettings import mdnet.base.settings.WebSettings
import org.http4k.core.Body import org.http4k.core.Body
import org.http4k.core.Method import org.http4k.core.Method
@ -9,16 +12,13 @@ import org.http4k.core.Response
import org.http4k.core.Status import org.http4k.core.Status
import org.http4k.core.then import org.http4k.core.then
import org.http4k.filter.ServerFilters import org.http4k.filter.ServerFilters
import org.http4k.format.Gson.auto
import org.http4k.routing.ResourceLoader import org.http4k.routing.ResourceLoader
import org.http4k.routing.bind import org.http4k.routing.bind
import org.http4k.routing.routes import org.http4k.routing.routes
import org.http4k.routing.singlePageApp import org.http4k.routing.singlePageApp
import org.http4k.server.Http4kServer import org.http4k.server.Http4kServer
import org.http4k.server.Netty
import org.http4k.server.asServer import org.http4k.server.asServer
import java.util.concurrent.atomic.AtomicReference
import org.http4k.format.Gson.auto
import java.time.Instant
fun getUiServer( fun getUiServer(
webSettings: WebSettings, webSettings: WebSettings,
@ -43,5 +43,5 @@ fun getUiServer(
singlePageApp(ResourceLoader.Classpath("/webui")) singlePageApp(ResourceLoader.Classpath("/webui"))
) )
) )
.asServer(Netty(webSettings.uiPort)) .asServer(WebUiNetty(webSettings.uiHostname, webSettings.uiPort))
} }

View file

@ -7,10 +7,14 @@ data class ClientSettings(
@field:SerializedName("max_cache_size_mib") val maxCacheSizeMib: Long = 20480, @field:SerializedName("max_cache_size_mib") val maxCacheSizeMib: Long = 20480,
@field:SerializedName("max_bandwidth_mib_per_hour") val maxBandwidthMibPerHour: Long = 0, @field:SerializedName("max_bandwidth_mib_per_hour") val maxBandwidthMibPerHour: Long = 0,
@field:SerializedName("max_burst_rate_kib_per_second") val maxBurstRateKibPerSecond: Long = 0, @field:SerializedName("max_burst_rate_kib_per_second") val maxBurstRateKibPerSecond: Long = 0,
@field:SerializedName("client_hostname") val clientHostname: String = "0.0.0.0",
@field:SerializedName("client_port") val clientPort: Int = 443, @field:SerializedName("client_port") val clientPort: Int = 443,
@field:Secret @field:SerializedName("client_secret") val clientSecret: String = "PASTE-YOUR-SECRET-HERE", @field:Secret @field:SerializedName("client_secret") val clientSecret: String = "PASTE-YOUR-SECRET-HERE",
@field:SerializedName("threads") val threads: Int = 32, @field:SerializedName("threads") val threads: Int = 32,
@field:SerializedName("web_settings") val webSettings: WebSettings? = null @field:SerializedName("web_settings") val webSettings: WebSettings? = null
) )
data class WebSettings(@field:SerializedName("ui_port") val uiPort: Int = 8080) data class WebSettings(
@field:SerializedName("ui_hostname") val uiHostname: String = "127.0.0.1",
@field:SerializedName("ui_port") val uiPort: Int = 8080
)