Initial port to kotlin multiplatform (#399)

* Initial port to kotlin multiplatform

* Fix ObfuscationUtil casing
This commit is contained in:
Ben Bader 2020-09-11 22:13:56 -07:00 коммит произвёл GitHub
Родитель 5a724f679f
Коммит 7cd69f007c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
48 изменённых файлов: 404 добавлений и 216 удалений

Просмотреть файл

@ -65,6 +65,8 @@ allprojects {
'com.squareup.okio:okio:2.8.0'
],
okioMulti: 'com.squareup.okio:okio-multiplatform:2.8.0',
testing: [
"org.junit.jupiter:junit-jupiter:5.6.2",

Просмотреть файл

@ -19,20 +19,54 @@
* See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
*/
apply plugin: 'org.jetbrains.kotlin.jvm'
apply plugin: 'com.vanniktech.maven.publish'
apply plugin: 'org.jetbrains.kotlin.multiplatform'
description = 'Provides a minimal Thrift runtime to support classes generated by Thrifty'
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
kotlin {
jvm {
compilations.main.kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
platform("org.jetbrains.kotlin:kotlin-bom")
api "org.jetbrains.kotlin:kotlin-stdlib"
api 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9'
api libraries.okio
sourceSets {
all {
languageSettings {
useExperimentalAnnotation("kotlin.ExperimentalMultiplatform")
}
}
testImplementation "org.jetbrains.kotlin:kotlin-reflect"
testImplementation libraries.testing
commonMain {
dependencies {
api kotlin("stdlib-common")
api libraries.okioMulti
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
}
}
commonTest {
dependencies {
implementation kotlin("test-common")
implementation kotlin("test-annotations-common")
implementation "io.kotest:kotest-assertions-core:4.2.2"
implementation "io.kotest:kotest-common:4.2.2"
}
}
jvmMain {
}
jvmTest {
dependencies {
implementation kotlin("test-junit5")
implementation "io.kotest:kotest-assertions-core-jvm:4.2.2"
implementation "org.junit.jupiter:junit-jupiter:5.6.2"
}
}
}
}
jvmTest {
useJUnitPlatform()
}

Просмотреть файл

@ -21,7 +21,7 @@
package com.microsoft.thrifty
import com.microsoft.thrifty.protocol.Protocol
import java.io.IOException
import okio.IOException
/**
* An object that can read and write a Thrift struct of type [T] from and

Просмотреть файл

@ -21,7 +21,7 @@
package com.microsoft.thrifty
import com.microsoft.thrifty.protocol.Protocol
import java.io.IOException
import okio.IOException
/**
* An interface that Thrift struct objects should implement.

Просмотреть файл

@ -22,6 +22,8 @@ package com.microsoft.thrifty
import com.microsoft.thrifty.protocol.Protocol
import com.microsoft.thrifty.util.ProtocolUtil.skip
import kotlin.jvm.JvmField
import kotlin.jvm.JvmStatic
/**
* Represents a Thrift protocol-level error.

Просмотреть файл

@ -18,16 +18,14 @@
*
* See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
*/
package com.microsoft.thrifty.util
package com.microsoft.thrifty.internal
import java.io.ByteArrayOutputStream
/**
* A [ByteArrayOutputStream] that exposes its internal backing byte
* array. It is intended to reduce the number of memory copies made during
* serialization. Use with extreme caution.
*/
class UnsafeByteArrayOutputStream(count: Int) : ByteArrayOutputStream(count) {
val buffer: ByteArray
get() = buf
expect class AtomicInteger(initialValue: Int) {
fun get(): Int
fun incrementAndGet(): Int
}
expect class AtomicBoolean(initialValue: Boolean) {
fun get(): Boolean
fun compareAndSet(expected: Boolean, update: Boolean): Boolean
}

Просмотреть файл

@ -0,0 +1,34 @@
/*
* Thrifty
*
* Copyright (c) Microsoft Corporation
*
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
* WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE,
* FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
*
* See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
*/
package com.microsoft.thrifty.internal
import kotlinx.coroutines.CoroutineDispatcher
import okio.IOException
expect annotation class DefaultMethod()
expect class ProtocolException(message: String) : IOException
expect interface Closeable {
fun close()
}
expect val DefaultDispatcher: CoroutineDispatcher

Просмотреть файл

@ -43,4 +43,4 @@ interface Adapter<T> {
* @param struct A struct to be written out.
*/
fun write(protocol: Protocol, struct: T)
}
}

Просмотреть файл

@ -0,0 +1,39 @@
/*
* Thrifty
*
* Copyright (c) Microsoft Corporation
*
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
* WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE,
* FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
*
* See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
*/
package com.microsoft.thrifty.protocol
import com.microsoft.thrifty.transport.Transport
import okio.IOException
import kotlin.jvm.JvmField
abstract class BaseProtocol(
@JvmField
protected val transport: Transport
) : Protocol {
override fun close() {
transport.close()
}
@Throws(IOException::class)
override fun flush() {
transport.flush()
}
}

Просмотреть файл

@ -21,13 +21,13 @@
package com.microsoft.thrifty.protocol
import com.microsoft.thrifty.TType
import com.microsoft.thrifty.internal.ProtocolException
import com.microsoft.thrifty.transport.Transport
import okio.ByteString
import okio.ByteString.Companion.toByteString
import java.io.EOFException
import java.io.IOException
import java.io.UnsupportedEncodingException
import java.net.ProtocolException
import okio.EOFException
import okio.IOException
import kotlin.jvm.JvmOverloads
/**
* An implementation of the simple Thrift binary protocol.
@ -168,18 +168,14 @@ class BinaryProtocol @JvmOverloads constructor(
@Throws(IOException::class)
override fun writeDouble(dub: Double) {
writeI64(java.lang.Double.doubleToLongBits(dub))
writeI64(dub.toRawBits())
}
@Throws(IOException::class)
override fun writeString(str: String) {
try {
val bs = str.toByteArray(charset("UTF-8"))
writeI32(bs.size)
transport.write(bs)
} catch (e: UnsupportedEncodingException) {
throw AssertionError(e)
}
val bs = str.encodeToByteArray()
writeI32(bs.size)
transport.write(bs)
}
@Throws(IOException::class)
@ -315,7 +311,7 @@ class BinaryProtocol @JvmOverloads constructor(
@Throws(IOException::class)
override fun readDouble(): Double {
return java.lang.Double.longBitsToDouble(readI64())
return Double.fromBits(readI64())
}
@Throws(IOException::class)
@ -342,7 +338,7 @@ class BinaryProtocol @JvmOverloads constructor(
private fun readStringWithSize(size: Int): String {
val encoded = ByteArray(size)
readFully(encoded, size)
return String(encoded, Charsets.UTF_8)
return encoded.decodeToString()
}
@Throws(IOException::class)

Просмотреть файл

@ -44,13 +44,12 @@
package com.microsoft.thrifty.protocol
import com.microsoft.thrifty.TType
import com.microsoft.thrifty.internal.ProtocolException
import com.microsoft.thrifty.transport.Transport
import okio.ByteString
import okio.ByteString.Companion.toByteString
import java.io.EOFException
import java.io.IOException
import java.io.UnsupportedEncodingException
import java.net.ProtocolException
import okio.EOFException
import okio.IOException
/**
* An implementation of the Thrift compact binary protocol.
@ -210,7 +209,7 @@ class CompactProtocol(transport: Transport) : BaseProtocol(transport) {
@Throws(IOException::class)
override fun writeDouble(dub: Double) {
val bits = java.lang.Double.doubleToLongBits(dub)
val bits = dub.toRawBits()
// Doubles get written out in little-endian order
buffer[0] = (bits and 0xFFL).toByte()
@ -226,13 +225,9 @@ class CompactProtocol(transport: Transport) : BaseProtocol(transport) {
@Throws(IOException::class)
override fun writeString(str: String) {
try {
val bytes = str.toByteArray(charset("UTF-8"))
writeVarint32(bytes.size)
transport.write(bytes)
} catch (e: UnsupportedEncodingException) {
throw AssertionError(e)
}
val bytes = str.encodeToByteArray()
writeVarint32(bytes.size)
transport.write(bytes)
}
@Throws(IOException::class)
@ -289,8 +284,8 @@ class CompactProtocol(transport: Transport) : BaseProtocol(transport) {
val protocolId = readByte()
if (protocolId != PROTOCOL_ID) {
throw ProtocolException(
"Expected protocol ID " + Integer.toHexString(PROTOCOL_ID.toInt())
+ " but got " + Integer.toHexString(protocolId.toInt()))
"Expected protocol ID " + PROTOCOL_ID.toInt()
+ " but got " + protocolId.toInt().toString(radix = 16))
}
val versionAndType = readByte()
val version = (VERSION_MASK.toInt() and versionAndType.toInt()).toByte()
@ -437,7 +432,7 @@ class CompactProtocol(transport: Transport) : BaseProtocol(transport) {
or ((buffer[5].toLong() and 0xFFL) shl 40)
or ((buffer[6].toLong() and 0xFFL) shl 48)
or ((buffer[7].toLong() and 0xFFL) shl 56))
return java.lang.Double.longBitsToDouble(bits)
return Double.fromBits(bits)
}
@Throws(IOException::class)
@ -448,7 +443,7 @@ class CompactProtocol(transport: Transport) : BaseProtocol(transport) {
}
val bytes = ByteArray(length)
readFully(bytes, length)
return String(bytes, Charsets.UTF_8)
return bytes.decodeToString()
}
@Throws(IOException::class)
@ -569,9 +564,7 @@ class CompactProtocol(transport: Transport) : BaseProtocol(transport) {
private var top: Int
fun push(value: Short) {
if (top + 1 == stack.size) {
val biggerStack = ShortArray(stack.size shl 1)
System.arraycopy(stack, 0, biggerStack, 0, stack.size)
stack = biggerStack
stack = stack.copyOf(stack.size shl 1)
}
stack[++top] = value
}

Просмотреть файл

@ -20,6 +20,8 @@
*/
package com.microsoft.thrifty.protocol
import kotlin.jvm.JvmField
class FieldMetadata(
@JvmField val name: String,
@JvmField val typeId: Byte,

Просмотреть файл

@ -44,15 +44,15 @@
package com.microsoft.thrifty.protocol
import com.microsoft.thrifty.TType
import com.microsoft.thrifty.internal.ProtocolException
import com.microsoft.thrifty.transport.Transport
import okio.Buffer
import okio.ByteString
import okio.ByteString.Companion.decodeBase64
import java.io.IOException
import java.io.UnsupportedEncodingException
import java.net.ProtocolException
import java.util.ArrayDeque
import java.util.ArrayList
import okio.IOException
import kotlin.jvm.JvmField
import kotlin.jvm.JvmOverloads
import kotlin.jvm.JvmStatic
/**
* Json protocol implementation for thrift.
@ -76,13 +76,13 @@ class JsonProtocol @JvmOverloads constructor(
// Push a new Json context onto the stack.
private fun pushContext(c: JsonBaseContext) {
contextStack.push(context)
contextStack.addFirst(context)
context = c
}
// Pop the last Json context off the stack
private fun popContext() {
context = contextStack.pop()
context = contextStack.removeFirst()
}
// Reset the context stack to its initial state
@ -158,12 +158,7 @@ class JsonProtocol @JvmOverloads constructor(
if (escapeNum) {
transport.write(QUOTE)
}
try {
val buf = str.toByteArray(charset("UTF-8"))
transport.write(buf)
} catch (e: UnsupportedEncodingException) {
throw AssertionError(e)
}
transport.write(str.encodeToByteArray())
if (escapeNum) {
transport.write(QUOTE)
}
@ -188,12 +183,7 @@ class JsonProtocol @JvmOverloads constructor(
if (escapeNum) {
transport.write(QUOTE)
}
try {
val b = str.toByteArray(charset("UTF-8"))
transport.write(b, 0, b.size)
} catch (e: UnsupportedEncodingException) {
throw AssertionError(e)
}
transport.write(str.encodeToByteArray())
if (escapeNum) {
transport.write(QUOTE)
}
@ -230,12 +220,7 @@ class JsonProtocol @JvmOverloads constructor(
resetContext() // THRIFT-3743
writeJsonArrayStart()
writeJsonInteger(VERSION)
try {
val b = name.toByteArray(charset("UTF-8"))
writeJsonString(b)
} catch (e: UnsupportedEncodingException) {
throw AssertionError(e)
}
writeJsonString(name.encodeToByteArray())
writeJsonInteger(typeId.toLong())
writeJsonInteger(seqId.toLong())
}
@ -343,12 +328,7 @@ class JsonProtocol @JvmOverloads constructor(
@Throws(IOException::class)
override fun writeString(str: String) {
try {
val b = str.toByteArray(charset("UTF-8"))
writeJsonString(b)
} catch (e: UnsupportedEncodingException) {
throw AssertionError(e)
}
writeJsonString(str.encodeToByteArray())
}
@Throws(IOException::class)
@ -384,28 +364,34 @@ class JsonProtocol @JvmOverloads constructor(
+ hexVal(tmpbuf[3]).toInt()).toShort()
try {
when {
Character.isHighSurrogate(cu.toChar()) -> {
cu.toChar().isHighSurrogate() -> {
if (codeunits.size > 0) {
throw ProtocolException("Expected low surrogate char")
}
codeunits.add(cu.toChar())
}
Character.isLowSurrogate(cu.toChar()) -> {
cu.toChar().isLowSurrogate() -> {
if (codeunits.size == 0) {
throw ProtocolException("Expected high surrogate char")
}
codeunits.add(cu.toChar())
buffer.write(String(intArrayOf(codeunits[0].toInt(), codeunits[1].toInt()), 0, 2)
.toByteArray(charset("UTF-8")))
val bytes = Buffer()
.writeUtf8CodePoint(codeunits[0].toInt())
.writeUtf8CodePoint(codeunits[1].toInt())
.readUtf8()
.encodeToByteArray()
buffer.write(bytes)
codeunits.clear()
}
else -> {
buffer.write(String(intArrayOf(cu.toInt()), 0, 1).toByteArray(charset("UTF-8")))
val bytes = Buffer()
.writeUtf8CodePoint(cu.toInt())
.readUtf8()
.encodeToByteArray()
buffer.write(bytes)
}
}
continue
} catch (e: UnsupportedEncodingException) {
throw AssertionError(e)
} catch (ex: IOException) {
throw ProtocolException("Invalid unicode sequence")
}
@ -457,7 +443,7 @@ class JsonProtocol @JvmOverloads constructor(
readJsonSyntaxChar(QUOTE)
}
return try {
java.lang.Long.valueOf(str)
str.toLong()
} catch (ex: NumberFormatException) {
throw ProtocolException("Bad data encountered in numeric data")
}
@ -470,9 +456,9 @@ class JsonProtocol @JvmOverloads constructor(
context.read()
return if (reader.peek() == QUOTE[0]) {
val str = readJsonString(true)
val dub = java.lang.Double.valueOf(str.utf8())
if (!context.escapeNum() && !java.lang.Double.isNaN(dub)
&& !java.lang.Double.isInfinite(dub)) {
val dub = str.utf8().toDouble()
if (!context.escapeNum() && !dub.isNaN()
&& !dub.isInfinite()) {
// Throw exception -- we should not be in a string in this case
throw ProtocolException("Numeric data unexpectedly quoted")
}
@ -483,7 +469,7 @@ class JsonProtocol @JvmOverloads constructor(
readJsonSyntaxChar(QUOTE)
}
try {
java.lang.Double.valueOf(readJsonNumericChars())
readJsonNumericChars().toDouble()
} catch (ex: NumberFormatException) {
throw ProtocolException("Bad data encountered in numeric data")
}
@ -530,12 +516,7 @@ class JsonProtocol @JvmOverloads constructor(
if (readJsonInteger() != VERSION) {
throw ProtocolException("Message contained bad version.")
}
val name: String
name = try {
readJsonString(false).utf8()
} catch (ex: UnsupportedEncodingException) {
throw AssertionError(ex)
}
val name = readJsonString(false).utf8()
val type = readJsonInteger().toByte()
val seqid = readJsonInteger().toInt()
return MessageMetadata(name, type, seqid)

Просмотреть файл

@ -20,6 +20,8 @@
*/
package com.microsoft.thrifty.protocol
import kotlin.jvm.JvmField
class ListMetadata(
@JvmField val elementTypeId: Byte,
@JvmField val size: Int,

Просмотреть файл

@ -20,6 +20,8 @@
*/
package com.microsoft.thrifty.protocol
import kotlin.jvm.JvmField
class MapMetadata(
@JvmField val keyTypeId: Byte,
@JvmField val valueTypeId: Byte,

Просмотреть файл

@ -20,6 +20,8 @@
*/
package com.microsoft.thrifty.protocol
import kotlin.jvm.JvmField
class MessageMetadata(
name: String?,
@JvmField val type: Byte,

Просмотреть файл

@ -20,9 +20,10 @@
*/
package com.microsoft.thrifty.protocol
import com.microsoft.thrifty.internal.Closeable
import com.microsoft.thrifty.internal.DefaultMethod
import okio.ByteString
import java.io.Closeable
import java.io.IOException
import okio.IOException
interface Protocol : Closeable {
@ -156,7 +157,7 @@ interface Protocol : Closeable {
@Throws(IOException::class)
fun flush()
@JvmDefault
@DefaultMethod
fun reset() {
// to be implemented by implementations as needed
}

Просмотреть файл

@ -20,6 +20,8 @@
*/
package com.microsoft.thrifty.protocol
import kotlin.jvm.JvmField
class SetMetadata(
@JvmField val elementTypeId: Byte,
@JvmField val size: Int,

Просмотреть файл

@ -20,14 +20,11 @@
*/
package com.microsoft.thrifty.protocol
import com.microsoft.thrifty.internal.ProtocolException
import com.microsoft.thrifty.transport.Transport
import com.microsoft.thrifty.util.UnsafeByteArrayOutputStream
import okio.Buffer
import okio.ByteString
import java.io.IOException
import java.io.OutputStreamWriter
import java.net.ProtocolException
import java.util.ArrayDeque
import java.util.Deque
import okio.IOException
/**
* A protocol that maps Thrift data to idiomatic JSON.
@ -128,7 +125,14 @@ class SimpleJsonProtocol(transport: Transport?) : BaseProtocol(transport!!) {
init {
for (i in 0..31) {
// Control chars must be escaped
ESCAPES[i] = String.format("\\u%04x", i).toCharArray()
val chars = CharArray(6)
chars[0] = '\\'
chars[1] = 'u'
chars[2] = '0'
chars[3] = '0'
chars[4] = "0123456789abcdef"[(i shr 4) and 0xF]
chars[5] = "0123456789abcdef"[i and 0xF]
ESCAPES[i] = chars
}
ESCAPES['\\'.toInt()] = charArrayOf('\\', '\\')
ESCAPES['\"'.toInt()] = charArrayOf('\\', '"')
@ -146,7 +150,7 @@ class SimpleJsonProtocol(transport: Transport?) : BaseProtocol(transport!!) {
// nothing
}
}
private val writeStack: Deque<WriteContext> = ArrayDeque()
private val writeStack = ArrayDeque<WriteContext>()
private var binaryOutputMode = BinaryOutputMode.HEX
fun withBinaryOutputMode(mode: BinaryOutputMode): SimpleJsonProtocol {
binaryOutputMode = mode
@ -243,57 +247,56 @@ class SimpleJsonProtocol(transport: Transport?) : BaseProtocol(transport!!) {
@Throws(IOException::class)
override fun writeByte(b: Byte) {
writeContext()!!.beforeWrite()
val toWrite = b.toString().toByteArray(Charsets.UTF_8)
val toWrite = b.toString().encodeToByteArray()
transport.write(toWrite)
}
@Throws(IOException::class)
override fun writeI16(i16: Short) {
writeContext()!!.beforeWrite()
transport.write(i16.toString().toByteArray(Charsets.UTF_8))
transport.write(i16.toString().encodeToByteArray())
}
@Throws(IOException::class)
override fun writeI32(i32: Int) {
writeContext()!!.beforeWrite()
transport.write(i32.toString().toByteArray(Charsets.UTF_8))
transport.write(i32.toString().encodeToByteArray())
}
@Throws(IOException::class)
override fun writeI64(i64: Long) {
writeContext()!!.beforeWrite()
transport.write(i64.toString().toByteArray(Charsets.UTF_8))
transport.write(i64.toString().encodeToByteArray())
}
@Throws(IOException::class)
override fun writeDouble(dub: Double) {
writeContext()!!.beforeWrite()
transport.write(dub.toString().toByteArray(Charsets.UTF_8))
transport.write(dub.toString().encodeToByteArray())
}
@Throws(IOException::class)
override fun writeString(str: String) {
writeContext()!!.beforeWrite()
val len = str.length
val baos = UnsafeByteArrayOutputStream(len)
val writer = OutputStreamWriter(baos, Charsets.UTF_8)
writer.write('"'.toInt())
val buffer = Buffer()
buffer.writeUtf8CodePoint('"'.toInt())
for (i in 0 until len) {
val c = str[i]
if (c.toInt() < 128) {
val maybeEscape = ESCAPES[c.toInt()]
if (maybeEscape != null) {
writer.write(maybeEscape)
maybeEscape.forEach { buffer.writeUtf8CodePoint(it.toInt()) } // These are known to be equivalent
} else {
writer.write(c.toInt())
buffer.writeUtf8CodePoint(c.toInt())
}
} else {
writer.write(c.toInt())
buffer.writeUtf8("$c") // Not sure how to get code points from a string in MPP
}
}
writer.write('"'.toInt())
writer.flush()
transport.write(baos.buffer, 0, baos.size())
buffer.writeUtf8CodePoint('"'.toInt())
val bs = buffer.readByteArray()
transport.write(bs, 0, bs.size)
}
@Throws(IOException::class)
@ -307,11 +310,11 @@ class SimpleJsonProtocol(transport: Transport?) : BaseProtocol(transport!!) {
}
private fun pushWriteContext(context: WriteContext) {
writeStack.push(context)
writeStack.addFirst(context)
}
private fun writeContext(): WriteContext? {
var top = writeStack.peek()
var top = writeStack.firstOrNull()
if (top == null) {
top = defaultWriteContext
}
@ -320,7 +323,7 @@ class SimpleJsonProtocol(transport: Transport?) : BaseProtocol(transport!!) {
@Throws(IOException::class)
private fun popWriteContext() {
val context = writeStack.pollFirst()
val context = writeStack.removeFirstOrNull()
if (context == null) {
throw ProtocolException("stack underflow")
} else {

Просмотреть файл

@ -20,6 +20,8 @@
*/
package com.microsoft.thrifty.protocol
import kotlin.jvm.JvmField
class StructMetadata(
@JvmField val name: String,
)

Просмотреть файл

@ -23,11 +23,11 @@ package com.microsoft.thrifty.service
import com.microsoft.thrifty.Struct
import com.microsoft.thrifty.ThriftException
import com.microsoft.thrifty.ThriftException.Companion.read
import com.microsoft.thrifty.internal.AtomicBoolean
import com.microsoft.thrifty.internal.AtomicInteger
import com.microsoft.thrifty.internal.Closeable
import com.microsoft.thrifty.protocol.Protocol
import java.io.Closeable
import java.io.IOException
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import okio.IOException
/**
* Implements a basic service client that executes methods synchronously.

Просмотреть файл

@ -22,7 +22,8 @@ package com.microsoft.thrifty.service
import com.microsoft.thrifty.protocol.MessageMetadata
import com.microsoft.thrifty.protocol.Protocol
import java.io.IOException
import okio.IOException
import kotlin.jvm.JvmField
/**
* A closure capturing all data necessary to send and receive an asynchronous

Просмотреть файл

@ -25,7 +25,7 @@ package com.microsoft.thrifty.service
* caller.
*
* @param T the type of result expected, or [Unit].
</T> */
*/
interface ServiceMethodCallback<T> {
/**
* Invoked upon successful return from a service call with the result, if

Просмотреть файл

@ -21,6 +21,7 @@
package com.microsoft.thrifty.transport
import okio.Buffer
import kotlin.jvm.JvmOverloads
class BufferTransport @JvmOverloads constructor(
private val b: Buffer = Buffer()

Просмотреть файл

@ -20,8 +20,7 @@
*/
package com.microsoft.thrifty.transport
import com.microsoft.thrifty.util.UnsafeByteArrayOutputStream
import java.io.EOFException
import okio.EOFException
/**
* A transport decorator that reads from and writes to the underlying transport
@ -35,7 +34,7 @@ class FramedTransport(
private var remainingBytes = 0
// Write state
private var pendingWrite: UnsafeByteArrayOutputStream? = null
private var pendingWrite: SimpleBuffer? = null
override fun close() {
inner.close()
@ -71,14 +70,14 @@ class FramedTransport(
override fun write(buffer: ByteArray, offset: Int, count: Int) {
if (pendingWrite == null) {
pendingWrite = UnsafeByteArrayOutputStream(count.coerceAtLeast(32))
pendingWrite = SimpleBuffer(count)
}
pendingWrite!!.write(buffer, offset, count)
}
override fun flush() {
val write = pendingWrite ?: return
val size = write.size()
val size = write.size
if (size == 0) {
return
}
@ -89,7 +88,39 @@ class FramedTransport(
headerBytes[2] = ((size shr 8) and 0xFF).toByte()
headerBytes[3] = ( size and 0xFF).toByte()
inner.write(headerBytes)
inner.write(pendingWrite!!.buffer, 0, size)
pendingWrite!!.reset()
inner.write(write.buf, 0, size)
write.reset()
}
private class SimpleBuffer(count: Int = 32) {
var buf: ByteArray = ByteArray(count.coerceAtLeast(32))
var size: Int = 0
fun write(buffer: ByteArray, offset: Int, count: Int) {
if (size + count > buf.size) {
buf = buf.copyOf(nextPowerOfTwo(size + count))
}
buffer.copyInto(
destination = buf,
destinationOffset = size,
startIndex = offset,
endIndex = offset + count)
size += count
}
fun reset() {
buf = ByteArray(32)
size = 0
}
private fun nextPowerOfTwo(num: Int): Int {
var n = num - 1
n = n or (n ushr 1)
n = n or (n ushr 2)
n = n or (n ushr 4)
n = n or (n ushr 8)
n = n or (n ushr 16)
return n + 1
}
}
}

Просмотреть файл

@ -20,15 +20,16 @@
*/
package com.microsoft.thrifty.transport
import java.io.Closeable
import java.io.IOException
import com.microsoft.thrifty.internal.Closeable
import com.microsoft.thrifty.internal.DefaultMethod
import okio.IOException
interface Transport : Closeable {
@Throws(IOException::class)
fun read(buffer: ByteArray, offset: Int, count: Int): Int
@Throws(IOException::class)
@JvmDefault
@DefaultMethod
fun write(data: ByteArray) {
write(data, 0, data.size)
}

Просмотреть файл

@ -20,12 +20,12 @@
*/
package com.microsoft.thrifty.util
import kotlin.jvm.JvmStatic
/**
* Utility methods for printing obfuscated versions of sensitive data.
*/
object ObfuscationUtil {
private val HEX_CHARS = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F')
@JvmStatic
fun summarizeCollection(collection: Collection<*>?, collectionType: String, elementType: String): String {
return when (collection) {
@ -49,17 +49,6 @@ object ObfuscationUtil {
}
val hashcode = value.hashCode()
// Integer.toHexString(int) doesn't pad to 8 chars;
// this is simple enough to do ourselves.
val hexChars = CharArray(8)
hexChars[0] = HEX_CHARS[hashcode shr 28 and 0xF]
hexChars[1] = HEX_CHARS[hashcode shr 24 and 0xF]
hexChars[2] = HEX_CHARS[hashcode shr 20 and 0xF]
hexChars[3] = HEX_CHARS[hashcode shr 16 and 0xF]
hexChars[4] = HEX_CHARS[hashcode shr 12 and 0xF]
hexChars[5] = HEX_CHARS[hashcode shr 8 and 0xF]
hexChars[6] = HEX_CHARS[hashcode shr 4 and 0xF]
hexChars[7] = HEX_CHARS[hashcode and 0xF]
return String(hexChars)
return hashcode.toString(radix = 16).toUpperCase().padStart(length = 8, padChar = '0')
}
}

Просмотреть файл

@ -21,9 +21,10 @@
package com.microsoft.thrifty.util
import com.microsoft.thrifty.TType
import com.microsoft.thrifty.internal.ProtocolException
import com.microsoft.thrifty.protocol.Protocol
import java.io.IOException
import java.net.ProtocolException
import okio.IOException
import kotlin.jvm.JvmStatic
object ProtocolUtil {
@JvmStatic

Просмотреть файл

@ -0,0 +1,24 @@
/*
* Thrifty
*
* Copyright (c) Microsoft Corporation
*
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
* WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE,
* FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
*
* See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
*/
package com.microsoft.thrifty
class ThriftExceptionTest {
}

Просмотреть файл

@ -21,6 +21,7 @@
package com.microsoft.thrifty.protocol
import com.microsoft.thrifty.TType
import com.microsoft.thrifty.internal.ProtocolException
import com.microsoft.thrifty.transport.BufferTransport
import com.microsoft.thrifty.util.ProtocolUtil.skip
import io.kotest.assertions.fail
@ -31,9 +32,9 @@ import okio.Buffer
import okio.ByteString
import okio.ByteString.Companion.decodeHex
import okio.ByteString.Companion.encodeUtf8
import org.junit.jupiter.api.Test
import java.io.IOException
import java.net.ProtocolException
import okio.IOException
import kotlin.math.PI
import kotlin.test.Test
class BinaryProtocolTest {
@Test
@ -127,8 +128,8 @@ class BinaryProtocolTest {
// Doubles go on the wire as the 8-byte blobs from
// Double#doubleToLongBits().
proto.writeDouble(Math.PI)
buffer.readLong() shouldBe java.lang.Double.doubleToLongBits(Math.PI)
proto.writeDouble(PI)
buffer.readLong() shouldBe PI.toBits()
}
@Test

Просмотреть файл

@ -23,8 +23,9 @@ package com.microsoft.thrifty.protocol
import com.microsoft.thrifty.transport.BufferTransport
import io.kotest.matchers.shouldBe
import okio.Buffer
import org.junit.jupiter.api.Test
import java.io.IOException
import okio.IOException
import kotlin.math.PI
import kotlin.test.Test
class CompactProtocolTest {
@Test
@ -82,7 +83,7 @@ class CompactProtocolTest {
.i32_thing(0xFFFF)
.i64_thing(0xFFFFFFFFL)
.string_thing("foo")
.double_thing(Math.PI)
.double_thing(PI)
.bool_thing(true)
.build()
val buffer = Buffer()

Просмотреть файл

@ -25,7 +25,8 @@ import com.microsoft.thrifty.transport.BufferTransport
import io.kotest.matchers.shouldBe
import okio.Buffer
import okio.ByteString.Companion.encodeUtf8
import org.junit.jupiter.api.Test
import kotlin.math.PI
import kotlin.test.Test
class JsonProtocolTest {
private val buffer = Buffer()
@ -154,7 +155,7 @@ class JsonProtocolTest {
.i32_thing(0xFFFF)
.i64_thing(0xFFFFFFFFL)
.string_thing("foo")
.double_thing(Math.PI)
.double_thing(PI)
.bool_thing(true)
.build()
val buffer = Buffer()

Просмотреть файл

@ -26,7 +26,7 @@ import io.kotest.matchers.shouldBe
import okio.Buffer
import okio.ByteString.Companion.encodeUtf8
import okio.ByteString.Companion.toByteString
import org.junit.jupiter.api.Test
import kotlin.test.Test
class SimpleJsonProtocolTest {
private val buffer = Buffer()

Просмотреть файл

@ -26,7 +26,8 @@ import com.microsoft.thrifty.StructBuilder
import com.microsoft.thrifty.TType
import com.microsoft.thrifty.ThriftField
import com.microsoft.thrifty.util.ProtocolUtil.skip
import java.io.IOException
import okio.IOException
import kotlin.jvm.JvmField
class Xtruct private constructor(builder: Builder) : Struct {
@ThriftField(fieldId = 1)

Просмотреть файл

@ -23,9 +23,8 @@ package com.microsoft.thrifty.transport
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.matchers.shouldBe
import okio.Buffer
import org.junit.jupiter.api.Test
import java.io.EOFException
import java.nio.charset.StandardCharsets
import okio.EOFException
import kotlin.test.Test
class FramedTransportTest {
@Test
@ -33,7 +32,7 @@ class FramedTransportTest {
val buffer = Buffer()
val bufferTransport = BufferTransport(buffer)
val transport = FramedTransport(bufferTransport)
transport.write("abcde".toByteArray(StandardCharsets.UTF_8))
transport.write("abcde".encodeToByteArray())
transport.flush()
buffer.readInt() shouldBe 5
@ -50,7 +49,7 @@ class FramedTransportTest {
transport.read(readBuffer, 0, 5) shouldBe 5
buffer.size shouldBe 5L
String(readBuffer, Charsets.US_ASCII) shouldBe "abcde"
readBuffer.decodeToString() shouldBe "abcde"
}
@Test
@ -79,7 +78,7 @@ class FramedTransportTest {
transport.read(readBuffer, 0, 10) shouldBe 6
transport.read(readBuffer, 6, 4) shouldBe 4
String(readBuffer, Charsets.UTF_8) shouldBe "abcdefghij"
readBuffer.decodeToString() shouldBe "abcdefghij"
}
@Test

Просмотреть файл

@ -21,7 +21,7 @@
package com.microsoft.thrifty.util
import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test
import kotlin.test.Test
class ObfuscationUtilTest {
@Test
@ -58,6 +58,12 @@ class ObfuscationUtilTest {
ObfuscationUtil.hash(obj) shouldBe "12345678"
}
@Test
fun summarizeSingleObjectZeroPads() {
val obj = 0x5678
ObfuscationUtil.hash(obj) shouldBe "00005678"
}
@Test
fun summarizeNullObjext() {
val obj: String? = null

Просмотреть файл

@ -21,6 +21,7 @@
package com.microsoft.thrifty.util
import com.microsoft.thrifty.TType
import com.microsoft.thrifty.internal.ProtocolException
import com.microsoft.thrifty.protocol.BinaryProtocol
import com.microsoft.thrifty.protocol.Xtruct
import com.microsoft.thrifty.transport.BufferTransport
@ -30,8 +31,7 @@ import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.throwable.shouldHaveMessage
import okio.Buffer
import okio.ByteString.Companion.encodeUtf8
import org.junit.jupiter.api.Test
import java.net.ProtocolException
import kotlin.test.Test
class ProtocolUtilTest {
private val buffer = Buffer()

Просмотреть файл

@ -0,0 +1,25 @@
/*
* Thrifty
*
* Copyright (c) Microsoft Corporation
*
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
* WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE,
* FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
*
* See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
*/
package com.microsoft.thrifty.internal
actual typealias AtomicInteger = java.util.concurrent.atomic.AtomicInteger
actual typealias AtomicBoolean = java.util.concurrent.atomic.AtomicBoolean

Просмотреть файл

@ -0,0 +1,32 @@
/*
* Thrifty
*
* Copyright (c) Microsoft Corporation
*
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
* WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE,
* FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
*
* See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
*/
package com.microsoft.thrifty.internal
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
actual typealias DefaultMethod = JvmDefault
actual typealias ProtocolException = java.net.ProtocolException
actual typealias Closeable = java.io.Closeable
actual val DefaultDispatcher: CoroutineDispatcher = Dispatchers.IO

Просмотреть файл

@ -60,10 +60,7 @@ class SocketTransport internal constructor(
}
fun socketFactory(socketFactory: SocketFactory?): Builder {
if (socketFactory == null) {
throw NullPointerException("socketFactory")
}
this.socketFactory = socketFactory
this.socketFactory = requireNotNull(socketFactory) { "socketFactory" }
return this
}
@ -116,18 +113,18 @@ class SocketTransport internal constructor(
override fun close() {
val socket = socket
val `in` = inputStream
val out = outputStream
val input = inputStream
val output = outputStream
this.socket = null
if (`in` != null) {
if (input != null) {
try {
`in`.close()
input.close()
} catch (ignored: IOException) {
}
}
if (out != null) {
if (output != null) {
try {
out.close()
output.close()
} catch (ignored: IOException) {
}
}

Просмотреть файл

@ -1,18 +0,0 @@
package com.microsoft.thrifty.protocol
import com.microsoft.thrifty.transport.Transport
import java.io.IOException
abstract class BaseProtocol(
@JvmField
protected val transport: Transport
) : Protocol {
override fun close() {
transport.close()
}
@Throws(IOException::class)
override fun flush() {
transport.flush()
}
}