All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
de.gesellix.docker.compose.adapters.ListToPortConfigsAdapter.kt Maven / Gradle / Ivy
package de.gesellix.docker.compose.adapters
import com.squareup.moshi.FromJson
import com.squareup.moshi.JsonReader
import com.squareup.moshi.ToJson
import de.gesellix.docker.compose.types.PortConfig
import de.gesellix.docker.compose.types.PortConfigs
import java.net.InetAddress
class ListToPortConfigsAdapter {
@ToJson
fun toJson(@PortConfigsType portConfigs: PortConfigs): List> {
throw UnsupportedOperationException()
}
@FromJson
@PortConfigsType
fun fromJson(reader: JsonReader): PortConfigs {
val portConfigs = arrayListOf()
when (reader.peek()) {
JsonReader.Token.BEGIN_ARRAY -> {
reader.beginArray()
while (reader.hasNext()) {
portConfigs.addAll(parsePortConfigEntry(reader))
}
reader.endArray()
}
else -> {
// ...
}
}
return PortConfigs(portConfigs = portConfigs)
}
fun parsePortConfigEntry(reader: JsonReader): List {
when (reader.peek()) {
JsonReader.Token.NUMBER -> {
val value = reader.nextInt().toString()
return parsePortDefinition(value)
}
JsonReader.Token.STRING -> {
val value = reader.nextString()
return parsePortDefinition(value)
}
JsonReader.Token.BEGIN_OBJECT -> {
reader.beginObject()
val portConfig = PortConfig(mode = "", protocol = "", target = 0, published = 0)
while (reader.hasNext()) {
val name = reader.nextName()
when (reader.peek()) {
JsonReader.Token.STRING -> {
val value = reader.nextString()
writeProperty(portConfig, name, value)
}
JsonReader.Token.NUMBER -> {
val value = reader.nextInt()
writeProperty(portConfig, name, value)
}
else -> {
// ...
}
}
}
reader.endObject()
return listOf(portConfig)
}
else -> {
// ...
}
}
return emptyList()
}
fun parsePortDefinition(portSpec: String): List {
var (rawIP, hostPort, containerPort) = splitParts(portSpec)
val (proto, plainContainerPort) = splitProto(containerPort)
if (plainContainerPort.isEmpty()) {
throw IllegalStateException("No port specified: '$portSpec'")
}
validateProto(proto)
if (rawIP.isNotBlank()) {
val address = InetAddress.getByName(rawIP)
rawIP = address.hostAddress
}
val (startPort, endPort) = parsePortRange(plainContainerPort)
var (startHostPort, endHostPort) = listOf(0, 0)
if (hostPort.isNotEmpty()) {
val (parsedStart, parsedEnd) = parsePortRange(hostPort)
if ((endPort - startPort) != (parsedEnd - parsedStart)) {
// Allow host port range if containerPort is not a range.
// In this case, use the host port range as the dynamic
// host port range to allocate into.
if (endPort != startPort) {
throw IllegalStateException("Invalid ranges specified for container and host Ports: '$containerPort' and '$hostPort'")
}
}
startHostPort = parsedStart
endHostPort = parsedEnd
}
val portMappings = arrayListOf>()
for (i in (0..(endPort - startPort))) {
containerPort = "${startPort + i}"
if (hostPort.isNotEmpty()) {
hostPort = "${startHostPort + i}"
}
// Set hostPort to a range only if there is a single container port
// and a dynamic host port.
if (startPort == endPort && startHostPort != endHostPort) {
hostPort = "$hostPort-$endHostPort"
}
val port = newPort(proto.lowercase(), containerPort)
portMappings.add(hashMapOf().let { mapping ->
mapping["port"] = port
mapping["binding"] = hashMapOf().let { binding ->
binding["proto"] = proto.lowercase()
binding["hostIP"] = rawIP
binding["hostPort"] = hostPort
binding
}
mapping
})
}
val exposedPorts = sortedSetOf()
val bindings = hashMapOf>>()
portMappings.forEach { portMapping ->
val port = portMapping["port"] as String
exposedPorts.add(port)
if (!bindings.containsKey(port)) {
bindings[port] = arrayListOf()
}
bindings[port]?.add(portMapping["binding"] as Map)
}
val portConfigs = arrayListOf()
exposedPorts.forEach { port ->
bindings[port]?.forEach { binding ->
var hostPortAsInt = 0
if (binding["hostPort"] != "") {
hostPortAsInt = binding["hostPort"]?.toString()?.toInt()!!
}
portConfigs.add(PortConfig(
protocol = binding["proto"].toString(),
target = port.split('/')[0].toInt(),
published = hostPortAsInt,
mode = "ingress"
))
}
}
return portConfigs
}
// newPort creates a new instance of a port String given a protocol and port number or port range
private fun newPort(proto: String, port: String): String {
// Check for parsing issues on "port" now so we can avoid having
// to check it later on.
var (portStartInt, portEndInt) = listOf(0, 0)
if (port.isNotEmpty()) {
val (parsedStart, parsedEnd) = parsePortRange(port)
portStartInt = parsedStart
portEndInt = parsedEnd
}
if (portStartInt == portEndInt) {
return "$portStartInt/$proto"
}
return "$portStartInt-$portEndInt/$proto"
}
private fun parsePortRange(ports: String): List {
if (!ports.contains('-')) {
return listOf(ports.toInt(), ports.toInt())
}
val startAndEnd = ports.split('-')
val start = startAndEnd[0].toInt()
val end = startAndEnd[1].toInt()
if (end < start) {
throw IllegalStateException("Invalid range specified for the Port '$ports'")
}
return listOf(start, end)
}
private fun validateProto(proto: String) {
if (!listOf("tcp", "udp").contains(proto.lowercase())) {
throw IllegalStateException("Invalid proto '$proto'")
}
}
private fun splitProto(rawPort: String): List {
val parts = rawPort.split('/')
if (rawPort.isEmpty() || parts.isEmpty() || parts[0].isEmpty()) {
return listOf("", "")
}
if (parts.size == 1) {
return listOf("tcp", rawPort)
}
if (parts[1].isEmpty()) {
return listOf("tcp", parts[0])
}
return listOf(parts[1], parts[0])
}
private fun splitParts(rawPort: String): List {
val parts = rawPort.split(':')
return when (parts.size) {
1 -> listOf("", "", parts[0])
2 -> listOf("", parts[0], parts[1])
3 -> listOf(parts[0], parts[1], parts[2])
else -> listOf(parts.take(parts.size - 2).joinToString(":"), parts[parts.size - 2], "${parts.size - 1}")
}
}
}