mirror of
https://github.com/tursom/TursomServer.git
synced 2025-03-04 06:40:11 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
3a20ab01d4
@ -111,10 +111,10 @@ fun ByteArray.toShort(offset: Int = 0): Short {
|
||||
fun ByteArray.toInt(offset: Int = 0): Int {
|
||||
return if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
|
||||
this[offset].toInt() and 0xff or (this[offset + 1].toInt() shl 8 and 0xff00) or
|
||||
(this[offset + 2].toInt() shl 16 and 0xff0000) or (this[offset + 3].toInt() shl 24 and 0xff000000.toInt())
|
||||
(this[offset + 2].toInt() shl 16 and 0xff0000) or (this[offset + 3].toInt() shl 24 and 0xff000000.toInt())
|
||||
} else {
|
||||
this[offset + 3].toInt() and 0xff or (this[offset + 2].toInt() shl 8 and 0xff00) or
|
||||
(this[offset + 1].toInt() shl 16 and 0xff0000) or (this[offset].toInt() shl 24 and 0xff000000.toInt())
|
||||
(this[offset + 1].toInt() shl 16 and 0xff0000) or (this[offset].toInt() shl 24 and 0xff000000.toInt())
|
||||
}
|
||||
}
|
||||
|
||||
@ -695,13 +695,13 @@ inline fun toShort(get: () -> Byte): Short {
|
||||
inline fun toInt(get: () -> Byte): Int {
|
||||
return if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
|
||||
get().toInt() and 0xff or (get().toInt() shl 8 and 0xff00) or
|
||||
(get().toInt() shl 16 and 0xff0000) or (get().toInt() shl 24 and 0xff000000.toInt())
|
||||
(get().toInt() shl 16 and 0xff0000) or (get().toInt() shl 24 and 0xff000000.toInt())
|
||||
} else {
|
||||
val i1 = get()
|
||||
val i2 = get()
|
||||
val i3 = get()
|
||||
get().toInt() and 0xff or (i3.toInt() shl 8 and 0xff00) or
|
||||
(i2.toInt() shl 16 and 0xff0000) or (i1.toInt() shl 24 and 0xff000000.toInt())
|
||||
(i2.toInt() shl 16 and 0xff0000) or (i1.toInt() shl 24 and 0xff000000.toInt())
|
||||
}
|
||||
}
|
||||
|
||||
@ -720,4 +720,29 @@ inline fun toFloat(get: () -> Byte): Float {
|
||||
|
||||
inline fun toDouble(get: () -> Byte): Double {
|
||||
return Double.fromBits(toLong(get))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val UPPER_HEX_ARRAY = "0123456789ABCDEF".toCharArray()
|
||||
private val LOWER_HEX_ARRAY = "0123456789abcdef".toCharArray()
|
||||
|
||||
private inline fun toHexString(upper: Boolean, length: Int, toBytes: ((Byte) -> Unit) -> Unit): String {
|
||||
val hexArray = if (upper) UPPER_HEX_ARRAY else LOWER_HEX_ARRAY
|
||||
val hexChars = CharArray(length)
|
||||
var i = 0
|
||||
toBytes { b ->
|
||||
@Suppress("NAME_SHADOWING") val b = b.toInt()
|
||||
hexChars[i shl 1] = hexArray[b ushr 4 and 0x0F]
|
||||
hexChars[(i shl 1) + 1] = hexArray[b and 0x0F]
|
||||
i++
|
||||
}
|
||||
return String(hexChars)
|
||||
}
|
||||
|
||||
fun Char.toHexString(upper: Boolean = true): String = toHexString(upper, 4, ::toBytes)
|
||||
fun Short.toHexString(upper: Boolean = true): String = toHexString(upper, 4, ::toBytes)
|
||||
fun Int.toHexString(upper: Boolean = true): String = toHexString(upper, 8, ::toBytes)
|
||||
fun Long.toHexString(upper: Boolean = true): String = toHexString(upper, 16, ::toBytes)
|
||||
fun Float.toHexString(upper: Boolean = true): String = toHexString(upper, 8, ::toBytes)
|
||||
fun Double.toHexString(upper: Boolean = true): String = toHexString(upper, 16, ::toBytes)
|
||||
|
||||
|
@ -1,9 +1,14 @@
|
||||
package cn.tursom.core
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
||||
/**
|
||||
* 被改造过的雪花ID
|
||||
* |---------|------------|-----------|------------|
|
||||
* | 空位(1) | 时间戳(43) | 自增位(7) | 机器ID(13) |
|
||||
* |---------|------------|-----------|------------|
|
||||
* 时间戳仅在初始化时使用, 与序列号接壤, 这样做可以避免某一时间内大量请求导致的ID爆炸
|
||||
* 当前方案在ID溢出时, 溢出的数据会让时间戳 +1.
|
||||
* 这样做, 只要节点不重启或者在重启前平均QPS没有超标, 重启后分配的ID仍能唯一
|
||||
@ -14,37 +19,78 @@ import java.util.concurrent.atomic.AtomicLong
|
||||
*
|
||||
* 当前最多支持 8192 个节点同时上线, 未来如果节点数超过了 8192 个, 也可以以ID生成的最晚时间为代价提升节点最高数量
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class Snowflake(
|
||||
@Suppress("MemberVisibilityCanBePrivate") val nodeId: Int
|
||||
@Suppress("MemberVisibilityCanBePrivate") val nodeId: Int,
|
||||
val executorService: ScheduledExecutorService? = null,
|
||||
val updateRateMs: Long = defaultUpdateRateMs,
|
||||
val workMode: WorkMode = WorkMode.INCREMENT,
|
||||
val incrementLength: Int = 7
|
||||
) {
|
||||
constructor(workerId: String) : this(parseId(workerId))
|
||||
constructor(
|
||||
workerId: String,
|
||||
executorService: ScheduledExecutorService? = null,
|
||||
updateRateMs: Long = defaultUpdateRateMs,
|
||||
workMode: WorkMode = WorkMode.INCREMENT
|
||||
) : this(parseId(workerId), executorService, updateRateMs, workMode)
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
val timestamp = System.currentTimeMillis().and(0x00_00_07_ff__ff_ff_ff_ff).shl(7)
|
||||
private val seed = AtomicLong((nodeId and 0x1fff).toLong().shl(50) or timestamp)
|
||||
val id: Long get() = seed.incrementAndGet()
|
||||
|
||||
override fun toString() = "Snowflake(workerId=${nodeId
|
||||
}, timestamp=0x${timestamp.toByteArray().toHexString()
|
||||
}, seed=0x${seed.get().toByteArray().toHexString()})"
|
||||
|
||||
companion object {
|
||||
fun parseId(workerId: String): Int {
|
||||
var id = 0
|
||||
var step = 1
|
||||
for (index in workerId.length - 1 downTo 0) {
|
||||
if (Character.isDigit(workerId[index])) {
|
||||
id += (workerId[index] - '0') * step
|
||||
step *= 10
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (step != 1) {
|
||||
return id
|
||||
} else {
|
||||
throw NumberFormatException(workerId)
|
||||
}
|
||||
}
|
||||
private var _timestamp = System.currentTimeMillis().shl(incrementLength + 13).and(0x7f_ff_ff_ff__ff_ff_ff_ff)
|
||||
set(value) {
|
||||
field = value
|
||||
seed = AtomicLong((nodeId and 0x1fff).toLong() or field)
|
||||
}
|
||||
|
||||
val timestamp: Long
|
||||
get() = _timestamp
|
||||
|
||||
private var seed = AtomicLong((nodeId and 0x1fff).toLong() or timestamp)
|
||||
val id: Long get() = seed.getAndAdd(incrementBase)
|
||||
|
||||
init {
|
||||
executorService?.scheduleWithFixedDelay({
|
||||
when (workMode) {
|
||||
WorkMode.REALTIME -> {
|
||||
val timestamp = System.currentTimeMillis()
|
||||
.shl(incrementLength + 13)
|
||||
.and(0x7f_ff_ff_ff__ff_ff_ff_ff)
|
||||
if (seed.get() < timestamp - 1.shl(incrementLength + 13)) {
|
||||
_timestamp = timestamp
|
||||
}
|
||||
}
|
||||
WorkMode.INCREMENT -> _timestamp += 1.shl(incrementLength + 13)
|
||||
WorkMode.NO_INCREMENT -> {
|
||||
}
|
||||
}
|
||||
}, updateRateMs, updateRateMs, TimeUnit.MICROSECONDS)
|
||||
}
|
||||
|
||||
override fun toString() = "Snowflake(workerId=${nodeId
|
||||
}, timestamp=0x${timestamp.toHexString(false)
|
||||
}, seed=0x${seed.get().toHexString(false)})"
|
||||
|
||||
enum class WorkMode {
|
||||
REALTIME, INCREMENT, NO_INCREMENT
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val defaultUpdateRateMs = 16L
|
||||
const val incrementBase = 0x2000L
|
||||
fun parseId(workerId: String): Int {
|
||||
var id = 0
|
||||
var step = 1
|
||||
for (index in workerId.length - 1 downTo 0) {
|
||||
if (Character.isDigit(workerId[index])) {
|
||||
id += (workerId[index] - '0') * step
|
||||
step *= 10
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (step != 1) {
|
||||
return id
|
||||
} else {
|
||||
throw NumberFormatException(workerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,12 @@ import java.security.NoSuchAlgorithmException
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.jar.JarFile
|
||||
import java.util.zip.*
|
||||
import java.util.zip.Deflater
|
||||
import java.util.zip.GZIPInputStream
|
||||
import java.util.zip.GZIPOutputStream
|
||||
import java.util.zip.Inflater
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.experimental.and
|
||||
|
||||
|
||||
inline fun <reified T> Array<out T?>.excludeNull(): List<T> {
|
||||
@ -52,6 +56,13 @@ inline fun <T> usingTime(action: () -> T): Long {
|
||||
return t2 - t1
|
||||
}
|
||||
|
||||
inline fun <T> usingNanoTime(action: () -> T): Long {
|
||||
val t1 = System.nanoTime()
|
||||
action()
|
||||
val t2 = System.nanoTime()
|
||||
return t2 - t1
|
||||
}
|
||||
|
||||
inline fun <T> Collection<T>.toString(action: (T) -> Any): String {
|
||||
val iterator = iterator()
|
||||
if (!iterator.hasNext()) return "[]"
|
||||
@ -169,13 +180,27 @@ fun ByteArray.sha512(): ByteArray = sha512.digest(this)
|
||||
|
||||
fun String.sha512(): String = toByteArray().sha512().toHexString()
|
||||
|
||||
private val HEX_ARRAY = "0123456789abcdef".toCharArray()
|
||||
fun ByteArray.toHexString(): String {
|
||||
|
||||
fun ByteArray.toHexString(upper: Boolean = true): String = if (upper) toUpperHexString() else toLowerHexString()
|
||||
|
||||
private val UPPER_HEX_ARRAY = "0123456789ABCDEF".toCharArray()
|
||||
fun ByteArray.toUpperHexString(): String {
|
||||
val hexChars = CharArray(size * 2)
|
||||
for (i in indices) {
|
||||
val b = this[i].toInt()
|
||||
hexChars[i shl 1] = HEX_ARRAY[b ushr 4 and 0x0F]
|
||||
hexChars[(i shl 1) + 1] = HEX_ARRAY[b and 0x0F]
|
||||
val b = this[i]
|
||||
hexChars[i shl 1] = UPPER_HEX_ARRAY[b.toInt() ushr 4 and 0x0F]
|
||||
hexChars[(i shl 1) + 1] = UPPER_HEX_ARRAY[(b and 0x0F).toInt()]
|
||||
}
|
||||
return String(hexChars)
|
||||
}
|
||||
|
||||
private val LOWER_HEX_ARRAY = "0123456789abcdef".toCharArray()
|
||||
fun ByteArray.toLowerHexString(): String {
|
||||
val hexChars = CharArray(size * 2)
|
||||
for (i in indices) {
|
||||
val b = this[i]
|
||||
hexChars[i shl 1] = LOWER_HEX_ARRAY[b.toInt() ushr 4 and 0x0F]
|
||||
hexChars[(i shl 1) + 1] = LOWER_HEX_ARRAY[(b and 0x0F).toInt()]
|
||||
}
|
||||
return String(hexChars)
|
||||
}
|
||||
@ -184,22 +209,26 @@ fun String.fromHexString(): ByteArray {
|
||||
val source = toLowerCase()
|
||||
val data = ByteArray(length / 2)
|
||||
for (i in 0 until length / 2) {
|
||||
data[i] = ((HEX_ARRAY.indexOf(source[i * 2]) shl 4) + HEX_ARRAY.indexOf(source[i * 2 + 1])).toByte()
|
||||
data[i] = ((LOWER_HEX_ARRAY.indexOf(source[i * 2]) shl 4) + LOWER_HEX_ARRAY.indexOf(source[i * 2 + 1])).toByte()
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
fun ByteArray.toUTF8String() = String(this, Charsets.UTF_8)
|
||||
|
||||
fun String.base64() = this.toByteArray().base64().toUTF8String()
|
||||
|
||||
fun ByteArray.base64(): ByteArray {
|
||||
return Base64.getEncoder().encode(this)
|
||||
}
|
||||
|
||||
fun String.base64decode() = Base64.getDecoder().decode(this).toUTF8String()
|
||||
fun String.base64(): String = this.toByteArray().base64().toUTF8String()
|
||||
fun ByteArray.base64(): ByteArray = Base64.getEncoder().encode(this)
|
||||
fun String.base64Url(): String = this.toByteArray().base64Url().toUTF8String()
|
||||
fun ByteArray.base64Url(): ByteArray = Base64.getUrlEncoder().encode(this)
|
||||
fun String.base64Mime(): String = this.toByteArray().base64Mime().toUTF8String()
|
||||
fun ByteArray.base64Mime(): ByteArray = Base64.getMimeEncoder().encode(this)
|
||||
|
||||
fun String.base64decode(): String = Base64.getDecoder().decode(this).toUTF8String()
|
||||
fun ByteArray.base64decode(): ByteArray = Base64.getDecoder().decode(this)
|
||||
fun String.base64UrlDecode(): String = Base64.getUrlDecoder().decode(this).toUTF8String()
|
||||
fun ByteArray.base64UrlDecode(): ByteArray = Base64.getUrlDecoder().decode(this)
|
||||
fun String.base64MimeDecode(): String = Base64.getMimeDecoder().decode(this).toUTF8String()
|
||||
fun ByteArray.base64MimeDecode(): ByteArray = Base64.getMimeDecoder().decode(this)
|
||||
|
||||
fun String.digest(type: String) = toByteArray().digest(type)?.toHexString()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user