Refactor snowflake id generation to improve randomness

This commit is contained in:
Daniel Supernault 2021-09-01 22:46:57 -06:00
parent e95b702e23
commit e5aea490b1
No known key found for this signature in database
GPG key ID: 0DEF1C662C9033F7
9 changed files with 320 additions and 296 deletions

View file

@ -4,7 +4,7 @@ namespace App;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Model;
use Pixelfed\Snowflake\HasSnowflakePrimary;
use App\HasSnowflakePrimary;
class Collection extends Model
{

View file

@ -3,7 +3,7 @@
namespace App;
use Illuminate\Database\Eloquent\Model;
use Pixelfed\Snowflake\HasSnowflakePrimary;
use App\HasSnowflakePrimary;
class CollectionItem extends Model
{

View file

@ -0,0 +1,19 @@
<?php
namespace App;
use App\Services\SnowflakeService;
trait HasSnowflakePrimary
{
public static function bootHasSnowflakePrimary()
{
static::saving(function ($model) {
if (is_null($model->getKey())) {
$keyName = $model->getKeyName();
$id = SnowflakeService::next();
$model->setAttribute($keyName, $id);
}
});
}
}

View file

@ -4,7 +4,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Pixelfed\Snowflake\HasSnowflakePrimary;
use App\HasSnowflakePrimary;
class Poll extends Model
{

View file

@ -3,7 +3,6 @@
namespace App;
use Illuminate\Database\Eloquent\Model;
use Pixelfed\Snowflake\HasSnowflakePrimary;
class Place extends Model
{

View file

@ -4,7 +4,7 @@ namespace App;
use Auth, Cache, DB, Storage;
use App\Util\Lexer\PrettyNumber;
use Pixelfed\Snowflake\HasSnowflakePrimary;
use App\HasSnowflakePrimary;
use Illuminate\Database\Eloquent\{Model, SoftDeletes};
use App\Services\FollowerService;

View file

@ -8,6 +8,20 @@ use Cache;
class SnowflakeService {
public static function byDate(Carbon $ts = null)
{
if($ts instanceOf Carbon) {
$ts = now()->parse($ts)->timestamp;
} else {
return self::next();
}
return ((round($ts * 1000) - 1549756800000) << 22)
| (random_int(1,31) << 17)
| (random_int(1,31) << 12)
| $seq;
}
public static function next()
{
$seq = Cache::get('snowflake:seq');
@ -19,19 +33,11 @@ class SnowflakeService {
}
if($seq >= 4095) {
$seq = 0;
Cache::put('snowflake:seq', 0);
$seq = 0;
}
if($ts == null) {
$ts = microtime(true);
}
if($ts instanceOf Carbon) {
$ts = now()->parse($ts)->timestamp;
}
return ((round($ts * 1000) - 1549756800000) << 22)
return ((round(microtime(true) * 1000) - 1549756800000) << 22)
| (random_int(1,31) << 17)
| (random_int(1,31) << 12)
| $seq;

View file

@ -4,7 +4,7 @@ namespace App;
use Auth, Cache, Hashids, Storage;
use Illuminate\Database\Eloquent\Model;
use Pixelfed\Snowflake\HasSnowflakePrimary;
use App\HasSnowflakePrimary;
use App\Http\Controllers\StatusController;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Models\Poll;

View file

@ -5,7 +5,7 @@ namespace App;
use Auth;
use Storage;
use Illuminate\Database\Eloquent\Model;
use Pixelfed\Snowflake\HasSnowflakePrimary;
use App\HasSnowflakePrimary;
use App\Util\Lexer\Bearcap;
class Story extends Model