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 @@ image {/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"; }