Merge branch 'main' of github.com:EdgeStanding/lae

This commit is contained in:
iVampireSP.com 2022-11-23 11:48:41 +08:00
commit 882d447754
No known key found for this signature in database
GPG Key ID: 2F7B001CA27A8132
12 changed files with 250 additions and 125 deletions

View File

@ -29,7 +29,7 @@ protected function schedule(Schedule $schedule)
$schedule->command('sanctum:prune-expired --hours=24')->daily(); $schedule->command('sanctum:prune-expired --hours=24')->daily();
// 扣费 // 扣费
$schedule->job(new HostCost(now()->hour))->hourly()->withoutOverlapping()->onOneServer(); $schedule->job(new HostCost(now()->minute))->everyMinute()->withoutOverlapping()->onOneServer();
// 获取模块暴露的信息(服务器等) // 获取模块暴露的信息(服务器等)
$schedule->job(new FetchModule())->withoutOverlapping()->everyMinute(); $schedule->job(new FetchModule())->withoutOverlapping()->everyMinute();

View File

@ -61,21 +61,14 @@ public function store(Request $request): RedirectResponse
$module->name = $request->name; $module->name = $request->name;
$module->api_token = $api_token; $module->api_token = $api_token;
$module->url = $request->url; $module->url = $request->url;
$module->status = $request->status;
$module->save(); $module->save();
return redirect()->route('admin.modules.index')->with('success', '模块创建成功, 请重置以获得 API Token。'); return redirect()->route('admin.modules.index')->with('success', '模块创建成功, 请重置以获得 API Token。');
} }
private function rules(): array
{
return [
'id' => 'required|string|max:255',
'name' => 'required|string|max:255',
'url' => 'required|url',
];
}
/** /**
* Display the specified resource. * Display the specified resource.
* *
@ -128,6 +121,7 @@ public function update(Request $request, Module $module): RedirectResponse
$module->id = $request->id; $module->id = $request->id;
$module->name = $request->name; $module->name = $request->name;
$module->url = $request->url; $module->url = $request->url;
$module->status = $request->status;
$module->save(); $module->save();
@ -156,4 +150,15 @@ public function destroy(Module $module): RedirectResponse
return redirect()->route('admin.modules.index')->with('success', '模块已删除。'); return redirect()->route('admin.modules.index')->with('success', '模块已删除。');
} }
private function rules(): array
{
return [
'id' => 'required|string|max:255',
'name' => 'required|string|max:255',
'url' => 'required|url',
'status' => 'required|string|in:up,down,maintenance',
];
}
} }

View File

@ -20,6 +20,4 @@ public function call(Request $request, Module $module): JsonResponse
{ {
return (new \App\Http\Controllers\Modules\ModuleController())->call($request, $module); return (new \App\Http\Controllers\Modules\ModuleController())->call($request, $module);
} }
} }

View File

@ -32,11 +32,15 @@ public function __construct()
*/ */
public function handle() public function handle()
{ {
// now 添加1.5小时 // 删除所有模块中不存在的主机
//
Host::with('module')->where('created_at', '<', now()->subHour())->chunk(100, function ($hosts) { Host::with('module')->where('created_at', '<', now()->subHour())->chunk(100, function ($hosts) {
foreach ($hosts as $host) { foreach ($hosts as $host) {
// 忽略维护中的模块
if ($host->module->status !== 'up') {
continue;
}
$http = Http::module($host->module->api_token, $host->module->url); $http = Http::module($host->module->api_token, $host->module->url);
$response = $http->get('hosts/' . $host->id); $response = $http->get('hosts/' . $host->id);

View File

@ -13,17 +13,17 @@ class HostCost implements ShouldQueue
{ {
use InteractsWithQueue, Queueable, SerializesModels, Lock; use InteractsWithQueue, Queueable, SerializesModels, Lock;
public $hour, $cache, $user; public $minute, $cache, $user;
/** /**
* Create a new job instance. * Create a new job instance.
* *
* @return void * @return void
*/ */
public function __construct($hour) public function __construct($minute)
{ {
// //
$this->hour = $hour; $this->minute = $minute;
} }
/** /**
@ -34,7 +34,7 @@ public function __construct($hour)
public function handle() public function handle()
{ {
// chunk hosts and load user // chunk hosts and load user
Host::where('hour_at', $this->hour)->whereIn('status', ['running', 'stopped'])->with('user')->chunk(1000, function ($hosts) { Host::where('minute_at', $this->minute)->whereIn('status', ['running', 'stopped'])->with('user')->chunk(500, function ($hosts) {
foreach ($hosts as $host) { foreach ($hosts as $host) {
$host->cost(); $host->cost();
} }

View File

@ -36,13 +36,13 @@ public function handle()
{ {
// 获取运行完成的时间 // 获取运行完成的时间
$last_run = Cache::get('servers_updated_at', false); // $last_run = Cache::get('servers_updated_at', false);
if ($last_run !== false) { // if ($last_run !== false) {
// 如果和上次运行时间间隔小于一分钟,则不运行 // // 如果和上次运行时间间隔小于一分钟,则不运行
if (now()->diffInMinutes($last_run) < 1) { // if (now()->diffInMinutes($last_run) < 1) {
return; // return;
} // }
} // }
// //
Module::whereNotNull('url')->chunk(100, function ($modules) { Module::whereNotNull('url')->chunk(100, function ($modules) {
@ -58,8 +58,13 @@ public function handle()
continue; continue;
} }
if ($response->successful()) { if ($response->successful()) {
// 如果模块状态不为 up则更新为 up
if ($module->status !== 'up') {
$module->status = 'up';
}
$json = $response->json(); $json = $response->json();
if (isset($json['data']['servers']) && is_array($json['data']['servers'])) { if (isset($json['data']['servers']) && is_array($json['data']['servers'])) {
@ -79,10 +84,18 @@ public function handle()
broadcast(new ServerEvent($servers)); broadcast(new ServerEvent($servers));
} }
// $module->update([
// 'data' => $response->json() } else {
// ]);
// if module return maintenance, then set module status to maintenance
if ($response->status() == 503) {
$module->status = 'maintenance';
} else {
$module->status = 'down';
}
} }
$module->save();
} }
// if local // if local
@ -93,7 +106,7 @@ public function handle()
} }
// 缓存运行完成的时间 // 缓存运行完成的时间
Cache::put('servers_updated_at', now(), now()->addMinutes(10)); // Cache::put('servers_updated_at', now(), now()->addMinutes(10));
}); });
} }
} }

View File

@ -98,6 +98,7 @@ protected static function boot()
static::creating(function ($model) { static::creating(function ($model) {
$model->hour_at = now()->hour; $model->hour_at = now()->hour;
$model->minute_at = now()->minute_at;
if ($model->price !== null) { if ($model->price !== null) {
$model->price = round($model->price, 2); $model->price = round($model->price, 2);
@ -201,7 +202,10 @@ public function safeDelete(): bool
{ {
// 如果创建时间大于大于 1 小时 // 如果创建时间大于大于 1 小时
if ($this->created_at->diffInHours(now()) > 1) { if ($this->created_at->diffInHours(now()) > 1) {
$this->cost(); // 如果当前时间比扣费时间小,则说明没有扣费。执行扣费。
if (now()->minute < $this->minute_at) {
$this->cost();
}
} }
dispatch(new \App\Jobs\Module\Host($this, 'delete')); dispatch(new \App\Jobs\Module\Host($this, 'delete'));

View File

@ -0,0 +1,47 @@
<?php
use App\Models\Host;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('hosts', function (Blueprint $table) {
//
$table->tinyInteger('minute_at')->index()->nullable()->after('hour_at');
});
echo PHP_EOL . '将开始刷新主机的分钟数...';
Host::chunk(100, function ($hosts) {
foreach ($hosts as $host) {
echo '刷新: ' . $host->id . PHP_EOL;
$host->minute_at = $host->created_at->minute;
$host->save();
}
});
echo ' 完成!' . PHP_EOL;
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('hosts', function (Blueprint $table) {
//
$table->dropColumn('minute_at');
});
}
};

View File

@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('modules', function (Blueprint $table) {
//
$table->enum('status', ['up', 'down', 'maintenance'])->index()->default('down')->after('url');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('modules', function (Blueprint $table) {
//
$table->dropColumn('status');
});
}
};

View File

@ -3,27 +3,37 @@
@section('title', '新建模块') @section('title', '新建模块')
@section('content') @section('content')
<h3>新建模块</h3> <h3>新建模块</h3>
<form method="POST" action="{{ route('admin.modules.store')}}"> <form method="POST" action="{{ route('admin.modules.store')}}">
@csrf @csrf
<div class="form-group"> <div class="form-group">
<label for="name">ID</label> <label for="name">ID</label>
<input type="text" class="form-control" id="id" name="id"> <input type="text" class="form-control" id="id" name="id">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="name">名称</label> <label for="name">名称</label>
<input type="text" class="form-control" id="name" name="name"> <input type="text" class="form-control" id="name" name="name">
</div> </div>
<div class="form-group mt-1"> <div class="form-group mt-1">
<label for="name">对端地址</label> <label for="name">对端地址</label>
<input type="text" class="form-control" id="url" name="url"> <input type="text" class="form-control" id="url" name="url">
</div> </div>
<button type="submit" class="btn btn-primary mt-3">提交</button> <!-- 选择状态 -->
</form> <div class="form-group mt-1">
<label for="status">状态</label>
<select class="form-control" id="status" name="status">
<option value="up">正常</option>
<option value="down">异常</option>
<option value="maintenance">维护模式</option>
</select>
</div>
@endsection <button type="submit" class="btn btn-primary mt-3">提交</button>
</form>
@endsection

View File

@ -3,45 +3,53 @@
@section('title', '模块:' . $module->name) @section('title', '模块:' . $module->name)
@section('content') @section('content')
<h3>{{ $module->name }}</h3> <h3>{{ $module->name }}</h3>
<a class="mt-3" href="{{ route('admin.modules.show', $module) }}">查看</a> <a class="mt-3" href="{{ route('admin.modules.show', $module) }}">查看</a>
<form method="POST" action="{{ route('admin.modules.update', $module)}}"> <form method="POST" action="{{ route('admin.modules.update', $module)}}">
@csrf @csrf
@method('PATCH') @method('PATCH')
<div class="form-group"> <div class="form-group">
<label for="name">ID (修改后,路由也会改变)</label> <label for="name">ID (修改后,路由也会改变)</label>
<input type="text" class="form-control" id="id" name="id" value="{{ $module->id }}"> <input type="text" class="form-control" id="id" name="id" value="{{ $module->id }}">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="name">名称</label> <label for="name">名称</label>
<input type="text" class="form-control" id="name" name="name" value="{{ $module->name }}"> <input type="text" class="form-control" id="name" name="name" value="{{ $module->name }}">
</div> </div>
<div class="form-group mt-1"> <div class="form-group mt-1">
<label for="name">对端地址</label> <label for="name">对端地址</label>
<input type="text" class="form-control" id="url" name="url" value="{{ $module->url }}"> <input type="text" class="form-control" id="url" name="url" value="{{ $module->url }}">
</div> </div>
<div class="form-check mt-1"> <div class="form-group mt-1">
<input class="form-check-input" type="checkbox" value="1" id="reset_api_token" name="reset_api_token"> <label for="status">状态</label>
<label class="form-check-label" for="reset_api_token"> <select class="form-control" id="status" name="status">
重置 Api Token(重置后,需要到对应的模块中更新,否则会导致模块无法正常工作) <option value="up" @if ($module->status === 'up') selected @endif>正常</option>
</label> <option value="down" @if ($module->status === 'down') selected @endif>异常</option>
</div> <option value="maintenance" @if ($module->status === 'maintenance') selected @endif>维护模式</option>
</select>
</div>
<button type="submit" class="btn btn-primary mt-3">提交</button> <div class="form-check mt-1">
</form> <input class="form-check-input" type="checkbox" value="1" id="reset_api_token" name="reset_api_token">
<label class="form-check-label" for="reset_api_token">
重置 Api Token(重置后,需要到对应的模块中更新,否则会导致模块无法正常工作)
</label>
</div>
<button type="submit" class="btn btn-primary mt-3">提交</button>
</form>
<hr/> <hr />
<form method="POST" action="{{ route('admin.modules.destroy', $module)}}" <form method="POST" action="{{ route('admin.modules.destroy', $module)}}" onsubmit="return confirm('删除后,业务将无法正常进行。')">
onsubmit="return confirm('删除后,业务将无法正常进行。')"> @csrf
@csrf @method('DELETE')
@method('DELETE') <button type="submit" class="btn btn-danger">删除</button>
<button type="submit" class="btn btn-danger">删除</button> </form>
</form>
@endsection @endsection

View File

@ -3,17 +3,18 @@
@section('title', '模块:' . $module->name) @section('title', '模块:' . $module->name)
@section('content') @section('content')
<h3>{{ $module->name }}</h3> <h3>{{ $module->name }}</h3>
<a class="mt-3" href="{{ route('admin.modules.edit', $module) }}">编辑</a> <p>状态: {{ $module->status }}</p>
<h4 class="mt-2">收益</h4> <a class="mt-3" href="{{ route('admin.modules.edit', $module) }}">编辑</a>
<div> <h4 class="mt-2">收益</h4>
<x-module-earning :module="$module"/> <div>
</div> <x-module-earning :module="$module" />
</div>
<h4 class="mt-2">主机</h4> <h4 class="mt-2">主机</h4>
<div class="overflow-auto"> <div class="overflow-auto">
<table class="table table-hover"> <table class="table table-hover">
<thead> <thead>
<th>ID</th> <th>ID</th>
<th>名称</th> <th>名称</th>
<th>用户</th> <th>用户</th>
@ -21,41 +22,41 @@
<th>创建时间</th> <th>创建时间</th>
<th>更新时间</th> <th>更新时间</th>
<th>操作</th> <th>操作</th>
</thead> </thead>
<tbody> <tbody>
@foreach ($hosts as $host) @foreach ($hosts as $host)
<tr> <tr>
<td> <td>
<a href="{{ route('admin.hosts.edit', $host) }}"> <a href="{{ route('admin.hosts.edit', $host) }}">
{{ $host->id }} {{ $host->id }}
</a> </a>
</td> </td>
<td> <td>
{{ $host->name }} {{ $host->name }}
</td> </td>
<td> <td>
<a href="{{ route('admin.users.edit', $host->user_id) }}"> {{ $host->user->name }}</a> <a href="{{ route('admin.users.edit', $host->user_id) }}"> {{ $host->user->name }}</a>
</td> </td>
<td> <td>
{{ $host->price }} {{ $host->price }}
</td> </td>
<td> <td>
{{ $host->created_at }} {{ $host->created_at }}
</td> </td>
<td> <td>
{{ $host->updated_at }} {{ $host->updated_at }}
</td> </td>
<td> <td>
<a href="{{ route('admin.hosts.edit', $host) }}" class="btn btn-primary btn-sm">编辑</a> <a href="{{ route('admin.hosts.edit', $host) }}" class="btn btn-primary btn-sm">编辑</a>
</td> </td>
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>
</table> </table>
</div> </div>
{{-- 分页 --}} {{-- 分页 --}}
{{ $hosts->links() }} {{ $hosts->links() }}
@endsection @endsection