Network.kt
package com.hexagonkt.core
import java.io.File
import java.net.*
import java.util.*
/** Internet address used to bind services to all local network interfaces. */
val ALL_INTERFACES: InetAddress by lazy { inetAddress(0, 0, 0, 0) }
/** Internet address used to bind services to the loop-back interface. */
val LOOPBACK_INTERFACE: InetAddress by lazy { inetAddress(127, 0, 0, 1) }
/**
* Syntactic sugar to create an Internet address.
*
* @param bytes Bytes used in the address.
* @return The Internet address corresponding with the supplied bytes.
*/
fun inetAddress(vararg bytes: Byte): InetAddress =
InetAddress.getByAddress(bytes)
/**
* Return a random free port (not used by any other local process).
*
* @return Random free port number.
*/
fun freePort(): Int =
ServerSocket(0).use { it.localPort }
/**
* Check if a port is already opened.
*
* @param port Port number to check.
* @return True if the port is open, false otherwise.
*/
fun isPortOpened(port: Int): Boolean =
try {
Socket("localhost", port).use { it.isConnected }
}
catch (e: Exception) {
false
}
fun urlOf(url: String): URL =
URI(url).toURL()
fun URL.responseCode(): Int =
try {
(openConnection() as HttpURLConnection).responseCode
}
catch (e: java.lang.Exception) {
400
}
fun URL.responseSuccessful(): Boolean =
responseCode() in 200 until 300
fun URL.responseFound(): Boolean =
responseCode().let { it in 200 until 500 && it != 404 }
// TODO Review the next functions, not all cases are covered
fun URL.exists(): Boolean =
when (protocol) {
"http" -> responseSuccessful()
"https" -> responseSuccessful()
"file" -> File(file).let { it.exists() && !it.isDirectory }
"classpath" -> try { openConnection(); true } catch (_: Exception) { false }
else -> false
}
fun URL.firstVariant(vararg suffixes: String): URL {
val extension = file.substringAfter('.')
val fileName = file.removeSuffix(".$extension")
suffixes.forEach {
val u = urlOf("$protocol:$fileName$it.$extension")
if (u.exists())
return u
}
return this
}
fun URL.localized(locale: Locale): URL {
val language = locale.language
val country = locale.country
return firstVariant("_${language}_$country", "_${language}")
}