This commit is contained in:
iVampireSP.com 2023-05-14 16:53:10 +08:00
parent 7f5bd004a2
commit fe04c15a07
No known key found for this signature in database
GPG Key ID: 2F7B001CA27A8132
14 changed files with 71 additions and 114 deletions

View File

@ -2,6 +2,7 @@
namespace App\Console;
use App\Jobs\Cost;
use Illuminate\Console\Scheduling\Schedule;
use App\Http\Controllers\Admin\ServerController;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@ -17,7 +18,7 @@ protected function schedule(Schedule $schedule): void
(new ServerController())->checkServer();
})->everyMinute()->name('FrpServer')->withoutOverlapping()->onOneServer();
// $schedule->job(new Cost())->hourly()->name('FrpServerCost')->withoutOverlapping()->onOneServer();
$schedule->job(new Cost())->hourly()->name('FrpServerCost')->withoutOverlapping()->onOneServer();
// every three days
// $schedule->job(new ReviewWebsiteJob())->daily()->name('reviewWebsiteJob')->withoutOverlapping()->onOneServer();

View File

@ -34,6 +34,12 @@ public function handler(Request $request, $key)
return $this->failed('此服务器暂时不接受新的连接。');
}
// cache
$cache_key = 'frpTunnel_data_' . $request->input('content')['proxy_name'] . '_lock';
if (Cache::has($cache_key)) {
return $this->failed('此隧道正在被操作,请稍后再试。');
}
// Search tunnel
$host = Tunnel::where('client_token', $request->input('content')['proxy_name'])->where('server_id', $server->id)->first();
if (is_null($host)) {

View File

@ -2,12 +2,14 @@
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\TunnelRequest;
use App\Models\Server;
use App\Models\Tunnel;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Requests\TunnelRequest;
use App\Support\Frp;
use Illuminate\Support\Facades\Cache;
class TunnelController extends Controller
{
@ -150,7 +152,21 @@ public function store(Request $request)
public function show(TunnelRequest $tunnelRequest, Tunnel $tunnel)
{
unset($tunnelRequest);
$tunnel->load('server');
$tunnel['config'] = $tunnel->getConfig();
$frp = new Frp($tunnel->server);
$traffic = $frp->traffic($tunnel->client_token) ?? [];
if (!$traffic) {
$traffic = [];
}
$tunnel['traffic'] = $traffic;
return $this->success($tunnel);
}

View File

@ -12,6 +12,7 @@ public function index(Request $request)
return view('spa');
}
return view('index');
return redirect()->route('login');
// return view('index');
}
}

View File

@ -1,15 +0,0 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class SpaController extends Controller
{
public function __invoke(Request $request)
{
// return view('spa');
}
}

View File

@ -2,7 +2,6 @@
namespace App\Jobs;
use App\Models\Host;
use App\Models\Server;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
@ -10,30 +9,23 @@
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class Cost implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private $http;
/**
* Execute the job.
*
* @return void
*/
public function handle_old()
public function handle()
{
$this->http = Http::remote('remote')->asForm();
Server::with('hosts')->where('status', 'up')->whereNot('price_per_gb', 0)->chunk(100, function ($servers) {
Server::with('tunnels')->where('status', 'up')->chunk(100, function ($servers) {
foreach ($servers as $server) {
// $ServerCheckJob = new ServerCheckJob($server->id);
// $ServerCheckJob->handle();
foreach ($server->hosts as $host) {
foreach ($server->tunnels as $host) {
$host->load('user');
Log::debug('------------');
@ -41,15 +33,11 @@ public function handle_old()
Log::debug('属于用户: ' . $host->user->name);
$cache_key = 'frpTunnel_data_' . $host->client_token;
// $tunnel = 'frp_user_' . $host->client_token;
// $tunnel_user_id = Cache::get($tunnel);
$tunnel_data = Cache::get($cache_key, null);
if (!is_null($tunnel_data)) {
$traffic = ($tunnel_data['today_traffic_in'] ?? 0) + ($tunnel_data['today_traffic_out'] ?? 0);
// $traffic = 1073741824 * 10;
Log::debug('本次使用的流量: ' . round($traffic / 1024 / 1024 / 1024, 2) ?? 0);
$day = date('d');
@ -63,7 +51,6 @@ public function handle_old()
$used_traffic_gb = round($used_traffic / 1024 / 1024 / 1024, 2);
// Log::debug('上次使用的流量: ' . $used_traffic);
Log::debug('上次使用的流量 GB: ' . $used_traffic_gb);
$used_traffic = $traffic - $used_traffic;
@ -73,47 +60,11 @@ public function handle_old()
$left_traffic = 0;
if ($host->user->free_traffic > 0) {
Log::debug('开始扣除免费流量时的 used_traffic: ' . round($used_traffic / 1024 / 1024 / 1024, 2));
$user_free_traffic = round($host->user->free_traffic * 1024 * 1024 * 1024, 2);
Log::debug('用户免费流量: ' . round($user_free_traffic / 1024 / 1024 / 1024, 2));
// $used_traffic -= $user_free_traffic;
// $used_traffic = abs($used_traffic);
Log::debug('扣除免费流量时的 used_traffic: ' . $used_traffic / 1024 / 1024 / 1024);
// 获取剩余
$left_traffic = $user_free_traffic - $used_traffic;
Log::debug('计算后剩余的免费流量: ' . $left_traffic / 1024 / 1024 / 1024);
// 保存
if ($left_traffic < 0) {
$left_traffic = 0;
}
// 保留两位小数
$left_traffic = round($left_traffic / 1024 / 1024 / 1024, 2);
$host->user->free_traffic = $left_traffic;
$host->user->save();
}
$used_traffic = abs($used_traffic);
Log::debug('实际用量:' . $used_traffic / 1024 / 1024 / 1024);
// $used_traffic -= $server->free_traffic * 1024 * 1024 * 1024;
// // $used_traffic = abs($used_traffic);
// Log::debug('服务器免费流量: ' . $server->free_traffic * 1024 * 1024 * 1024);
// Log::debug('使用的流量(减去服务器免费流量): ' . $used_traffic);
if ($used_traffic > 0 && $left_traffic == 0) {
Log::debug('此时 used_traffic: ' . $used_traffic);
@ -124,24 +75,10 @@ public function handle_old()
$gb = round($traffic, 2);
// 计算价格
$cost = $traffic * $host->server->price_per_gb;
$cost = abs($cost);
Log::debug('此时 traffic: ' . $traffic);
// 记录到日志
// if local
// if (config('app.env') == 'local') {
Log::debug('计费:' . $host->server->name . ' ' . $host->name . ' ' . $gb . 'GB ' . $cost . ' 的 CNY 消耗');
// }
// 如果计费金额大于 0则扣费
if ($cost > 0) {
// 发送扣费请求
$this->http->post('hosts/' . $host->host_id . '/cost', [
'amount' => $cost,
'description' => $host->name . ' 的 ' . $gb . ' GB 流量费用。',
]);
}
// lock for update
$host->user->balance -= $traffic * $host->user->cost;
}
}
}

View File

@ -56,6 +56,9 @@ public function close()
$cache_key = 'frpTunnel_data_' . $this->client_token;
Cache::forget($cache_key);
$cache_key = 'frpTunnel_data_' . $this->client_token . '_lock';
Cache::put($cache_key, 1, 30);
$this->run_id = null;
$this->saveQuietly();
}

View File

@ -22,7 +22,7 @@ class User extends Authenticatable
'name',
'email',
'password',
'auth_code'
'traffic'
];
/**

View File

@ -17,6 +17,9 @@ public function up(): void
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->bigInteger('traffic')->default(0)->comment('流量');
$table->rememberToken();
$table->timestamps();
});

View File

@ -1,24 +1,24 @@
<template>
<div>
<h1>Index</h1>
<p>Index page</p>
<p>Current time: {{ time }}</p>
<h1>欢迎</h1>
</div>
<div>
<p>用户名: {{ user.name }}</p>
<div class="mt-3">
<p>用户名: {{ user.name }}</p>
<p>剩余流量: {{ user.traffic }}GB</p>
</div>
</template>
<script setup>
import { ref } from "vue";
import http from '../plugins/http'
const time = ref(new Date().toLocaleTimeString());
const user = ref({
name: 'loading...'
name: 'loading...',
traffic: ''
})
http.get('user').then((res) => {
@ -26,9 +26,4 @@ http.get('user').then((res) => {
})
http.get('tunnels').then((res) => {
console.log(res.data)
})
</script>

View File

@ -1,3 +0,0 @@
<template>
<h1>您名下的隧道</h1>
</template>

View File

@ -9,9 +9,9 @@
<th scope="col">协议</th>
<th scope="col">本地地址</th>
<th scope="col">远程端口/域名</th>
<th scope="col">连接数</th>
<!-- <th scope="col">连接数</th>
<th scope="col">下载流量</th>
<th scope="col">上载流量</th>
<th scope="col">上载流量</th> -->
<th scope="col">服务器</th>
<th scope="col">状态</th>
</tr>
@ -52,9 +52,9 @@
</span>
</td>
<td>0</td>
<td>0.000 Bytes</td>
<!-- <td>0</td>
<td>0.000 Bytes</td>
<td>0.000 Bytes</td> -->
<td>{{ tunnel.server.name }}</td>

View File

@ -4,7 +4,7 @@
</div>
<div>
<div v-show="chart" id="chart" style="height: 400px"></div>
<div id="chart" style="height: 400px"></div>
</div>
<div>
@ -16,6 +16,10 @@
</pre>
</div>
<!-- <div v-if="tunnel.tunnel">
</div> -->
<div v-if="tunnel.run_id" class="mb-3">
<h2>强制下线</h2>
<button class="btn btn-primary" @click="kickTunnel()">强制下线</button>
@ -34,6 +38,7 @@ import { onMounted, onUnmounted, ref } from "vue";
import http from "../../plugins/http";
import router from "../../plugins/router";
import * as echarts from "echarts";
import Humanize from 'humanize-plus'
const showChart = ref(false);
let chart = undefined;
@ -128,11 +133,13 @@ let chartOptions = {
function initChart() {
let chartDom = document.getElementById("chart");
chart = echarts.init(chartDom, {
backgroundColor: "transparent",
renderer: "svg",
});
chartOptions && chart.setOption(chartOptions);
}
@ -147,7 +154,9 @@ function deleteTunnel() {
}
function kickTunnel() {
http.post(`/tunnels/${tunnel_id}/close`);
http.post(`/tunnels/${tunnel_id}/close`).then(() => {
refresh();
});
}
function refresh() {
@ -160,8 +169,12 @@ function refresh() {
// console.log(res.data);
if (res.data.traffic) {
console.log(res.data.traffic)
console.log(showChart.value)
if (!showChart.value) {
// initChart()
initChart()
showChart.value = true;
}

View File

@ -57,7 +57,7 @@
<script>
function updateTraffic(userId, input) {
const url = '/users/' + userId
const url = '/admin/users/' + userId
// xml http request
const xhr = new XMLHttpRequest();
xhr.open('PATCH', url);