Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: extract info from generated id, provide compress form of ID, up…
…date README
- Loading branch information
Showing
7 changed files
with
140 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package com.septech.snowflake4s | ||
|
||
import java.time.{Instant, LocalDateTime, Month, ZoneId, ZonedDateTime} | ||
|
||
private [snowflake4s] object Encoding { | ||
|
||
/** | ||
* This is a Custom Epoch, mean for reference time: October 18, 1989, 16:53:40 UTC - | ||
* The date of Galileo Spacecraft was launched to explored Jupiter and its moon from Kennedy Space Center, Florida, US. | ||
* | ||
* Galileo is also the name used for the satellite navigation system of the European Union. | ||
* It uses 22 August 1999 for Epoch instead of the Unix Epoch(January 1st, 1970). | ||
*/ | ||
final val zoneId = ZoneId.of("US/Eastern") | ||
final val GALILEO_LAUNCHED_DATETIME: ZonedDateTime = | ||
LocalDateTime.of(1989, Month.OCTOBER, 18, 16, 53, 40).atZone(zoneId) | ||
|
||
final val EPOCH: Long = Option(System.getProperty("snowflake4s.twitter.epoch")) | ||
.map(ZonedDateTime.parse) | ||
.map(_.toInstant.toEpochMilli) | ||
.getOrElse(GALILEO_LAUNCHED_DATETIME.toInstant.toEpochMilli) | ||
|
||
final private val workerIdBits: Long = 5L | ||
final private val datacenterIdBits: Long = 5L | ||
final private val sequenceBits: Long = 12L | ||
final private val workerIdShift: Long = sequenceBits | ||
final private val machineIdShift: Long = sequenceBits + workerIdBits | ||
final private val timestampLeftShift: Long = sequenceBits + workerIdBits + datacenterIdBits | ||
final private val sequenceMask: Long = -1L ^ (-1L << sequenceBits) | ||
|
||
def encode(id: Id): Long = { | ||
(id.timestamp - EPOCH) << timestampLeftShift | | ||
id.machineId << machineIdShift | | ||
id.workerId << workerIdShift | | ||
id.counter | ||
} | ||
|
||
def decode(value: Long): Id = { | ||
Id( | ||
value >> sequenceBits & (-1L ^ (-1L << workerIdBits)), | ||
(value >> machineIdShift) & (-1L ^ (-1L << datacenterIdBits)), | ||
(value >> timestampLeftShift) + EPOCH, | ||
value & sequenceMask | ||
) | ||
} | ||
|
||
def getDateTime(id: Id): ZonedDateTime = { | ||
Instant.ofEpochMilli(id.timestamp).atZone(zoneId) | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.septech.snowflake4s | ||
|
||
import java.time.ZonedDateTime | ||
import com.github.tototoshi.base62.Base62 | ||
|
||
case class Id(workerId: Long, machineId: Long, timestamp: Long, counter: Long) { | ||
|
||
def toLong: Long = encode | ||
|
||
override def toString: String = encode.toString | ||
|
||
def encode: Long = { | ||
Encoding.encode(this) | ||
} | ||
|
||
def getDate: ZonedDateTime = { | ||
Encoding.getDateTime(this) | ||
} | ||
|
||
def toBase62: String = new Base62().encode(encode) | ||
} | ||
|
||
object Id { | ||
def from(id: Long): Id = { | ||
Encoding.decode(id) | ||
} | ||
|
||
def fromBase62(id: String): Id = from(new Base62().decode(id)) | ||
|
||
def next: Id = Snowflake4s.generator.generate() | ||
|
||
def bulk(numOfIds: Int): List[Id] = Snowflake4s.generator.bulkGenerate(numOfIds) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
src/test/scala/com/septech/snowflake4s/Snowflake4sTest.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.septech.snowflake4s | ||
|
||
import org.scalatest.flatspec.AnyFlatSpec | ||
|
||
import java.time.{LocalDateTime, ZoneId} | ||
|
||
class Snowflake4sTest extends AnyFlatSpec { | ||
it can "convert to various forms" in { | ||
|
||
val timezone = ZoneId.of("US/Eastern") | ||
val date = LocalDateTime.of(2021, 10, 15, 12, 30, 59, 127000000).atZone(timezone) | ||
val timestamp = date.toInstant.toEpochMilli | ||
// 1634315459127 | ||
|
||
val id = Id(1, 5, timestamp, 1) | ||
|
||
assert(Id.from(4234436103643992065L) == id) | ||
assert(id.toLong == 4234436103643992065L) | ||
assert(id.getDate == date) | ||
assert(id.toBase62 == "52nlGCNq00n") | ||
assert(Id.fromBase62("52nlGCNq00n") == id) | ||
} | ||
} |