Skip to content

Commit 761757d

Browse files
committed
feat: add codecs and serializers for InetAddress, Inet4Address, and Inet6Address; implement error handling for invalid addresses
1 parent ab7879a commit 761757d

File tree

13 files changed

+147
-36
lines changed

13 files changed

+147
-36
lines changed

surf-api-core/surf-api-core-api/src/main/kotlin/dev/slne/surf/surfapi/core/api/serializer/SurfCodecs.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ import dev.slne.surf.surfapi.core.api.serializer.java.datetime.datetime.zdt.Zone
2020
import dev.slne.surf.surfapi.core.api.serializer.java.datetime.time.local.LocalTimeCodec
2121
import dev.slne.surf.surfapi.core.api.serializer.java.datetime.zone.id.ZoneIdCodec
2222
import dev.slne.surf.surfapi.core.api.serializer.java.datetime.zone.offset.ZoneOffsetCodec
23+
import dev.slne.surf.surfapi.core.api.serializer.java.ip.inet.InetAddressCodec
24+
import dev.slne.surf.surfapi.core.api.serializer.java.ip.inetsocket.InetSocketAddressCodec
25+
import dev.slne.surf.surfapi.core.api.serializer.java.ip.ipv4.Inet4AddressCodec
26+
import dev.slne.surf.surfapi.core.api.serializer.java.ip.ipv6.Inet6AddressCodec
2327
import dev.slne.surf.surfapi.core.api.serializer.java.uri.URICodec
2428
import dev.slne.surf.surfapi.core.api.serializer.java.uuid.JavaUUIDCodec
2529
import dev.slne.surf.surfapi.core.api.serializer.spongepowered.math.matrix.m2d.SpongeMatrix2dCodec
@@ -105,5 +109,9 @@ object SurfCodecs {
105109
val LOCAL_TIME = LocalTimeCodec.CODEC
106110
val ZONE_ID = ZoneIdCodec.CODEC
107111
val ZONE_OFFSET = ZoneOffsetCodec.CODEC
112+
val INET_ADDRESS = InetAddressCodec.CODEC
113+
val INET_SOCKET_ADDRESS = InetSocketAddressCodec.CODEC
114+
val INET4_ADDRESS = Inet4AddressCodec.CODEC
115+
val INET6_ADDRESS = Inet6AddressCodec.CODEC
108116
// endregion
109117
}

surf-api-core/surf-api-core-api/src/main/kotlin/dev/slne/surf/surfapi/core/api/serializer/SurfSerializerModule.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ import dev.slne.surf.surfapi.core.api.serializer.java.datetime.datetime.zdt.Zone
2121
import dev.slne.surf.surfapi.core.api.serializer.java.datetime.time.local.LocalTimeSerializer
2222
import dev.slne.surf.surfapi.core.api.serializer.java.datetime.zone.id.ZonedIdSerializer
2323
import dev.slne.surf.surfapi.core.api.serializer.java.datetime.zone.offset.ZoneOffsetSerializer
24+
import dev.slne.surf.surfapi.core.api.serializer.java.ip.inet.InetAddressSerializer
25+
import dev.slne.surf.surfapi.core.api.serializer.java.ip.inetsocket.InetSocketAddressSerializer
26+
import dev.slne.surf.surfapi.core.api.serializer.java.ip.ipv4.Inet4AddressSerializer
27+
import dev.slne.surf.surfapi.core.api.serializer.java.ip.ipv6.Inet6AddressSerializer
2428
import dev.slne.surf.surfapi.core.api.serializer.java.uri.URISerializer
2529
import dev.slne.surf.surfapi.core.api.serializer.java.uuid.JavaUUIDSerializer
2630
import dev.slne.surf.surfapi.core.api.serializer.spongepowered.math.matrix.m2d.SpongeMatrix2dSerializer
@@ -110,6 +114,10 @@ object SurfSerializerModule {
110114
contextual(LocalTimeSerializer)
111115
contextual(ZonedIdSerializer)
112116
contextual(ZoneOffsetSerializer)
117+
contextual(InetAddressSerializer)
118+
contextual(InetSocketAddressSerializer)
119+
contextual(Inet4AddressSerializer)
120+
contextual(Inet6AddressSerializer)
113121
}
114122

115123
val all = SerializersModule {

surf-api-core/surf-api-core-api/src/main/kotlin/dev/slne/surf/surfapi/core/api/serializer/codec-extensions.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,24 @@ fun <A> Codec<A>.positive(
5353
}
5454
}
5555

56+
@JvmName("positiveLong")
5657
fun Codec<Long>.positive(zeroAllowed: Boolean = true) = positive(zeroAllowed, 0L, Long::compareTo)
58+
59+
@JvmName("positiveInt")
5760
fun Codec<Int>.positive(zeroAllowed: Boolean = true) = positive(zeroAllowed, 0, Int::compareTo)
61+
62+
@JvmName("positiveDouble")
5863
fun Codec<Double>.positive(zeroAllowed: Boolean = true) =
5964
positive(zeroAllowed, 0.0, Double::compareTo)
6065

66+
@JvmName("positiveFloat")
6167
fun Codec<Float>.positive(zeroAllowed: Boolean = true) = positive(zeroAllowed, 0f, Float::compareTo)
68+
69+
@JvmName("positiveShort")
6270
fun Codec<Short>.positive(zeroAllowed: Boolean = true) =
6371
positive(zeroAllowed, 0.toShort(), Short::compareTo)
6472

73+
@JvmName("positiveByte")
6574
fun Codec<Byte>.positive(zeroAllowed: Boolean = true) =
6675
positive(zeroAllowed, 0.toByte(), Byte::compareTo)
6776

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
package dev.slne.surf.surfapi.core.api.serializer.java.ip.inet
22

33
import com.mojang.serialization.Codec
4+
import com.mojang.serialization.DataResult
45
import java.net.InetAddress
6+
import java.net.UnknownHostException
57

68
object InetAddressCodec {
7-
val CODEC: Codec<InetAddress> =
8-
Codec.STRING.xmap({ InetAddress.getByName(it) }, { it.hostName })
9+
val CODEC: Codec<InetAddress> = Codec.STRING
10+
.comapFlatMap({ hostName ->
11+
try {
12+
DataResult.success(InetAddress.getByName(hostName))
13+
} catch (e: UnknownHostException) {
14+
DataResult.error { "Unknown host: $hostName (${e.message ?: "no details"})" }
15+
} catch (e: SecurityException) {
16+
DataResult.error { "Security exception when resolving host: $hostName (${e.message ?: "no details"})" }
17+
}
18+
}, InetAddress::getHostName)
919
}

surf-api-core/surf-api-core-api/src/main/kotlin/dev/slne/surf/surfapi/core/api/serializer/java/ip/inet/InetAddressSerializer.kt

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,26 @@ package dev.slne.surf.surfapi.core.api.serializer.java.ip.inet
55
import kotlinx.serialization.ExperimentalSerializationApi
66
import kotlinx.serialization.KSerializer
77
import kotlinx.serialization.Serializable
8-
import kotlinx.serialization.Serializer
8+
import kotlinx.serialization.descriptors.PrimitiveKind
9+
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
10+
import kotlinx.serialization.encoding.Decoder
11+
import kotlinx.serialization.encoding.Encoder
912
import java.net.InetAddress
1013

1114
typealias SerializableInetAddress = @Serializable(with = InetAddressSerializer::class) InetAddress
1215

13-
@Serializer(forClass = InetAddress::class)
14-
object InetAddressSerializer : KSerializer<InetAddress>
16+
object InetAddressSerializer : KSerializer<InetAddress> {
17+
override val descriptor =
18+
PrimitiveSerialDescriptor("surfapi.java.ip.InetAddress", PrimitiveKind.STRING)
19+
20+
override fun serialize(
21+
encoder: Encoder,
22+
value: InetAddress,
23+
) {
24+
encoder.encodeString(value.hostAddress)
25+
}
26+
27+
override fun deserialize(decoder: Decoder): InetAddress {
28+
return InetAddress.getByName(decoder.decodeString())
29+
}
30+
}

surf-api-core/surf-api-core-api/src/main/kotlin/dev/slne/surf/surfapi/core/api/serializer/java/ip/inetsocket/InetSocketAddressCodec.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ package dev.slne.surf.surfapi.core.api.serializer.java.ip.inetsocket
22

33
import com.mojang.serialization.Codec
44
import com.mojang.serialization.codecs.RecordCodecBuilder
5+
import dev.slne.surf.surfapi.core.api.serializer.ranged
56
import java.net.InetSocketAddress
67

78
object InetSocketAddressCodec {
89
val CODEC: Codec<InetSocketAddress> = RecordCodecBuilder.create { instance ->
910
instance.group(
1011
Codec.STRING.fieldOf("address").forGetter(InetSocketAddress::getHostName),
11-
Codec.INT.fieldOf("port").forGetter(InetSocketAddress::getPort),
12-
).apply(instance) { address, port ->
13-
InetSocketAddress(address, port)
14-
}
12+
Codec.INT
13+
.ranged(0, 0xFFFF)
14+
.fieldOf("port")
15+
.forGetter(InetSocketAddress::getPort),
16+
).apply(instance, ::InetSocketAddress)
1517
}
1618
}

surf-api-core/surf-api-core-api/src/main/kotlin/dev/slne/surf/surfapi/core/api/serializer/java/ip/inetsocket/InetSocketAddressSerializer.kt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ import kotlinx.serialization.KSerializer
77
import kotlinx.serialization.Serializable
88
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
99
import kotlinx.serialization.descriptors.element
10-
import kotlinx.serialization.encoding.Decoder
11-
import kotlinx.serialization.encoding.Encoder
12-
import kotlinx.serialization.encoding.decodeStructure
13-
import kotlinx.serialization.encoding.encodeStructure
10+
import kotlinx.serialization.encoding.*
1411
import java.net.InetSocketAddress
1512

1613
typealias SerializableInetSocketAddress = @Serializable(with = InetSocketAddressSerializer::class) InetSocketAddress
@@ -37,10 +34,11 @@ object InetSocketAddressSerializer : KSerializer<InetSocketAddress> {
3734
hostname = decodeStringElement(descriptor, 0)
3835
port = decodeIntElement(descriptor, 1)
3936
} else while (true) {
40-
when (decodeElementIndex(descriptor)) {
37+
when (val index = decodeElementIndex(descriptor)) {
4138
0 -> hostname = decodeStringElement(descriptor, 0)
4239
1 -> port = decodeIntElement(descriptor, 1)
43-
else -> break
40+
CompositeDecoder.DECODE_DONE -> break
41+
else -> error("Unexpected index: $index")
4442
}
4543
}
4644

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
package dev.slne.surf.surfapi.core.api.serializer.java.ip.ipv4
22

33
import com.mojang.serialization.Codec
4+
import com.mojang.serialization.DataResult
5+
import dev.slne.surf.surfapi.core.api.serializer.java.ip.inet.InetAddressCodec
46
import java.net.Inet4Address
7+
import java.util.function.Function
58

69
object Inet4AddressCodec {
7-
val CODEC: Codec<Inet4Address> =
8-
Codec.STRING.xmap({ Inet4Address.getByName(it) as Inet4Address }, { it.hostName })
10+
val CODEC: Codec<Inet4Address> = InetAddressCodec.CODEC.comapFlatMap({ address ->
11+
if (address is Inet4Address) {
12+
DataResult.success(address)
13+
} else {
14+
DataResult.error { "Not an IPv4 address: $address" }
15+
}
16+
}, Function.identity())
917
}

surf-api-core/surf-api-core-api/src/main/kotlin/dev/slne/surf/surfapi/core/api/serializer/java/ip/ipv4/Inet4AddressSerializer.kt

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,31 @@
22

33
package dev.slne.surf.surfapi.core.api.serializer.java.ip.ipv4
44

5+
import dev.slne.surf.surfapi.core.api.serializer.java.ip.inet.InetAddressSerializer
56
import kotlinx.serialization.ExperimentalSerializationApi
67
import kotlinx.serialization.KSerializer
78
import kotlinx.serialization.Serializable
8-
import kotlinx.serialization.Serializer
9+
import kotlinx.serialization.descriptors.SerialDescriptor
10+
import kotlinx.serialization.encoding.Decoder
11+
import kotlinx.serialization.encoding.Encoder
912
import java.net.Inet4Address
1013

1114
typealias SerializableInet4Address = @Serializable(with = Inet4AddressSerializer::class) Inet4Address
1215

13-
@Serializer(forClass = Inet4Address::class)
14-
object Inet4AddressSerializer : KSerializer<Inet4Address>
16+
object Inet4AddressSerializer : KSerializer<Inet4Address> {
17+
override val descriptor =
18+
SerialDescriptor("surfapi.java.ip.Inet4Address", InetAddressSerializer.descriptor)
19+
20+
override fun serialize(
21+
encoder: Encoder,
22+
value: Inet4Address,
23+
) {
24+
encoder.encodeSerializableValue(InetAddressSerializer, value)
25+
}
26+
27+
override fun deserialize(decoder: Decoder): Inet4Address {
28+
val address = decoder.decodeSerializableValue(InetAddressSerializer)
29+
require(address is Inet4Address) { "Not an IPv4 address: $address" }
30+
return address
31+
}
32+
}
Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
package dev.slne.surf.surfapi.core.api.serializer.java.ip.ipv6
22

33
import com.mojang.serialization.Codec
4+
import com.mojang.serialization.DataResult
5+
import dev.slne.surf.surfapi.core.api.serializer.java.ip.inet.InetAddressCodec
46
import java.net.Inet6Address
7+
import java.util.function.Function
58

69
object Inet6AddressCodec {
7-
val CODEC: Codec<Inet6Address> =
8-
Codec.STRING.xmap({ Inet6Address.getByName(it) as Inet6Address }, { it.hostName })
10+
val CODEC: Codec<Inet6Address> = InetAddressCodec.CODEC.comapFlatMap({ address ->
11+
if (address is Inet6Address) {
12+
DataResult.success(address)
13+
} else {
14+
DataResult.error { "Not an IPv6 address: $address" }
15+
}
16+
}, Function.identity())
917
}

0 commit comments

Comments
 (0)