Skip to content

Commit 5d69c63

Browse files
authored
Merge pull request #34 from infocyph/feature/update
Feature/update
2 parents c6c1162 + 71dc3d4 commit 5d69c63

29 files changed

Lines changed: 670 additions & 526 deletions

.github/workflows/security-standards.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ jobs:
1616
actions: read
1717
contents: read
1818
with:
19-
php_versions: '["8.3","8.4","8.5"]'
19+
php_versions: '["8.2","8.3","8.4","8.5"]'
2020
dependency_versions: '["prefer-lowest","prefer-stable"]'
2121
php_extensions: "bcmath"
2222
coverage: "xdebug"
2323
composer_flags: ""
2424
phpstan_memory_limit: "1G"
2525
psalm_threads: "1"
2626
run_analysis: true
27+
run_svg_report: true
28+
artifact_retention_days: 61

captainhook.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"options": []
2424
},
2525
{
26-
"action": "composer ic:tests",
26+
"action": "composer ic:ci",
2727
"options": []
2828
}
2929
]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Infocyph\UID\Configuration;
6+
7+
use DateTimeInterface;
8+
9+
trait ResolvesCustomEpoch
10+
{
11+
public function resolveCustomEpochMs(): ?int
12+
{
13+
return self::resolveEpochValue($this->customEpoch);
14+
}
15+
16+
private static function resolveEpochValue(DateTimeInterface|int|string|null $customEpoch): ?int
17+
{
18+
if ($customEpoch === null) {
19+
return null;
20+
}
21+
22+
if ($customEpoch instanceof DateTimeInterface) {
23+
return (int) $customEpoch->format('Uv');
24+
}
25+
26+
if (is_int($customEpoch)) {
27+
return $customEpoch;
28+
}
29+
30+
$epoch = strtotime($customEpoch);
31+
32+
return $epoch === false ? null : $epoch * 1000;
33+
}
34+
}

src/Configuration/SnowflakeConfig.php

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
final readonly class SnowflakeConfig
1414
{
15+
use ResolvesCustomEpoch;
16+
1517
private ?Closure $nodeResolver;
1618

1719
/**
@@ -30,25 +32,6 @@ public function __construct(
3032
$this->nodeResolver = $nodeResolver ? $nodeResolver(...) : null;
3133
}
3234

33-
public function resolveCustomEpochMs(): ?int
34-
{
35-
if ($this->customEpoch === null) {
36-
return null;
37-
}
38-
39-
if ($this->customEpoch instanceof DateTimeInterface) {
40-
return (int) $this->customEpoch->format('Uv');
41-
}
42-
43-
if (is_int($this->customEpoch)) {
44-
return $this->customEpoch;
45-
}
46-
47-
$epoch = strtotime($this->customEpoch);
48-
49-
return $epoch === false ? null : $epoch * 1000;
50-
}
51-
5235
/**
5336
* @return array{0:int,1:int}
5437
*/

src/Configuration/SonyflakeConfig.php

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
final readonly class SonyflakeConfig
1414
{
15+
use ResolvesCustomEpoch;
16+
1517
private ?Closure $machineIdResolver;
1618

1719
/**
@@ -28,25 +30,6 @@ public function __construct(
2830
$this->machineIdResolver = $machineIdResolver ? $machineIdResolver(...) : null;
2931
}
3032

31-
public function resolveCustomEpochMs(): ?int
32-
{
33-
if ($this->customEpoch === null) {
34-
return null;
35-
}
36-
37-
if ($this->customEpoch instanceof DateTimeInterface) {
38-
return (int) $this->customEpoch->format('Uv');
39-
}
40-
41-
if (is_int($this->customEpoch)) {
42-
return $this->customEpoch;
43-
}
44-
45-
$epoch = strtotime($this->customEpoch);
46-
47-
return $epoch === false ? null : $epoch * 1000;
48-
}
49-
5033
public function resolveMachineId(): int
5134
{
5235
if ($this->machineIdResolver === null) {

src/IdComparator.php

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Infocyph\UID;
66

77
use Infocyph\UID\Contracts\IdValueInterface;
8+
use Infocyph\UID\Support\UnsignedDecimal;
89

910
final class IdComparator
1011
{
@@ -17,7 +18,7 @@ public static function compare(IdValueInterface|string $left, IdValueInterface|s
1718
$rightString = $right instanceof IdValueInterface ? $right->toString() : $right;
1819

1920
if (preg_match('/^\d+$/', $leftString) && preg_match('/^\d+$/', $rightString)) {
20-
return self::compareUnsignedDecimals($leftString, $rightString);
21+
return UnsignedDecimal::compare($leftString, $rightString);
2122
}
2223

2324
return strcmp($leftString, $rightString);
@@ -35,19 +36,4 @@ public static function sort(array $ids): array
3536

3637
return $ids;
3738
}
38-
39-
private static function compareUnsignedDecimals(string $left, string $right): int
40-
{
41-
$left = ltrim($left, '0');
42-
$right = ltrim($right, '0');
43-
$left = $left === '' ? '0' : $left;
44-
$right = $right === '' ? '0' : $right;
45-
46-
$lengthComparison = strlen($left) <=> strlen($right);
47-
if ($lengthComparison !== 0) {
48-
return $lengthComparison;
49-
}
50-
51-
return strcmp($left, $right);
52-
}
5339
}

src/KSUID.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Exception;
1010
use Infocyph\UID\Contracts\IdAlgorithmInterface;
1111
use Infocyph\UID\Support\BaseEncoder;
12+
use Infocyph\UID\Support\BinaryUnpack;
1213

1314
final class KSUID implements IdAlgorithmInterface
1415
{
@@ -60,11 +61,7 @@ public static function parse(string $ksuid): array
6061
}
6162

6263
$bytes = self::toBytes($ksuid);
63-
$unpackedTimestamp = unpack('N', substr($bytes, 0, 4));
64-
($unpackedTimestamp !== false) || throw new Exception('Unable to parse KSUID timestamp');
65-
$timestampValue = $unpackedTimestamp[1] ?? null;
66-
is_int($timestampValue) || throw new Exception('Unable to parse KSUID timestamp');
67-
$timestamp = $timestampValue + self::$epoch;
64+
$timestamp = BinaryUnpack::u32(substr($bytes, 0, 4), 'Unable to parse KSUID timestamp') + self::$epoch;
6865
$data['time'] = new DateTimeImmutable('@' . $timestamp);
6966
$data['payload'] = bin2hex(substr($bytes, 4));
7067

src/Sequence/FilesystemSequenceProvider.php

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Infocyph\UID\Sequence;
66

77
use Infocyph\UID\Exceptions\FileLockException;
8+
use Infocyph\UID\Support\FileLock;
89

910
final readonly class FilesystemSequenceProvider implements SequenceProviderInterface
1011
{
@@ -40,21 +41,13 @@ public function next(string $type, int $machineId, int $timestamp): int
4041
*/
4142
private function acquireLock(string $fileLocation)
4243
{
43-
($handle = fopen($fileLocation, 'c+')) || throw new FileLockException(
44+
return FileLock::acquire(
45+
$fileLocation,
46+
$this->waitTime,
47+
$this->maxAttempts,
4448
'Failed to open sequence file: ' . $fileLocation,
49+
'Unable to acquire sequence lock: ' . $fileLocation,
4550
);
46-
47-
for ($attempts = 0; $attempts < $this->maxAttempts; $attempts++) {
48-
if (flock($handle, LOCK_EX | LOCK_NB)) {
49-
return $handle;
50-
}
51-
52-
usleep($this->waitTime);
53-
}
54-
55-
fclose($handle);
56-
57-
throw new FileLockException('Unable to acquire sequence lock: ' . $fileLocation);
5851
}
5952

6053
private function sequenceFileLocation(string $type, int $machineId): string

src/Sequence/PsrSimpleCacheSequenceProvider.php

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Closure;
88
use Infocyph\UID\Exceptions\FileLockException;
9+
use Infocyph\UID\Support\FileLock;
910
use Psr\SimpleCache\CacheInterface;
1011
use Throwable;
1112

@@ -79,21 +80,14 @@ public function next(string $type, int $machineId, int $timestamp): int
7980
private function acquireLock(string $key)
8081
{
8182
$lockFile = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'uid-cache-lock-' . md5($key) . '.lck';
82-
($handle = fopen($lockFile, 'c+')) || throw new FileLockException(
83+
84+
return FileLock::acquire(
85+
$lockFile,
86+
$this->waitTime,
87+
$this->maxAttempts,
8388
'Unable to open sequence cache lock file: ' . $lockFile,
89+
'Unable to acquire sequence cache lock for key: ' . $key,
8490
);
85-
86-
for ($attempt = 0; $attempt < $this->maxAttempts; $attempt++) {
87-
if (flock($handle, LOCK_EX | LOCK_NB)) {
88-
return $handle;
89-
}
90-
91-
usleep($this->waitTime);
92-
}
93-
94-
fclose($handle);
95-
96-
throw new FileLockException('Unable to acquire sequence cache lock for key: ' . $key);
9791
}
9892

9993
private function key(string $type, int $machineId): string

0 commit comments

Comments
 (0)