'array', 'suspended_at' => 'datetime', ]; // get user hosts public function getUserHosts($user_id = null) { return $this->where('user_id', $user_id)->with('module', function ($query) { $query->select(['id', 'name']); })->get(); } // user public function user(): BelongsToAlias { return $this->belongsTo(User::class); } // module public function module(): BelongsToAlias { return $this->belongsTo(Module::class); } // workOrders public function workOrders(): HasManyAlias { return $this->hasMany(WorkOrder::class); } // scope public function scopeActive($query) { return $query->where('status', 'running')->where('price', '!=', 0); } public function scopeThisUser($query, $module = null) { if ($module) { return $query->where('user_id', auth()->id())->where('module_id', $module); } else { return $query->where('user_id', auth()->id()); } } // cost public function cost($price = null, $auto = true): bool { $this->load('user'); $transaction = new Transaction(); $drops = $transaction->getDrops($this->user_id); if ($price !== null) { $real_price = $price; } else { $real_price = $this->price; } if ($real_price == 0) { return true; } $real_price = round($real_price ?? 0, 8); $amount = $price / config('drops.rate') + 1; // if drops <= price if ($drops < $real_price) { try { // 算出需要补充多少 Drops $need = $real_price - $drops; // 算出需要补充多少余额 $need_amount = $need / config('drops.rate') + 1; $this->user->toDrops($amount + $need_amount); } catch (BalanceNotEnoughException) { $this->update([ 'status' => 'suspended', ]); return false; } } else if ($this->status == 'suspended') { $this->update([ 'status' => 'stopped', ]); } $month = now()->month; $month_cache_key = 'user_' . $this->user_id . '_month_' . $month . '_hosts_drops'; $hosts_drops = Cache::get($month_cache_key, []); // 统计 Host 消耗的 Drops if (isset($hosts_drops[$this->id])) { $hosts_drops[$this->id] += $real_price; } else { $hosts_drops[$this->id] = $real_price; } Cache::put($month_cache_key, $hosts_drops, 604800); $transaction->reduceDrops($this->user_id, $this->id, $this->module_id, $auto, $real_price); broadcast(new UserEvent($this->user_id, 'balances.drops.reduced', $this->user)); // 检测用户余额是否足够 if ($this->user->balance < 0) { $this->update([ 'status' => 'suspended', ]); } return true; } public function costBalance($amount = 1) { $transaction = new Transaction(); $month = now()->month; $month_cache_key = 'user_' . $this->user_id . '_month_' . $month . '_hosts_balances'; $hosts_drops = Cache::get($month_cache_key, []); // 统计 Host 消耗的 Drops if (isset($hosts_drops[$this->id])) { $hosts_drops[$this->id] += $amount; } else { $hosts_drops[$this->id] = $amount; } Cache::put($month_cache_key, $hosts_drops, 604800); $left = $transaction->reduceHostAmount($this->user_id, $this->id, $this->module_id, $amount); broadcast(new UserEvent($this->user_id, 'balances.amount.reduced', $this->user)); if ($left < 0) { $this->update([ 'status' => 'suspended', ]); } return true; } protected static function boot() { parent::boot(); static::created(function ($model) { broadcast(new UserEvent($model->user_id, 'hosts.created', $model)); }); static::updating(function ($model) { if ($model->status == 'suspended') { $model->suspended_at = now(); } else if ($model->status == 'running') { $model->suspended_at = null; } broadcast(new UserEvent($model->user_id, 'hosts.updating', $model)); }); // when Updated static::updated(function ($model) { dispatch(new \App\Jobs\Remote\Host($model, 'patch')); Cache::forget('user_hosts_' . $model->user_id); Cache::forget('user_tasks_' . $model->user_id); broadcast(new UserEvent($model->user_id, 'hosts.updated', $model)); }); // // static::deleting(function ($model) { // broadcast(new UserEvent($model->user_id, 'hosts.deleting', $model)); // }); static::deleting(function ($model) { Cache::forget('user_tasks_' . $model->user_id); }); static::deleted(function ($model) { broadcast(new UserEvent($model->user_id, 'hosts.deleted', $model)); Cache::forget('user_tasks_' . $model->user_id); Cache::forget('user_hosts_' . $model->user_id); }); } }