diff --git a/resources/views/tabler/user/node.tpl b/resources/views/tabler/user/node.tpl
index 2afcc329d..386a20412 100644
--- a/resources/views/tabler/user/node.tpl
+++ b/resources/views/tabler/user/node.tpl
@@ -69,7 +69,11 @@
{/if}
-
{$oNode->name}
+ {if in_array($oNode->pid, $aServerLiveIds)}
+
{$oNode->name}
+ {else}
+
{$oNode->name}
+ {/if}
{$oNode->memo_front}
diff --git a/src/Command/Cron.php b/src/Command/Cron.php
index 4270aeaf7..2188afda8 100755
--- a/src/Command/Cron.php
+++ b/src/Command/Cron.php
@@ -67,13 +67,20 @@ EOL;
time() - Config::obtain('last_daily_job_time') > 86399
) {
$jobs->cleanDb();
-// $jobs->resetNodeBandwidth();
$jobs->reportPayUser(); // 付费用户统计
- $jobs->resetDuckBandwidth(); // 重置每日的duck流量
- $jobs->reportBandWidth(); // 报告流量给tg
- $jobs->resetFreeUserBandwidth(); // 重置免费用户的流量
- $jobs->sendDailyTrafficReport(); // 流量报告?不重要
- $jobs->clearTodayWidth(); // 重置每日的用户使用流量
+// $jobs->resetDuckBandwidth(); // 重置每日的duck流量 || 没有duck了
+// $jobs->reportBandWidth(); // 报告流量给tg || 改写了
+// $jobs->resetFreeUserBandwidth(); // 重置免费用户的流量 || 傻逼功能
+// $jobs->sendDailyTrafficReport(); // 流量报告?不重要 || 不发送了,容易黑名单 * 应该跟注册邮箱分开,再说
+// $jobs->clearTodayWidth(); // 重置每日的用户使用流量 || 改逻辑了,不重置
+
+ //// 节点统计组
+ $jobs->zhuanfa_width_merge(); // 合并转发耗流统计,要在node计算之前
+ $jobs->day_width_report_zhuanfa(); // 汇报每天耗流 - 转发
+ $jobs->day_width_report(); // 汇报每天耗流
+ $jobs->resetZhuanfaBandwidth(); // zhuanfa流量自动重置
+ $jobs->resetNodeBandwidth(); // 要在最后,其他计算完再重置
+ //// 节点统计组 end
$jobs->smtpClearDayCount(); // 重置stmp的day_count
@@ -100,7 +107,7 @@ EOL;
$jobs->sendTelegramDiary();
}
- $jobs->resetTodayBandwidth();
+ $jobs->resetTodayBandwidth(); // 重置user的width
if (Config::obtain('telegram_daily_job')) {
$jobs->sendTelegramDailyJob();
@@ -159,11 +166,14 @@ EOL;
}
if ($minute === 0) {
- $jobs->mergeBandWidth();
+ $jobs->hour_width_report(); // 检测小时耗流
+// $jobs->mergeBandWidth(); || 逻辑改变,不用了
}
// Run email queue
$jobs->processEmailQueue();
$jobs->processEmailQueue_bulk(); // 群发
+
+ $jobs->todayOk();
}
}
diff --git a/src/Controllers/User/NodeController.php b/src/Controllers/User/NodeController.php
index 8d5a8a2d1..e75dd201b 100755
--- a/src/Controllers/User/NodeController.php
+++ b/src/Controllers/User/NodeController.php
@@ -24,10 +24,12 @@ final class NodeController extends BaseController
{
$oNodeList = Node::where("type", 1)->orderBy("order_group")->orderBy("name")->get();
+ $aServerLiveIds = Node::where("type", 2)->where("online", 1)->pluck("id")->toArray();
return $response->write(
$this->view()
->assign('oNodeList', $oNodeList)
+ ->assign('aServerLiveIds', $aServerLiveIds)
->fetch('user/node.tpl')
);
}
diff --git a/src/Models/Node.php b/src/Models/Node.php
index 5a9e5f4af..2887a2082 100755
--- a/src/Models/Node.php
+++ b/src/Models/Node.php
@@ -11,6 +11,8 @@ use function dns_get_record;
use function time;
use const DNS_A;
use const DNS_AAAA;
+//use DateTime;
+use Illuminate\Support\Carbon;
/**
* @property int $id 节点ID
@@ -156,4 +158,37 @@ final class Node extends Model
}
}
}
+
+ // 计算距离重置日
+// public function getResetDayLimitAttribute()
+// {
+// if (!$this->bandwidthlimit_resetday) {
+// return false;
+// }
+//
+// $iDayNow = (int) date("d");
+// return (int) $this->bandwidthlimit_resetday - $iDayNow;
+// }
+ public function getResetDayLimitAttribute()
+ {
+ if (!$this->bandwidthlimit_resetday) {
+ return false;
+ }
+
+ $iResetDay = (int) $this->bandwidthlimit_resetday;
+ $oNow = Carbon::now();
+
+ // 创建目标日期:设定为本月的重置日
+ // 如果重置日超过了当月最大天数(如重置日31号,当前月2月),Carbon会自动处理
+ $oTargetDate = $oNow->copy()->day($iResetDay);
+
+ // 如果目标日期已经在今天之前,说明重置日在下个月
+ if ($oTargetDate->isPast()) {
+ $oTargetDate->addMonth();
+ }
+
+ // 返回相差天数
+ return $oNow->diffInDays($oTargetDate);
+ }
+
}
diff --git a/src/Models/Zhuanfas.php b/src/Models/Zhuanfas.php
index 9a5bf8274..a94918223 100755
--- a/src/Models/Zhuanfas.php
+++ b/src/Models/Zhuanfas.php
@@ -11,5 +11,23 @@ final class Zhuanfas extends Model
protected $connection = 'default';
protected $table = 'zhuanfas';
+ public function getResetDayLimitAttribute()
+ {
+ // 1. 基础防御:日期为空或无效直接返回
+ if (!$this->end_date || $this->end_date === '0000-00-00') {
+ return false;
+ }
+
+ // 2. 将日期转为 Unix 时间戳 (原生)
+ $iTargetTimestamp = strtotime($this->end_date);
+ $iNowTimestamp = time();
+
+ // 3. 计算差值 (秒)
+ $iDiffSeconds = $iTargetTimestamp - $iNowTimestamp;
+
+ // 4. 转为天数
+ // 如果日期已过,这里会得到负数;如果想返回 0 替代负数,请加一个判断
+ return (int) floor($iDiffSeconds / 86400);
+ }
}
diff --git a/src/Services/Cron.php b/src/Services/Cron.php
index 8053192de..06ba6b260 100755
--- a/src/Services/Cron.php
+++ b/src/Services/Cron.php
@@ -418,19 +418,19 @@ final class Cron
// echo $e->getMessage() . PHP_EOL;
// }
//
-// if (Config::obtain('telegram_node_offline')) {
-// $notice_text = str_replace(
-// '%node_name%',
-// $node->name,
-// Config::obtain('telegram_node_offline_text')
-// );
-//
-// try {
-// (new Telegram())->send(0, $notice_text);
-// } catch (TelegramSDKException $e) {
-// echo $e->getMessage();
-// }
-// }
+ if (Config::obtain('telegram_node_offline')) {
+ $notice_text = str_replace(
+ '%node_name%',
+ $node->name,
+ Config::obtain('telegram_node_offline_text')
+ );
+
+ try {
+ (new Telegram())->send(0, $notice_text);
+ } catch (TelegramSDKException $e) {
+ echo $e->getMessage();
+ }
+ }
$node->online = 0;
$node->save();
@@ -450,19 +450,19 @@ final class Cron
// echo $e->getMessage() . PHP_EOL;
// }
-// if (Config::obtain('telegram_node_online')) {
-// $notice_text = str_replace(
-// '%node_name%',
-// $node->name,
-// Config::obtain('telegram_node_online_text')
-// );
-//
-// try {
-// (new Telegram())->send(0, $notice_text);
-// } catch (TelegramSDKException $e) {
-// echo $e->getMessage();
-// }
-// }
+ if (Config::obtain('telegram_node_online')) {
+ $notice_text = str_replace(
+ '%node_name%',
+ $node->name,
+ Config::obtain('telegram_node_online_text')
+ );
+
+ try {
+ (new Telegram())->send(0, $notice_text);
+ } catch (TelegramSDKException $e) {
+ echo $e->getMessage();
+ }
+ }
$node->online = 1;
$node->save();
@@ -1516,22 +1516,45 @@ final class Cron
echo Tools::toDateTime(time()) . ' Successfully removed inactive user\'s Link and Invite' . PHP_EOL;
}
- // 废弃
+ // 重置node(server)流量
public static function resetNodeBandwidth(): void
{
- (new Node())->where('bandwidthlimit_resetday', date('d'))->update(['node_bandwidth' => 0]);
+ (new Node())->where('bandwidthlimit_resetday', date('d'))->update(['node_bandwidth' => 0, 'prev_hour_width' => 0, 'prev_day_width' => 0]);
echo Tools::toDateTime(time()) . ' 重设节点流量完成' . PHP_EOL;
}
- // 机器到日期重置流量
- public static function resetDuckBandwidth(): void
+ // 重置转发流量
+// public static function resetZhuanfaBandwidth(): void
+// {
+// // 原子性批量更新:保持 end_date 的“日”不变,月份自动顺延
+// Zhuanfas::whereDate('end_date', '<=', date("Y-m-d"))
+// ->update([
+// 'use_width' => 0,
+// 'today_width' => 0,
+// 'end_date' => DB::raw("DATE_ADD(end_date, INTERVAL 1 MONTH)"),
+// ]);
+// }
+ public static function resetZhuanfaBandwidth(): void
{
- (new Ducks())->where('width_reset_day', date('d'))->update(['use_width' => 0]);
-
- echo Tools::toDateTime(time()) . ' 重设机器流量完成' . PHP_EOL;
+ Zhuanfas::where('end_date', '!=', '0000-00-00')
+ ->whereNotNull('end_date')
+ ->whereDate('end_date', '<=', date('Y-m-d'))
+ ->update([
+ 'use_width' => 0,
+ 'today_width' => 0,
+ 'end_date' => DB::raw("DATE_ADD(NOW(), INTERVAL 1 MONTH)")
+ ]);
}
+ // 机器到日期重置流量 废弃
+// public static function resetDuckBandwidth(): void
+// {
+// (new Ducks())->where('width_reset_day', date('d'))->update(['use_width' => 0]);
+//
+// echo Tools::toDateTime(time()) . ' 重设机器流量完成' . PHP_EOL;
+// }
+
// public static function resetZhuanfaBandwidth(): void
// {
// (new Ducks())->where('end_date', date('Y-m-d'))->update(['use_width' => 0]);
@@ -1539,234 +1562,436 @@ final class Cron
// echo Tools::toDateTime(time()) . ' 重设机器流量完成' . PHP_EOL;
// }
- // 每小时,统计节点流量,入库,tg警报
- public static function mergeBandWidth(): void
+ // 每小时检测server耗流
+ public static function hour_width_report(): void
{
-
- $oNodeAll = Node::where('type', 1)->get();
-
- $aZhuanfaFlowNow = [];
- $aDuckFlowNow = [];
+ $oServers = Node::where('type', 2)->get();
+
$sMsg = "";
-
- // 统计node流量
- foreach ($oNodeAll as $oNodeRow) {
+ foreach ($oServers as $oServer) {
+ $iRunWidth = $oServer->node_bandwidth - $oServer->prev_hour_width;
- if ($oNodeRow->node_bandwidth == 0) {
-
- if ($oNodeRow->is_shadow != 1) {
-
- $sMsg .= '🚨【'.$oNodeRow->name."】小时未耗流,可能异常。\n";
-
- }
-
+ if ($iRunWidth <= 0) {
+ $sMsg .= '🚨【'.$oServer->duck_code."】小时未耗流,可能异常。\n";
}
- @$aZhuanfaFlowNow[$oNodeRow->zhuanfa_code] += $oNodeRow->node_bandwidth;
- @$aDuckFlowNow[$oNodeRow->duck_code] += $oNodeRow->node_bandwidth;
-
+ $oServer->prev_hour_width = $oServer->node_bandwidth;
+ $oServer->save();
}
- // 入库zhunafa
- foreach ($aZhuanfaFlowNow as $k => $v) {
-
- if ($v) {
- Zhuanfas::where('code', $k)->increment('today_width', $v);
- Zhuanfas::where('code', $k)->increment('use_width', $v);
- }
-
- }
-
- // 入库duck
- foreach ($aDuckFlowNow as $k => $v) {
-
- if ($v) {
- Ducks::where('code', $k)->increment('today_width', $v);
- Ducks::where('code', $k)->increment('use_width', $v);
- }
-
- }
-
- // 清空node流量
- Node::query()->update(['node_bandwidth' => 0]);
-
if ($sMsg) {
(new Telegram())->send(0, $sMsg);
}
-
}
- // 每日报表
- public static function reportBandWidth(): void
+ // 每天汇报server耗流
+ public static function day_width_report(): void
{
-
- $oZhuanfas = new Zhuanfas();
- $oDucks = new Ducks();
-
- // 流量报告,转发
- $oTgSendFormat = new TgSendFormat();
- $oTgSendFormat->sTitleEmoji = "\n\n";
- $oTgSendFormat->sTitle = "# 转发流量";
- $today = new DateTime();
-
- $oZhuanfasAll = $oZhuanfas->all();
- foreach ($oZhuanfasAll as $oZhuanfasRow) {
-
- $targetDate = new DateTime($oZhuanfasRow->end_date);
- $interval = $today->diff($targetDate);
-
- if ($today > $targetDate) {
- $iDiffDay = -$interval->days;
- } else {
- $iDiffDay = $interval->days;
- }
-
- $oTgSendFormat->rowAdd(
- $oZhuanfasRow->name,
- $oZhuanfasRow->today_width,
- $oZhuanfasRow->use_width,
- $oZhuanfasRow->max_width,
- $iDiffDay
- );
-
- }
-
- $sTgReport = $oTgSendFormat->typeA();
-
- (new Telegram())->send(0, $sTgReport);
-
- // 流量报告,机器
$oTgSendFormat = new TgSendFormat();
$oTgSendFormat->sTitleEmoji = "\n\n";
$oTgSendFormat->sTitle = "# 机器流量";
- $oDucksAll = $oDucks->orderBy('code')->get();
- foreach ($oDucksAll as $oDucksRow) {
-
- if ($oDucksRow->width_reset_day == 0) {
- $iWidthResetDay = 0;
- } if ($oDucksRow->width_reset_day > date('d')) {
- $iWidthResetDay = $oDucksRow->width_reset_day - date('d');
- } else {
- $date = new DateTime();
- $date->modify('first day of next month');
- $date->setDate((int)$date->format('Y'), (int)$date->format('m'), $oDucksRow->width_reset_day);
- $sEndDate = $date;
-
- $currentDate = new DateTime();
- $interval = $currentDate->diff($sEndDate);
- $iWidthResetDay = $interval->days;
- }
+ $oServers = Node::where('type', 2)->get();
+
+ if ($oServers->isEmpty()) {
+ return;
+ }
+
+ foreach ($oServers as $oServer) {
+ $iTodayWidth = $oServer->node_bandwidth - $oServer->prev_day_width;
$oTgSendFormat->rowAdd(
- $oDucksRow->code,
- $oDucksRow->today_width,
- $oDucksRow->use_width,
- $oDucksRow->max_width,
- $iWidthResetDay,
- $oDucksRow->memo
+ $oServer->duck_code,
+ $iTodayWidth,
+ $oServer->node_bandwidth,
+ $oServer->node_bandwidth_limit,
+ $oServer->reset_day_limit
+ );
+
+ $oServer->prev_day_width = $oServer->node_bandwidth;
+ $oServer->save();
+ }
+
+ (new Telegram())->send(0, $oTgSendFormat->typeA());
+ }
+
+ // 每天merge的zhuanfa耗流
+ public static function zhuanfa_width_merge(): void
+ {
+ $oServers = Node::where('type', 2)
+ ->whereNotNull('zhuanfa_code')
+ ->whereNotIn('zhuanfa_code', ['none', ''])
+ ->get();
+
+ $aZhuanfaToday = [];
+ foreach ($oServers as $oServer) {
+ $iTodayWidth = max(0, $oServer->node_bandwidth - $oServer->prev_day_width);
+ $aZhuanfaToday[$oServer->zhuanfa_code] = ($aZhuanfaToday[$oServer->zhuanfa_code] ?? 0) + $iTodayWidth;
+ }
+
+ foreach ($aZhuanfaToday as $sZhuanfaCode => $iZhuanfaWidthToday) {
+ $oZhuanfa = Zhuanfas::updateOrCreate(['code' => $sZhuanfaCode]);
+ $oZhuanfa->today_width = $iZhuanfaWidthToday; // 这个覆盖是可以的,因为这是当前周期的总量
+ $oZhuanfa->save();
+ $oZhuanfa->increment('use_width', $iZhuanfaWidthToday); // 这里使用原子递增
+ }
+ }
+
+ public static function day_width_report_zhuanfa(): void
+ {
+ $oZhuanfas = Zhuanfas::where("status", 1)->get();
+
+ if ($oZhuanfas->isEmpty()) {
+ return;
+ }
+
+ $oTgSendFormat = new TgSendFormat();
+ $oTgSendFormat->sTitleEmoji = "\n\n";
+ $oTgSendFormat->sTitle = "# 转发流量";
+
+ foreach ($oZhuanfas as $oZhuanfa) {
+ $oTgSendFormat->rowAdd(
+ $oZhuanfa->name,
+ $oZhuanfa->today_width,
+ $oZhuanfa->use_width,
+ $oZhuanfa->max_width,
+ $oZhuanfa->reset_day_limit
);
-
}
$sTgReport = $oTgSendFormat->typeA();
-
+
(new Telegram())->send(0, $sTgReport);
}
+// public static function mergeBandWidth__old(): void
+// {
+//
+// $oNodeAll = Node::where('type', 1)->get();
+//
+// $aZhuanfaFlowNow = [];
+// $aDuckFlowNow = [];
+// $sMsg = "" ;
+//
+// // 统计node流量
+// foreach ($oNodeAll as $oNodeRow) {
+//
+// if ($oNodeRow->node_bandwidth == 0) {
+//
+// if ($oNodeRow->is_shadow != 1) {
+//
+// $sMsg .= '🚨【'.$oNodeRow->name."】小时未耗流,可能异常。\n";
+//
+// }
+//
+// }
+//
+// @$aZhuanfaFlowNow[$oNodeRow->zhuanfa_code] += $oNodeRow->node_bandwidth;
+// @$aDuckFlowNow[$oNodeRow->duck_code] += $oNodeRow->node_bandwidth;
+//
+// }
+//
+// // 入库zhunafa
+// foreach ($aZhuanfaFlowNow as $k => $v) {
+//
+// if ($v) {
+// Zhuanfas::where('code', $k)->increment('today_width', $v);
+// Zhuanfas::where('code', $k)->increment('use_width', $v);
+// }
+//
+// }
+//
+// // 入库duck
+// foreach ($aDuckFlowNow as $k => $v) {
+//
+// if ($v) {
+// Ducks::where('code', $k)->increment('today_width', $v);
+// Ducks::where('code', $k)->increment('use_width', $v);
+// }
+//
+// }
+//
+// // 清空node流量
+// Node::query()->update(['node_bandwidth' => 0]);
+//
+// if ($sMsg) {
+// (new Telegram())->send(0, $sMsg);
+// }
+//
+// }
+
+ //// 每日报表
+// public static function reportBandWidth(): void
+// {
+// //// 流量报告,转发
+// $oZhuanfas = new Zhuanfas();
+// $oTgSendFormat = new TgSendFormat();
+// $oTgSendFormat->sTitleEmoji = "\n\n";
+// $oTgSendFormat->sTitle = "# 转发流量";
+// $today = new DateTime();
+//
+// $oZhuanfasAll = $oZhuanfas->all();
+// foreach ($oZhuanfasAll as $oZhuanfasRow) {
+//
+// $targetDate = new DateTime($oZhuanfasRow->end_date);
+// $interval = $today->diff($targetDate);
+//
+// if ($today > $targetDate) {
+// $iDiffDay = -$interval->days;
+// } else {
+// $iDiffDay = $interval->days;
+// }
+//
+// $oTgSendFormat->rowAdd(
+// $oZhuanfasRow->name,
+// $oZhuanfasRow->today_width,
+// $oZhuanfasRow->use_width,
+// $oZhuanfasRow->max_width,
+// $iDiffDay
+// );
+//
+// }
+//
+// $sTgReport = $oTgSendFormat->typeA();
+//
+// (new Telegram())->send(0, $sTgReport);
+//
+// //// 流量报告,直连
+// $oTgSendFormat = new TgSendFormat();
+// $oTgSendFormat->sTitleEmoji = "\n\n";
+// $oTgSendFormat->sTitle = "# 直连流量";
+//
+// $oServers = Node::where('type', 2)
+// ->where(function ($query) {
+// $query->whereNull('zhuanfa_code')
+// ->orWhereIn('zhuanfa_code', ['none', '']);
+// })
+// ->get();
+//
+// foreach ($oServers as $oServer) {
+//// $oTgSendFormat->rowAdd(
+//// $oServer->name,
+////// $oServer->
+//// );
+// }
+//
+//
+//
+// // 流量报告,机器
+//// $oTgSendFormat = new TgSendFormat();
+//// $oTgSendFormat->sTitleEmoji = "\n\n";
+//// $oTgSendFormat->sTitle = "# 机器流量";
+////
+//// $oDucksAll = $oDucks->orderBy('code')->get();
+//// foreach ($oDucksAll as $oDucksRow) {
+////
+//// if ($oDucksRow->width_reset_day == 0) {
+//// $iWidthResetDay = 0;
+//// } if ($oDucksRow->width_reset_day > date('d')) {
+//// $iWidthResetDay = $oDucksRow->width_reset_day - date('d');
+//// } else {
+//// $date = new DateTime();
+//// $date->modify('first day of next month');
+//// $date->setDate((int)$date->format('Y'), (int)$date->format('m'), $oDucksRow->width_reset_day);
+//// $sEndDate = $date;
+////
+//// $currentDate = new DateTime();
+//// $interval = $currentDate->diff($sEndDate);
+//// $iWidthResetDay = $interval->days;
+//// }
+////
+//// $oTgSendFormat->rowAdd(
+//// $oDucksRow->code,
+//// $oDucksRow->today_width,
+//// $oDucksRow->use_width,
+//// $oDucksRow->max_width,
+//// $iWidthResetDay,
+//// $oDucksRow->memo
+//// );
+////
+//// }
+////
+//// $sTgReport = $oTgSendFormat->typeA();
+////
+//// (new Telegram())->send(0, $sTgReport);
+//
+// }
+
+// public static function reportBandWidth_olddd(): void
+// {
+//
+// $oZhuanfas = new Zhuanfas();
+// $oDucks = new Ducks();
+//
+// // 流量报告,转发
+// $oTgSendFormat = new TgSendFormat();
+// $oTgSendFormat->sTitleEmoji = "\n\n";
+// $oTgSendFormat->sTitle = "# 转发流量";
+// $today = new DateTime();
+//
+// $oZhuanfasAll = $oZhuanfas->all();
+// foreach ($oZhuanfasAll as $oZhuanfasRow) {
+//
+// $targetDate = new DateTime($oZhuanfasRow->end_date);
+// $interval = $today->diff($targetDate);
+//
+// if ($today > $targetDate) {
+// $iDiffDay = -$interval->days;
+// } else {
+// $iDiffDay = $interval->days;
+// }
+//
+// $oTgSendFormat->rowAdd(
+// $oZhuanfasRow->name,
+// $oZhuanfasRow->today_width,
+// $oZhuanfasRow->use_width,
+// $oZhuanfasRow->max_width,
+// $iDiffDay
+// );
+//
+// }
+//
+// $sTgReport = $oTgSendFormat->typeA();
+//
+// (new Telegram())->send(0, $sTgReport);
+//
+// // 流量报告,机器
+// $oTgSendFormat = new TgSendFormat();
+// $oTgSendFormat->sTitleEmoji = "\n\n";
+// $oTgSendFormat->sTitle = "# 机器流量";
+//
+// $oDucksAll = $oDucks->orderBy('code')->get();
+// foreach ($oDucksAll as $oDucksRow) {
+//
+// if ($oDucksRow->width_reset_day == 0) {
+// $iWidthResetDay = 0;
+// } if ($oDucksRow->width_reset_day > date('d')) {
+// $iWidthResetDay = $oDucksRow->width_reset_day - date('d');
+// } else {
+// $date = new DateTime();
+// $date->modify('first day of next month');
+// $date->setDate((int)$date->format('Y'), (int)$date->format('m'), $oDucksRow->width_reset_day);
+// $sEndDate = $date;
+//
+// $currentDate = new DateTime();
+// $interval = $currentDate->diff($sEndDate);
+// $iWidthResetDay = $interval->days;
+// }
+//
+// $oTgSendFormat->rowAdd(
+// $oDucksRow->code,
+// $oDucksRow->today_width,
+// $oDucksRow->use_width,
+// $oDucksRow->max_width,
+// $iWidthResetDay,
+// $oDucksRow->memo
+// );
+//
+// }
+//
+// $sTgReport = $oTgSendFormat->typeA();
+//
+// (new Telegram())->send(0, $sTgReport);
+//
+// }
+
// 每日清空duck和转发的每日流量
- public static function clearTodayWidth(): void
- {
- Ducks::query()->update(['today_width' => 0]);
- Zhuanfas::query()->update(['today_width' => 0]);
- }
+// public static function clearTodayWidth(): void
+// {
+// Ducks::query()->update(['today_width' => 0]);
+// Zhuanfas::query()->update(['today_width' => 0]);
+// }
- public static function reportBandWidth_back(): void
- {
- $oNode = new Node();
- $oZhuanfas = new Zhuanfas();
- $oDucks = new Ducks();
-
- $oNodeAll = $oNode->all();
-
- foreach ($oNodeAll as $oNodeRow) {
-
- @ $iZhuanfaFlowToday[$oNodeRow->zhuanfa_code] += $oNodeRow->node_bandwidth;
- @ $iDuckFlowToday[$oNodeRow->duck_code] += $oNodeRow->node_bandwidth;
-
- $oZhuanfas->where('code', $oNodeRow->zhuanfa_code)->increment('use_width', $oNodeRow->node_bandwidth);
- $oDucks->where('code', $oNodeRow->duck_code)->increment('use_width', $oNodeRow->node_bandwidth);
- $oNode->where('id', $oNodeRow->id)->update(['node_bandwidth' => 0]);
-
- }
-
-
- // 流量报告,转发
- $oTgSendFormat = new TgSendFormat();
- $oTgSendFormat->sTitleEmoji = "⚡️⚡️⚡️⚡️⚡️⚡️";
- $oTgSendFormat->sTitle = "# 转发流量";
- $today = new DateTime();
-
- $oZhuanfasAll = $oZhuanfas->all();
- foreach ($oZhuanfasAll as $oZhuanfasRow) {
-
- $targetDate = new DateTime($oZhuanfasRow->end_date);
- $interval = $today->diff($targetDate);
-
- $oTgSendFormat->rowAdd(
- $oZhuanfasRow->name,
- $iZhuanfaFlowToday[$oZhuanfasRow->code],
- $oZhuanfasRow->use_width,
- $oZhuanfasRow->max_width,
- $interval->days
- );
-
- }
-
- $sTgReport = $oTgSendFormat->typeA();
-
- (new Telegram())->send(0, $sTgReport);
-
- // 流量报告,机器
- $oTgSendFormat = new TgSendFormat();
- $oTgSendFormat->sTitleEmoji = "\n\n";
- $oTgSendFormat->sTitle = "# 机器流量";
-
- $oDucksAll = $oDucks->orderBy('code')->get();
- foreach ($oDucksAll as $oDucksRow) {
-
- if ($oDucksRow->width_reset_day == 0) {
- $iWidthResetDay = 0;
- } if ($oDucksRow->width_reset_day > date('d')) {
- $iWidthResetDay = $oDucksRow->width_reset_day - date('d');
- } else {
- $date = new DateTime();
- $date->modify('first day of next month');
- $date->setDate((int)$date->format('Y'), (int)$date->format('m'), $oDucksRow->width_reset_day);
- $sEndDate = $date;
-
- $currentDate = new DateTime();
- $interval = $currentDate->diff($sEndDate);
- $iWidthResetDay = $interval->days;
- }
-
- $oTgSendFormat->rowAdd(
- $oDucksRow->code,
- $iDuckFlowToday[$oDucksRow->code] ?? 0,
- $oDucksRow->use_width,
- $oDucksRow->max_width,
- $iWidthResetDay
- );
-
- }
-
- $sTgReport = $oTgSendFormat->typeA();
-
- (new Telegram())->send(0, $sTgReport);
-
- }
+// public static function reportBandWidth_back(): void
+// {
+// $oNode = new Node();
+// $oZhuanfas = new Zhuanfas();
+// $oDucks = new Ducks();
+//
+// $oNodeAll = $oNode->all();
+//
+// foreach ($oNodeAll as $oNodeRow) {
+//
+// @ $iZhuanfaFlowToday[$oNodeRow->zhuanfa_code] += $oNodeRow->node_bandwidth;
+// @ $iDuckFlowToday[$oNodeRow->duck_code] += $oNodeRow->node_bandwidth;
+//
+// $oZhuanfas->where('code', $oNodeRow->zhuanfa_code)->increment('use_width', $oNodeRow->node_bandwidth);
+// $oDucks->where('code', $oNodeRow->duck_code)->increment('use_width', $oNodeRow->node_bandwidth);
+// $oNode->where('id', $oNodeRow->id)->update(['node_bandwidth' => 0]);
+//
+// }
+//
+//
+// // 流量报告,转发
+// $oTgSendFormat = new TgSendFormat();
+// $oTgSendFormat->sTitleEmoji = "⚡️⚡️⚡️⚡️⚡️⚡️";
+// $oTgSendFormat->sTitle = "# 转发流量";
+// $today = new DateTime();
+//
+// $oZhuanfasAll = $oZhuanfas->all();
+// foreach ($oZhuanfasAll as $oZhuanfasRow) {
+//
+// $targetDate = new DateTime($oZhuanfasRow->end_date);
+// $interval = $today->diff($targetDate);
+//
+// $oTgSendFormat->rowAdd(
+// $oZhuanfasRow->name,
+// $iZhuanfaFlowToday[$oZhuanfasRow->code],
+// $oZhuanfasRow->use_width,
+// $oZhuanfasRow->max_width,
+// $interval->days
+// );
+//
+// }
+//
+// $sTgReport = $oTgSendFormat->typeA();
+//
+// (new Telegram())->send(0, $sTgReport);
+//
+// // 流量报告,机器
+// $oTgSendFormat = new TgSendFormat();
+// $oTgSendFormat->sTitleEmoji = "\n\n";
+// $oTgSendFormat->sTitle = "# 机器流量";
+//
+// $oDucksAll = $oDucks->orderBy('code')->get();
+// foreach ($oDucksAll as $oDucksRow) {
+//
+// if ($oDucksRow->width_reset_day == 0) {
+// $iWidthResetDay = 0;
+// } if ($oDucksRow->width_reset_day > date('d')) {
+// $iWidthResetDay = $oDucksRow->width_reset_day - date('d');
+// } else {
+// $date = new DateTime();
+// $date->modify('first day of next month');
+// $date->setDate((int)$date->format('Y'), (int)$date->format('m'), $oDucksRow->width_reset_day);
+// $sEndDate = $date;
+//
+// $currentDate = new DateTime();
+// $interval = $currentDate->diff($sEndDate);
+// $iWidthResetDay = $interval->days;
+// }
+//
+// $oTgSendFormat->rowAdd(
+// $oDucksRow->code,
+// $iDuckFlowToday[$oDucksRow->code] ?? 0,
+// $oDucksRow->use_width,
+// $oDucksRow->max_width,
+// $iWidthResetDay
+// );
+//
+// }
+//
+// $sTgReport = $oTgSendFormat->typeA();
+//
+// (new Telegram())->send(0, $sTgReport);
+//
+// }
+ public static function todayOk()
+ {
+ (new Telegram())->send(0, "今日任务处理完成");
+ }
// 用户流量每日重置
public static function resetTodayBandwidth(): void
diff --git a/src/Services/Tg/Hook/Mod/Node.php b/src/Services/Tg/Hook/Mod/Node.php
index 6ea598b1a..f7c5d589f 100644
--- a/src/Services/Tg/Hook/Mod/Node.php
+++ b/src/Services/Tg/Hook/Mod/Node.php
@@ -5,6 +5,8 @@ namespace App\Services\Tg\Hook\Mod;
use App\Models\Node as ModelNode;
use App\Services\Tg\Hook\Dog;
use App\Services\TomTool\Http;
+use Illuminate\Support\Facades\DB;
+use App\Utils\Tools;
class Node extends Base {
@@ -34,7 +36,67 @@ class Node extends Base {
}
- public function Clone($aParam)
+ public function fly()
+ {
+ $oServers = ModelNode::where("type", 2)->orderBy("order_group")->get();
+
+ //// 取出pwd
+ $aPwds = [];
+ foreach ($oServers as $oServer) {
+ $aChildPwds = ModelNode::where("pid", $oServer->id)->pluck("password")->toArray();
+ $aPwds[$oServer->id] = $aChildPwds;
+ }
+
+ //// 清空旧node
+ ModelNode::where("type", 1)->delete();
+
+ //// new分身
+ $aNodes = [];
+ foreach ($oServers as $oServer) {
+ for ($i=0; $i<$oServer->fly; $i++) {
+ $oNode = $oServer->replicate();
+ $oNode->pid = $oServer->id;
+ $aNodes[$oServer->order_group][] = $oNode;
+ }
+ }
+
+ //// 打乱、命名、落库
+ $aNodeNameCodeCount = [];
+ $iDone = 0;
+ $iNodeId = 1001;
+ foreach ($aNodes as $iOrderGroup => $aNodeOrderGroups) {
+ shuffle($aNodeOrderGroups);
+ foreach ($aNodeOrderGroups as $oNode) {
+ if (preg_match('/\$([^\$]+)\$/', $oNode->name, $aMatches)) {
+ $sNodeNameCode = $aMatches[1];
+ } else {
+ continue;
+ }
+
+ if (!isset($aNodeNameCodeCount[$sNodeNameCode])) {
+ $aNodeNameCodeCount[$sNodeNameCode] = 1;
+ }
+
+ $iNodeNum = $aNodeNameCodeCount[$sNodeNameCode]++;
+ $iNodeNum = sprintf("%02d", $iNodeNum);
+
+ $oNode->id = $iNodeId;
+ $oNode->name = preg_replace('/\$.*?\$/', $iNodeNum, $oNode->name);
+ $oNode->type = 1;
+ $oNode->node_bandwidth = 0;
+ $oNode->node_bandwidth_limit = 0;
+ $oNode->bandwidthlimit_resetday = 0;
+ $oNode->is_shadow = 0;
+ $oNode->password = array_pop($aPwds[$oNode->pid]) ?? Tools::genRandomChar(32);
+ $iDone += $oNode->save();
+ $iNodeId++;
+ }
+ }
+
+ return "搞定,生成".$iDone."节点";
+ }
+
+ public function clone($aParam)
{
// list(, $iNodeId) = explode(" ", $sText, 2);
diff --git a/src/Services/Tg/Hook/Mod/Test.php b/src/Services/Tg/Hook/Mod/Test.php
index aaef53102..ee55634e8 100644
--- a/src/Services/Tg/Hook/Mod/Test.php
+++ b/src/Services/Tg/Hook/Mod/Test.php
@@ -168,6 +168,17 @@ final class Test extends Base
}
+ public function nodeReport()
+ {
+ $jobs = new Cron();
+ $jobs->zhuanfa_width_merge(); // 合并转发耗流统计,要在node计算之前
+ $jobs->day_width_report_zhuanfa(); // 汇报每天耗流 - 转发
+// $jobs->hour_width_report(); // 检测小时耗流
+ $jobs->day_width_report(); // 汇报每天耗流
+ $jobs->resetZhuanfaBandwidth(); // zhuanfa流量自动重置
+ $jobs->resetNodeBandwidth(); // 要在最后,其他计算完再重置
+ }
+
public function badian()
{
$jobs = new Cron();
diff --git a/src/Services/TomTool/TgSendFormat.php b/src/Services/TomTool/TgSendFormat.php
index 6f3d38717..359953b71 100755
--- a/src/Services/TomTool/TgSendFormat.php
+++ b/src/Services/TomTool/TgSendFormat.php
@@ -58,7 +58,7 @@ final class TgSendFormat
$sFlowMix .= ",余".$iMaxWidth - $iUseWidth."g";
}
- if ($iMaxWidth != 0) {
+ if ($iMaxWidth != 0 && $iLimitDay !== false) {
$sFlowMix .= ",置".$iLimitDay."d";
}