Skip to content

Commit 451610d

Browse files
authored
Merge pull request #2 from calebdw/sonyflake
feat: add sonyflake support
2 parents 22ca389 + b965abd commit 451610d

File tree

4 files changed

+105
-12
lines changed

4 files changed

+105
-12
lines changed

README.md

+27-4
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,22 @@ php artisan vendor:publish --provider="CalebDW\Laraflake\ServiceProvider"
5454

5555
## Configuration
5656

57-
### Snowflake Epoch
57+
### Snowflake Type
58+
59+
The Snowflake type determines the class used to generate Snowflakes.
60+
61+
The default Snowflake type is `Godruoyi\Snowflake\Snowflake` which uses 41 bits for the epoch, 5 bits for the data center ID, 5 bits for the worker ID, and 12 bits for the sequence.
62+
This allows for up to `1024` workers and `4096` unique IDs per worker per millisecond.
63+
64+
You can change the Snowflake type to `Godruoyi\Snowflake\Sonyflake` which uses 39 bits for the epoch, 16 bits for the machine ID, and 8 bits for the sequence.
65+
This allows for up to `65535` machines and `256` unique IDs per worker per *10 milliseconds*.
66+
67+
### Epoch
68+
69+
The timestamp encoded in the Snowflake is the difference between the time of creation and a given starting epoch/timestamp.
70+
Snowflakes use 41 bits and can generate IDs for up to 69 years past the given epoch.
71+
Sonyflakes use 39 bits and can generate IDs for up to 174 years past the given epoch.
5872

59-
The 41-bit timestamp encoded in the Snowflake is the difference between the time of creation and a given starting epoch/timestamp.
60-
Snowflakes can be generated for up to 69 years past the given epoch.
6173
In most cases you should set this value to the current date using a format of `YYYY-MM-DD`.
6274

6375
> **Note**:
@@ -66,9 +78,18 @@ as that may reduce the number of years for which you can generate timestamps.
6678

6779
### Data Center & Worker IDs
6880

69-
If using distributed systems, you'll need to set the data center and worker IDs that the application should use when generating Snowflakes.
81+
> **Note**: This is only used for the `Snowflake` type.
82+
83+
You can set the data center and worker IDs that the application should use when generating Snowflakes.
7084
These are used to ensure that each worker generates unique Snowflakes and can range from `0` to `31` (up to `1024` unique workers).
7185

86+
### Machine ID
87+
88+
> **Note**: This is only used for the `Sonyflake` type.
89+
90+
You can set the machine ID that the application should use when generating Sonyflakes.
91+
This is used to ensure that each machine generates unique Sonyflakes and can range from `0` to `65535`.
92+
7293
## Usage
7394

7495
> **WARNING**: Do not create new instances of the Snowflake generator (as this could cause collisions), always use the Snowflake singleton from the container.
@@ -81,6 +102,7 @@ use Godruoyi\Snowflake\Snowflake;
81102
resolve('snowflake')->id(); // (string) "5585066784854016"
82103
resolve(Snowflake::class)->id(); // (string) "5585066784854016"
83104
```
105+
84106
This package also provides a `snowflake` helper function, a `Snowflake` facade, and a `Str::snowflakeId` macro for convenience:
85107

86108
```php
@@ -130,6 +152,7 @@ class Post extends Model
130152
```
131153

132154
The trait provides several features for the model's Snowflake columns:
155+
133156
- the generation of Snowflakes for new records
134157
- route model binding
135158
- automatic casting from database integers to strings which prevents truncation in languages that do not support 64-bit integers (such as JavaScript).

config/laraflake.php

+24-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,19 @@
22

33
declare(strict_types=1);
44

5+
use Godruoyi\Snowflake\Snowflake;
6+
57
return [
8+
/*
9+
|--------------------------------------------------------------------------
10+
| Snowflake Type
11+
|--------------------------------------------------------------------------
12+
|
13+
| The class to use by Laraflake when generating unique identifiers.
14+
| The default is the Snowflake class, but you can also use the Sonyflake class.
15+
*/
16+
'snowflake_type' => Snowflake::class,
17+
618
/*
719
|--------------------------------------------------------------------------
820
| Snowflake Epoch
@@ -17,7 +29,7 @@
1729

1830
/*
1931
|--------------------------------------------------------------------------
20-
| Data Center & Worker IDs
32+
| Snowflake Data Center & Worker IDs
2133
|--------------------------------------------------------------------------
2234
|
2335
| These values represents the data center and worker ids that should be used
@@ -26,4 +38,15 @@
2638
*/
2739
'datacenter_id' => env('LARAFLAKE_DATACENTER_ID', 0),
2840
'worker_id' => env('LARAFLAKE_WORKER_ID', 0),
41+
42+
/*
43+
|--------------------------------------------------------------------------
44+
| Sonyflake Machine ID
45+
|--------------------------------------------------------------------------
46+
|
47+
| This value represents the machine id that should be used by Sonyflake when
48+
| generating unique identifiers. The value must be 0--65535 (2^16 - 1).
49+
|
50+
*/
51+
'machine_id' => env('LARAFLAKE_MACHINE_ID', 0),
2952
];

src/ServiceProvider.php

+30-7
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,25 @@
1515
use Godruoyi\Snowflake\RedisSequenceResolver;
1616
use Godruoyi\Snowflake\SequenceResolver;
1717
use Godruoyi\Snowflake\Snowflake;
18+
use Godruoyi\Snowflake\Sonyflake;
1819
use Godruoyi\Snowflake\SwooleSequenceResolver;
1920
use Illuminate\Contracts\Cache\Repository;
2021
use Illuminate\Database\Schema\Blueprint;
2122
use Illuminate\Foundation\Console\AboutCommand;
2223
use Illuminate\Support\ServiceProvider as IlluminateServiceProvider;
2324
use Illuminate\Support\Str;
2425
use Illuminate\Validation\Rule;
25-
26+
use InvalidArgumentException;
27+
28+
/**
29+
* @phpstan-type LaraflakeConfig array{
30+
* datacenter_id: int,
31+
* worker_id: int,
32+
* epoch: string,
33+
* machine_id: int,
34+
* snowflake_type: class-string<Snowflake>,
35+
* }
36+
*/
2637
class ServiceProvider extends IlluminateServiceProvider
2738
{
2839
/** @inheritDoc */
@@ -42,13 +53,22 @@ public function boot(): void
4253
$this->registerMixins();
4354

4455
AboutCommand::add('Laraflake', function () {
45-
/** @var array{datacenter_id: int, worker_id: int, epoch: string} $config */
56+
/** @var LaraflakeConfig $config */
4657
$config = config('laraflake');
4758

4859
return [
60+
'Snowflake Type' => $config['snowflake_type'],
61+
...match ($config['snowflake_type']) {
62+
Snowflake::class => [
63+
'Datacenter ID' => $config['datacenter_id'],
64+
'Worker ID' => $config['worker_id'],
65+
],
66+
Sonyflake::class => [
67+
'Machine ID' => $config['machine_id'],
68+
],
69+
default => [],
70+
},
4971
'Epoch' => $config['epoch'],
50-
'Datacenter ID' => $config['datacenter_id'],
51-
'Worker ID' => $config['worker_id'],
5272
'Sequence Resolver' => $this->getPrettyResolver(),
5373
'Version' => InstalledVersions::getPrettyVersion('calebdw/laraflake'),
5474
];
@@ -67,11 +87,14 @@ protected function registerMixins(): void
6787
protected function registerSnowflake(): void
6888
{
6989
$this->app->singleton(Snowflake::class, function ($app) {
70-
/** @var array{datacenter_id: int, worker_id: int, epoch: string} $config */
90+
/** @var LaraflakeConfig $config */
7191
$config = config('laraflake');
7292

73-
return (new Snowflake($config['datacenter_id'], $config['worker_id']))
74-
->setStartTimeStamp(strtotime($config['epoch']) * 1000)
93+
return (match ($config['snowflake_type']) {
94+
Snowflake::class => new Snowflake($config['datacenter_id'], $config['worker_id']),
95+
Sonyflake::class => new Sonyflake($config['machine_id']),
96+
default => throw new InvalidArgumentException("Invalid Snowflake type: {$config['snowflake_type']}"),
97+
})->setStartTimeStamp(strtotime($config['epoch']) * 1000)
7598
->setSequenceResolver($app->make(SequenceResolver::class));
7699
});
77100
$this->app->alias(Snowflake::class, 'laraflake');

tests/Feature/ServiceProviderTest.php

+24
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
use Godruoyi\Snowflake\LaravelSequenceResolver;
66
use Godruoyi\Snowflake\RandomSequenceResolver;
77
use Godruoyi\Snowflake\SequenceResolver;
8+
use Godruoyi\Snowflake\Snowflake;
9+
use Godruoyi\Snowflake\Sonyflake;
810
use Illuminate\Contracts\Cache\Repository;
911

1012
it('binds random sequence resolver when there is not a cache', function () {
@@ -28,3 +30,25 @@
2830
->assertSuccessful()
2931
->expectsOutputToContain('Laraflake');
3032
});
33+
34+
it('supports Sonyflakes', function () {
35+
config()->set('laraflake.snowflake_type', Sonyflake::class);
36+
37+
expect(app()->make(Snowflake::class))
38+
->toBeInstanceOf(Sonyflake::class);
39+
40+
test()->artisan('about')
41+
->assertSuccessful()
42+
->expectsOutputToContain('Sonyflake');
43+
});
44+
45+
it('throws exception for invalid snowflake type', function () {
46+
config()->set('laraflake.snowflake_type', 'invalid');
47+
48+
test()->artisan('about')
49+
->assertSuccessful()
50+
->doesntExpectOutputToContain('Sonyflake');
51+
52+
expect(app()->make(Snowflake::class))
53+
->toBeInstanceOf(Sonyflake::class);
54+
})->throws(InvalidArgumentException::class);

0 commit comments

Comments
 (0)