Skip to content

Commit b7c7db9

Browse files
author
olme04
committed
mime/auth type improvements
1 parent 4a7bedb commit b7c7db9

30 files changed

+365
-419
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package io.rsocket.kotlin
2+
3+
import io.ktor.utils.io.core.*
4+
import io.rsocket.kotlin.frame.io.*
5+
import kotlin.experimental.*
6+
7+
//used for MimeType, AuthType and later in LeaseStrategy
8+
public interface CompactType {
9+
public interface WithId : CompactType {
10+
public val identifier: Byte
11+
}
12+
13+
public interface WithName : CompactType {
14+
public val text: String
15+
}
16+
17+
public interface WellKnown : CompactType, WithId, WithName
18+
}
19+
20+
@Suppress("UNCHECKED_CAST")
21+
//TODO: type relations
22+
public abstract class CompactTypeFactory<
23+
Type : CompactType,
24+
WithId : CompactType.WithId,
25+
WithName : CompactType.WithName,
26+
WellKnown,
27+
> internal constructor(
28+
private val withIdConstructor: (identifier: Byte) -> WithId,
29+
private val withNameConstructor: (text: String) -> WithName,
30+
wellKnownValues: Array<WellKnown>,
31+
) where WellKnown : CompactType.WellKnown, WellKnown : Enum<WellKnown> {
32+
private val wellKnownByIdentifier: Array<Any?> = arrayOfNulls<Any?>(128)
33+
private val wellKnownByName: MutableMap<String, WellKnown> = HashMap(128)
34+
35+
init {
36+
wellKnownValues.forEach {
37+
wellKnownByIdentifier[it.identifier.toInt()] = it
38+
wellKnownByName[it.text] = it
39+
}
40+
}
41+
42+
//TODO is it needed?
43+
public fun WellKnown(text: String): WellKnown? = wellKnownByName[text]
44+
public fun WellKnown(identifier: Byte): WellKnown? = wellKnownByIdentifier[identifier.toInt()] as WellKnown?
45+
public fun WellKnown(identifier: Int): WellKnown? = wellKnownByIdentifier[identifier] as WellKnown?
46+
47+
public fun WithName(text: String): WithName = (WellKnown(text) ?: withNameConstructor(text)) as WithName
48+
public fun WithId(identifier: Byte): WithId = (WellKnown(identifier) ?: withIdConstructor(identifier)) as WithId
49+
public fun WithId(identifier: Int): WithId = WithId(identifier.toByte())
50+
51+
public operator fun invoke(text: String): WithName = WithName(text)
52+
public operator fun invoke(identifier: Byte): WithId = WithId(identifier)
53+
public operator fun invoke(identifier: Int): WithId = WithId(identifier)
54+
}
55+
56+
internal fun CompactType.WellKnown.toString(typeName: String): String = "$typeName(id=$identifier, text=$text)"
57+
internal fun CompactType.WithId.toString(typeName: String): String = "$typeName(id=$identifier)"
58+
internal fun CompactType.WithName.toString(typeName: String): String = "$typeName(text=$text)"
59+
60+
internal abstract class AbstractCompactTypeWithId(final override val identifier: Byte) : CompactType.WithId {
61+
init {
62+
require(identifier > 0) { "Mime-type identifier must be positive but was '${identifier}'" }
63+
}
64+
65+
final override fun equals(other: Any?): Boolean {
66+
if (this === other) return true
67+
if (other == null || this::class != other::class) return false
68+
69+
other as AbstractCompactTypeWithId
70+
71+
if (identifier != other.identifier) return false
72+
73+
return true
74+
}
75+
76+
final override fun hashCode(): Int {
77+
return identifier.hashCode()
78+
}
79+
80+
abstract override fun toString(): String
81+
}
82+
83+
internal abstract class AbstractCompactTypeWithName(final override val text: String) : CompactType.WithName {
84+
init {
85+
require(text.all { it.code <= 0x7f }) { "String should be an ASCII encodded string" }
86+
require(text.length in 1..128) { "Mime-type text length must be in range 1..128 but was '${text.length}'" }
87+
}
88+
89+
final override fun equals(other: Any?): Boolean {
90+
if (this === other) return true
91+
if (other == null || this::class != other::class) return false
92+
93+
other as AbstractCompactTypeWithName
94+
95+
if (text != other.text) return false
96+
97+
return true
98+
}
99+
100+
final override fun hashCode(): Int {
101+
return text.hashCode()
102+
}
103+
104+
abstract override fun toString(): String
105+
}
106+
107+
private const val KnownTypeFlag: Byte = Byte.MIN_VALUE
108+
109+
internal fun BytePacketBuilder.writeCompactType(type: CompactType) {
110+
when (type) {
111+
is CompactType.WithId -> writeByte(type.identifier or KnownTypeFlag)
112+
is CompactType.WithName -> {
113+
val typeBytes = type.text.encodeToByteArray()
114+
writeByte(typeBytes.size.toByte()) //write length
115+
writeFully(typeBytes) //write type
116+
}
117+
}
118+
}
119+
120+
internal fun <T : CompactType> ByteReadPacket.readCompactType(factory: CompactTypeFactory<T, *, *, *>): T {
121+
val byte = readByte()
122+
return if (byte check KnownTypeFlag) {
123+
val identifier = byte xor KnownTypeFlag
124+
factory(identifier)
125+
} else {
126+
val stringType = readTextExactBytes(byte.toInt())
127+
factory(stringType)
128+
} as T
129+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright 2015-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.rsocket.kotlin
18+
19+
public sealed interface MimeType : CompactType {
20+
public companion object : CompactTypeFactory<MimeType, WithId, WithName, WellKnown>(::WithIdImpl, ::WithNameImpl, enumValues())
21+
22+
public sealed interface WithId : MimeType, CompactType.WithId
23+
public sealed interface WithName : MimeType, CompactType.WithName
24+
public enum class WellKnown(
25+
public override val text: String,
26+
public override val identifier: Byte,
27+
) : MimeType, CompactType.WellKnown, WithId, WithName {
28+
ApplicationAvro("application/avro", 0x00),
29+
ApplicationCbor("application/cbor", 0x01),
30+
ApplicationGraphql("application/graphql", 0x02),
31+
ApplicationGzip("application/gzip", 0x03),
32+
ApplicationJavascript("application/javascript", 0x04),
33+
ApplicationJson("application/json", 0x05),
34+
ApplicationOctetStream("application/octet-stream", 0x06),
35+
ApplicationPdf("application/pdf", 0x07),
36+
ApplicationThrift("application/vnd.apache.thrift.binary", 0x08),
37+
ApplicationProtoBuf("application/vnd.google.protobuf", 0x09),
38+
ApplicationXml("application/xml", 0x0A),
39+
ApplicationZip("application/zip", 0x0B),
40+
AudioAac("audio/aac", 0x0C),
41+
AudioMp3("audio/mp3", 0x0D),
42+
AudioMp4("audio/mp4", 0x0E),
43+
AudioMpeg3("audio/mpeg3", 0x0F),
44+
AudioMpeg("audio/mpeg", 0x10),
45+
AudioOgg("audio/ogg", 0x11),
46+
AudioOpus("audio/opus", 0x12),
47+
AudioVorbis("audio/vorbis", 0x13),
48+
ImageBmp("image/bmp", 0x14),
49+
ImageGif("image/gif", 0x15),
50+
ImageHeicSequence("image/heic-sequence", 0x16),
51+
ImageHeic("image/heic", 0x17),
52+
ImageHeifSequence("image/heif-sequence", 0x18),
53+
ImageHeif("image/heif", 0x19),
54+
ImageJpeg("image/jpeg", 0x1A),
55+
ImagePng("image/png", 0x1B),
56+
ImageTiff("image/tiff", 0x1C),
57+
MultipartMixed("multipart/mixed", 0x1D),
58+
TextCss("text/css", 0x1E),
59+
TextCsv("text/csv", 0x1F),
60+
TextHtml("text/html", 0x20),
61+
TextPlain("text/plain", 0x21),
62+
TextXml("text/xml", 0x22),
63+
VideoH264("video/H264", 0x23),
64+
VideoH265("video/H265", 0x24),
65+
VideoVp8("video/VP8", 0x25),
66+
ApplicationHessian("application/x-hessian", 0x26),
67+
ApplicationJavaObject("application/x-java-object", 0x27),
68+
ApplicationCloudeventsJson("application/cloudevents+json", 0x28),
69+
ApplicationCapnProto("application/x-capnp", 0x29),
70+
ApplicationFlatBuffers("application/x-flatbuffers", 0x2A),
71+
72+
MessageRSocketMimeType("message/x.rsocket.mime-type.v0", 0x7A),
73+
MessageRSocketAcceptMimeTypes("message/x.rsocket.accept-mime-types.v0", 0x7b),
74+
MessageRSocketAuthentication("message/x.rsocket.authentication.v0", 0x7C),
75+
MessageRSocketTracingZipkin("message/x.rsocket.tracing-zipkin.v0", 0x7D),
76+
MessageRSocketRouting("message/x.rsocket.routing.v0", 0x7E),
77+
MessageRSocketCompositeMetadata("message/x.rsocket.composite-metadata.v0", 0x7F);
78+
79+
override fun toString(): String = toString("MimeType")
80+
}
81+
82+
private class WithIdImpl(identifier: Byte) : WithId, AbstractCompactTypeWithId(identifier) {
83+
override fun toString(): String = toString("MimeType")
84+
}
85+
86+
private class WithNameImpl(text: String) : WithName, AbstractCompactTypeWithName(text) {
87+
override fun toString(): String = toString("MimeType")
88+
}
89+
}
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,41 @@
11
package io.rsocket.kotlin.configuration
22

3-
import io.rsocket.kotlin.core.*
3+
import io.rsocket.kotlin.*
44

55
public sealed interface MimeTypeConfiguration {
6-
public val metadata: MimeTypeWithName
7-
public val data: MimeTypeWithName
6+
public val metadata: MimeType.WithName
7+
public val data: MimeType.WithName
88
}
99

1010
public sealed interface MimeTypeConnectConfiguration : MimeTypeConfiguration, ConnectConfiguration
1111

1212
public sealed interface MimeTypeClientConnectConfiguration : MimeTypeConnectConfiguration {
13-
public fun metadata(mimeType: MimeTypeWithName)
14-
public fun data(mimeType: MimeTypeWithName)
13+
public fun metadata(mimeType: MimeType.WithName)
14+
public fun data(mimeType: MimeType.WithName)
1515
}
1616

1717
public sealed interface MimeTypeServerConnectConfiguration : MimeTypeConnectConfiguration
1818

1919
internal class MimeTypeClientConnectConfigurationImpl(
2020
private val configurationState: ConfigurationState,
2121
) : MimeTypeClientConnectConfiguration {
22-
override var metadata: MimeTypeWithName = WellKnownMimeType.ApplicationOctetStream
22+
override var metadata: MimeType.WithName = MimeType.WellKnown.ApplicationOctetStream
2323
private set
24-
override var data: MimeTypeWithName = WellKnownMimeType.ApplicationOctetStream
24+
override var data: MimeType.WithName = MimeType.WellKnown.ApplicationOctetStream
2525
private set
2626

27-
override fun metadata(mimeType: MimeTypeWithName) {
27+
override fun metadata(mimeType: MimeType.WithName) {
2828
configurationState.checkNotConfigured()
2929
metadata = mimeType
3030
}
3131

32-
override fun data(mimeType: MimeTypeWithName) {
32+
override fun data(mimeType: MimeType.WithName) {
3333
configurationState.checkNotConfigured()
3434
data = mimeType
3535
}
3636
}
3737

3838
internal class MimeTypeServerConnectConfigurationImpl(
39-
override val metadata: MimeTypeWithName,
40-
override val data: MimeTypeWithName,
39+
override val metadata: MimeType.WithName,
40+
override val data: MimeType.WithName,
4141
) : MimeTypeServerConnectConfiguration

rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/configuration/PayloadConfiguration.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package io.rsocket.kotlin.configuration
22

3-
import io.rsocket.kotlin.core.*
3+
import io.rsocket.kotlin.*
44

55
public sealed interface PayloadConfiguration {
66
//TODO: Long?
@@ -55,8 +55,8 @@ internal class PayloadClientConnectConfigurationImpl(
5555

5656
internal class PayloadServerConnectConfigurationImpl(
5757
configurationState: ConfigurationState,
58-
metadataMimeType: MimeTypeWithName,
59-
dataMimeType: MimeTypeWithName,
58+
metadataMimeType: MimeType.WithName,
59+
dataMimeType: MimeType.WithName,
6060
) : PayloadServerConnectConfiguration, PayloadConnectConfigurationImpl(configurationState) {
6161
override val mimeType: MimeTypeServerConnectConfigurationImpl =
6262
MimeTypeServerConnectConfigurationImpl(metadataMimeType, dataMimeType)

rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/configuration/RSocketConfiguration.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package io.rsocket.kotlin.configuration
22

33
import io.ktor.utils.io.core.*
4-
import io.rsocket.kotlin.core.*
4+
import io.rsocket.kotlin.*
55
import io.rsocket.kotlin.payload.*
66
import kotlin.time.*
77

@@ -52,8 +52,8 @@ internal class RSocketServerConnectConfigurationImpl(
5252
configurationState: ConfigurationState,
5353
keepAliveInterval: Duration,
5454
keepAliveMaxLifetime: Duration,
55-
metadataMimeType: MimeTypeWithName,
56-
dataMimeType: MimeTypeWithName,
55+
metadataMimeType: MimeType.WithName,
56+
dataMimeType: MimeType.WithName,
5757
setupPayload: Payload,
5858
) : RSocketServerConnectConfiguration, RSocketConnectConfigurationImpl() {
5959
override val setup: SetupServerConnectConfigurationImpl =

rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connect/RSocketContext.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ package io.rsocket.kotlin.connect
44

55
import io.rsocket.kotlin.*
66
import io.rsocket.kotlin.configuration.*
7-
import io.rsocket.kotlin.core.*
87
import io.rsocket.kotlin.frame.*
98
import io.rsocket.kotlin.frame.io.*
109
import io.rsocket.kotlin.internal.*
@@ -214,8 +213,8 @@ internal class RSocketServerConnectContextImpl(
214213
deferredRequester: Deferred<RSocket>,
215214
keepAliveInterval: Duration,
216215
keepAliveMaxLifetime: Duration,
217-
metadataMimeType: MimeTypeWithName,
218-
dataMimeType: MimeTypeWithName,
216+
metadataMimeType: MimeType.WithName,
217+
dataMimeType: MimeType.WithName,
219218
setupPayload: Payload,
220219
) : RSocketServerConnectContext, RSocketConnectContextImpl(session, deferredRequester) {
221220
override val isServer: Boolean get() = true

rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/connect/RSocketServer.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
package io.rsocket.kotlin.connect
2020

2121
import io.rsocket.kotlin.*
22-
import io.rsocket.kotlin.core.*
2322
import io.rsocket.kotlin.frame.*
2423
import io.rsocket.kotlin.frame.io.*
2524
import io.rsocket.kotlin.logging.*
@@ -131,10 +130,8 @@ private class RSocketServerImpl(
131130
deferred,
132131
keepAliveInterval = setupFrame.keepAliveIntervalMillis.milliseconds,
133132
keepAliveMaxLifetime = setupFrame.keepAliveMaxLifetimeMillis.milliseconds,
134-
metadataMimeType = WellKnownMimeType(setupFrame.metadataMimeTypeText)
135-
?: CustomMimeType(setupFrame.metadataMimeTypeText),
136-
dataMimeType = WellKnownMimeType(setupFrame.dataMimeTypeText)
137-
?: CustomMimeType(setupFrame.dataMimeTypeText),
133+
metadataMimeType = MimeType(setupFrame.metadataMimeTypeText),
134+
dataMimeType = MimeType(setupFrame.dataMimeTypeText),
138135
setupPayload = setupFrame.payload,
139136
)
140137
connectContext.configure(beforeConfigurators, afterConfigurators, peerConfigurator)

rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/core/MimeType.kt

Lines changed: 0 additions & 46 deletions
This file was deleted.

0 commit comments

Comments
 (0)