diff --git a/src/Contracts/RateLimiterContract.php b/src/Contracts/RateLimiterContract.php new file mode 100644 index 0000000..4b7cdbe --- /dev/null +++ b/src/Contracts/RateLimiterContract.php @@ -0,0 +1,13 @@ +getPrivateFutureClient([], $body)->post('tpsl/position/place_order', [ + return $this->getPrivateFutureClient([], $body)->post('tpsl/position/place_order', [ 'json' => $body, ]); - - return $response; } } diff --git a/src/LaravelBitunixApiServiceProvider.php b/src/LaravelBitunixApiServiceProvider.php index 77819af..9e9aa0b 100644 --- a/src/LaravelBitunixApiServiceProvider.php +++ b/src/LaravelBitunixApiServiceProvider.php @@ -3,6 +3,7 @@ namespace Msr\LaravelBitunixApi; use Msr\LaravelBitunixApi\Commands\LaravelBitunixApiCommand; +use Msr\LaravelBitunixApi\Contracts\RateLimiterContract; use Msr\LaravelBitunixApi\Requests\ChangeLeverageRequestContract; use Msr\LaravelBitunixApi\Requests\ChangeMarginModeRequestContract; use Msr\LaravelBitunixApi\Requests\FlashClosePositionRequestContract; @@ -13,8 +14,10 @@ use Msr\LaravelBitunixApi\Requests\GetTradingPairsRequestContract; use Msr\LaravelBitunixApi\Requests\PlaceOrderRequestContract; use Msr\LaravelBitunixApi\Requests\PlacePositionTpSlOrderRequestContract; use Msr\LaravelBitunixApi\Requests\PlaceTpSlOrderRequestContract; +use Msr\LaravelBitunixApi\Support\CacheRateLimiter; use Spatie\LaravelPackageTools\Package; use Spatie\LaravelPackageTools\PackageServiceProvider; +use Illuminate\Contracts\Cache\Factory as CacheFactory; class LaravelBitunixApiServiceProvider extends PackageServiceProvider { @@ -47,5 +50,11 @@ class LaravelBitunixApiServiceProvider extends PackageServiceProvider $this->app->bind(PlaceTpSlOrderRequestContract::class, LaravelBitunixApi::class); $this->app->bind(PlacePositionTpSlOrderRequestContract::class, LaravelBitunixApi::class); $this->app->bind(GetTradingPairsRequestContract::class, LaravelBitunixApi::class); + + $this->app->bind(RateLimiterContract::class, function ($app) { + return new CacheRateLimiter( + $app->make(CacheFactory::class)->store() + ); + }); } } diff --git a/src/Support/CacheRateLimiter.php b/src/Support/CacheRateLimiter.php new file mode 100644 index 0000000..fee64e2 --- /dev/null +++ b/src/Support/CacheRateLimiter.php @@ -0,0 +1,57 @@ +makeCacheKey($bucket, $identity); + $minIntervalMicroseconds = (int) (($perSeconds / $maxRequests) * 1_000_000); + + $lastRequestAt = $this->cache->get($cacheKey); + + if (is_numeric($lastRequestAt)) { + $elapsedMicroseconds = (int) ((microtime(true) - (float) $lastRequestAt) * 1_000_000); + + if ($elapsedMicroseconds < $minIntervalMicroseconds) { + $sleepMicroseconds = $minIntervalMicroseconds - $elapsedMicroseconds; + + if ($sleepMicroseconds > 0) { + usleep($sleepMicroseconds); + } + } + } + + $this->cache->put( + $cacheKey, + microtime(true), + now()->addSeconds((int) max(1, ceil($perSeconds * 2))) + ); + } + + protected function makeCacheKey(string $bucket, string $identity): string + { + return sprintf( + 'laravel_bitunix_api:rate_limit:%s:%s', + $bucket, + sha1($identity) + ); + } +}