no message

This commit is contained in:
hellcat 2025-12-18 17:11:59 +08:00
parent f6ed0fb75c
commit d8c015d8cf
25 changed files with 2333 additions and 8130 deletions

1
.gitignore vendored
View File

@ -2,5 +2,6 @@
public/fn/
public/client/
public/feed/
public/sub/
README.md
_env/

View File

@ -0,0 +1,230 @@
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
//use voku\helper\AntiXSS;
use App\Models\ArticleList as ArticleList;
use App\Services\TomTool\HttpV2;
use App\Models\Option as ModelOption;
use App\Services\TomTool\Telegram\Slave as TeleSlave;
class FreenodeController extends Controller
{
static $sEnding = [
"clash" => ".yaml",
"v2ray" => ".txt",
];
static $aCountry = [
"美国",
"美国",
"日本",
"日本",
"新加坡",
"新加坡",
"香港",
"香港",
"台湾",
"台湾",
"越南",
"越南",
"俄罗斯",
"新西兰",
"瑞士",
"荷兰",
"冰岛",
"爱尔兰",
"乌克兰",
"泰国",
"阿根廷",
"葡萄牙",
"美国",
"日本",
"新加坡",
"台湾",
"香港",
"韩国",
"德国",
"土耳其",
"法国",
"加拿大",
"加拿大",
];
public function receive(Request $request)
{
$aData = $request->all();
$sData = json_encode($aData);
$sFnDir = "sub";
$sDateCode = date("Ymd");
$aResult = [];
foreach ($aData as $sFnClient => $sFnContent) {
$sFnFilePath = $sFnDir."/".$sDateCode."-".$sFnClient.$this->endingByClient($sFnClient);
file_put_contents($sFnFilePath, $sFnContent);
$aResult[$sFnClient] = "以更新:".env("APP_URL")."/".$sFnFilePath;
}
$this->saveArticleHtml();
TeleSlave::warn()->enableSlaveQueue(false)->setMsgA($aResult)->send();
return ["is_done" => true];
}
private function saveArticleHtml()
{
$sDateCode = date("Ymd");
/// test
// ArticleList::where("code", $sDateCode)->delete();
//// test end
$oArticleList = ArticleList::where("code", $sDateCode)->first();
if ($oArticleList) {
return false;
}
$this->_saveArticle($sDateCode);
$sHtmlUrl = $this->_saveHtml($sDateCode);
TeleSlave::log()->enableSlaveQueue(false)->send("新fn文章".$sHtmlUrl);
return $sHtmlUrl;
}
private function _saveHtml($sDateCode)
{
$sFreenodeNewUrl = env("APP_URL")."/fn/single/".$sDateCode;
$sFreeNodePath = "fn/".$sDateCode.".html";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $sFreenodeNewUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$sFreeNodeNewView = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); // 获取 HTTP 响应代码
if ($httpCode !== 200) {
ArticleList::where("code", $sDateCode)->delete();
$sMsg = "fn站saveHtml时发生了 $httpCode 错误 -> ".$sFreenodeNewUrl;
TeleSlave::warn()->enableSlaveQueue(false)->send($sMsg);
return;
}
curl_close($ch);
file_put_contents($sFreeNodePath, $sFreeNodeNewView);
$sHtmlUrl = env("APP_URL")."/fn/".$sDateCode.".html";
return $sHtmlUrl;
}
private function endingByClient($sFnClient)
{
if (isset(self::$sEnding[$sFnClient])) {
$sEnding = self::$sEnding[$sFnClient];
} else {
$sEnding = ".none";
}
return $sEnding;
}
private function _saveArticle($sDateCode)
{
$sTime = time();
$sTimePrev = strtotime("-1 day");
$sDateCode = date("Ymd", $sTime);
$sDateCodePrev = date("Ymd", $sTimePrev);
$aOption = ModelOption::_all();
//// 图片
$iPrevImgId = ArticleList::where("code", $sDateCodePrev)->first()?->img_id;
if ($iPrevImgId >= env('article_img_count')) {
$iImgId = 1;
} else {
$iImgId = $iPrevImgId + 1;
}
//// 地区
$iCountryLimit = rand(5, 12);
$aCountryKey = array_rand(self::$aCountry, $iCountryLimit);
$aCountry = [];
foreach ($aCountryKey as $sCountryKey) {
$aCountry[] = self::$aCountry[$sCountryKey];
}
$sNodeZone = implode("", $aCountry);
//// 标题
$aTitlePool = [
date('Y', $sTime).$aOption["freenode_title"]
];
$iTitlePoolRandKey = array_rand($aTitlePool);
$sTitle = $aTitlePool[$iTitlePoolRandKey];
//// 内容
$aOptionFnClient = explode(",", $aOption["freenode_client"]);
$iNodeSpeed = rand((int) env("freenode_speed_min"), (int) env("freenode_speed_max"));
$iNodeCount = rand((int) env("freenode_count_min"), (int) env("freenode_count_max"));
$sContent = "
<p>本次更新共".$iNodeCount."个可用节点,最高速度".$iNodeSpeed."M/S。</p>
<p>覆盖".$sNodeZone."等多个区域。</p>
<p>复制下方的v2ray/Clash订阅链接在客户端添加即可正常使用。<br />
";
// 副标题
$sTitleSub = "
本次更新共".$iNodeCount."个可用节点,最高速度".$iNodeSpeed."M/S。
覆盖".$sNodeZone."等多个区域。
复制下方的v2ray/Clash订阅链接在客户端添加即可正常使用。
";
// 标签
$aTagPool = [
'[1][2][3][4][5][6][7][8][11]',
'[11][3][1][2][5][6][4][8][7]',
'[3][2][1][4][7][8][6][5][4]',
'[4][3][1][2][5][8][7][6][5]',
];
$iTagPoolRandKey = array_rand($aTagPool);
$sTag = $aTagPool[$iTagPoolRandKey];
$oFreenoodList = new ArticleList();
$oFreenoodList->img_id = $iImgId;
$oFreenoodList->date_str = date('n月j日', $sTime);
$oFreenoodList->created_at = $sTime;
$oFreenoodList->title = $sTitle;
$oFreenoodList->code = $sDateCode;
$oFreenoodList->tags = $sTag;
$oFreenoodList->type = 'node';
$oFreenoodList->content = $sContent;
$oFreenoodList->title_sub = $sTitleSub;
$r = $oFreenoodList->save();
if ($r != true) {
$sMsg = " - article insert - fail.";
echo $sMsg;
TeleSlave::warn()->enableSlaveQueue(false)->send($sMsg);
}
return true;
}
}

View File

@ -84,9 +84,25 @@ class SingleController extends Controller
$this->aData['pageKw'] = "Clash,Quantumult,Shadowrocket,SSR,v2ray,免费节点,节点,订阅链接";
$this->aData['v2rayPath'] = env('APP_URL')."/feed/v2ray-".$iCode.".txt";
// $this->aData['v2rayPath'] = env('APP_URL')."/feed/v2ray-".$iCode.".txt";
//
// $this->aData['clashPath'] = env('APP_URL')."/feed/clash-".$iCode.".yaml";
$this->aData['clashPath'] = env('APP_URL')."/feed/clash-".$iCode.".yaml";
$aOption = Option::_all();
$aOptionFreenodeClient = explode(",", $aOption["freenode_client"]);
foreach ($aOptionFreenodeClient as $sFnClient) {
$sEnding = ".txt";
if ($sFnClient == "v2ray") {
$sEnding = ".txt";
} else if ($sFnClient == "clash") {
$sEnding = ".yaml";
}
$this->aData["fnFilePath"][$sFnClient] = env('APP_URL')."/sub/".$iCode."-v2ray.txt";
}
$this->aData['jichang'] = Jichang::first()->toArray();

View File

@ -0,0 +1,15 @@
<?php
//namespace App\Http\Controllers;
//
//use Illuminate\Http\Request;
////use App\Models\ArticleList;
////use App\Models\Tags;
////use App\Services\Time;
////use App\Models\Option as ModelOption;
//
//class ExecFreenodeController
//{
//
//}

114
app/Services/Cron.php Normal file
View File

@ -0,0 +1,114 @@
<?php
declare(strict_types=1);
namespace App\Services;
//use App\Services\Cron\HttpQueue as CronHttpQueue;
//use App\Services\Cron\Book as CronBook;
//use App\Services\Cron\FreenodeCrawl as CronFreenodeCrawl;
//use App\Services\Cron\FreenodePool as CronFreenodePool;
//use App\Services\Cron\FreenodeFile as CronFreenodeFile;
//use App\Services\Cron\FreenodeMerge as CronFreenodeMerge;
//use App\Services\Cron\FreenodeLog as CronFreenodeLog;
//use App\Services\Cron\FreenodeSync as CronFreenodeSync;
//use App\Services\Cron\ArticleSchema as CronArticleSchema;
//use App\Services\TomTool\Telegram\Slave as TeleSlave;
//use App\Services\Cron\FreenodeSync as CronFreenodeSync;
final class Cron
{
public bool $bIsTest = false;
public ?int $iTestH = null;
public ?int $iTestI = null;
public ?int $iTestS = null;
public function run(): void
{
try {
$h = (int) date("H");
$i = (int) date("i");
$s = (int) date("s");
if ($this->bIsTest) {
$h = (int) ($this->iTestH ?? $h);
$i = (int) ($this->iTestI ?? $i);
$s = (int) ($this->iTestS ?? $s);
}
echo "cron开始执行 \n";
if ($h % 8 === 0 && $i === 3) {
// CronBook::randbox_notify();
// CronFreenodeSync::
}
if ($h % 6 === 0 && $i === 3) {
// CronFreenodeCrawl::run();
// CronFreenodePool::save();
// CronFreenodeMerge::save();
// CronFreenodeMerge::baseToSite();
// CronFreenodeSync::run();
}
if ($i % 3 === 0) {
// CronArticleSchema::cacheTgSave();
// CronArticleSchema::pushToSlave();
// CronHttpQueue::pop();
}
if ($i === 0) {
// ReportSender::handle();
}
if ($h == 5 && $i === 3) {
// CronFreenodeFile::clear();
}
if ($h == 15 && $i == 3) {
// CronFreenodeLog::fromLast();
}
} catch (\Throwable $e) {
$sMsg = "";
$sMsg .= "--- cron 异常 ---\n";
$sMsg .= "类型: " . get_class($e) . "\n";
$sMsg .= "信息: " . $e->getMessage() . "\n";
$sMsg .= "文件: " . $e->getFile() . " 在第 " . $e->getLine() . "\n";
$sMsg .= "代码跟踪:\n" . $e->getTraceAsString() . "\n";
$sMsg .= "-----------------------------\n";
echo $sMsg;
TeleSlave::fail()->send($sMsg);
}
}
public function setTestH(int $h): void
{
$this->enableTestMode();
$this->iTestH = $h;
}
public function setTestI(int $i): void
{
$this->enableTestMode();
$this->iTestI = $i;
}
public function setTestS(int $s): void
{
$this->enableTestMode();
$this->iTestS = $s;
}
public function enableTestMode(bool $enable = true): void
{
$this->bIsTest = $enable;
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Services;
use App\Models\Freenode;
class ServicesFreenodeSync {
// public static function strToNames($sTagsStr)
// {
//
// $sTagsStr = substr($sTagsStr, 1, -1);
// $aTagsId = explode('][', $sTagsStr);
// $aTagsMap = Tags::all()->toArray();
//
// foreach ($aTagsId as $aTagsIdRow) {
// $aTagNames[] = $aTagsMap[$aTagsIdRow-1];
// }
//
// return $aTagNames;
//
// }
}

415
app/Services/TomTool/Flow.php Executable file
View File

@ -0,0 +1,415 @@
<?php
declare(strict_types=1);
namespace App\Services\TomTool;
use App\Services\TomTool\TelegramVdb;
/**
默认:
name:none
isDone:false
new:
$oResult = Flow::make("name");
快速:
Flow::make("name")->fail("kkkkkkk");
进阶:
Flow::make("name")->noDone()->msg("哟哟哟哟哟哟")->sendTg()->fetch();
业务:
step()
msg()
data()
aData()
jData()
sData()
code()
put()
merge()
toDone()
noDone()
step("start")
action:
reset()
done(?$msg)
fail(?$msg, ?$aParentResult)
sendTg() 伪action
fetch() or get()
fetchAll() or geAll()
set
enableTg();
parent($aParentResult);
with:
withTraceId();
withTimestamp();
withStep();
判断:
::isDone($aResult);
::isFail($aResult);
*/
class Flow
{
protected array $aStep = [];
protected array $aParent = [];
protected bool $isToTg = false;
protected bool $isToTgOne = false;
protected array $aResult = [
'isDone' => false,
];
protected string $sName;
private bool $isChain = false;
public function __construct(string $name = 'none')
{
$this->sName = $name;
$this->aStep[] = "{$this->sName}::start";
}
// new
public static function make(string $name = 'none'): self
{
return new self($name);
}
// new
public static function start($sName = 'none')
{
$oInstance = new self($sName);
$oInstance->isChain = true;
return $oInstance;
}
// option
public function enableTg(bool $flag = true): self
{
$this->isToTg = $flag;
return $this;
}
// option
public function enableTgOne(bool $flag = true): self
{
$this->enableTg(true);
$this->isToTgOne = $flag;
return $this;
}
// option
public function parent(array $aParentResult): self
{
$this->aParent = $aParentResult;
return $this;
}
// data
public function step(string $step): self
{
$this->aStep[] = "{$this->sName}::{$step}";
return $this;
}
// data
public function msg($msg = "msg未设置"): self
{
if (is_array($msg)) {
$msg = json_encode($msg);
}
$this->put('sMsg', $msg);
return $this;
}
// data
public function aData(array $data): self
{
$this->put('aData', $data);
return $this;
}
// data
public function aDataPut($k, $v)
{
$this->aResult["aData"][$k] = $v;
return $this;
}
// data
public function sData(string $data): self
{
$this->put('sData', $data);
return $this;
}
// data
public function code(string $code): self
{
$this->put('sCode', $code);
return $this;
}
// data
public function put(string $key, mixed $value, $sDataKey = ''): self
{
if ($sDataKey) {
$this->aResult[$sDataKey][$key] = $value;
} else {
$this->aResult[$key] = $value;
}
return $this;
}
// data
public function merge(array $data): self
{
foreach ($data as $k => $v) {
$this->put($k, $v);
}
return $this;
}
// data
public function setDone(bool $b = true): self
{
$this->aResult['isDone'] = $b;
return $this;
}
// data
public function setFail(string $step = ''): self
{
if ($step) {
$this->step($step);
}
$this->aResult['isDone'] = false;
return $this;
}
// with
public function withTraceId(string $id = null): self
{
$this->aResult['sTraceId'] = $id ?? uniqid('trace_', true);
return $this;
}
// with
public function withTimestamp(): self
{
$this->aResult['sTimestamp'] = (new \DateTime())->format(\DateTime::ATOM);
return $this;
}
// with
public function withStep(bool $flag = true): self
{
if ($flag) {
$this->withParentStep();
$this->aResult['aStep'] = $this->aStep;
} else {
unset($this->aResult['aStep']);
}
return $this;
}
// action
public function reset(): self
{
$this->aStep = [$this->sName . '::start'];
$this->aParent = [];
$this->isToTg = false;
$this->isToTgOne = false;
$this->aResult = ['isDone' => false];
return $this;
}
// action
public function done(mixed $msg = null)
{
$this->setDone();
if ($msg) {
$this->msg($msg);
}
return $this->get();
}
// action
public function fail(mixed $msg = null, array $aParentResult = [])
{
$this->setFail('fail');
if ($aParentResult) {
$this->aParent = $aParentResult;
}
if ($msg) {
$this->msg($msg);
}
return $this->getFull();
}
// action
// public function sendTg() // 伪装成非set
// {
// $this->enableTgOne();
// return $this;
// }
// action
public function sendTg($sBotCode = 'base', $sChatCode = 'base')
{
}
public function getDataA()
{
return $this->aResult["aData"] ?? [];
}
public function getDataS()
{
return (string) $this->aResult["sData"] ?? '';
}
public function getDataI()
{
return (int) $this->aResult["iData"] ?? 0;
}
public function getDataB()
{
return (bool) $this->aResult["bData"] ?? false;
}
public function getDataX()
{
return $this->aResult["xData"] ?? '';
}
public function setDataA(array $aData): self
{
$this->aData($aData);
return $this;
}
public function setDataB(bool $bData): self
{
$this->aResult["bData"] = $bData;
return $this;
}
public function setDataS(string $sData): self
{
$this->aResult["sData"] = $sData;
return $this;
}
public function setDataI(int $iData): self
{
$this->aResult["iData"] = $iData;
return $this;
}
public function setDataX($xData): self
{
$this->aResult["xData"] = $xData;
return $this;
}
public function getResult(): array
{
return $this->aResult;
}
// action
public function get()
{
if ($this->isToTg) {
$this->_sendTg();
}
if ($this->isToTgOne) {
$this->isToTg = false;
$this->isToTgOne = false;
}
if ($this->isChain) {
return $this;
}
return $this->aResult;
}
// action
public function getFull()
{
$this->withStep();
return $this->get();
}
// action
public function toArray()
{
return $this->aResult;
}
// helper
public function isDone()
{
return $this->aResult["isDone"] ?? false;
}
// helper
public function isFail()
{
return !$this->isDone();
}
// helper
public static function isDoneResult(array $aResult): bool
{
return $aResult['isDone'] ?? false;
}
// helper
public static function isFailResult(array $aResult): bool
{
return !self::isDoneResult($aResult);
}
// shell
public function fetch()
{
return $this->get();
}
// shell
public function fetchAll()
{
return $this->getFull();
}
private function _sendTg()
{
TelegramVdb::make()->dataArr($this->aResult)->save();
}
protected function addStepParent(): void
{
$this->aStep[] = $this->aParent;
}
protected function withParentStep(): void
{
if ($this->aParent) {
$this->addStepParent();
}
}
}

261
app/Services/TomTool/HttpV2.php Executable file
View File

@ -0,0 +1,261 @@
<?php
// 版本25-12-12
declare(strict_types=1);
namespace App\Services\TomTool;
use App\Services\TomTool\Flow;
use Exception;
/**
默认:
method:post
new:
HttpV2::make($url)
基本:
HttpV2::make($url)->send()
进阶:
HttpV2::make($url, "get")->setDataA($aData)->enableJsonAs()->enableAsync()->optMethod("get")->send();
action:
send()
data:
xData()
sData()
jData()
sData()
set:
optMethod()
enableJsonAs()
enableJsonSend()
enableJsonReturn()
@note:
默认关闭 SSL 验证(适用于开发环境),生产环境建议开启
异步模式下不会返回响应内容,仅快速触发请求
*/
class HttpV2
{
protected string $method;
protected $data = [];
protected string $url;
protected bool $sendJson = false;
protected bool $returnJson = false;
protected bool $async = false;
// private bool $isChain = false;
// private array $aResult = [
// "isDone" = false
// ];
public static function make(string $url, string $method = 'post'): self
{
$instance = new self();
$instance->url = $url;
$instance->optMethod($method);
return $instance;
}
// public static function start(string $sUrl, string $sMethod = 'post'): self
// {
// $oInstance = new self();
// $oInstance->url = $sUrl;
// $oInstance->method = $sMethod;
// $oInstance->isChain = true;
// return $oInstance;
// }
//
// public function isDone()
// {
// return $this->aResult["isDone"] ?? false;
// }
//
// public function isFail()
// {
// return !$this->isDone();
// }
// public function getResult()
// {
// return $this->aResult;
// }
public function optMethod(string $method): self
{
$this->method = strtolower($method);
return $this;
}
public function setDataX($xData)
{
$this->setData($xData);
return $this;
}
public function setDataA($aData)
{
$this->setData($aData);
return $this;
}
public function setDataS($sData)
{
$this->setData($sData);
return $this;
}
public function setData($xData)
{
// if (is_array($xData)) {
// json_encode($xData)
// }
$this->data = $xData;
return $this;
}
// public function aData($aData = [])
// {
// $this->data($aData);
// return $this;
// }
//
// public function sData($sData = '')
// {
// $this->data($sData);
// return $this;
// }
//
// public function jData($jData = '')
// {
// $this->data($jData);
// return $this;
// }
//
// public function xData($xData = '')
// {
// $this->data($xData);
// return $this;
// }
//
// public function data($data = ''): self
// {
// $this->data = $data;
// return $this;
// }
public function enableJsonSend(bool $flag = true): self
{
$this->sendJson = $flag;
return $this;
}
public function enableJsonReturn(bool $flag = true): self
{
$this->returnJson = $flag;
return $this;
}
public function enableJsonAs(): self
{
$this->sendJson = true;
$this->returnJson = true;
return $this;
}
public function enableAsync(bool $flag = true): self
{
$this->async = $flag;
return $this;
}
public function send(): string
{
$oFlow = Flow::make("HttpV2::send");
$ch = curl_init();
$headers = [];
// 构建 URL 和请求体
if ($this->method === 'get') {
$url = $this->url . '?' . http_build_query($this->data);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPGET, true);
} else {
curl_setopt($ch, CURLOPT_URL, $this->url);
$payload = $this->sendJson ? json_encode($this->data) : http_build_query($this->data);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
if ($this->method === 'post') {
curl_setopt($ch, CURLOPT_POST, true);
} else {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($this->method));
}
if ($this->sendJson) {
$headers[] = 'Content-Type: application/json';
$headers[] = 'Content-Length: ' . strlen($payload);
}
}
if ($this->returnJson) {
$headers[] = 'Accept: application/json';
}
if (!empty($headers)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
// SSL 设置
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
// 异步发送
if ($this->async) {
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 200);
curl_setopt($ch, CURLOPT_NOSIGNAL, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
curl_exec($ch);
curl_close($ch);
return 'sent';
}
// 阻塞执行
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
if (curl_errno($ch)) {
$error = curl_error($ch);
curl_close($ch);
throw new Exception("cURL Error: {$error}");
}
curl_close($ch);
return $response;
// $this->aResult = $oFlow->sData($response)->done();
//
// if ($this->isChain) {
// return $this;
// }
//
// return $this->aResult;
}
// public static function response(int $code, string $message = ''): void
// {
// http_response_code($code);
// echo $message;
// exit;
// }
}

View File

@ -0,0 +1,139 @@
<?php
declare(strict_types=1);
namespace App\Services\TomTool\Telegram;
use App\Services\HttpQueue as ServiceHttpQueue;
use App\Services\TomTool\Flow;
use App\Services\TomTool\Telegram\Sdk as ServiceTelegramSdk;
use App\Models\TelegramKey as ModelTelegramKey;
/**
注意是master服务器端专用的这里会对code找mapslave不会。
new:
start(?$sBodeCode, ?$sChatCode)
set:
setBotCode()
setChatCode()
setBotToken()
setChatId()
setMsgS()
action:
send()
*/
final class Master
{
public string $sBotCode = "base";
public string $sChatCode = "base";
public string $sBotToken = '';
public int $iChatId = 0;
public string $sMsg = '';
public bool $enableQueue = false; // 应该用不到了
public bool $bKeyBegin = false;
public static function start($sBotCode = 'base', $sChatCode = 'base'): self
{
$oInstance = new self();
$oInstance->sBotCode = $sBotCode;
$oInstance->sChatCode = $sChatCode;
return $oInstance;
}
public function setBotCode(string $sBotCode): self
{
$this->sBotCode = $sBotCode;
return $this;
}
public function setChatCode(string $sChatCode): self
{
$this->sChatCode = $sChatCode;
return $this;
}
public function setBotToken(string $sBotToken): self
{
$this->sBotToken = $sBotToken;
return $this;
}
public function setChatId(int $iChatId): self
{
$this->iChatId = $iChatId;
return $this;
}
public function setMsgS(string $sMsg): self
{
$this->sMsg = $sMsg;
return $this;
}
public function send($sMsg = ''): Flow
{
if ($sMsg) {
$this->sMsg = $sMsg;
}
if (!$this->sMsg) {
throw new \Exception("未设置msg");
}
$this->keyBegin();
if ($this->enableQueue) {
$aData = $this->buildDataTom();
$oFlow = ServiceHttpQueue::start("telegram_local")->arg($aData)->save();
} else {
$oFlow = ServiceTelegramSdk::start()
->setBotToken($this->sBotToken)
->setChatId($this->iChatId)
->setMsgS($this->sMsg)
->send();
}
return $oFlow;
}
private function keyBegin()
{
if (!$this->bKeyBegin) {
if (!$this->sBotToken) {
$this->sBotToken = ModelTelegramKey::botTokenByCode($this->sBotCode);
}
if (!$this->iChatId) {
$this->iChatId = ModelTelegramKey::chatIdByCode($this->sChatCode);
}
if (!$this->sBotToken || !$this->iChatId) {
throw new \RuntimeException("botToken或chatId没找到botCode={$this->sBotCode}chatCode={$this->sChatCode}");
}
$this->bKeyBegin = true;
}
}
private function buildDataTom(): array
{
return [
"sBotCode" => $this->sBotCode ?? '',
"sChatCode" => $this->sChatCode ?? '',
"sBotToken" => $this->sBotToken ?? '',
"iChatId" => $this->iChatId ?? '',
"sMsg" => $this->sMsg ?? '',
];
}
}

View File

@ -0,0 +1,134 @@
<?php
declare(strict_types=1);
namespace App\Services\TomTool\Telegram;
use Telegram\Bot\Api;
use Telegram\Bot\Exceptions\TelegramSDKException;
use App\Services\TomTool\Flow;
class Sdk
{
public $sMsgFormat = [];
public $sMsgFormatType = 'none';
public $sBotToken = '';
public $iChatId = 0;
public $sMsg;
public $oApi;
private const ALLOWED_FORMATS = ['none', 'html', 'markdown', 'markdownV2'];
public static function start()
{
$oInstance = new self();
return $oInstance;
}
public function setBotToken($sBotToken)
{
$this->oApi = new Api($sBotToken);
$this->sBotToken = $sBotToken;
return $this;
}
public function setChatId($iChatId)
{
$this->iChatId = $iChatId;
return $this;
}
public function setMsgS($sMsg = '')
{
$this->sMsg = $sMsg;
return $this;
}
public function send()
{
$oFlow = Flow::start("tg_sdk_send");
$this->msgFormat();
try {
$r = $this->oApi->sendMessage($this->sMsgFormat);
if (!$r->isOk()) {
return $oFlow->fail();
}
} catch (TelegramSDKException $e) {
return $oFlow->fail(['error' => $e->getMessage()]);
}
return $oFlow->done();
}
public function getMsgFormat()
{
$this->msgFormat();
return $this->sMsgFormat;
}
public function msgFormat()
{
if (!in_array($this->sMsgFormatType, self::ALLOWED_FORMATS, true)) {
throw new \RuntimeException("不支持的格式类型: {$this->sMsgFormatType}");
}
$method = 'msgFormat_' . $this->sMsgFormatType;
$this->sMsgFormat = $this->$method();
return $this;
}
private function msgFormat_none()
{
return [
'chat_id' => $this->iChatId,
'text' => $this->sMsg,
'parse_mode' => '',
'disable_web_page_preview' => false,
'reply_to_message_id' => null,
'reply_markup' => null,
];
}
private function msgFormat_html()
{
return [
'chat_id' => $this->iChatId,
'text' => strip_tags($this->sMsg, [
'b', 'strong', 'i', 'em', 'u', 'ins', 's', 'strike', 'del', 'span', 'tg-spoiler', 'a', 'tg-emoji',
'code', 'pre',
]),
'parse_mode' => 'HTML',
'disable_web_page_preview' => false,
'reply_to_message_id' => null,
'reply_markup' => null,
];
}
private function msgFormat_markdown()
{
return [
'chat_id' => $this->iChatId,
'text' => $this->sMsg,
'parse_mode' => 'Markdown',
'disable_web_page_preview' => false,
'reply_to_message_id' => null,
'reply_markup' => null,
];
}
private function msgFormat_markdownV2()
{
return [
'chat_id' => $this->iChatId,
'text' => $this->sMsg,
'parse_mode' => 'MarkdownV2',
'disable_web_page_preview' => false,
'reply_to_message_id' => null,
'reply_markup' => null,
];
}
}

View File

@ -0,0 +1,322 @@
<?php
// 版本 25/12/12
declare(strict_types=1);
namespace App\Services\TomTool\Telegram;
use App\Services\TomTool\HttpV2;
use App\Services\TomTool\Telegram\Sdk as ServiceTelegramSdk;
use App\Services\TomTool\Flow;
use App\Services\HttpQueue as ServiceHttpQueue;
/**
提醒:
master自身已经没有队列了收到slave消息直接转发
默认:
走本地队列发送到master
走异步
new:
start()
log()
warn()
fail()
notify()
opt:
enableMaster(:true)
enableMasterQueue(:true)
enableSlaveQueue(:true)
enableDetail(:true)
set:
setMsgS()
setMsgA()
setBotCode()
setChatCode()
setBotToken()
setChatId()
action:
send()
sendMaster()
sendLocal()
*/
class Slave
{
public string $sBotCode;
public string $sChatCode;
public string $sBotToken = '';
public int $iChatId = 0;
public string $sMsg = '';
public bool $enableMaster = true;
public bool $enableMasterQueue = false; // 这里之前想错了不会有master队列只在slave有master转发就行了
public bool $enableSlaveQueue = true;
public bool $enableDetail = true;
public bool $enableAsync = true;
private bool $enableSend = true;
// new
public static function start(string $sBotCode = 'base', string $sChatCode = 'base'): self
{
$oInstance = new self;
$oInstance->sBotCode = $sBotCode;
$oInstance->sChatCode = $sChatCode;
$oInstance->enableSend = filter_var($_ENV["tg_send_enable"] ?? true, FILTER_VALIDATE_BOOLEAN);
return $oInstance;
}
// new
public static function log(string $sChatCode = 'admin'): self
{
return self::start("log", $sChatCode);
}
// new
public static function warn(string $sChatCode = 'admin'): self
{
return self::start("warn", $sChatCode);
}
// new
public static function fail(string $sChatCode = 'admin'): self
{
return self::start("fail", $sChatCode);
}
// new
public static function notify(string $sChatCode = 'admin'): self
{
return self::start("fail", $sChatCode);
}
// opt
public function enableAsync(bool $b = true): self
{
$this->enableAsync = $b;
return $this;
}
// opt
public function enableDetail(bool $b = true): self
{
$this->enableDetail = $b;
return $this;
}
// opt
public function enableSlaveQueue(bool $b = true): self
{
$this->enableSlaveQueue = $b;
return $this;
}
// opt
public function enableMaster(bool $b = true): self
{
$this->enableMaster = $b;
return $this;
}
// opt
public function enableMasterQueue(bool $b = true): self
{
$this->enableMasterQueue = $b;
return $this;
}
// set
public function setMsgS(string $sMsg = ''): self
{
if ($this->enableDetail) {
$sMsg = "[ ".$this->getEnvSiteCode()." | ".date("d:H:i:s")." ] ".$sMsg;
}
$this->sMsg = $sMsg;
return $this;
}
// set
public function setMsgA(array $aMsg = []): self
{
$aMsgNew = $aMsg;
if ($this->enableDetail) {
$aMsgNew = [];
$aMsgNew["site_code"] = $this->getEnvSiteCode();
$aMsgNew["date"] = date("Y-m-d H:i:s");
$aMsgNew["data"] = $aMsg;
}
$this->sMsg = json_encode($aMsgNew, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
return $this;
}
// set
public function setBotCode(string $sBotCode): self
{
$this->sBotCode = $sBotCode;
return $this;
}
// set
public function setChatCode(string $sChatCode): self
{
$this->sChatCode = $sChatCode;
return $this;
}
// set
public function setBotToken(string $sBotToken): self
{
$this->sBotToken = $sBotToken;
return $this;
}
// set
public function setChatId(int $iChatId): self
{
$this->iChatId = $iChatId;
return $this;
}
// action
public function send($xMsg = ''): Flow
{
if ($this->enableSend == false) {
$oFlow = Flow::start();
return $oFlow->done("不发送");
}
if ($xMsg) {
if (is_array($xMsg)) {
$this->setMsgA($xMsg);
} else {
$this->setMsgS($xMsg);
}
}
if (!$this->sMsg) {
throw new Exception("未设置msg");
}
if ($this->enableMaster) {
$oFlow = $this->_send_master();
} else {
$oFlow = $this->_send_local();
}
return $oFlow;
}
// action
public function sendMaster($xMsg = ''): Flow
{
$this->enableMaster(true);
return $this->send($xMsg);
}
// action
public function sendLocal($xMsg = ''): Flow
{
$this->enableMaster(false);
return $this->send($xMsg);
}
private function _send_master(): Flow
{
$aData = $this->buildDataTom();
if ($this->enableSlaveQueue) {
$oFlow = ServiceHttpQueue::start("telegram_master")->arg($aData)->save();
} else {
$oFlow = Flow::start("_send_master");
$sUrlMaSterBase = $_ENV["url_master_base"] ?? "";
if (!$sUrlMaSterBase) {
throw new \Exception("未设置env的url_master_base");
}
$sUrlMasterPost = "https://".$sUrlMaSterBase."/api/telegram/post";
try {
$oHttpV2 = HttpV2::make($sUrlMasterPost);
if ($this->enableAsync) {
$oHttpV2 = $oHttpV2->enableAsync();
}
$r = $oHttpV2->enableJsonAs()->setData($aData)->send();
if ($this->enableAsync) {
return $oFlow->sData("async")->done("async");
} else {
$a = json_decode($r, true);
$isDone = $a["isDone"] ?? false;
if ($isDone) {
return $oFlow->done();
} else {
return $oFlow->fail($r);
}
}
} catch (\Throwable $e) {
$oFlow = $oFlow->fail($e->getMessage());
}
}
return $oFlow;
}
private function _send_local(): Flow
{
if ($this->enableSlaveQueue) {
$aData = $this->buildDataTom();
$oFlow = ServiceHttpQueue::start("telegram_local")->arg($aData)->save();
} else {
$oFlow = ServiceTelegramSdk::start($this->sBotToken, $this->iChatId)->setMsgS($this->sMsg)->send();
}
return $oFlow;
}
private function buildDataTom(): array
{
return [
"sBotCode" => $this->sBotCode ?? '',
"sChatCode" => $this->sChatCode ?? '',
"sBotToken" => $this->sBotToken ?? '',
"iChatId" => $this->iChatId ?? '',
"enableMasterQueue" => $this->enableMasterQueue ?? '',
"enableMaster" => $this->enableMaster,
"sMsg" => $this->sMsg ?? '',
];
}
private function getEnvSiteCode(): string
{
$sEnvSiteCode = $_ENV["site_code"] ?? "未设置env的site_code";
return $sEnvSiteCode;
}
}

View File

@ -0,0 +1,121 @@
<?php
declare(strict_types=1);
namespace App\Services\IM;
use App\Models\Config;
use Telegram\Bot\Api;
use Telegram\Bot\Exceptions\TelegramSDKException;
use function strip_tags;
// 没有必须默认使用base配置
final class TelegramV2
{
private Api $bot;
public $iTo;
public $sToken;
public $sMsgType = false;
public function __construct($sToken = "base", $sTo = "base")
{
$this->setToken($sToken);
$this->setTo($sTo);
// $this->bot = new Api($this->sToken);
}
public function setMsgType($sMsgType)
{
$this->sMsgType = $sMsgType;
}
public function setTo($xTo, $sType = "code")
{
$iChatId = $xTo;
if ($sType == "code") {
// $sEnvKey = "tgChat_".$xTo;
$iChatId = $_ENV['tgChat'][$iChatId];
}
$this->iTo = $iChatId;
}
public function setToken($xToken, $sType = "code")
{
$sToken = $xToken;
if ($sType == "code") {
// $sEnvKey = "tgToken_".$xToken;
$sToken = $_ENV['tgToken'][$sToken];
}
$this->sToken = $sToken;
$this->bot = new Api($this->sToken);
}
public function send($sMsg, $sMsgType = 'str')
{
if ($sMsgType == "arr") {
$sMsg = json_encode($sMsg, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
}
if ($this->sMsgType === false) {
$sendMessage = [
'chat_id' => $this->iTo,
'text' => $sMsg,
'parse_mode' => '',
'disable_web_page_preview' => false,
'reply_to_message_id' => null,
'reply_markup' => null,
];
} else if ($this->sMsgType === "html") {
$sendMessage = [
'chat_id' => $this->iTo,
'text' => strip_tags(
$sMsg,
['b', 'strong', 'i', 'em', 'u', 'ins', 's', 'strike','del', 'span','tg-spoiler', 'a', 'tg-emoji',
'code', 'pre',
]
),
'parse_mode' => 'HTML',
'disable_web_page_preview' => false,
'reply_to_message_id' => null,
'reply_markup' => null,
];
} else if ($this->sMsgType === "markdown") {
$sendMessage = [
'chat_id' => $this->iTo,
'text' => $sMsg,
'parse_mode' => 'Markdown',
'disable_web_page_preview' => false,
'reply_to_message_id' => null,
'reply_markup' => null,
];
} else if ($this->sMsgType === "markdownV2") {
$sendMessage = [
'chat_id' => $this->iTo,
'text' => $sMsg,
'parse_mode' => 'MarkdownV2',
'disable_web_page_preview' => false,
'reply_to_message_id' => null,
'reply_markup' => null,
];
} else {
$sendMessage = [
'chat_id' => $this->iTo,
'text' => $sMsg,
'parse_mode' => '',
'disable_web_page_preview' => false,
'reply_to_message_id' => null,
'reply_markup' => null,
];
}
return $this->bot->sendMessage($sendMessage);
}
}

View File

@ -0,0 +1,362 @@
<?php
declare(strict_types=1);
namespace App\Services\TomTool;
use App\Services\HttpQueue as ServiceHttpQueue;
use App\Services\TomTool\Flow;
use App\Models\TelegramKey as ModelTelegramKey;
use Telegram\Bot\Api;
use Telegram\Bot\Exceptions\TelegramSDKException;
use function strip_tags;
/**
更新:
data会save清空不再属于set
new:
TelegramVdb::make(?$botCode, ?$chatCode)
快速:
TelegramVdb::make()->save($sData)
进阶:
TelegramVdb::make()->dataArr($aData)->setFormat("html")->save();
TelegramVdb::make()->setFormat()->data($xData)->toJson()->save();
data
data[Arr/Str/Json]($data)
data($aData)->toJson()
action:
save()
set:
setChatCode($code)
setBotCode($code)
setChatId($id) 覆盖code
setBotToken($token) 覆盖code
setFormat($type)
enableDate()
*/
final class TelegramVdb
{
public $sBotCode;
public $sChatCode;
public $sBotToken = null;
public $iChatId = null;
public $sMsg = '';
public $sMsgFormat = '';
public $sMsgFormatType = 'none';
public $bEnableDate = false;
private $bKeyBegin = false;
public $sClient = "master";
private const ALLOWED_FORMATS = ['none', 'html', 'markdown', 'markdownV2'];
public static function log()
{
return self::make("log", "admin");
}
public static function warn()
{
return self::make("warn", "admin");
}
public static function fail()
{
return self::make("fail", "admin");
}
public static function notify()
{
return self::make("notify", "admin");
}
public static function make($sBotCode = "base", $sChatCode = "base")
{
$oInstance = new self();
$oInstance->sBotCode = $sBotCode;
$oInstance->sChatCode = $sChatCode;
return $oInstance;
}
public function send($sMsg = '')
{
return $this->_ok($sMsg, true);
}
public function save($sMsg = '')
{
return $this->_ok($sMsg);
}
private function sendNow()
{
$oResult = Flow::make("send");
$oBot = new Api($this->sBotToken);
$r = $oBot->sendMessage($this->sMsgFormat);
if ($r->isOk()){
return $oResult->done();
} else {
return $oResult->fail("send失败");
}
}
private function HttpQueueSave()
{
$aTelegramArg = [
"bot_token" => $this->sBotToken,
"chat_id" => $this->iChatId,
"msg" => $this->sMsgFormat,
];
$aReturn = ServiceHttpQueue::start("telegram")->arg($aTelegramArg)->save()->getResult();
return $aReturn;
}
public function _ok($sMsg = '', $bSendNow = false)
{
$bTgSendEnable = $_ENV["tg_send_enable"] ?? false;
if (!$bTgSendEnable) {
return false;
}
$oResult = Flow::make("save");
$this->keyBegin();
if ($sMsg) {
if (is_array($sMsg)) {
$this->aData($sMsg);
} else {
$this->sData($sMsg);
}
}
$this->msgFormat();
if ($bSendNow) {
$aReturn = $this->sendNow();
} else {
$aReturn = $this->HttpQueueSave();
}
$this->sMsg = '';
return $aReturn;
}
public function enableDate($b = true)
{
$this->bEnableDate = $b;
return $this;
}
public function data($xData)
{
$this->sMsg = $xData;
return $this;
}
public function jData($sMsg = '')
{
$this->dataJson($sMsg);
return $this;
}
public function aData($sMsg = [])
{
$this->dataArr($sMsg);
return $this;
}
public function sData($sMsg = '')
{
$this->dataStr($sMsg);
return $this;
}
public function toJson()
{
$this->withDateArr();
$this->sMsg = json_encode($this->sMsg, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
return $this;
}
public function dataStr($sMsg = '')
{
$this->withDateStr();
$this->sMsg = $sMsg;
return $this;
}
public function dataArr($sMsg = [])
{
$this->withDateArr();
$this->sMsg = json_encode($sMsg, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
return $this;
}
public function dataJson($sMsg = '')
{
$this->dataStr($sMsg);
return $this;
}
private function withDateArr()
{
if ($this->bEnableDate) {
$this->sMsg["date"] = date("Y-m-d H:i:s");
}
}
private function withDateStr()
{
if ($this->bEnableDate) {
$this->sMsg = '['.date("Y-m-d H:i:s").'] '.$this->sMsg;
}
}
public function setFormat($sMsgFormatType = "none")
{
$this->sMsgFormatType = $sMsgFormatType;
return $this;
}
public function setBotCode($sBotCode)
{
$this->sBotCode = $sBotCode;
$this->bKeyBegin = false;
return $this;
}
public function setChatCode($sChatCode)
{
$this->sChatCode = $sChatCode;
$this->bKeyBegin = false;
return $this;
}
public function setBotToken($sBotToken)
{
$this->sBotToken = $sBotToken;
return $this;
}
public function setChatId($iChatId)
{
$this->iChatId = $iChatId;
return $this;
}
private function keyBegin()
{
if (!$this->bKeyBegin) {
if (!$this->sBotToken) {
$this->sBotToken = $this->botTokenByCode();
}
if (!$this->iChatId) {
$this->iChatId = $this->chatIdByCode();
}
if (!$this->sBotToken || !$this->iChatId) {
throw new \RuntimeException("botToken或chatId没找到botCode={$this->sBotCode}chatCode={$this->sChatCode}");
}
$this->bKeyBegin = true;
}
return $this;
}
private function msgFormat()
{
if (!in_array($this->sMsgFormatType, self::ALLOWED_FORMATS, true)) {
throw new \RuntimeException("不支持的格式类型: {$this->sMsgFormatType}");
}
$method = 'msgFormat_' . $this->sMsgFormatType;
$this->$method();
return $this;
}
private function botTokenByCode()
{
return ModelTelegramKey::botTokenByCode($this->sBotCode);
}
private function chatIdByCode()
{
return ModelTelegramKey::chatIdByCode($this->sChatCode);
}
private function msgFormat_none()
{
$this->sMsgFormat = [
'chat_id' => $this->iChatId,
'text' => $this->sMsg,
'parse_mode' => '',
'disable_web_page_preview' => false,
'reply_to_message_id' => null,
'reply_markup' => null,
];
return $this;
}
private function msgFormat_html()
{
$this->sMsgFormat = [
'chat_id' => $this->iChatId,
'text' => strip_tags($this->sMsg, [
'b', 'strong', 'i', 'em', 'u', 'ins', 's', 'strike', 'del', 'span', 'tg-spoiler', 'a', 'tg-emoji',
'code', 'pre',
]),
'parse_mode' => 'HTML',
'disable_web_page_preview' => false,
'reply_to_message_id' => null,
'reply_markup' => null,
];
return $this;
}
private function msgFormat_markdown()
{
$this->sMsgFormat = [
'chat_id' => $this->iChatId,
'text' => $this->sMsg,
'parse_mode' => 'Markdown',
'disable_web_page_preview' => false,
'reply_to_message_id' => null,
'reply_markup' => null,
];
return $this;
}
private function msgFormat_markdownV2()
{
$this->sMsgFormat = [
'chat_id' => $this->iChatId,
'text' => $this->sMsg,
'parse_mode' => 'MarkdownV2',
'disable_web_page_preview' => false,
'reply_to_message_id' => null,
'reply_markup' => null,
];
return $this;
}
}

View File

@ -0,0 +1,130 @@
<?php
declare(strict_types=1);
namespace App\Services\TomTool;
use Throwable as ThrowableBase;
use Illuminate\Database\QueryException;
use App\Services\TomTool\TelegramVdb;
/**
new:
$oThrowableHandler = ThrowableHandler::make($e);
快速:
$aResult = ThrowableHandler::make($e)->toArr();
action
fetch() or get()
set:
enableTg()
enableTrace()
setMaxDepth()
*/
class ThrowableHandler
{
protected bool $tgEnable = false;
protected bool $showTrace = false;
protected int $maxDepth = 3;
protected ThrowableBase $e;
public static function make(ThrowableBase $e): self
{
$oInstance = new self();
$oInstance->e = $e;
return $oInstance;
}
public function fetch()
{
return $this->get();
}
public function get(): array
{
$data = $this->buildExceptionData($this->e, 0);
if ($this->tgEnable) {
$this->sendTelegram($data);
}
return $data;
}
public function toArr(): array
{
return $this->get();
}
public function toJson(): string
{
return json_encode($this->get(), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
public function enableTg(bool $enable = true): self
{
$this->tgEnable = $enable;
return $this;
}
public function enableTrace(bool $enable = true): self
{
$this->showTrace = $enable;
return $this;
}
public function setMaxDepth(int $depth): self
{
$this->maxDepth = max(1, $depth);
return $this;
}
protected function buildExceptionData(ThrowableBase $e, int $depth): array
{
$data = [
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
];
$code = $e->getCode();
if ($code !== null && $code !== 0) {
$data['code'] = $code;
}
if ($this->showTrace) {
$filteredTrace = array_filter($e->getTrace(), function ($frame) {
return empty($frame['file']) || !str_contains($frame['file'], '/vendor/');
});
$traceLines = [];
foreach ($filteredTrace as $frame) {
$file = $frame['file'] ?? '[internal]';
$line = $frame['line'] ?? '';
$func = isset($frame['class'], $frame['function'])
? "{$frame['class']}{$frame['type']}{$frame['function']}"
: ($frame['function'] ?? '[unknown]');
$traceLines[] = "{$file}:{$line} {$func}()";
}
$data['trace'] = implode("\n", $traceLines);
}
if ($depth < $this->maxDepth && $e->getPrevious() instanceof ThrowableBase) {
$data['previous'] = $this->buildExceptionData($e->getPrevious(), $depth + 1);
}
return $data;
}
protected function sendTelegram(array $data): void
{
TelegramVdb::make()->aData($data)->save();
}
}

21
app/Services/TomTool/Tom.php Executable file
View File

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Services\TomTool;
class Tom
{
public static function toJson($aData)
{
return json_encode($aData, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
public static function toJsonBr($aData)
{
$sData = self::toJson($aData);
$sData = str_replace("\\n", "<br>", $sData);
return $sData;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
User-agent: *
Disallow:
Allow: /

View File

@ -95,24 +95,16 @@
<h2>免费节点订阅链接:</h2>
<p><strong>v2ray订阅链接:</strong></p>
<p>
<a href='javascript:;' data-clipboard-text="{{$aData['v2rayPath']}}" class='copy-permalink'>
<span class='subCopy'>
<i class='iconfont icon-link'></i> {{$aData['v2rayPath']}}
</span>
</a>
</p>
<p><strong>clash订阅链接</strong></p>
<p>
<a href='javascript:;' data-clipboard-text="{{$aData['clashPath']}}" class='copy-permalink'>
<span class='subCopy'>
<i class='iconfont icon-link'></i> {{$aData['clashPath']}}
</span>
</a>
</p>
@foreach ($aData["fnFilePath"] as $sFnClient => $sFilePath)
<p><strong>{{$sFnClient}}订阅链接:</strong></p>
<p>
<a href='javascript:;' data-clipboard-text="{{$sFilePath}}" class='copy-permalink'>
<span class='subCopy'>
<i class='iconfont icon-link'></i> {{$sFilePath}}
</span>
</a>
</p>
@endforeach
<p>温馨提示:</p>
<p>本站提供的都是免费且公共的节点,稳定性与长时间连接速率无法与收费版的高速机场节点相提并论,不能奢望太多。</p>

View File

@ -10,9 +10,12 @@ use App\Http\Controllers\HtmlController;
use App\Http\Controllers\SakaiController;
use App\Http\Controllers\Api\GithubController;
use App\Http\Controllers\Api\TG\HookController;
use App\Http\Controllers\Api\FreenodeController as ApiFreenodeController;
//Route::get('/', [ArticleListController::class, 'fn'])->middleware('test');
Route::any('/api/freenode/receive', [ApiFreenodeController::class, 'receive']);
Route::get('/test1', [SakaiController::class, 'test1']);
Route::get('/test2', [SakaiController::class, 'test2']);
Route::get('/test3', [SakaiController::class, 'test3']);

14
scripts/cron.php Normal file
View File

@ -0,0 +1,14 @@
<?php
error_reporting(E_ALL & ~E_DEPRECATED);
require __DIR__ . '/../vendor/autoload.php';
$app = require_once __DIR__ . '/../bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
$service = $app->make(App\Services\Cron::class);
//$service->setTestI(5);
$result = $service->run();
print_r($result);