Snowflake'ler
GameVox, Discord API'sinin döndüreceği her yerde ID'leri Discord'un 64 bitlik snowflake formatında döndürür. Bit düzeni, sıralama ve zaman damgası çıkarma hesabı aynıdır: mevcut snowflake ayrıştırma kodun değişiklik olmadan çalışır.
Format
Discord'unkiyle aynı: 64 bitlik işaretsiz bir tam sayı içinde big-endian olarak 42 bit zaman damgası + 5 bit worker + 5 bit process + 12 bit artış.
┌─ 42 bits ─────────────────┬─ 5 ─┬─ 5 ─┬─ 12 ────────┐
│ GameVox epoch'undan bu ya │ wkr │ prc │ increment │
└───────────────────────────┴─────┴─────┴─────────────┘
63 22 21 17 16 12 11 0 Her bölüm Discord ile eşleşir:
- Zaman damgası (42 bit): GameVox epoch'undan bu yana geçen milisaniye, aşağıya bak.
- Worker ID (5 bit): çalışan her api görevine başlangıçta Redis atomik sayacıyla atanır.
- Process ID (5 bit): benzersiz bir üretim havuzu için worker ile eşleştirilir.
- Artış (12 bit): her (worker, process) için milisaniye başına sıra numarası.
Epoch
GameVox, Discord ile aynı epoch'u kullanır: 1420070400000 (2015-01-01 00:00:00 UTC). Discord için yazılmış bir snowflake ayrıştırıcısı GameVox ID'lerinde değişiklik olmadan çalışır: değiştirilecek bir sabit yok.
const SNOWFLAKE_EPOCH = 1420070400000n; Veri formatı
REST / gateway üzerinden giden her snowflake bir sayı olarak değil, JSON string olarak serileştirilir. JavaScript Number.MAX_SAFE_INTEGER (253-1) üzerindeki değerlerde hassasiyet kaybeder ve bir snowflake bunu düzenli olarak aşar. Hesaplama yapman gerektiğinde her zaman BigInt ile ayrıştır, diğer her yerde string olarak sakla.
// Doğru
const id = BigInt(message.id);
// Yanlış: sessizce hassasiyet kaybı
const id = Number(message.id); Zaman damgasını çıkarma
JavaScript
function snowflakeToDate(snowflake) {
const EPOCH = 1420070400000n; // Discord ile aynı
const ms = Number((BigInt(snowflake) >> 22n) + EPOCH);
return new Date(ms);
}
console.log(snowflakeToDate('182955831900192769'));
// → Date nesnesi: bu snowflake'in üretildiği an Python
from datetime import datetime, timezone
SNOWFLAKE_EPOCH = 1420070400000
def snowflake_to_dt(snowflake):
ms = (int(snowflake) >> 22) + SNOWFLAKE_EPOCH
return datetime.fromtimestamp(ms / 1000, tz=timezone.utc) Java
long SNOWFLAKE_EPOCH = 1420070400000L;
long ms = (Long.parseUnsignedLong(snowflake) >>> 22) + SNOWFLAKE_EPOCH;
Instant when = Instant.ofEpochMilli(ms); Sıralama
Zaman damgası yüksek bitlerde olduğu için iki snowflake'in sözlük sırasına göre string karşılaştırması onları kronolojik olarak sıralar, tıpkı Discord'daki gibi. Mesajlar endpoint'indeki before / after / around sayfalamasının ayrı bir zaman damgası alanı olmadan çalışmasının nedeni budur.
// Bir mesaj dizisinde, en eskiden → en yeniye:
messages.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0); Yerel veriler ve takma ad tablosu
Arka planda GameVox'un yerel nesneleri (sunucular, kanallar, kullanıcılar, mesajlar vb.) UUIDv4 kullanır. Bot uyumluluk katmanı, bir nesne bir bota ilk kez gösterildiğinde kalıcı bir snowflake üretir ve bu eşleşmeyi snowflake_aliases tablosunda saklar. O nesneye yapılan sonraki her başvuru (REST veya gateway üzerinden) aynı snowflake'i kullanır.
Mesajlar için snowflake'leri, kaynak zaman damgası olarak mesajın created_at değeriyle geriye dönük dolduruyoruz; böylece bir bot bir kanala ilk katıldığında geçmiş mesajlar doğru sıralanır. Diğer her şey için takma ad, ilk gösterimde zaman damgası olarak NOW() ile tembel biçimde üretilir; yani snowflake, nesnenin oluşturulduğu anı değil, botun nesneyi gördüğü anı yansıtır.
Sharding hash'i
Standart Discord shard formülü olduğu gibi çalışır:
shardId = (BigInt(guildId) >> 22n) % BigInt(numShards); 2.500'den az sunucudaki botlar tek bir shard üzerinde ([0, 1]) çalışır ve bunu hiç düşünmek zorunda kalmaz. Daha büyük botlar, Discord'un sağladığı yaklaşık eşit hash dağılımının aynısını alır, çünkü en üstteki 42 bit rastgele değil, zamanla monoton artar.
Dikkat edilmesi gerekenler
- Snowflake'leri bir sayı sabitiyle
==kullanarak karşılaştırma. Bunlar veri formatında string'dir: bir string ile karşılaştır ya da ikisini deBigInt'e çevir. - 42 bitlik zaman damgası, epoch'tan yaklaşık 139 yıl sonra başa döner. GameVox'un snowflake'leri 2165'e kadar geçerlidir.
- Bir sunucunun / kanalın / rolün oluşturulma zamanını snowflake'inden çıkarmaya çalışma. Bot platformundan önce var olan yerel nesneler snowflake'lerini oluşturulduklarında değil, bir bota ilk gösterildiklerinde aldı. Mesajlar istisnadır (
created_atile geriye dönük doldurulur).