From 5a1356e26f249ad6c5d449aa5273c1a321e71963 Mon Sep 17 00:00:00 2001 From: "iVampireSP.com" Date: Tue, 30 Aug 2022 17:20:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E8=BF=9B=20=E6=89=A3=E8=B4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Console/Kernel.php | 2 +- .../User/BalanceNotEnoughException.php | 10 ++++ .../Controllers/User/BalanceController.php | 54 +++++++++++++++++++ app/Http/Controllers/UserController.php | 19 +++++++ app/Jobs/UserSave.php | 16 +++++- app/Models/Host.php | 54 +++++++++++-------- app/Models/User.php | 41 +++++++++++++- app/Models/User/Drop.php | 17 ++++++ ...8_30_081930_add_balance_to_users_table.php | 39 ++++++++++++++ routes/api.php | 2 +- 10 files changed, 225 insertions(+), 29 deletions(-) create mode 100644 app/Exceptions/User/BalanceNotEnoughException.php create mode 100644 app/Http/Controllers/User/BalanceController.php create mode 100644 app/Http/Controllers/UserController.php create mode 100644 database/migrations/2022_08_30_081930_add_balance_to_users_table.php diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 91da5e4..4a028c4 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -22,7 +22,7 @@ protected function schedule(Schedule $schedule) // dispatch HostCost job $schedule->job(new HostCost())->everyFiveMinutes(); - $schedule->job(new UserSave())->everyTenMinutes(); + // $schedule->job(new UserSave())->everyTenMinutes(); $schedule->job(new Remote\FetchModule())->everyMinute()->onOneServer(); $schedule->job(new Remote\PushHost())->everyMinute()->onOneServer(); $schedule->job(new Remote\PushWorkOrder())->everyMinute()->onOneServer(); diff --git a/app/Exceptions/User/BalanceNotEnoughException.php b/app/Exceptions/User/BalanceNotEnoughException.php new file mode 100644 index 0000000..be10c73 --- /dev/null +++ b/app/Exceptions/User/BalanceNotEnoughException.php @@ -0,0 +1,10 @@ +user(); + return $this->success($balance); + } + + public function store(Request $request) + { + + // 充值 + $request->validate([ + 'amount' => 'required|numeric', + ]); + + $balance = $request->user(); + + // 启用事物 + \DB::beginTransaction(); + try { + $balance->increment('amount', $request->amount); + \DB::commit(); + } catch (\Exception $e) { + \DB::rollBack(); + return $this->error($e->getMessage()); + } + + return $this->success($balance); + } + + + // // 转换为 drops + // public function transfer($amount = 1) + // { + // $balance = auth('sanctum')->user(); + // $balance->decrement('amount', $request->amount); + // return $this->success($balance); + // } + + + + +} diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php new file mode 100644 index 0000000..448d847 --- /dev/null +++ b/app/Http/Controllers/UserController.php @@ -0,0 +1,19 @@ +user(); + + $user['drops'] = (float) Cache::get('user_drops_' . $user['id'], 0); + + return $this->success($user); + } +} diff --git a/app/Jobs/UserSave.php b/app/Jobs/UserSave.php index 1596f6a..ba105f6 100644 --- a/app/Jobs/UserSave.php +++ b/app/Jobs/UserSave.php @@ -11,6 +11,7 @@ use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Cache; +use Log; class UserSave implements ShouldQueue { @@ -34,7 +35,11 @@ public function __construct() */ public function handle() { - Host::active()->chunk(100, function ($hosts) { + + // 弃用 + return false; + + Host::all()->chunk(100, function ($hosts) { foreach ($hosts as $host) { $this->cache_key = 'user_' . $host->user_id; @@ -43,11 +48,18 @@ public function handle() if (Cache::has($this->cache_key)) { // if user is not instances of Model $user = Cache::get($this->cache_key); + + Log::debug($user); + + if ($user instanceof User) { - $this->await($this->cache_key, function () use ($user, $host) { + $this->await($this->cache_key, function () use ($user) { $user->save(); }); } + } else { + // save cache + $this->cache->put($this->cache_key, $host->user, now()->addDay()); } } }); diff --git a/app/Models/Host.php b/app/Models/Host.php index b26825b..fee9f2e 100644 --- a/app/Models/Host.php +++ b/app/Models/Host.php @@ -2,12 +2,14 @@ namespace App\Models; +use Log; use App\Models\Module\Module; use App\Exceptions\CommonException; use App\Models\WorkOrder\WorkOrder; use Illuminate\Support\Facades\Cache; -use Illuminate\Database\Eloquent\Model; // use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Database\Eloquent\Model; +use App\Exceptions\User\BalanceNotEnoughException; use Illuminate\Database\Eloquent\Factories\HasFactory; class Host extends Model @@ -77,21 +79,26 @@ public function scopeThisUser($query, $module = null) public function cost($price = null) { - $cache_key = 'user_' . $this->user_id; + $this->load('user'); - // if cache has user - if (Cache::has($cache_key)) { - // if user is not instances of Model - $user = Cache::get($cache_key); - - if (!($user instanceof User)) { - $user = Cache::put($cache_key, $this->user, now()->addDay()); - } + if ($this->user->balance < 10) { + $amount = 1; + } else if ($this->user->balance < 100) { + $amount = 10; + } else if ($this->user->balance < 1000) { + $amount = 100; + } else if ($this->user->balance < 10000) { + $amount = 1000; } else { - $user = Cache::put($cache_key, $this->user, now()->addDay()); + $amount = 10000; } + $cache_key = 'user_drops_' . $this->user_id; + + $drops = Cache::get($cache_key); + + // Log::debug($user); @@ -103,24 +110,25 @@ public function cost($price = null) $this->price = $this->managed_price; } + // if drops <= price + if ($drops < $this->price) { + try { + $this->user->toDrops($amount); + } catch (BalanceNotEnoughException) { + $this->update([ + 'status' => 'suspended', + ]); - $user->drops -= (int) $this->price; - - // update cache - Cache::put($cache_key, $user, now()->addDay()); - - - // if $user->drops <= 0 - if ($user->drops <= 0) { - $this->update([ - 'status' => 'suspended', - ]); + return false; + } } else if ($this->status == 'suspended') { $this->update([ - 'status' => 'running', + 'status' => 'stopped', ]); } + Cache::decrement($cache_key, $this->price); + return true; } diff --git a/app/Models/User.php b/app/Models/User.php index 23b4063..4347baf 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -3,10 +3,14 @@ namespace App\Models; // use Illuminate\Contracts\Auth\MustVerifyEmail; +use Laravel\Sanctum\HasApiTokens; +use App\Exceptions\CommonException; +use App\Exceptions\User\BalanceNotEnoughException; +use Illuminate\Support\Facades\Cache; +use Illuminate\Notifications\Notifiable; +use Illuminate\Contracts\Cache\LockTimeoutException; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; -use Illuminate\Notifications\Notifiable; -use Laravel\Sanctum\HasApiTokens; class User extends Authenticatable { @@ -40,5 +44,38 @@ class User extends Authenticatable */ protected $casts = [ 'email_verified_at' => 'datetime', + 'balance' => 'float', ]; + + + public function toDrops($amount = 1) + { + $rate = Cache::get('drops_rate', 100); + $total = $amount * $rate; + + $cache_key = 'user_drops_' . $this->id; + + $lock = Cache::lock("lock_" . $cache_key, 5); + try { + $lock->block(5); + + // if user balance <= 0 + if ($this->balance < $amount) { + throw new BalanceNotEnoughException('余额不足'); + } + + $this->balance -= $amount; + $this->save(); + + // increment user drops + Cache::increment($cache_key, $total); + + } catch (LockTimeoutException) { + throw new CommonException('暂时无法处理此请求,请稍后再试。'); + } finally { + optional($lock)->release(); + } + + return $this; + } } diff --git a/app/Models/User/Drop.php b/app/Models/User/Drop.php index 94909b1..d17c2b9 100644 --- a/app/Models/User/Drop.php +++ b/app/Models/User/Drop.php @@ -46,6 +46,23 @@ public static function boot() $rate = Cache::get('drops_rate', 100); $drops->total = $drops->amount * $rate; + + $this->cache_key = 'user_' . $drops->user_id; + + // if cache has user + + // if (Cache::has($this->cache_key)) { + // // if user is not instances of Model + // $user = Cache::get($this->cache_key); + // if ($user instanceof User) { + // $this->await($this->cache_key, function () use ($user) { + // $user->save(); + // }); + // } + + // // delete cache + // Cache::forget($this->cache_key); + // } }); // created diff --git a/database/migrations/2022_08_30_081930_add_balance_to_users_table.php b/database/migrations/2022_08_30_081930_add_balance_to_users_table.php new file mode 100644 index 0000000..18489d8 --- /dev/null +++ b/database/migrations/2022_08_30_081930_add_balance_to_users_table.php @@ -0,0 +1,39 @@ +decimal('balance', 10, 2)->default(0)->after('password'); + + // drop column if exists + if (Schema::hasColumn('users', 'drops')) { + $table->dropColumn('drops'); + } + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function (Blueprint $table) { + // + $table->dropColumn('balance'); + }); + } +}; diff --git a/routes/api.php b/routes/api.php index 63a3d5d..1587f20 100644 --- a/routes/api.php +++ b/routes/api.php @@ -4,7 +4,7 @@ use App\Http\Controllers\User\DropController; use App\Http\Controllers\User\TaskController; use App\Http\Controllers\Remote\ModuleController; -use App\Http\Controllers\Admin\User\UserController; +use App\Http\Controllers\UserController; use App\Http\Controllers\User\WorkOrder\ReplyController; use App\Http\Controllers\User\WorkOrder\WorkOrderController;