Generating a CUID (Collision-resistant Unique Identifier) in Kotlin involves using similar principles as in other languages: current timestamp, a counter, machine fingerprint, and randomness. Below is an example implementation in Kotlin.
Steps to Generate a CUID in Kotlin
- Timestamp: Get the current timestamp in milliseconds.
- Counter: Use a counter to handle multiple CUIDs generated in a short period.
- Fingerprint: Generate a machine-specific fingerprint.
- Randomness: Add random characters to further reduce the risk of collisions.
- Base36 Encoding: Encode the components using Base36 for readability.
Example Code
import java.net.InetAddress
import java.security.MessageDigest
import java.util.*
import kotlin.math.floor
object CUIDGenerator {
private const val BASE36_CHARS = "0123456789abcdefghijklmnopqrstuvwxyz"
private var counter = 0
private var lastTimestamp: Long = 0
@Synchronized
fun generateCUID(): String {
val timestamp = System.currentTimeMillis()
if (timestamp == lastTimestamp) {
counter++
} else {
lastTimestamp = timestamp
counter = 0
}
val timestampBase36 = encodeBase36(timestamp)
val counterBase36 = encodeBase36(counter.toLong())
val fingerprint = getMachineFingerprint()
val randomString = getRandomString(4)
return "c$timestampBase36$counterBase36$fingerprint$randomString"
}
private fun encodeBase36(value: Long): String {
var v = value
val result = StringBuilder()
while (v > 0) {
result.insert(0, BASE36_CHARS[(v % 36).toInt()])
v /= 36
}
return result.toString().padStart(8, '0')
}
private fun getMachineFingerprint(): String {
return try {
val hostname = InetAddress.getLocalHost().hostName
val md = MessageDigest.getInstance("MD5")
val hashBytes = md.digest(hostname.toByteArray())
hashBytes.joinToString("") { "%02x".format(it) }.substring(0, 4)
} catch (e: Exception) {
"0000"
}
}
private fun getRandomString(length: Int): String {
val random = Random()
val result = StringBuilder(length)
repeat(length) {
result.append(BASE36_CHARS[random.nextInt(36)])
}
return result.toString()
}
}
fun main() {
println(CUIDGenerator.generateCUID())
}
Explanation
Base36 Encoding:
- The
encodeBase36
function converts a number to a Base36 encoded string, padded to ensure a consistent length.
- The
Timestamp:
val timestamp = System.currentTimeMillis()
gets the current timestamp in milliseconds.
Counter:
- A counter is used to handle multiple CUIDs generated within the same millisecond. The counter is incremented and reset as needed. This is synchronized to ensure thread safety.
Machine Fingerprint:
getMachineFingerprint
generates a fingerprint using the MD5 hash of the machine's hostname.
Random String:
getRandomString
generates a random string of specified length using Base36 characters.
Combine Components:
- The
generateCUID
function combines the timestamp, counter, fingerprint, and random parts to form the final CUID.
- The
Summary
This Kotlin implementation of CUID generation uses available functions and libraries to handle timestamps, hashing, randomness, and counters. This approach ensures that the generated CUIDs are unique, readable, and collision-resistant, making them suitable for various applications.