NodeController.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Controllers\Admin;
  4. use App\Controllers\BaseController;
  5. use App\Models\Node;
  6. use App\Models\Setting;
  7. use App\Utils\CloudflareDriver;
  8. use App\Utils\Telegram;
  9. use App\Utils\Tools;
  10. use Exception;
  11. use Psr\Http\Message\ResponseInterface;
  12. use Slim\Http\Request;
  13. use Slim\Http\Response;
  14. final class NodeController extends BaseController
  15. {
  16. public static $details = [
  17. 'field' => [
  18. 'op' => '操作',
  19. 'id' => '节点ID',
  20. 'name' => '名称',
  21. 'server' => '地址',
  22. 'sort' => '类型',
  23. 'traffic_rate' => '倍率',
  24. 'node_class' => '等级',
  25. 'node_group' => '组别',
  26. 'node_bandwidth_limit' => '流量限制',
  27. 'node_bandwidth' => '已用流量',
  28. 'bandwidthlimit_resetday' => '重置日',
  29. ],
  30. ];
  31. public static $update_field = [
  32. 'name',
  33. 'server',
  34. 'mu_only',
  35. 'traffic_rate',
  36. 'info',
  37. 'node_group',
  38. 'node_speedlimit',
  39. 'status',
  40. 'sort',
  41. 'node_ip',
  42. 'node_class',
  43. 'node_bandwidth_limit',
  44. 'bandwidthlimit_resetday',
  45. ];
  46. /**
  47. * 后台节点页面
  48. *
  49. * @param array $args
  50. */
  51. public function index(Request $request, Response $response, array $args): ResponseInterface
  52. {
  53. return $response->write(
  54. $this->view()
  55. ->assign('details', self::$details)
  56. ->display('admin/node/index.tpl')
  57. );
  58. }
  59. /**
  60. * 后台创建节点页面
  61. *
  62. * @param array $args
  63. */
  64. public function create(Request $request, Response $response, array $args): ResponseInterface
  65. {
  66. return $response->write(
  67. $this->view()
  68. ->assign('update_field', self::$update_field)
  69. ->display('admin/node/create.tpl')
  70. );
  71. }
  72. /**
  73. * 后台添加节点
  74. *
  75. * @param array $args
  76. */
  77. public function add(Request $request, Response $response, array $args): ResponseInterface
  78. {
  79. $node = new Node();
  80. $node->name = $request->getParam('name');
  81. $node->server = trim($request->getParam('server'));
  82. $node->mu_only = $request->getParam('mu_only');
  83. $node->traffic_rate = $request->getParam('traffic_rate');
  84. $node->info = $request->getParam('info');
  85. $node->type = ($request->getParam('type') === 'true') ? 1 : 0;
  86. $node->node_group = $request->getParam('node_group');
  87. $node->node_speedlimit = $request->getParam('node_speedlimit');
  88. $node->status = $request->getParam('status');
  89. $node->sort = $request->getParam('sort');
  90. if ($request->getParam('custom_config') !== null) {
  91. $node->custom_config = $request->getParam('custom_config');
  92. } else {
  93. $node->custom_config = '{}';
  94. }
  95. $req_node_ip = trim($request->getParam('node_ip'));
  96. $success = true;
  97. $server_list = explode(';', $node->server);
  98. if (Tools::isIPv4($req_node_ip)) {
  99. $success = $node->changeNodeIp($req_node_ip);
  100. } else {
  101. $success = $node->changeNodeIp($server_list[0]);
  102. }
  103. if (! $success) {
  104. return $response->withJson([
  105. 'ret' => 0,
  106. 'msg' => '获取节点IP失败,请检查您输入的节点地址是否正确!',
  107. ]);
  108. }
  109. $node->node_class = $request->getParam('node_class');
  110. $node->node_bandwidth_limit = $request->getParam('node_bandwidth_limit') * 1024 * 1024 * 1024;
  111. $node->bandwidthlimit_resetday = $request->getParam('bandwidthlimit_resetday');
  112. $node->password = Tools::genRandomChar(32);
  113. $node->load = '';
  114. $node->uptime = 0;
  115. $node->save();
  116. if ($_ENV['cloudflare_enable'] === true) {
  117. $domain_name = explode('.' . $_ENV['cloudflare_name'], $node->server);
  118. CloudflareDriver::updateRecord($domain_name[0], $node->node_ip);
  119. }
  120. if (Setting::obtain('telegram_add_node')) {
  121. try {
  122. Telegram::send(
  123. str_replace(
  124. '%node_name%',
  125. $request->getParam('name'),
  126. Setting::obtain('telegram_add_node_text')
  127. )
  128. );
  129. } catch (Exception $e) {
  130. return $response->withJson([
  131. 'ret' => 1,
  132. 'msg' => '节点添加成功,但Telegram通知失败',
  133. 'node_id' => $node->id,
  134. ]);
  135. }
  136. }
  137. return $response->withJson([
  138. 'ret' => 1,
  139. 'msg' => '节点添加成功',
  140. 'node_id' => $node->id,
  141. ]);
  142. }
  143. /**
  144. * 后台编辑指定节点页面
  145. *
  146. * @param array $args
  147. */
  148. public function edit(Request $request, Response $response, array $args): ResponseInterface
  149. {
  150. $id = $args['id'];
  151. $node = Node::find($id);
  152. return $response->write(
  153. $this->view()
  154. ->assign('node', $node)
  155. ->assign('update_field', self::$update_field)
  156. ->display('admin/node/edit.tpl')
  157. );
  158. }
  159. /**
  160. * 后台更新指定节点内容
  161. *
  162. * @param array $args
  163. */
  164. public function update(Request $request, Response $response, array $args): ResponseInterface
  165. {
  166. $id = $args['id'];
  167. $node = Node::find($id);
  168. $node->name = $request->getParam('name');
  169. $node->node_group = $request->getParam('group');
  170. $node->server = trim($request->getParam('server'));
  171. $node->mu_only = $request->getParam('mu_only');
  172. $node->traffic_rate = $request->getParam('rate');
  173. $node->info = $request->getParam('info');
  174. $node->node_speedlimit = $request->getParam('node_speedlimit');
  175. $node->type = ($request->getParam('type') === 'true') ? 1 : 0;
  176. $node->sort = $request->getParam('sort');
  177. if ($request->getParam('custom_config') !== null) {
  178. $node->custom_config = $request->getParam('custom_config');
  179. } else {
  180. $node->custom_config = '{}';
  181. }
  182. $req_node_ip = trim($request->getParam('node_ip'));
  183. $success = true;
  184. $server_list = explode(';', $node->server);
  185. if (Tools::isIPv4($req_node_ip)) {
  186. $success = $node->changeNodeIp($req_node_ip);
  187. } else {
  188. $success = $node->changeNodeIp($server_list[0]);
  189. }
  190. if (! $success) {
  191. return $response->withJson([
  192. 'ret' => 0,
  193. 'msg' => '更新节点IP失败,请检查您输入的节点地址是否正确!',
  194. ]);
  195. }
  196. $node->status = $request->getParam('status');
  197. $node->node_class = $request->getParam('class');
  198. $node->node_bandwidth_limit = $request->getParam('node_bandwidth_limit') * 1024 * 1024 * 1024;
  199. $node->bandwidthlimit_resetday = $request->getParam('bandwidthlimit_resetday');
  200. $node->save();
  201. if (Setting::obtain('telegram_update_node')) {
  202. try {
  203. Telegram::send(
  204. str_replace(
  205. '%node_name%',
  206. $request->getParam('name'),
  207. Setting::obtain('telegram_update_node_text')
  208. )
  209. );
  210. } catch (Exception $e) {
  211. return $response->withJson([
  212. 'ret' => 1,
  213. 'msg' => '修改成功,但Telegram通知失败',
  214. ]);
  215. }
  216. }
  217. return $response->withJson([
  218. 'ret' => 1,
  219. 'msg' => '修改成功',
  220. ]);
  221. }
  222. /**
  223. * @param array $args
  224. */
  225. public function resetNodePassword(Request $request, Response $response, array $args)
  226. {
  227. $id = $args['id'];
  228. $node = Node::find($id);
  229. $password = Tools::genRandomChar(32);
  230. $node->password = $password;
  231. $node->save();
  232. return $response->withJson([
  233. 'ret' => 1,
  234. 'msg' => '重置通讯密钥成功',
  235. ]);
  236. }
  237. /**
  238. * 后台删除指定节点
  239. *
  240. * @param array $args
  241. */
  242. public function delete(Request $request, Response $response, array $args): ResponseInterface
  243. {
  244. $id = $request->getParam('id');
  245. $node = Node::find($id);
  246. if (! $node->delete()) {
  247. return $response->withJson([
  248. 'ret' => 0,
  249. 'msg' => '删除失败',
  250. ]);
  251. }
  252. if (Setting::obtain('telegram_delete_node')) {
  253. try {
  254. Telegram::send(
  255. str_replace(
  256. '%node_name%',
  257. $node->name,
  258. Setting::obtain('telegram_delete_node_text')
  259. )
  260. );
  261. } catch (Exception $e) {
  262. return $response->withJson([
  263. 'ret' => 1,
  264. 'msg' => '删除成功,但Telegram通知失败',
  265. ]);
  266. }
  267. }
  268. return $response->withJson([
  269. 'ret' => 1,
  270. 'msg' => '删除成功',
  271. ]);
  272. }
  273. public function copy($request, $response, $args)
  274. {
  275. try {
  276. $old_node_id = $request->getParam('id');
  277. $old_node = Node::find($old_node_id);
  278. $new_node = new Node();
  279. // https://laravel.com/docs/9.x/eloquent#replicating-models
  280. $new_node = $old_node->replicate([
  281. 'node_bandwidth',
  282. 'bandwidthlimit_resetday',
  283. ]);
  284. $new_node->name .= ' (副本)';
  285. $new_node->node_bandwidth = 0;
  286. $new_node->bandwidthlimit_resetday = date('d');
  287. $new_node->save();
  288. } catch (\Exception $e) {
  289. return $response->withJson([
  290. 'ret' => 0,
  291. 'msg' => $e->getMessage(),
  292. ]);
  293. }
  294. return $response->withJson([
  295. 'ret' => 1,
  296. 'msg' => '复制成功',
  297. ]);
  298. }
  299. /**
  300. * 后台节点页面 AJAX
  301. *
  302. * @param array $args
  303. */
  304. public function ajax(Request $request, Response $response, array $args): ResponseInterface
  305. {
  306. $nodes = Node::orderBy('id', 'desc')->get();
  307. foreach ($nodes as $node) {
  308. $node->op = '<button type="button" class="btn btn-red" id="delete-node"
  309. onclick="deleteNode(' . $node->id . ')">删除</button><button type="button" class="btn btn-orange" id="copy-node"
  310. onclick="copyNode(' . $node->id . ')">复制</button>
  311. <a class="btn btn-blue" href="/admin/node/' . $node->id . '/edit">编辑</a>';
  312. $node->type = $node->type();
  313. $node->sort = $node->sort();
  314. $node->outaddress = $node->getOutAddress();
  315. $node->node_bandwidth = Tools::flowToGB($node->node_bandwidth);
  316. $node->node_bandwidth_limit = Tools::flowToGB($node->node_bandwidth_limit);
  317. $node->node_heartbeat = $node->nodeHeartbeat();
  318. $node->mu_only = $node->muOnly();
  319. }
  320. return $response->withJson([
  321. 'nodes' => $nodes,
  322. ]);
  323. }
  324. }