NodeController.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  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. /**
  17. * 后台节点页面
  18. *
  19. * @param array $args
  20. */
  21. public function index(Request $request, Response $response, array $args): ResponseInterface
  22. {
  23. $table_config = [];
  24. $table_config['total_column'] = [
  25. 'op' => '操作',
  26. 'id' => 'ID',
  27. 'name' => '节点名称',
  28. 'type' => '显示与隐藏',
  29. 'sort' => '类型',
  30. 'server' => '节点地址',
  31. 'outaddress' => '出口地址',
  32. 'node_ip' => '节点IP',
  33. 'info' => '节点信息',
  34. 'status' => '状态',
  35. 'traffic_rate' => '流量比率',
  36. 'node_group' => '节点群组',
  37. 'node_class' => '节点等级',
  38. 'node_speedlimit' => '节点限速/Mbps',
  39. 'node_bandwidth' => '已走流量/GB',
  40. 'node_bandwidth_limit' => '流量限制/GB',
  41. 'bandwidthlimit_resetday' => '流量重置日',
  42. 'node_heartbeat' => '上一次活跃时间',
  43. 'mu_only' => '只启用单端口多用户',
  44. ];
  45. $table_config['default_show_column'] = ['op', 'id', 'name', 'sort'];
  46. $table_config['ajax_url'] = 'node/ajax';
  47. return $response->write(
  48. $this->view()
  49. ->assign('table_config', $table_config)
  50. ->display('admin/node/index.tpl')
  51. );
  52. }
  53. /**
  54. * 后台创建节点页面
  55. *
  56. * @param array $args
  57. */
  58. public function create(Request $request, Response $response, array $args): ResponseInterface
  59. {
  60. return $response->write(
  61. $this->view()
  62. ->display('admin/node/create.tpl')
  63. );
  64. }
  65. /**
  66. * 后台添加节点
  67. *
  68. * @param array $args
  69. */
  70. public function add(Request $request, Response $response, array $args): ResponseInterface
  71. {
  72. $node = new Node();
  73. $node->name = $request->getParam('name');
  74. $node->server = trim($request->getParam('server'));
  75. $node->mu_only = $request->getParam('mu_only');
  76. $node->traffic_rate = $request->getParam('rate');
  77. $node->info = $request->getParam('info');
  78. $node->type = $request->getParam('type');
  79. $node->node_group = $request->getParam('group');
  80. $node->node_speedlimit = $request->getParam('node_speedlimit');
  81. $node->status = $request->getParam('status');
  82. $node->sort = $request->getParam('sort');
  83. if ($request->getParam('custom_config') !== null) {
  84. $node->custom_config = $request->getParam('custom_config');
  85. } else {
  86. $node->custom_config = '{}';
  87. }
  88. $req_node_ip = trim($request->getParam('node_ip'));
  89. $success = true;
  90. $server_list = explode(';', $node->server);
  91. if (Tools::isIPv4($req_node_ip)) {
  92. $success = $node->changeNodeIp($req_node_ip);
  93. } else {
  94. $success = $node->changeNodeIp($server_list[0]);
  95. }
  96. if (! $success) {
  97. return $response->withJson([
  98. 'ret' => 0,
  99. 'msg' => '获取节点IP失败,请检查您输入的节点地址是否正确!',
  100. ]);
  101. }
  102. $node->node_class = $request->getParam('class');
  103. $node->node_bandwidth_limit = $request->getParam('node_bandwidth_limit') * 1024 * 1024 * 1024;
  104. $node->bandwidthlimit_resetday = $request->getParam('bandwidthlimit_resetday');
  105. $node->password = Tools::genRandomChar(32);
  106. $node->save();
  107. if ($_ENV['cloudflare_enable'] === true) {
  108. $domain_name = explode('.' . $_ENV['cloudflare_name'], $node->server);
  109. CloudflareDriver::updateRecord($domain_name[0], $node->node_ip);
  110. }
  111. if (Setting::obtain('telegram_add_node')) {
  112. try {
  113. Telegram::send(
  114. str_replace(
  115. '%node_name%',
  116. $request->getParam('name'),
  117. Setting::obtain('telegram_add_node_text')
  118. )
  119. );
  120. } catch (Exception $e) {
  121. return $response->withJson([
  122. 'ret' => 1,
  123. 'msg' => '节点添加成功,但Telegram通知失败',
  124. 'node_id' => $node->id,
  125. ]);
  126. }
  127. }
  128. return $response->withJson([
  129. 'ret' => 1,
  130. 'msg' => '节点添加成功',
  131. 'node_id' => $node->id,
  132. ]);
  133. }
  134. /**
  135. * 后台编辑指定节点页面
  136. *
  137. * @param array $args
  138. */
  139. public function edit(Request $request, Response $response, array $args): ResponseInterface
  140. {
  141. $id = $args['id'];
  142. $node = Node::find($id);
  143. return $response->write(
  144. $this->view()
  145. ->assign('node', $node)
  146. ->display('admin/node/edit.tpl')
  147. );
  148. }
  149. /**
  150. * 后台更新指定节点内容
  151. *
  152. * @param array $args
  153. */
  154. public function update(Request $request, Response $response, array $args): ResponseInterface
  155. {
  156. $id = $args['id'];
  157. $node = Node::find($id);
  158. $node->name = $request->getParam('name');
  159. $node->node_group = $request->getParam('group');
  160. $node->server = trim($request->getParam('server'));
  161. $node->mu_only = $request->getParam('mu_only');
  162. $node->traffic_rate = $request->getParam('rate');
  163. $node->info = $request->getParam('info');
  164. $node->node_speedlimit = $request->getParam('node_speedlimit');
  165. $node->type = $request->getParam('type');
  166. $node->sort = $request->getParam('sort');
  167. if ($request->getParam('custom_config') !== null) {
  168. $node->custom_config = $request->getParam('custom_config');
  169. } else {
  170. $node->custom_config = '{}';
  171. }
  172. $req_node_ip = trim($request->getParam('node_ip'));
  173. $success = true;
  174. $server_list = explode(';', $node->server);
  175. if (Tools::isIPv4($req_node_ip)) {
  176. $success = $node->changeNodeIp($req_node_ip);
  177. } else {
  178. $success = $node->changeNodeIp($server_list[0]);
  179. }
  180. if (! $success) {
  181. return $response->withJson([
  182. 'ret' => 0,
  183. 'msg' => '更新节点IP失败,请检查您输入的节点地址是否正确!',
  184. ]);
  185. }
  186. $node->status = $request->getParam('status');
  187. $node->node_class = $request->getParam('class');
  188. $node->node_bandwidth_limit = $request->getParam('node_bandwidth_limit') * 1024 * 1024 * 1024;
  189. $node->bandwidthlimit_resetday = $request->getParam('bandwidthlimit_resetday');
  190. $node->save();
  191. if (Setting::obtain('telegram_update_node')) {
  192. try {
  193. Telegram::send(
  194. str_replace(
  195. '%node_name%',
  196. $request->getParam('name'),
  197. Setting::obtain('telegram_update_node_text')
  198. )
  199. );
  200. } catch (Exception $e) {
  201. return $response->withJson([
  202. 'ret' => 1,
  203. 'msg' => '修改成功,但Telegram通知失败',
  204. ]);
  205. }
  206. }
  207. return $response->withJson([
  208. 'ret' => 1,
  209. 'msg' => '修改成功',
  210. ]);
  211. }
  212. /**
  213. * @param array $args
  214. */
  215. public function resetNodePassword(Request $request, Response $response, array $args)
  216. {
  217. $id = $args['id'];
  218. $node = Node::find($id);
  219. $password = Tools::genRandomChar(32);
  220. $node->password = $password;
  221. $node->save();
  222. return $response->withJson([
  223. 'ret' => 1,
  224. 'msg' => '重置通讯密钥成功',
  225. ]);
  226. }
  227. /**
  228. * 后台删除指定节点
  229. *
  230. * @param array $args
  231. */
  232. public function delete(Request $request, Response $response, array $args): ResponseInterface
  233. {
  234. $id = $request->getParam('id');
  235. $node = Node::find($id);
  236. if (! $node->delete()) {
  237. return $response->withJson([
  238. 'ret' => 0,
  239. 'msg' => '删除失败',
  240. ]);
  241. }
  242. if (Setting::obtain('telegram_delete_node')) {
  243. try {
  244. Telegram::send(
  245. str_replace(
  246. '%node_name%',
  247. $node->name,
  248. Setting::obtain('telegram_delete_node_text')
  249. )
  250. );
  251. } catch (Exception $e) {
  252. return $response->withJson([
  253. 'ret' => 1,
  254. 'msg' => '删除成功,但Telegram通知失败',
  255. ]);
  256. }
  257. }
  258. return $response->withJson([
  259. 'ret' => 1,
  260. 'msg' => '删除成功',
  261. ]);
  262. }
  263. /**
  264. * 后台节点页面 AJAX
  265. *
  266. * @param array $args
  267. */
  268. public function ajax(Request $request, Response $response, array $args): ResponseInterface
  269. {
  270. $query = Node::getTableDataFromAdmin(
  271. $request,
  272. static function (&$order_field): void {
  273. if (\in_array($order_field, ['op'])) {
  274. $order_field = 'id';
  275. }
  276. if (\in_array($order_field, ['outaddress'])) {
  277. $order_field = 'server';
  278. }
  279. }
  280. );
  281. $data = [];
  282. foreach ($query['datas'] as $value) {
  283. /** @var Node $value */
  284. $tempdata = [
  285. 'op' => <<<EOF
  286. <a class="btn btn-brand" href="/admin/node/{$value->id}/edit">编辑</a>
  287. <a class="btn btn-brand-accent" id="delete" value="{$value->id}" href="javascript:void(0);" onClick="delete_modal_show('{$value->id}')">删除</a>
  288. EOF,
  289. 'id' => $value->id,
  290. 'name' => $value->name,
  291. 'type' => $value->type(),
  292. 'sort' => $value->sort(),
  293. 'server' => $value->server,
  294. 'outaddress' => $value->getOutAddress(),
  295. 'node_ip' => $value->node_ip,
  296. 'info' => $value->info,
  297. 'status' => $value->status,
  298. 'traffic_rate' => $value->traffic_rate,
  299. 'node_group' => $value->node_group,
  300. 'node_class' => $value->node_class,
  301. 'node_speedlimit' => $value->node_speedlimit,
  302. 'node_bandwidth' => Tools::flowToGB($value->node_bandwidth),
  303. 'node_bandwidth_limit' => Tools::flowToGB($value->node_bandwidth_limit),
  304. 'bandwidthlimit_resetday' => $value->bandwidthlimit_resetday,
  305. 'node_heartbeat' => $value->nodeHeartbeat(),
  306. 'mu_only' => $value->muOnly(),
  307. ];
  308. $data[] = $tempdata;
  309. }
  310. return $response->withJson([
  311. 'draw' => $request->getParam('draw'),
  312. 'recordsTotal' => Node::count(),
  313. 'recordsFiltered' => $query['count'],
  314. 'data' => $data,
  315. ]);
  316. }
  317. }