Compare commits

...
649 Commits
Author SHA1 Message Date
Mr Chen 29a3e606e1 Merge pull request #586 from midoks/dev
0.17.1
2024-06-05 19:00:44 +08:00
Mr Chen d2b837f52c Update mw.py 2024-06-05 18:58:12 +08:00
Mr Chen 8984381ea2 0.17.1 2024-06-05 18:57:35 +08:00
Mr Chen ff015b19f7 Update install.sh 2024-06-05 18:14:40 +08:00
Mr Chen 1e71eedc19 Update install.sh 2024-06-05 18:13:40 +08:00
Mr Chen fbce4a1abc Update install.sh 2024-06-05 18:12:51 +08:00
Mr Chen d0cdab81d4 Update install.sh 2024-06-05 18:08:57 +08:00
Mr Chen a69d5367d7 Update task_manager_index.py 2024-06-05 17:48:26 +08:00
Mr Chen 8d0ee48aa6 Update task_manager_index.py 2024-06-05 17:47:13 +08:00
Mr Chen c24510e1e7 Update task_manager_index.py 2024-06-05 17:44:27 +08:00
Mr Chen 2e1c2e21b7 Update task_manager_index.py 2024-06-05 17:18:19 +08:00
Mr Chen fee8c8c3db Update task_manager_index.py 2024-06-05 17:13:16 +08:00
Mr Chen d94290019c Update task_manager_index.py 2024-06-05 17:08:42 +08:00
Mr Chen 27b914a905 Update task_manager_index.py 2024-06-05 17:01:45 +08:00
Mr Chen ded25a7c87 Update task_manager_index.py 2024-06-05 16:41:29 +08:00
Mr Chen 5ba5da4cd1 Update task_manager_index.py 2024-06-05 16:39:48 +08:00
Mr Chen cbb2a076e3 Update task_manager.js 2024-06-05 16:30:10 +08:00
Mr Chen 62df45da6a Update task_manager_index.py 2024-06-05 16:22:45 +08:00
Mr Chen e441d8dc87 Update task_manager_index.py 2024-06-05 16:22:12 +08:00
Mr Chen 6d77e923b7 Update task_manager_index.py 2024-06-05 16:22:04 +08:00
Mr Chen 17a40802ae Update task_manager_index.py 2024-06-05 16:16:10 +08:00
Mr Chen 13bb828a95 Update task_manager.js 2024-06-05 16:12:37 +08:00
Mr Chen eaa1a74dd6 Update task_manager_index.py 2024-06-05 16:05:46 +08:00
Mr Chen 80b615810c Update process_network_total.py 2024-06-05 15:56:27 +08:00
Mr Chen 23fe4928e0 Update task_manager_index.py 2024-06-05 15:31:09 +08:00
Mr Chen 5a37c742e2 Update info.json 2024-06-05 15:21:09 +08:00
Mr Chen b94af58524 Update task_manager_index.py 2024-06-05 15:14:48 +08:00
Mr Chen 082c90b769 update 2024-06-05 15:14:20 +08:00
Mr Chen 5012dc3a7b Update task_manager_index.py 2024-06-05 14:02:41 +08:00
Mr Chen a6619b6e9d Update task_manager_index.py 2024-06-05 13:56:34 +08:00
Mr Chen fe4ab5a013 Update task_manager_index.py 2024-06-05 13:40:27 +08:00
Mr Chen ade3a5621f Update process_network_total.py 2024-06-05 13:33:23 +08:00
Mr Chen 1cadeb3f59 Update task_manager_index.py 2024-06-05 13:19:44 +08:00
Mr Chen 05a2ba7f21 Update process_network_total.py 2024-06-05 13:18:06 +08:00
Mr Chen 1759b6bcb1 update 2024-06-05 13:16:56 +08:00
Mr Chen a9e4c1b793 Update task_manager_index.py 2024-06-05 12:59:31 +08:00
Mr Chen 650b565fdf Update task_manager_index.py 2024-06-05 12:58:19 +08:00
Mr Chen 7ab974e565 Update task_manager_index.py 2024-06-05 12:56:47 +08:00
Mr Chen 95f8faf30f Update task_manager.js 2024-06-05 12:14:29 +08:00
Mr Chen 3d69e3723e Update task_manager.js 2024-06-05 12:13:56 +08:00
Mr Chen 4420bbc36c Update task_manager.js 2024-06-05 12:08:33 +08:00
Mr Chen d5d96f6323 Update config_api.py 2024-06-05 12:01:38 +08:00
Mr Chen 0bc9ed9d49 Update task_manager.js 2024-06-05 12:01:13 +08:00
Mr Chen 95e29d6266 Update task_manager.js 2024-06-05 12:00:27 +08:00
Mr Chen 207cef200f update 2024-06-05 11:58:07 +08:00
Mr Chen 0082bcd159 Update site.css 2024-06-05 11:39:21 +08:00
Mr Chen f2a1674247 Update task_manager_index.py 2024-06-05 11:29:04 +08:00
Mr Chen cd1a3de04a Update task_manager_index.py 2024-06-05 11:27:26 +08:00
Mr Chen 60a0bd7a65 Update task_manager_index.py 2024-06-05 11:25:54 +08:00
Mr Chen a0696fc974 Update task_manager_index.py 2024-06-05 11:25:32 +08:00
Mr Chen 159660815b Update task_manager.js 2024-06-05 11:20:28 +08:00
Mr Chen 1c5a3f3c13 Update task_manager_index.py 2024-06-05 11:17:30 +08:00
Mr Chen b36fc58839 Update task_manager_index.py 2024-06-05 11:09:53 +08:00
Mr Chen 0cd7a7dc9e Update task_manager_index.py 2024-06-05 11:05:10 +08:00
Mr Chen 52724dd5b2 Update task_manager_index.py 2024-06-05 11:04:42 +08:00
Mr Chen dccea0e283 Update task_manager_index.py 2024-06-05 11:04:05 +08:00
Mr Chen 0f488b26d1 Update task_manager_index.py 2024-06-05 11:03:41 +08:00
Mr Chen c3b60695c7 Update task_manager_index.py 2024-06-05 10:54:21 +08:00
Mr Chen 6fe205dbfb Update task_manager_index.py 2024-06-05 10:51:36 +08:00
Mr Chen d8efd3f987 Update task_manager.js 2024-06-05 03:19:48 +08:00
Mr Chen 4c50e44e2c Update task_manager.js 2024-06-05 03:15:32 +08:00
Mr Chen 60717c3363 Update task_manager.js 2024-06-05 03:09:10 +08:00
Mr Chen 48388edcfc Update task_manager_index.py 2024-06-05 03:07:24 +08:00
Mr Chen 3c90a0fbe6 Update task_manager_index.py 2024-06-05 03:03:43 +08:00
Mr Chen 6eadb548a1 Update task_manager_index.py 2024-06-05 02:54:10 +08:00
Mr Chen 204be55c81 Update task_manager_index.py 2024-06-05 02:48:19 +08:00
Mr Chen a44ac7606a Update task_manager_index.py 2024-06-05 02:43:31 +08:00
Mr Chen 67505f7aef Update task_manager_index.py 2024-06-05 02:40:57 +08:00
Mr Chen 369dc69364 Update task_manager.js 2024-06-05 02:23:47 +08:00
Mr Chen 1ffe197d69 Update task_manager_index.py 2024-06-05 02:16:53 +08:00
Mr Chen 6a584ccf7b Update task_manager_index.py 2024-06-05 02:13:02 +08:00
Mr Chen 43aba019c0 Update task_manager_index.py 2024-06-05 02:09:19 +08:00
Mr Chen a0a61d3bbc Update task_manager.js 2024-06-05 01:15:34 +08:00
Mr Chen 9b008fcff9 Update task_manager_index.py 2024-06-05 01:09:51 +08:00
Mr Chen e80162cfa9 Update task_manager.js 2024-06-05 01:07:14 +08:00
Mr Chen 30b02aea33 update 2024-06-05 01:05:37 +08:00
Mr Chen 1cf49c24ef Update task_manager_index.py 2024-06-05 01:03:38 +08:00
Mr Chen 3bb0552ba6 Update task_manager_index.py 2024-06-05 00:52:03 +08:00
Mr Chen b33be2ab84 update 2024-06-05 00:50:42 +08:00
Mr Chen 8a4a63c85b Update task_manager.js 2024-06-05 00:39:40 +08:00
Mr Chen 640e8bbfa0 Update task_manager_index.py 2024-06-05 00:37:13 +08:00
Mr Chen e6463e0286 Update task_manager_index.py 2024-06-05 00:35:08 +08:00
Mr Chen c6cf6fef0b Update task_manager_index.py 2024-06-05 00:32:50 +08:00
Mr Chen a428636e1c Update task_manager_index.py 2024-06-05 00:31:17 +08:00
Mr Chen 6fd145fa52 Update index.html 2024-06-05 00:13:42 +08:00
Mr Chen 6164d462f3 Update task_manager.js 2024-06-05 00:08:28 +08:00
Mr Chen d05e72e1d7 Update task_manager_index.py 2024-06-04 23:42:37 +08:00
Mr Chen d9fbfcb184 Update task_manager_index.py 2024-06-04 22:28:35 +08:00
Mr Chen 660d95616d Update task_manager_index.py 2024-06-04 22:26:13 +08:00
Mr Chen 6160819920 Update task_manager.js 2024-06-04 22:17:14 +08:00
Mr Chen c83b2d5bc5 Update task_manager_index.py 2024-06-04 22:09:59 +08:00
Mr Chen 44d529d32f Update public.js 2024-06-04 20:36:31 +08:00
Mr Chen b81e51c0e8 Update task_manager.js 2024-06-04 20:35:43 +08:00
Mr Chen beccfe8519 update 2024-06-04 18:19:17 +08:00
Mr Chen 9e774fb629 update 2024-06-04 17:57:58 +08:00
Mr Chen 10c7ec8718 Update task_manager_index.py 2024-06-04 03:32:34 +08:00
Mr Chen 4bb9d0f002 Update task_manager.js 2024-06-04 01:51:09 +08:00
Mr Chen 39676d1a37 Update task_manager_index.py 2024-06-04 01:49:24 +08:00
Mr Chen 50f44afd82 update 2024-06-04 01:48:47 +08:00
Mr Chen 9884bbd0e3 Update task_manager.js 2024-06-04 01:38:53 +08:00
Mr Chen 39853e39c7 Update task_manager.js 2024-06-04 01:38:37 +08:00
Mr Chen 894656741d Update task_manager.js 2024-06-04 01:35:09 +08:00
Mr Chen 93ef3659f2 Update task_manager_index.py 2024-06-04 01:34:17 +08:00
Mr Chen 3ccf084a53 Update task_manager.js 2024-06-04 01:27:43 +08:00
Mr Chen aaa2b766a3 Update task_manager.js 2024-06-04 01:07:52 +08:00
Mr Chen dc1f03b7ae update 2024-06-04 01:04:16 +08:00
Mr Chen 36b50d3bf2 update 2024-06-04 01:01:15 +08:00
Mr Chen b9b7081eb4 Update task_manager_index.py 2024-06-04 00:38:18 +08:00
Mr Chen 808e65091d Update install.sh 2024-06-04 00:34:19 +08:00
Mr Chen 9b0c30e554 Update task_manager_index.py 2024-06-04 00:33:02 +08:00
Mr Chen ffec30883f Update task_manager_index.py 2024-06-04 00:30:29 +08:00
Mr Chen 900dfc6ca7 Update task_manager_index.py 2024-06-04 00:28:42 +08:00
Mr Chen 203b4d11a8 Update task_manager_index.py 2024-06-04 00:26:48 +08:00
Mr Chen 2ba57ab05f Update task_manager_index.py 2024-06-04 00:25:04 +08:00
Mr Chen 4b11415f36 Update task_manager_index.py 2024-06-04 00:23:52 +08:00
Mr Chen 1ef0c4b8f0 Update task_manager_index.py 2024-06-04 00:23:06 +08:00
Mr Chen 4d85ed4e88 Update task_manager_index.py 2024-06-04 00:22:42 +08:00
Mr Chen 6c40e57ff6 update 2024-06-04 00:19:15 +08:00
Mr Chen 19a4974537 Update stats.js 2024-06-03 23:09:30 +08:00
Mr Chen 6783e1507d Update mysql.js 2024-06-03 12:10:59 +08:00
Mr Chen 8f3e722a0f Update .gitignore 2024-06-03 00:43:38 +08:00
Mr Chen 3437d2e484 Update php.js 2024-06-01 12:17:10 +08:00
Mr Chen 06e654ae2e Merge pull request #585 from midoks/dev
ssh终端提高稳定性。
2024-06-01 02:08:55 +08:00
Mr Chen c3103a23c6 Update __init__.py 2024-06-01 01:57:36 +08:00
Mr Chen 55b38c2741 Update ssh_local.py 2024-06-01 01:55:14 +08:00
Mr Chen 9f30c1968d Update ssh_local.py 2024-06-01 01:53:53 +08:00
Mr Chen d2455768ff Update ssh_local.py 2024-06-01 01:53:39 +08:00
Mr Chen 6331155dc7 Update ssh_local.py 2024-06-01 01:51:27 +08:00
Mr Chen 06d9695d33 update 2024-06-01 01:50:29 +08:00
Mr Chen 80b35284ed Update ssh_terminal.py 2024-06-01 01:33:29 +08:00
Mr Chen 27c38153b8 Update ssh_terminal.py 2024-06-01 01:20:26 +08:00
Mr Chen db62524dab Update __init__.py 2024-06-01 01:19:04 +08:00
Mr Chen 190b858e46 update 2024-06-01 01:16:40 +08:00
Mr Chen be69e5838e Merge pull request #584 from midoks/dev
mysql插件 pv命令判断修复
2024-05-30 12:15:26 +08:00
Mr Chen b12122f53b update 2024-05-30 12:14:54 +08:00
Mr Chen 33be35eb60 Update config_api.py 2024-05-27 19:06:20 +08:00
Mr Chen 39b3f96ab5 Update index.js 2024-05-27 19:05:44 +08:00
Mr Chen 7d214f74fd Update public.js 2024-05-27 18:59:47 +08:00
Mr Chen 10aa140fe9 Update public.js 2024-05-27 18:59:39 +08:00
Mr Chen c68eaa9c61 Update public.js 2024-05-27 18:59:23 +08:00
Mr Chen 3cc6021540 Update public.js 2024-05-27 18:53:50 +08:00
Mr Chen bfe7d49e07 Update public.js 2024-05-27 18:53:44 +08:00
Mr Chen c02aacb0d5 Update public.js 2024-05-27 18:53:19 +08:00
Mr Chen 6d0f6fd171 Update index.js 2024-05-27 18:51:48 +08:00
Mr Chen 712061e814 Update index.js 2024-05-27 18:49:48 +08:00
Mr Chen 197dfa1b7e Update index.js 2024-05-27 18:48:41 +08:00
Mr Chen f21b66ddc0 Update index.js 2024-05-27 18:48:02 +08:00
Mr Chen 5e086537d6 Update index.js 2024-05-27 18:46:53 +08:00
Mr Chen 23532cb7e6 Update index.js 2024-05-27 18:43:40 +08:00
Mr Chen 864ee5caec Update index.js 2024-05-27 18:43:07 +08:00
Mr Chen 5db6d0332b Update config_api.py 2024-05-27 18:36:01 +08:00
Mr Chen eb9504658a update 2024-05-27 18:35:30 +08:00
Mr Chen a67389d611 Update stats.js 2024-05-27 18:07:12 +08:00
Mr Chen f6d4609947 Merge pull request #583 from midoks/dev
0.17.0
2024-05-27 17:47:09 +08:00
Mr Chen d2ddcebe3e 0.17.0 2024-05-27 17:46:06 +08:00
Mr Chen fd2f2c0aa9 Update config.js 2024-05-27 17:42:48 +08:00
Mr Chen 0aae3b0654 Update config_api.py 2024-05-27 17:39:03 +08:00
Mr Chen e56606ac61 Update config_api.py 2024-05-27 17:34:56 +08:00
Mr Chen 54e11700c2 Update config_api.py 2024-05-27 17:27:45 +08:00
Mr Chen fe3b8de490 update 2024-05-27 17:26:42 +08:00
Mr Chen 9874069100 Update config_api.py 2024-05-27 15:13:08 +08:00
Mr Chen 9419d6d55b Update config_api.py 2024-05-27 15:06:14 +08:00
Mr Chen 2f61facbda Update mw.py 2024-05-27 15:01:01 +08:00
Mr Chen 5cd8d7bf18 Update setting.py 2024-05-27 14:57:55 +08:00
Mr Chen 41f016050f Update mw.py 2024-05-27 14:51:39 +08:00
Mr Chen d931790dd3 Update mw.py 2024-05-27 14:50:56 +08:00
Mr Chen a81e63e131 Update mw.tpl 2024-05-27 14:47:38 +08:00
Mr Chen 30717079d4 Update mw.tpl 2024-05-27 14:46:56 +08:00
Mr Chen 3eb2fbb654 Update mw.py 2024-05-27 14:41:06 +08:00
Mr Chen cf54a430eb Update mw.py 2024-05-27 14:40:43 +08:00
Mr Chen 04925c0534 Update mw.py 2024-05-27 14:40:27 +08:00
Mr Chen 6473755127 Update mw.py 2024-05-27 14:39:13 +08:00
Mr Chen 35f40fc8fc Update mw.py 2024-05-27 14:37:09 +08:00
Mr Chen 088a4ab969 Update mw.py 2024-05-27 14:35:44 +08:00
Mr Chen 3c00ddad75 Update mw.py 2024-05-27 14:31:04 +08:00
Mr Chen 5edd9baeb6 Update config_api.py 2024-05-27 14:22:48 +08:00
Mr Chen 734548d764 update 2024-05-27 14:18:54 +08:00
Mr Chen e47d3a235d Update task.py 2024-05-27 13:59:19 +08:00
Mr Chen 0a93015720 Update tools.py 2024-05-27 12:24:23 +08:00
Mr Chen 1078d71370 Update tools.py 2024-05-27 12:23:53 +08:00
Mr Chen b482127044 update 2024-05-27 12:12:41 +08:00
Mr Chen 27b6ee135c Update config.js 2024-05-27 10:37:08 +08:00
Mr Chen cc2000267d Update config_api.py 2024-05-27 10:35:22 +08:00
Mr Chen c1e3655923 Update config_api.py 2024-05-27 09:34:21 +08:00
Mr Chen b0a6181dca up 2024-05-27 00:16:04 +08:00
Mr Chen 33e7efa440 Update config_api.py 2024-05-26 23:01:16 +08:00
Mr Chen 6d7a38dc08 Update config.js 2024-05-26 22:55:28 +08:00
Mr Chen 8a60965069 update 2024-05-26 22:50:29 +08:00
Mr Chen ef9d627095 Update config_api.py 2024-05-26 22:37:12 +08:00
Mr Chen b66acc8c2a Update config.js 2024-05-26 22:28:19 +08:00
Mr Chen fb56f6c190 Update config_api.py 2024-05-26 22:09:29 +08:00
Mr Chen af0f55e6ef Update config_api.py 2024-05-26 21:23:05 +08:00
Mr Chen fb95e2ad8d Update config_api.py 2024-05-26 21:22:41 +08:00
Mr Chen 138a6d3e66 Update config_api.py 2024-05-26 21:21:57 +08:00
Mr Chen 98b9065585 Update config_api.py 2024-05-26 21:19:49 +08:00
Mr Chen 36c3fae920 Update config.js 2024-05-26 21:17:58 +08:00
Mr Chen 70ee376958 Update config.js 2024-05-26 21:14:04 +08:00
Mr Chen 47b2f1b009 Update config_api.py 2024-05-26 17:01:31 +08:00
Mr Chen f2a35b97b0 Update config_api.py 2024-05-26 16:58:38 +08:00
Mr Chen c26e5dc40d update 2024-05-26 16:39:28 +08:00
Mr Chen 893b2d601c Update config.js 2024-05-26 15:49:56 +08:00
Mr Chen 28964721ec Update config_api.py 2024-05-26 15:47:48 +08:00
Mr Chen 5a2028d797 update 2024-05-26 15:46:12 +08:00
Mr Chen fcbe6a87df Update mw.py 2024-05-26 15:32:05 +08:00
Mr Chen 7f5cf75d68 update 2024-05-26 15:29:21 +08:00
Mr Chen c368638181 Update config_api.py 2024-05-26 15:13:53 +08:00
Mr Chen decc9d2b29 Update config_api.py 2024-05-26 14:08:37 +08:00
Mr Chen 7da2a90712 Update config_api.py 2024-05-26 14:01:53 +08:00
Mr Chen 7dd377460c Update config.js 2024-05-26 14:01:22 +08:00
Mr Chen 6b6ae63aea Update config.js 2024-05-26 14:00:22 +08:00
Mr Chen cc9a4b5536 Update config.js 2024-05-26 13:58:52 +08:00
Mr Chen fd44a312f6 Update config.js 2024-05-26 13:58:26 +08:00
Mr Chen a5802b4280 Update config_api.py 2024-05-26 13:56:40 +08:00
Mr Chen d8c928dc02 Update config.js 2024-05-26 13:56:29 +08:00
Mr Chen 339cdf662b Update cli.sh 2024-05-26 13:55:51 +08:00
Mr Chen 1e2a174e30 Update config_api.py 2024-05-26 13:55:47 +08:00
Mr Chen 2714538ad7 Update config_api.py 2024-05-26 13:54:50 +08:00
Mr Chen 8a43f67801 Update mw.py 2024-05-26 13:52:19 +08:00
Mr Chen f3f7ef4a3d Update config.js 2024-05-26 13:52:12 +08:00
Mr Chen 3523f8d6c8 update 2024-05-26 13:52:07 +08:00
Mr Chen eb8c2b6ad5 update 2024-05-26 00:48:03 +08:00
Mr Chen 438322361d Update files.js 2024-05-25 23:19:57 +08:00
Mr Chen c902f48931 Update config_api.py 2024-05-25 13:24:11 +08:00
Mr Chen e67a258e7a Update sphinx.js 2024-05-25 13:06:28 +08:00
Mr Chen 007993ed9e Update sphinx.js 2024-05-25 13:03:50 +08:00
Mr Chen 81171c0c7c Update webstats_common.lua 2024-05-25 11:44:00 +08:00
Mr Chen 15d07e4234 Merge pull request #582 from midoks/dev
网站统计-PV,UV优化
2024-05-25 11:36:02 +08:00
Mr Chen 786fac9142 Update webstats_common.lua 2024-05-25 11:31:56 +08:00
Mr Chen 5499c8795f update 2024-05-25 11:08:46 +08:00
Mr Chen 322698f345 Update init.sql 2024-05-24 23:31:30 +08:00
Mr Chen f229e03f10 Update stats.js 2024-05-23 15:52:32 +08:00
Mr Chen 6024dbcdb6 Merge pull request #581 from midoks/dev
网站统计 - 特殊处理
2024-05-23 15:51:59 +08:00
Mr Chen c874ea44eb 网站统计 - 特殊处理 2024-05-23 15:50:43 +08:00
Mr Chen c70e4d1412 Merge pull request #580 from midoks/dev
Update index.py
2024-05-23 14:03:08 +08:00
Mr Chen 235c5e329e Update index.py 2024-05-23 14:01:02 +08:00
Mr Chen b77bfab5a8 Merge pull request #579 from midoks/dev
新功能同步到mariadb
2024-05-23 13:11:41 +08:00
Mr Chen 890bbc4214 Update index.py 2024-05-23 13:05:44 +08:00
Mr Chen 2f86f4d6ff Update index.py 2024-05-23 13:04:34 +08:00
Mr Chen c9ced293e8 Update mariadb.js 2024-05-23 12:57:33 +08:00
Mr Chen 43f081aac1 Update mariadb.js 2024-05-23 12:56:09 +08:00
Mr Chen 49aa411248 Update index.py 2024-05-23 12:53:00 +08:00
Mr Chen d597e15402 Update index.py 2024-05-23 12:52:49 +08:00
Mr Chen a74ee3faf4 Update index.py 2024-05-23 12:52:39 +08:00
Mr Chen cfe55ca196 Update index.py 2024-05-23 12:51:24 +08:00
Mr Chen 2edffd36d0 Update requirements.txt 2024-05-23 12:07:31 +08:00
Mr Chen c7077ec283 Update index.py 2024-05-23 11:57:12 +08:00
Mr Chen cfcd4c2050 Update index.py 2024-05-23 11:55:28 +08:00
Mr Chen 2387af2880 Update index.py 2024-05-23 11:25:33 +08:00
Mr Chen 72f825c0c4 Update index.py 2024-05-23 11:23:55 +08:00
Mr Chen fbe4857944 Update index.py 2024-05-23 11:23:05 +08:00
Mr Chen 01fe75e553 Update index.py 2024-05-23 11:21:37 +08:00
Mr Chen 2bd607edad Update index.py 2024-05-23 11:20:35 +08:00
Mr Chen 9b9a806dee Update install.sh 2024-05-23 11:17:20 +08:00
Mr Chen 9bc6d392a0 Update index.py 2024-05-23 11:15:15 +08:00
Mr Chen 26b5dc7cd4 update 2024-05-23 11:04:08 +08:00
Mr Chen 80a690c431 Update mariadb.js 2024-05-23 10:48:15 +08:00
Mr Chen 71840ee1e2 update 2024-05-23 10:45:03 +08:00
Mr Chen fbdbb25a78 Update index.py 2024-05-23 10:36:10 +08:00
Mr Chen e546428596 Update public.js 2024-05-23 00:43:10 +08:00
Mr Chen a16259f718 Update public.js 2024-05-23 00:35:54 +08:00
Mr Chen df0b708462 Update backup.py 2024-05-23 00:16:38 +08:00
Mr Chen b3c383327d Update index.py 2024-05-23 00:15:35 +08:00
Mr Chen 8a9c99fb0d Merge pull request #578 from midoks/dev
Update requirements.txt
2024-05-22 22:22:33 +08:00
Mr Chen a22d90198c Update requirements.txt 2024-05-22 22:21:18 +08:00
Mr Chen dcae829a1c Merge pull request #577 from midoks/dev
0.16.9
2024-05-22 22:12:39 +08:00
Mr Chen de4e134be8 0.16.9
- mysql同步优化,享受丝滑般感觉。
- 网站统计 - 实时-可调节1-10s。
- 网站统计 - 加入大小条件。
- Sphinx优化。
2024-05-22 22:12:03 +08:00
Mr Chen ba96e62126 Update cmd.md 2024-05-22 22:11:07 +08:00
Mr Chen 990fb06567 Update .gitignore 2024-05-22 22:02:17 +08:00
Mr Chen 71c1034d12 Update .gitignore 2024-05-22 22:01:37 +08:00
Mr Chen 6582cbc09d update 2024-05-22 22:01:09 +08:00
Mr Chen 52bad278cc Update README.md 2024-05-22 19:48:12 +08:00
Mr Chen e023490002 网站统计加入大小条件 2024-05-22 19:44:25 +08:00
Mr Chen c1a7443597 Update r3.6.txt 2024-05-22 11:46:40 +08:00
Mr Chen 3f57e7da07 update 2024-05-22 11:45:51 +08:00
Mr Chen 0461bf3225 Update sphinx_make.py 2024-05-22 11:37:47 +08:00
Mr Chen ac0a503aa7 Update push_notice_msg.py 2024-05-22 10:57:45 +08:00
Mr Chen 706e9e98e7 Update redis.tpl 2024-05-22 10:50:08 +08:00
Mr Chen d9e878d607 Update redis_cluster.conf 2024-05-22 10:45:57 +08:00
Mr Chen ceb5f21814 Update redis_slave.conf 2024-05-22 10:44:45 +08:00
Mr Chen c8e689433b mw update_dev 2024-05-22 10:44:21 +08:00
Mr Chen f2171aa159 Update mw.tpl 2024-05-22 03:29:46 +08:00
Mr Chen 6eccdd510e update 2024-05-22 03:29:01 +08:00
Mr Chen c9a00809a4 Update redis_slave.conf 2024-05-22 02:57:42 +08:00
Mr Chen 9f1d8e43e6 Update redis_slave.conf 2024-05-22 02:54:26 +08:00
Mr Chen e8eda79a1a Update redis.conf 2024-05-22 02:54:06 +08:00
Mr Chen f25847d31d Update tidb.yaml 2024-05-22 02:53:27 +08:00
Mr Chen bda7dfa518 Update redis_slave.conf 2024-05-22 02:53:06 +08:00
Mr Chen 4115c29fe9 Update redis_slave.conf 2024-05-22 02:46:09 +08:00
Mr Chen f73e378fd6 Update index.py 2024-05-21 23:41:56 +08:00
Mr Chen aa9ab55fec Update sphinx_make.py 2024-05-21 23:39:19 +08:00
Mr Chen da5c44a747 Update sphinx_make.py 2024-05-21 23:39:04 +08:00
Mr Chen ee55c998ba Update sphinx_make.py 2024-05-21 23:28:55 +08:00
Mr Chen 2e75a56502 Update sphinx_make.py 2024-05-21 23:26:15 +08:00
Mr Chen a66279ba37 Update sphinx_make.py 2024-05-21 23:23:33 +08:00
Mr Chen 78bbae1f53 Update sphinx_make.py 2024-05-21 23:21:20 +08:00
Mr Chen a87def4325 Update sphinx_make.py 2024-05-21 22:29:32 +08:00
Mr Chen b84ac2daf1 Update sphinx_make.py 2024-05-21 20:58:22 +08:00
Mr Chen 7c9bf99669 Update sphinx_make.py 2024-05-21 20:56:38 +08:00
Mr Chen 599f6ecc51 Update sphinx_make.py 2024-05-21 20:42:38 +08:00
Mr Chen 47a17fbc46 Update sphinx_make.py 2024-05-21 20:40:31 +08:00
Mr Chen 80fa0ea62d Update sphinx_make.py 2024-05-21 20:40:15 +08:00
Mr Chen 83c78609a4 Update sphinx_make.py 2024-05-21 20:35:50 +08:00
Mr Chen 298d4b7981 Update sphinx_make.py 2024-05-21 20:33:22 +08:00
Mr Chen dc6f4e03e7 Update sphinx_make.py 2024-05-21 20:27:55 +08:00
Mr Chen 8b0b2b2d72 Update sphinx.js 2024-05-21 20:00:29 +08:00
Mr Chen d4087ce7f0 Update sphinx_make.py 2024-05-21 19:59:23 +08:00
Mr Chen f92df461ba Update sphinx_make.py 2024-05-21 19:58:43 +08:00
Mr Chen 9e015bc08c Update sphinx_make.py 2024-05-21 19:55:36 +08:00
Mr Chen 4bffd9a22d update 2024-05-21 19:43:25 +08:00
Mr Chen e2ef42fbbc Update sphinx.js 2024-05-21 19:23:30 +08:00
Mr Chen f10e05b7ee update 2024-05-21 19:20:07 +08:00
Mr Chen c15288cf09 update 2024-05-21 17:12:39 +08:00
Mr Chen 2461307d64 update 2024-05-21 16:57:05 +08:00
Mr Chen 95ec87346d update 2024-05-21 16:07:59 +08:00
Mr Chen f99c5b5fc4 update 2024-05-21 16:04:02 +08:00
Mr Chen adfd3bef2d Update app.js 2024-05-21 15:58:32 +08:00
Mr Chen c11631c0c3 Update index.html 2024-05-21 14:42:11 +08:00
Mr Chen 4f87725101 Update redis_slave.conf 2024-05-21 14:22:40 +08:00
Mr Chen 3a6695bb0d Update redis.conf 2024-05-21 14:22:02 +08:00
Mr Chen dd3bcced66 Update redis_slave.conf 2024-05-21 14:21:57 +08:00
Mr Chen 81a163f744 Update site.css 2024-05-21 03:08:08 +08:00
Mr Chen 19dd36fa8b Update sphinx_make.py 2024-05-21 00:22:03 +08:00
Mr Chen 9dcb028158 Update sphinx_make.py 2024-05-21 00:15:26 +08:00
Mr Chen 1ce841eac9 Update sphinx_make.py 2024-05-21 00:12:15 +08:00
Mr Chen c99311dad9 update 2024-05-21 00:07:48 +08:00
Mr Chen d7dd126a48 Update sphinx_make.py 2024-05-20 23:50:06 +08:00
Mr Chen ec8ab6bc45 Update sphinx_make.py 2024-05-20 23:48:03 +08:00
Mr Chen d5b87f450d Update sphinx_make.py 2024-05-20 23:46:23 +08:00
Mr Chen 0016f85132 Update sphinx_make.py 2024-05-20 23:18:48 +08:00
Mr Chen 32a6b36297 Update tools.py 2024-05-20 22:31:11 +08:00
Mr Chen 8da60ffc6b Update tools.py 2024-05-20 22:20:32 +08:00
Mr Chen 64d65a5cac Update sphinx_make.py 2024-05-20 20:14:48 +08:00
Mr Chen cf5b986d2e update 2024-05-20 14:11:27 +08:00
Mr Chen e1d0fc49bb Update install.sh 2024-05-20 00:34:08 +08:00
Mr Chen 68187ee7dd update 2024-05-20 00:21:09 +08:00
Mr Chen 9f7a7c5e59 Update rhel.sh 2024-05-20 00:10:44 +08:00
Mr Chen 90b14d59b0 Update install.sh 2024-05-19 23:51:32 +08:00
Mr Chen e8d1ea0a38 Update install.sh 2024-05-19 23:51:11 +08:00
Mr Chen edf8a5534a Update install.sh 2024-05-19 23:48:06 +08:00
Mr Chen 87bceced80 update 2024-05-19 23:18:48 +08:00
Mr Chen db3350e85c Update install.sh 2024-05-19 23:03:59 +08:00
Mr Chen 56b3aae0c7 Update install.sh 2024-05-19 22:22:52 +08:00
Mr Chen 01d5b75d90 Update install.sh 2024-05-19 22:15:43 +08:00
Mr Chen cbf3a15bf0 update 2024-05-19 22:06:47 +08:00
Mr Chen 2f0f6eaed6 Update install.sh 2024-05-19 21:54:20 +08:00
Mr Chen f0fcec44ff Update install.sh 2024-05-19 21:46:52 +08:00
Mr Chen fcfdfe822a up 2024-05-19 21:36:25 +08:00
Mr Chen d8e08812f9 update 2024-05-19 19:49:15 +08:00
Mr Chen d0ba142933 Update sphinx_make.py 2024-05-19 18:42:43 +08:00
Mr Chen b4e130c664 Update sphinx_make.py 2024-05-19 18:25:51 +08:00
Mr Chen 7503907f34 Update sphinx_make.py 2024-05-19 18:22:13 +08:00
Mr Chen 390df93477 Update sphinx_make.py 2024-05-19 18:20:55 +08:00
Mr Chen abcf6250e3 Update sphinx_make.py 2024-05-19 18:20:10 +08:00
Mr Chen 70370fcb0b Update sphinx_make.py 2024-05-19 18:19:57 +08:00
Mr Chen 57e7021be2 Update sphinx_make.py 2024-05-19 18:10:54 +08:00
Mr Chen 45b7abd0fb Update sphinx_make.py 2024-05-19 17:58:50 +08:00
Mr Chen a6d96bb4d8 Update sphinx_make.py 2024-05-19 17:57:27 +08:00
Mr Chen 2742ecfc67 Update sphinx_make.py 2024-05-19 17:49:08 +08:00
Mr Chen 60747c2f04 Update sphinx_make.py 2024-05-19 17:47:51 +08:00
Mr Chen 2b019a704a Update sphinx_make.py 2024-05-19 17:47:27 +08:00
Mr Chen 7e049a381b Update sphinx_make.py 2024-05-19 17:45:39 +08:00
Mr Chen 2f4cf46bcf Update sphinx_make.py 2024-05-19 17:45:27 +08:00
Mr Chen 706ee146b5 Update sphinx_make.py 2024-05-19 17:43:52 +08:00
Mr Chen 79b4d09d50 Update index.py 2024-05-19 17:37:47 +08:00
Mr Chen 2f0797daab Update sphinx_make.py 2024-05-19 17:34:37 +08:00
Mr Chen 8e47c73f5c Update sphinx_make.py 2024-05-19 17:27:22 +08:00
Mr Chen c90d752ae7 update 2024-05-19 17:21:19 +08:00
Mr Chen 7c96bbe72f Update sphinx_make.py 2024-05-19 16:56:27 +08:00
Mr Chen 53134b7ecc Update sphinx_make.py 2024-05-19 16:36:14 +08:00
Mr Chen bf859f7c7c Update sphinx_make.py 2024-05-19 16:29:16 +08:00
Mr Chen 0046d02ddf update 2024-05-19 16:24:33 +08:00
Mr Chen 5a0e7a3b60 update 2024-05-19 15:09:25 +08:00
Mr Chen a74ca20d0e up 2024-05-19 14:58:14 +08:00
Mr Chen 41109af522 Update install.sh 2024-05-19 11:27:13 +08:00
Mr Chen b3b23994eb Update sphinx.js 2024-05-19 02:40:11 +08:00
Mr Chen 02f3a147aa Update index.py 2024-05-19 02:36:34 +08:00
Mr Chen 10edf675f5 Update config_api.py 2024-05-19 02:35:24 +08:00
Mr Chen b07b6f0c94 update 2024-05-19 02:35:03 +08:00
Mr Chen 002639936e update 2024-05-19 01:32:31 +08:00
Mr Chen aac516c8f8 Update stats.js 2024-05-19 00:56:35 +08:00
Mr Chen efd07f6de2 网站统计 - 实时请求 可选择 2024-05-19 00:51:35 +08:00
Mr Chen fa17782573 Update index.py 2024-05-18 14:15:57 +08:00
Mr Chen 9ee3aebc8c Update index.py 2024-05-18 14:02:17 +08:00
Mr Chen b778c8cdeb Update index.py 2024-05-18 13:57:34 +08:00
Mr Chen 1d1e6b1d5b Update index.py 2024-05-18 12:49:46 +08:00
Mr Chen 70012ea7ee Update index.py 2024-05-18 11:56:56 +08:00
Mr Chen 0897fd9370 Update index.py 2024-05-18 11:51:51 +08:00
Mr Chen 477b8b38fd Update index.py 2024-05-18 10:58:10 +08:00
Mr Chen e805910b1b Update index.py 2024-05-18 10:54:06 +08:00
Mr Chen 2f9903753f Update index.py 2024-05-18 02:57:32 +08:00
Mr Chen 53cd6377bb Update stats.js 2024-05-18 00:57:55 +08:00
Mr Chen 56cf0271b8 Update index.py 2024-05-17 18:26:51 +08:00
Mr Chen 4fefb0efb2 Update index.py 2024-05-17 18:26:18 +08:00
Mr Chen 222b8bc4de Update index.py 2024-05-17 17:58:50 +08:00
Mr Chen dc0e6fe78a Update index.py 2024-05-17 17:57:14 +08:00
Mr Chen 22a21025af Update index.py 2024-05-17 17:56:11 +08:00
Mr Chen 7cd102c40f Update index.py 2024-05-17 17:55:47 +08:00
Mr Chen 5cd7a65737 Update index.py 2024-05-17 17:48:40 +08:00
Mr Chen c370486845 Update mysql.js 2024-05-17 16:59:08 +08:00
Mr Chen cb9857edf2 update 2024-05-17 16:51:10 +08:00
Mr Chen 8fb3410366 Update mysql.js 2024-05-17 16:26:55 +08:00
Mr Chen 659ef259b7 Update index.py 2024-05-17 15:44:33 +08:00
Mr Chen 9d89a92b78 Update mysql.js 2024-05-17 15:33:48 +08:00
Mr Chen 139f353034 update 2024-05-17 14:09:57 +08:00
Mr Chen 908b1cf684 Update backup.py 2024-05-17 14:05:25 +08:00
Mr Chen 07dc74c283 update 2024-05-17 13:56:47 +08:00
Mr Chen 61e136fb39 Update backup.py 2024-05-17 13:54:59 +08:00
Mr Chen 030e05b2cf Update index.py 2024-05-17 13:52:19 +08:00
Mr Chen 24750cfdb2 Update config_api.py 2024-05-17 13:35:26 +08:00
Mr Chen 975a69fce8 Update layout.html 2024-05-17 13:35:13 +08:00
Mr Chen 5f42f37ee2 Update mysql.sql 2024-05-17 05:24:48 +08:00
Mr Chen 9925daa363 Update index.py 2024-05-17 05:08:45 +08:00
Mr Chen 2572bde607 Update index.py 2024-05-17 05:05:06 +08:00
Mr Chen 572207105c Update index.py 2024-05-17 05:04:18 +08:00
Mr Chen 2b8804e960 同步问题 2024-05-17 05:01:39 +08:00
Mr Chen 310409c52b Update mw.tpl 2024-05-17 04:06:01 +08:00
Mr Chen 01e95fa6fb Update index.py 2024-05-17 03:36:27 +08:00
Mr Chen 848021a639 Update index.py 2024-05-17 03:27:20 +08:00
Mr Chen a679c0e90c Update index.py 2024-05-17 03:26:37 +08:00
Mr Chen 8d9eb6302c Update index.py 2024-05-17 03:20:29 +08:00
Mr Chen f6663ad370 Update index.py 2024-05-17 03:18:59 +08:00
Mr Chen 9964745e46 Update index.py 2024-05-17 01:49:11 +08:00
Mr Chen b570a4552a Update index.py 2024-05-17 01:48:00 +08:00
Mr Chen cd2655a6f9 Update index.py 2024-05-17 01:47:40 +08:00
Mr Chen 608b40a110 Update index.py 2024-05-17 01:46:17 +08:00
Mr Chen a65d42ed2e Update index.py 2024-05-17 01:43:57 +08:00
Mr Chen b0d8d4bef8 Update index.py 2024-05-17 01:43:19 +08:00
Mr Chen d9f657c236 Update index.py 2024-05-17 01:42:05 +08:00
Mr Chen de02bcd800 Update index.py 2024-05-17 01:39:46 +08:00
Mr Chen 1f8dbe1a5f Update index.py 2024-05-17 01:37:54 +08:00
Mr Chen 8f4949cf8d Update index.py 2024-05-17 01:35:43 +08:00
Mr Chen 6128186a2c Update index.py 2024-05-17 01:26:35 +08:00
Mr Chen 7f707f9aac Update index.py 2024-05-17 01:08:13 +08:00
Mr Chen 56c1cd88ee Update config_api.py 2024-05-17 01:02:36 +08:00
Mr Chen 5d0b8b1877 Update layout.html 2024-05-17 01:01:48 +08:00
Mr Chen e944c9fbc5 Update layout.html 2024-05-17 01:01:16 +08:00
Mr Chen 8cab94e26c Update config_api.py 2024-05-17 00:45:56 +08:00
Mr Chen edb26fd11c update 2024-05-17 00:44:52 +08:00
Mr Chen cfd3a07046 Update mysql.js 2024-05-17 00:32:27 +08:00
Mr Chen 8d4ffc431a Update index.py 2024-05-17 00:21:37 +08:00
Mr Chen 22b97ab255 updatae 2024-05-17 00:21:06 +08:00
Mr Chen 8cfc5c5344 Update stats.js 2024-05-16 21:09:10 +08:00
Mr Chen 01c9633a1b Update index.py 2024-05-16 20:32:22 +08:00
Mr Chen 160634d3d4 Update index.py 2024-05-16 20:09:21 +08:00
Mr Chen 59b4ec32a6 Update index.py 2024-05-16 19:58:22 +08:00
Mr Chen 08a2295cdc Update index.py 2024-05-16 19:57:51 +08:00
Mr Chen fb7dbd69e5 Update index.py 2024-05-16 19:43:55 +08:00
Mr Chen c212a30536 Update index.py 2024-05-16 19:42:04 +08:00
Mr Chen 7a7acd3a4d Update index.py 2024-05-16 19:39:45 +08:00
Mr Chen f5edd83164 Update index.py 2024-05-16 19:04:38 +08:00
Mr Chen 8ea3ac1a3c Update index.py 2024-05-16 19:04:21 +08:00
Mr Chen d241ceea3e Update index.py 2024-05-16 18:55:07 +08:00
Mr Chen 6b3f50374a Update index.py 2024-05-16 18:32:59 +08:00
Mr Chen b3ceb03365 Update index.py 2024-05-16 18:25:20 +08:00
Mr Chen 87b26a14df Update mysql.js 2024-05-16 18:25:02 +08:00
Mr Chen 9046a09c0a Update mysql.js 2024-05-16 18:18:22 +08:00
Mr Chen 8bbfdbbf66 Update index.py 2024-05-16 17:57:46 +08:00
Mr Chen fa2d5c690c Update index.py 2024-05-16 17:46:25 +08:00
Mr Chen 681dfc96cb update 2024-05-16 16:33:19 +08:00
Mr Chen 362f5eb427 Update index.py 2024-05-16 16:28:07 +08:00
Mr Chen b033bd1c73 Update index.py 2024-05-16 16:17:04 +08:00
Mr Chen ea94fa21d5 Update index.py 2024-05-16 16:14:51 +08:00
Mr Chen 36c1541179 Update index.py 2024-05-16 16:13:05 +08:00
Mr Chen d5864db956 update 2024-05-15 23:56:52 +08:00
Mr Chen 00008b657c Update index.py 2024-05-15 21:11:29 +08:00
Mr Chen 3abed25d71 Update index.py 2024-05-15 20:52:58 +08:00
Mr Chen 862ea95a77 Update index.py 2024-05-15 20:22:58 +08:00
Mr Chen 63d624d084 Update index.py 2024-05-15 20:11:59 +08:00
Mr Chen c580076307 Update index.py 2024-05-15 20:01:59 +08:00
Mr Chen 3fada81661 Update index.py 2024-05-15 20:00:36 +08:00
Mr Chen a3bd0c6bda Update index.py 2024-05-15 20:00:19 +08:00
Mr Chen 454b036908 Update index.py 2024-05-15 20:00:01 +08:00
Mr Chen 1af9b1ddaa Update index.py 2024-05-15 19:59:35 +08:00
Mr Chen 5818fb46f1 Update mysql.js 2024-05-15 19:36:15 +08:00
Mr Chen 1069fd5252 Update index.py 2024-05-15 19:33:53 +08:00
Mr Chen 76229b6651 Update index.py 2024-05-15 19:31:30 +08:00
Mr Chen 4c9e717559 Update index.py 2024-05-15 19:30:04 +08:00
Mr Chen 9ae61517a4 Update index.py 2024-05-15 19:20:02 +08:00
Mr Chen 952a173535 Update index.py 2024-05-15 19:11:28 +08:00
Mr Chen 5b9b03a153 Update index.py 2024-05-15 19:09:01 +08:00
Mr Chen 9475dbecfe Update index.py 2024-05-15 18:56:38 +08:00
Mr Chen 5a64835969 Update index.py 2024-05-15 18:56:00 +08:00
Mr Chen 8685f21ad9 Update index.py 2024-05-15 18:50:52 +08:00
Mr Chen 500ccff90b update 2024-05-15 17:48:41 +08:00
Mr Chen 85adb449c2 Update index.py 2024-05-15 17:38:49 +08:00
Mr Chen aa6748c09d Update index.py 2024-05-15 17:32:11 +08:00
Mr Chen 05992b5f82 Update index.py 2024-05-15 17:31:49 +08:00
Mr Chen 1a48e880d0 update 2024-05-15 17:29:02 +08:00
Mr Chen 1da749aea9 Update index.py 2024-05-15 14:45:23 +08:00
Mr Chen bf121ee6f8 Update index.py 2024-05-15 14:41:19 +08:00
Mr Chen 6b6e1f415f Update index.py 2024-05-15 14:40:33 +08:00
Mr Chen 5535d56304 Update index.py 2024-05-15 14:30:56 +08:00
Mr Chen bbc0dee2b6 Update index.py 2024-05-15 14:28:23 +08:00
Mr Chen 1da8f6bbb6 update 2024-05-15 14:21:43 +08:00
Mr Chen de15101a76 Update orm.py 2024-05-15 14:06:17 +08:00
Mr Chen ee99d14df3 Update index.py 2024-05-15 14:03:41 +08:00
Mr Chen 7bff08b3e5 Update index.py 2024-05-15 14:02:10 +08:00
Mr Chen faca0b183e update 2024-05-15 13:59:59 +08:00
Mr Chen 700b9a7c61 Update index.py 2024-05-15 13:53:30 +08:00
Mr Chen 53952d267e Update index.py 2024-05-15 13:42:57 +08:00
Mr Chen ff52646fd2 Update index.py 2024-05-15 13:40:00 +08:00
Mr Chen 1dcd4520f1 Update index.py 2024-05-15 13:37:23 +08:00
Mr Chen 21d86f0583 Update index.py 2024-05-15 13:33:08 +08:00
Mr Chen 3e95e3aaf2 Update index.py 2024-05-15 13:28:46 +08:00
Mr Chen 29c7367906 Update index.py 2024-05-15 13:01:44 +08:00
Mr Chen fc1e23f12d Update index.py 2024-05-15 12:31:52 +08:00
Mr Chen ae4af02909 Update index.py 2024-05-15 12:27:54 +08:00
Mr Chen 6b8716ae59 Update index.py 2024-05-15 12:07:57 +08:00
Mr Chen 661faf8503 Update index.py 2024-05-15 11:57:58 +08:00
Mr Chen d0881ff3eb Update index.py 2024-05-15 06:04:24 +08:00
Mr Chen b708d4821a Update index.py 2024-05-15 05:59:39 +08:00
Mr Chen 2f18bf5fb2 Update index.py 2024-05-15 05:50:25 +08:00
Mr Chen 2079076638 Update index.py 2024-05-15 05:42:44 +08:00
Mr Chen 6ec2e4f29f Update index.py 2024-05-15 05:41:51 +08:00
Mr Chen a07ed61305 Update index.py 2024-05-15 05:38:59 +08:00
Mr Chen 8031ea2c45 Update index.py 2024-05-15 05:35:14 +08:00
Mr Chen 24d3fc18d6 Update index.py 2024-05-15 05:05:29 +08:00
Mr Chen 4b200765aa Update index.py 2024-05-15 05:02:01 +08:00
Mr Chen 994ee32fbf Update index.py 2024-05-15 05:00:03 +08:00
Mr Chen c6a742a932 Update index.py 2024-05-15 04:57:51 +08:00
Mr Chen 478e03bca1 Update index.py 2024-05-15 04:42:42 +08:00
Mr Chen f4cff7bcf7 Update index.py 2024-05-15 04:35:52 +08:00
Mr Chen ff7d2f358e Update index.py 2024-05-15 04:35:12 +08:00
Mr Chen e114b07d7d Update index.py 2024-05-15 04:30:04 +08:00
Mr Chen 272b13b29c Update index.py 2024-05-15 04:24:13 +08:00
Mr Chen 8d875fe589 Update index.py 2024-05-15 04:23:17 +08:00
Mr Chen e85e6a7299 update 2024-05-15 04:22:14 +08:00
Mr Chen e8a3f8b014 Update orm.py 2024-05-15 04:16:49 +08:00
Mr Chen 585cd8b532 update_dev 2024-05-15 04:06:15 +08:00
Mr Chen c89ee89061 Update index.py 2024-05-15 01:20:42 +08:00
Mr Chen ea7310502f Update index.py 2024-05-15 01:19:02 +08:00
Mr Chen 507b34797d Update backup.py 2024-05-15 01:18:56 +08:00
Mr Chen 7baecfc4a0 Update README.md 2024-05-14 23:57:17 +08:00
Mr Chen 8a1b64a524 Update index.py 2024-05-14 23:21:44 +08:00
Mr Chen 89052225f9 Update index.py 2024-05-14 23:20:55 +08:00
Mr Chen b4c0030baa Update index.py 2024-05-14 23:20:26 +08:00
Mr Chen 342dfe407c Create README.md 2024-05-14 22:36:37 +08:00
Mr Chen f9020d3c7f Update index.py 2024-05-14 22:24:08 +08:00
Mr Chen d9eb331f32 Update index.py 2024-05-14 22:23:24 +08:00
Mr Chen bc9b5ab511 Update install.sh 2024-05-14 21:48:55 +08:00
Mr Chen b71e3196b8 Update index.py 2024-05-14 21:38:07 +08:00
Mr Chen 69b8c609aa Update index.py 2024-05-14 21:36:07 +08:00
Mr Chen b1ff41350c Update index.py 2024-05-14 21:02:24 +08:00
Mr Chen ddc9defe51 Update index.py 2024-05-14 20:59:46 +08:00
Mr Chen 2942e47630 Update backup.py 2024-05-14 20:58:49 +08:00
Mr Chen b825ed9c76 Update index.py 2024-05-14 20:56:01 +08:00
Mr Chen 5d2dd11163 Update index.py 2024-05-14 20:54:47 +08:00
Mr Chen 253de5e70f Update index.py 2024-05-14 20:11:59 +08:00
Mr Chen a1e900f5c9 Update index.py 2024-05-14 19:25:18 +08:00
Mr Chen cf44889c74 Update index.py 2024-05-14 19:25:00 +08:00
Mr Chen abd48636ab Update index.py 2024-05-14 19:03:17 +08:00
Mr Chen cc0cdd62b8 Update index.py 2024-05-14 16:24:33 +08:00
Mr Chen 0b95db3bd5 Update index.py 2024-05-14 16:13:06 +08:00
Mr Chen d473f0769f Update mongodb.js 2024-05-14 16:11:23 +08:00
Mr Chen dd498c2cfc update 2024-05-14 14:12:21 +08:00
Mr Chen 77b4d0452a Update mongodb.sh 2024-05-13 23:18:00 +08:00
Mr Chen 924e1ddbec Update layout.html 2024-05-13 22:35:10 +08:00
Mr Chen 3213cee5f8 Update mongodb.sh 2024-05-13 20:50:45 +08:00
Mr Chen 9fbf09f2ef Create tidb_debug.yaml 2024-05-13 10:41:00 +08:00
Mr Chen fd3e074cc3 Update install.sh 2024-05-13 03:18:02 +08:00
Mr Chen 574007da2c Update stats.js 2024-05-13 02:47:13 +08:00
Mr Chen ec6c1b2024 Update nginx.conf 2024-05-12 16:09:36 +08:00
Mr Chen 0dd6f47b2a Update index.py 2024-05-12 15:59:19 +08:00
Mr Chen 968827480e Update install.sh 2024-05-12 14:42:07 +08:00
Mr Chen 4bce8bb56d Update index.py 2024-05-12 14:35:53 +08:00
Mr Chen 00fa001c91 update 2024-05-12 14:27:36 +08:00
Mr Chen 2f65839b9a Update index.py 2024-05-12 14:17:49 +08:00
Mr Chen c0aa4bcc1e Update mongodb.js 2024-05-12 14:10:52 +08:00
Mr Chen 4bb345abc4 update 2024-05-12 14:06:56 +08:00
Mr Chen 3d552379bc update 2024-05-12 12:55:14 +08:00
Mr Chen 2de399b70f Update index.py 2024-05-12 12:46:41 +08:00
Mr Chen 7952570b45 update 2024-05-12 10:58:12 +08:00
Mr Chen 00269662bf Create tidb.yaml 2024-05-12 01:25:10 +08:00
Mr Chen fb6dbde4c9 Update config_api.py 2024-05-12 01:18:49 +08:00
Mr Chen 66a9ca2a5a Update files.js 2024-05-12 01:18:32 +08:00
Mr Chen 2e9561dd86 Update files_api.py 2024-05-12 01:10:04 +08:00
Mr Chen 47ff1e4458 Update r3.7.txt 2024-05-12 00:28:20 +08:00
Mr Chen 9f49595bad Update r3.6.txt 2024-05-12 00:28:08 +08:00
Mr Chen 3e6f4f32d5 Update install.sh 2024-05-11 23:42:26 +08:00
Mr Chen ae69d58ee8 Update install.sh 2024-05-11 23:40:45 +08:00
Mr Chen 1788054cc4 Update install.sh 2024-05-11 22:14:51 +08:00
Mr Chen 20b20d3cce Update index.py 2024-05-11 22:13:53 +08:00
Mr Chen 3fc3d90b6f Update install.sh 2024-05-11 22:09:57 +08:00
Mr Chen cef6db80a2 Update install.sh 2024-05-11 22:08:06 +08:00
Mr Chen 59aab80eab Update install.sh 2024-05-11 22:03:56 +08:00
Mr Chen 53c2c71d3e Update install.sh 2024-05-11 21:56:24 +08:00
Mr Chen d9d814202a Update install.sh 2024-05-11 21:51:40 +08:00
Mr Chen 941dbecfa2 Update index.py 2024-05-11 21:48:05 +08:00
Mr Chen cb7228c681 Update index.py 2024-05-11 21:47:55 +08:00
Mr Chen 7ac1cb2944 Update index.py 2024-05-11 21:47:46 +08:00
Mr Chen 0262d29218 Update install.sh 2024-05-11 21:46:48 +08:00
Mr Chen 5a955c2a33 tidb插件init 2024-05-11 20:21:07 +08:00
Mr Chen dd25ebe1e9 Merge pull request #574 from midoks/dev
修复
2024-05-11 13:54:29 +08:00
Mr Chen e92151c9c5 Update site_api.py 2024-05-11 13:52:52 +08:00
Mr Chen 16cc3eab40 Update site_api.py 2024-05-11 13:52:39 +08:00
Mr Chen 87138fc41f Merge pull request #573 from midoks/dev
迁移加入版本判断
2024-05-11 12:38:52 +08:00
Mr Chen 0787bff959 Update index.py 2024-05-11 12:36:57 +08:00
Mr Chen 8fc6855936 Merge pull request #572 from midoks/dev
mysql 不锁表导出
2024-05-11 12:13:27 +08:00
Mr Chen 43f21b4d58 Update backup.py 2024-05-11 12:06:59 +08:00
Mr Chen 56e75bc4cf Update backup.py 2024-05-11 11:59:38 +08:00
Mr Chen 10190201c7 Update backup.py 2024-05-11 11:46:49 +08:00
Mr Chen 3db2aa0034 Merge pull request #571 from midoks/dev
Update site_api.py
2024-05-11 11:08:09 +08:00
Mr Chen 9fa93b5c84 Update site_api.py 2024-05-11 11:07:23 +08:00
Mr Chen fe3e9eec35 Merge pull request #570 from midoks/dev
调优
2024-05-10 17:40:28 +08:00
Mr Chen 86a3922d4f Update index.html 2024-05-10 17:38:48 +08:00
Mr Chen aa50658245 update 2024-05-10 17:36:06 +08:00
Mr Chen 8cd78d7dea Update index.js 2024-05-10 17:25:19 +08:00
Mr Chen f33bfa214f Merge pull request #569 from midoks/dev
Update README.md
2024-05-10 16:26:26 +08:00
Mr Chen e231c38f1d Update README.md 2024-05-10 16:25:20 +08:00
Mr Chen a6a3cf7882 Merge pull request #568 from midoks/dev
0.16.8
2024-05-10 15:34:21 +08:00
Mr Chen a1afe5e846 0.16.8
- 首页对网络/磁盘IO进行更细致的展示。
2024-05-10 15:30:49 +08:00
Mr Chen 594e8c4b2b update 2024-05-10 14:36:38 +08:00
Mr Chen cc015bad61 update 2024-05-10 14:35:51 +08:00
Mr Chen bc9461dea6 update 2024-05-10 13:32:46 +08:00
Mr Chen 0a25598c15 Update config_api.py 2024-05-10 12:14:05 +08:00
Mr Chen 7a9a8a08b6 Update index.js 2024-05-10 12:13:51 +08:00
Mr Chen 8eb728defa index加入io统计展示 2024-05-10 12:04:21 +08:00
Mr Chen 7f8ffbf178 Update site.css 2024-05-10 04:36:43 +08:00
Mr Chen cb0027e903 Update system_api.py 2024-05-10 04:23:48 +08:00
Mr Chen e0ebdd922d Update site.css 2024-05-10 02:16:49 +08:00
Mr Chen d6f43a86c9 Update system_api.py 2024-05-10 02:16:39 +08:00
Mr Chen dfe7becdb1 Update system_api.py 2024-05-09 23:43:16 +08:00
Mr Chen 57f4162cb8 Update mongodb.js 2024-05-09 01:08:14 +08:00
Mr Chen a9ce4f2e23 Update mongodb.js 2024-05-09 01:05:03 +08:00
Mr Chen b501d62d91 Update mongodb.js 2024-05-09 01:03:41 +08:00
Mr Chen 45ffba1559 Merge pull request #567 from midoks/dev
mysql手动导入大文件sql
2024-05-08 17:02:59 +08:00
Mr Chen 28d0fbe106 手动导入大文件sql 2024-05-08 17:01:58 +08:00
Mr Chen eeb8fee3b3 Merge pull request #566 from midoks/dev
日志清理-改成每隔7天
2024-05-08 12:59:59 +08:00
Mr Chen 0e1fbdcfb9 update 2024-05-08 12:58:55 +08:00
Mr Chen df2744816b Merge pull request #565 from midoks/dev
php更新和安装脚本加入pv命令
2024-05-08 12:34:20 +08:00
Mr Chen 862c09778a Update euler.sh 2024-05-08 12:32:52 +08:00
Mr Chen 8f9a1888ff update 2024-05-08 12:32:37 +08:00
Mr Chen 66351dc3a7 update 2024-05-08 12:28:50 +08:00
Mr Chen 55c4709c93 Merge pull request #564 from midoks/dev
日志清理优化
2024-05-08 01:33:02 +08:00
Mr Chen e27ae42270 Update index.py 2024-05-08 01:27:23 +08:00
Mr Chen 70805de98e Update index.py 2024-05-08 01:26:43 +08:00
Mr Chen c0e09e43a2 Update index.py 2024-05-08 01:25:58 +08:00
Mr Chen b69a32c81f Update index.py 2024-05-08 01:20:29 +08:00
Mr Chen 2431833cce Update index.py 2024-05-08 01:19:53 +08:00
Mr Chen a85d8ec429 Update index.html 2024-05-08 01:15:59 +08:00
Mr Chen ce5a6edeea Update tool_task.py 2024-05-08 01:13:34 +08:00
Mr Chen aa195dea2c Update tool_task.py 2024-05-08 00:52:51 +08:00
Mr Chen 840a3c5911 Update layout.html 2024-05-08 00:27:09 +08:00
Mr Chen ca87ab78b3 Update layout.html 2024-05-08 00:11:04 +08:00
Mr Chen d9fc411168 Update layout.html 2024-05-08 00:00:37 +08:00
Mr Chen e468ab16eb Merge pull request #563 from midoks/dev
细节优化
2024-05-07 20:26:43 +08:00
Mr Chen c545062d07 Update index.py 2024-05-07 20:24:05 +08:00
Mr Chen e620fd67e3 Merge pull request #562 from midoks/dev
mongodb删除保护
2024-05-07 20:18:53 +08:00
Mr Chen aa9a412e9a mongodb删除保护 2024-05-07 20:18:23 +08:00
109 changed files with 8427 additions and 916 deletions
+24 -22
View File
@@ -87,6 +87,7 @@ venv/
ENV/
env.bak/
venv.bak/
lib/python*
# Spyder project settings
.spyderproject
@@ -98,6 +99,12 @@ venv.bak/
# mkdocs documentation
/site
bin
pyvenv.cfg
include
share
pip-selfcheck.json
# mypy
.mypy_cache/
@@ -108,7 +115,22 @@ tmp/*
*.swp
*.pem
*.zip
debug.out
mdioks.session-journal
*.session
logs/*
ssl/local
ssl/nginx
ssl/choose.pl
scripts/init.d/mw
scripts/mdserver-web
data/api_login.txt
data/sessions
data/*.db
data/iplist.txt
data/json/index.json
@@ -122,27 +144,11 @@ data/default.pl
data/backup.pl
data/debug.pl
data/default_site.pl
ssl/input.pl
lib/python*
bin
pyvenv.cfg
include
share
pip-selfcheck.json
scripts/init.d/mw
scripts/mdserver-web
data/api_login.txt
data/sessions
data/ssl.pl
data/port.pl
data/ipv6.pl
data/restart.pl
data/ssl.pl
data/edate.pl
data/osname.pl
data/only_netio_counters.pl
@@ -173,8 +179,4 @@ plugins/v2ray
plugins/frp
plugins/file_search
plugins/proxysql
debug.out
mdioks.session-journal
*.session
plugins/tidb
+3 -3
View File
@@ -18,7 +18,7 @@
[![Wiki](https://img.shields.io/badge/MW-Wiki-red?style=for-the-badge&logo=wiki)](https://github.com/midoks/mdserver-web/wiki)
[![](https://data.jsdelivr.com/v1/package/gh/midoks/mdserver-web/badge?style=for-the-badge)](https://www.jsdelivr.com/package/gh/midoks/mdserver-web)
[![jsdelivr](https://data.jsdelivr.com/v1/package/gh/midoks/mdserver-web/badge)](https://www.jsdelivr.com/package/gh/midoks/mdserver-web)
* SSH终端工具
* 面板收藏功能
@@ -110,9 +110,9 @@ docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:
```
### 版本更新 0.16.7
### 版本更新 0.17.1
- mongodb副本设置/备份/认证。
- 任务管理器-插件。
### JSDelivr安装地址
+318 -222
View File
@@ -28,7 +28,7 @@ from flask import request
class config_api:
__version = '0.16.7'
__version = '0.17.1'
__api_addr = 'data/api.json'
# 统一默认配置文件
@@ -42,7 +42,7 @@ class config_api:
'bind_domain' : 'data/bind_domain.pl', # 面板域名绑定
'unauth_status' : 'data/unauthorized_status.pl', # URL路径未成功显示状态
'auth_secret': 'data/auth_secret.pl', # 二次验证密钥
'ssl':'data/ssl.pl', # ssl设置
'ssl':'ssl/choose.pl', # ssl设置
'hook_database' : 'data/hook_database.json', # 数据库钩子
'hook_menu' : 'data/hook_menu.json', # 菜单钩子
'hook_global_static' : 'data/hook_global_static.json', # 静态文件钩子
@@ -362,19 +362,23 @@ class config_api:
return mw.getJson(cert)
def getPanelSslData(self):
cert = {}
keyPath = 'ssl/private.pem'
certPath = 'ssl/cert.pem'
rdata = {}
choose_file = self.__file['ssl']
rdata['choose'] = mw.readFile(choose_file)
keyPath = 'ssl/local/private.pem'
certPath = 'ssl/local/cert.pem'
if not os.path.exists(certPath):
# 不再自动生成证书
# mw.createSSL()
cert['privateKey'] = ''
cert['is_https'] = ''
cert['certPem'] = ''
cert['rep'] = os.path.exists('ssl/input.pl')
cert['info'] = {'endtime': 0, 'subject': '无',
'notAfter': '无', 'notBefore': '无', 'issuer': '无'}
return cert
mw.createLocalSSL()
cert = {}
cert['privateKey'] = mw.readFile(keyPath)
cert['is_https'] = ''
cert['certPem'] = mw.readFile(certPath)
cert['info'] = mw.getCertName(certPath)
rdata['local'] = cert
panel_ssl = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
if not os.path.exists(panel_ssl):
@@ -384,21 +388,68 @@ class config_api:
if ssl_data.find('$server_port !~ 443') != -1:
cert['is_https'] = 'checked'
keyPath = 'ssl/nginx/private.pem'
certPath = 'ssl/nginx/cert.pem'
cert = {}
cert['privateKey'] = mw.readFile(keyPath)
cert['certPem'] = mw.readFile(certPath)
cert['rep'] = os.path.exists('ssl/input.pl')
cert['info'] = mw.getCertName(certPath)
return cert
rdata['nginx'] = cert
return rdata
# 面板本地SSL设置
def setPanelLocalSslApi(self):
cert = {}
keyPath = 'ssl/local/private.pem'
certPath = 'ssl/local/cert.pem'
if not os.path.exists(certPath):
mw.createLocalSSL()
choose_file = self.__file['ssl']
mw.writeFile(choose_file, 'local')
mw.restartMw()
return mw.returnJson(True, '设置成功')
# 关闭SSL
def closePanelSslApi(self):
choose_file = self.__file['ssl']
if os.path.exists(choose_file):
os.remove(choose_file)
local_ssl = 'ssl/local'
if os.path.exists(local_ssl):
mw.execShell('rm -rf '+ local_ssl)
nginx_ssl = 'ssl/nginx'
if os.path.exists(nginx_ssl):
mw.execShell('rm -rf '+ nginx_ssl)
mw.restartMw()
return mw.returnJson(True, '关闭SSL成功')
# 保存面板证书
def savePanelSslApi(self):
keyPath = 'ssl/private.pem'
certPath = 'ssl/cert.pem'
checkCert = '/tmp/cert.pl'
choose = request.form.get('choose', '').strip()
certPem = request.form.get('certPem', '').strip()
privateKey = request.form.get('privateKey', '').strip()
if not mw.inArray(['local','nginx'], choose):
return mw.returnJson(True, '保存错误面板SSL类型!')
keyPath = 'ssl/'+choose+'/private.pem'
certPath = 'ssl/'+choose+'/cert.pem'
checkCert = '/tmp/cert.pl'
if not os.path.exists(keyPath):
return mw.returnJson(False, '【'+choose+'】SSL类型不存在,先申请!')
if(privateKey.find('KEY') == -1):
return mw.returnJson(False, '秘钥错误,请检查!')
if(certPem.find('CERTIFICATE') == -1):
@@ -411,258 +462,303 @@ class config_api:
mw.writeFile(certPath, certPem)
if not mw.checkCert(checkCert):
return mw.returnJson(False, '证书错误,请检查!')
mw.writeFile('ssl/input.pl', 'True')
return mw.returnJson(True, '证书已保存!')
# 设置面板SSL证书设置
def setPanelHttpToHttpsApi(self):
# def setPanelHttpToHttpsApi(self):
bind_domain = self.__file['bind_domain']
if not os.path.exists(bind_domain):
return mw.returnJson(False, '先要绑定域名!')
# bind_domain = self.__file['bind_domain']
# if not os.path.exists(bind_domain):
# return mw.returnJson(False, '先要绑定域名!')
keyPath = 'ssl/private.pem'
if not os.path.exists(keyPath):
return mw.returnJson(False, '未申请SSL证书!')
# choose_file = self.__file['ssl']
# choose = mw.readFile(choose_file)
# if choose == 'local':
# return mw.returnJson(False, '本地SSL无法使用!')
is_https = request.form.get('https', '').strip()
# keyPath = 'ssl/nginx/private.pem'
# if not os.path.exists(keyPath):
# return mw.returnJson(False, '未申请SSL证书!')
panel_ssl = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
if not os.path.exists(panel_ssl):
return mw.returnJson(False, '未开启面板SSL!')
# is_https = request.form.get('https', '').strip()
if is_https == 'false':
conf = mw.readFile(panel_ssl)
if conf:
if conf.find('ssl_certificate') == -1:
return mw.returnJson(False, '当前未开启SSL')
to = "#error_page 404/404.html;\n\
#HTTP_TO_HTTPS_START\n\
if ($server_port !~ 443){\n\
rewrite ^(/.*)$ https://$host$1 permanent;\n\
}\n\
#HTTP_TO_HTTPS_END"
conf = conf.replace('#error_page 404/404.html;', to)
mw.writeFile(panel_ssl, conf)
else:
conf = mw.readFile(panel_ssl)
if conf:
rep = "\n\\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
conf = re.sub(rep, '', conf)
rep = "\\s+if.+server_port.+\n.+\n\\s+\\s*}"
conf = re.sub(rep, '', conf)
mw.writeFile(panel_ssl, conf)
# panel_ssl = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
# if not os.path.exists(panel_ssl):
# return mw.returnJson(False, '未开启面板SSL!')
mw.restartWeb()
# if is_https == 'false':
# conf = mw.readFile(panel_ssl)
# if conf:
# if conf.find('ssl_certificate') == -1:
# return mw.returnJson(False, '当前未开启SSL')
# to = "#error_page 404/404.html;\n\
# #HTTP_TO_HTTPS_START\n\
# if ($server_port !~ 443){\n\
# rewrite ^(/.*)$ https://$host$1 permanent;\n\
# }\n\
# #HTTP_TO_HTTPS_END"
# conf = conf.replace('#error_page 404/404.html;', to)
# mw.writeFile(panel_ssl, conf)
# else:
# conf = mw.readFile(panel_ssl)
# if conf:
# rep = "\n\\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
# conf = re.sub(rep, '', conf)
# rep = "\\s+if.+server_port.+\n.+\n\\s+\\s*}"
# conf = re.sub(rep, '', conf)
# mw.writeFile(panel_ssl, conf)
action = '开启'
if is_https == 'true':
action = '关闭'
return mw.returnJson(True, action + 'HTTPS跳转成功!')
# mw.restartNginx()
# action = '开启'
# if is_https == 'true':
# action = '关闭'
# return mw.returnJson(True, action + 'HTTPS跳转成功!')
# 删除面板证书
def delPanelSslApi(self):
bind_domain = self.__file['bind_domain']
if not os.path.exists(bind_domain):
return mw.returnJson(False, '未绑定域名!')
ip = mw.getLocalIp()
if mw.isAppleSystem():
ip = '127.0.0.1'
siteName = mw.readFile(bind_domain).strip()
port = mw.readFile('data/port.pl').strip()
src_letpath = mw.getServerDir() + '/web_conf/letsencrypt/' + siteName
choose = request.form.get('choose', '').strip()
dst_letpath = mw.getRunDir() + '/ssl'
dst_csrpath = dst_letpath + '/cert.pem'
dst_keypath = dst_letpath + '/private.pem'
if not mw.inArray(['local','nginx'], choose):
return mw.returnJson(True, '删除错误面板SSL类型!')
if os.path.exists(src_letpath) or os.path.exists(dst_csrpath):
if os.path.exists(src_letpath):
mw.execShell('rm -rf ' + src_letpath)
if os.path.exists(dst_csrpath):
mw.execShell('rm -rf ' + dst_csrpath)
if os.path.exists(dst_keypath):
mw.execShell('rm -rf ' + dst_keypath)
# mw.restartWeb()
return mw.returnJson(True, '已经删除SSL!')
to_panel_url = 'http://'+ip+":"+port+'/config'
# mw.restartWeb()
return mw.returnJson(False, '已经不存在SSL!')
if choose == 'local':
dst_path = mw.getRunDir() + '/ssl/local'
ssl_file = self.__file['ssl']
if os.path.exists(dst_path):
mw.execShell('rm -rf ' + dst_path)
mw.execShell('rm -rf ' + ssl_file)
mw.restartMw();
return mw.returnJson(True, '删除本地面板SSL成功!',to_panel_url)
else:
return mw.returnJson(True, '已经删除本地面板SSL!',to_panel_url)
if choose == 'nginx':
bind_domain = self.__file['bind_domain']
if not os.path.exists(bind_domain):
return mw.returnJson(False, '未绑定域名!')
siteName = mw.readFile(bind_domain).strip()
src_path = mw.getServerDir() + '/web_conf/letsencrypt/' + siteName
dst_path = mw.getRunDir() + '/ssl/nginx'
dst_csrpath = dst_path + '/cert.pem'
dst_keypath = dst_path + '/private.pem'
if os.path.exists(src_path) or os.path.exists(dst_path):
if os.path.exists(src_letpath):
mw.execShell('rm -rf ' + src_letpath)
if os.path.exists(dst_csrpath):
mw.execShell('rm -rf ' + dst_csrpath)
if os.path.exists(dst_keypath):
mw.execShell('rm -rf ' + dst_keypath)
mw.restartNginx()
return mw.returnJson(True, '删除面板SSL成功!')
mw.restartNginx()
mw.restartMw()
return mw.returnJson(False, '已经删除面板SSL!')
return mw.returnJson(False, '未知类型!')
# 申请面板let证书
def applyPanelLetSslApi(self):
# def applyPanelAcmeSslApi(self):
# check domain is bind?
bind_domain = self.__file['bind_domain']
if not os.path.exists(bind_domain):
return mw.returnJson(False, '先要绑定域名!')
# bind_domain = self.__file['bind_domain']
# if not os.path.exists(bind_domain):
# return mw.returnJson(False, '先要绑定域名!')
siteName = mw.readFile(bind_domain).strip()
auth_to = mw.getRunDir() + "/tmp"
to_args = {
'domains': [siteName],
'auth_type': 'http',
'auth_to': auth_to,
}
# # 生成nginx配置
# domain = mw.readFile(bind_domain)
# panel_tpl = mw.getRunDir() + "/data/tpl/nginx_panel.conf"
# dst_panel_path = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
# if not os.path.exists(dst_panel_path):
# reg = r"^([\w\-\*]{1,100}\.){1,4}(\w{1,10}|\w{1,10}\.\w{1,10})$"
# if not re.match(reg, domain):
# return mw.returnJson(False, '主域名格式不正确')
src_letpath = mw.getServerDir() + '/web_conf/letsencrypt/' + siteName
src_csrpath = src_letpath + "/fullchain.pem" # 生成证书路径
src_keypath = src_letpath + "/privkey.pem" # 密钥文件路径
# op_dir = mw.getServerDir() + "/openresty"
# if not os.path.exists(op_dir):
# return mw.returnJson(False, '依赖OpenResty,先安装启动它!')
dst_letpath = mw.getRunDir() + '/ssl'
dst_csrpath = dst_letpath + '/cert.pem'
dst_keypath = dst_letpath + '/private.pem'
# content = mw.readFile(panel_tpl)
# content = content.replace("{$PORT}", "80")
# content = content.replace("{$SERVER_NAME}", domain)
# content = content.replace("{$PANAL_PORT}", mw.readFile('data/port.pl'))
# content = content.replace("{$LOGPATH}", mw.getRunDir() + '/logs')
# content = content.replace("{$PANAL_ADDR}", mw.getRunDir())
# mw.writeFile(dst_panel_path, content)
# mw.restartNginx()
is_already_apply = False
# siteName = mw.readFile(bind_domain).strip()
# auth_to = mw.getRunDir() + "/tmp"
# to_args = {
# 'domains': [siteName],
# 'auth_type': 'http',
# 'auth_to': auth_to,
# }
if not os.path.exists(src_letpath):
import cert_api
data = cert_api.cert_api().applyCertApi(to_args)
if not data['status']:
msg = data['msg']
if type(data['msg']) != str:
msg = data['msg'][0]
emsg = data['msg'][1]['challenges'][0]['error']
msg = msg + '<p><span>响应状态:</span>' + str(emsg['status']) + '</p><p><span>错误类型:</span>' + emsg[
'type'] + '</p><p><span>错误代码:</span>' + emsg['detail'] + '</p>'
return mw.returnJson(data['status'], msg, data['msg'])
else:
is_already_apply = True
# src_path = mw.getServerDir() + '/web_conf/letsencrypt/' + siteName
# src_csrpath = src_path + "/fullchain.pem" # 生成证书路径
# src_keypath = src_path + "/privkey.pem" # 密钥文件路径
mw.buildSoftLink(src_csrpath, dst_csrpath, True)
mw.buildSoftLink(src_keypath, dst_keypath, True)
mw.execShell('echo "lets" > "' + dst_letpath + '/README"')
# dst_path = mw.getRunDir() + '/ssl/nginx'
# dst_csrpath = dst_path + '/cert.pem'
# dst_keypath = dst_path + '/private.pem'
data = self.getPanelSslData()
# is_already_apply = False
tmp_well_know = auth_to + '/.well-known'
if os.path.exists(tmp_well_know):
mw.execShell('rm -rf ' + tmp_well_know)
# if not os.path.exists(src_path):
# import cert_api
# data = cert_api.cert_api().applyCertApi(to_args)
# if not data['status']:
# msg = data['msg']
# if type(data['msg']) != str:
# msg = data['msg'][0]
# emsg = data['msg'][1]['challenges'][0]['error']
# msg = msg + '<p><span>响应状态:</span>' + str(emsg['status']) + '</p><p><span>错误类型:</span>' + emsg[
# 'type'] + '</p><p><span>错误代码:</span>' + emsg['detail'] + '</p>'
# return mw.returnJson(data['status'], msg, data['msg'])
# else:
# is_already_apply = True
if is_already_apply:
return mw.returnJson(True, '重复申请!', data)
# mw.buildSoftLink(src_csrpath, dst_csrpath, True)
# mw.buildSoftLink(src_keypath, dst_keypath, True)
# mw.execShell('echo "acme" > "' + dst_path + '/README"')
return mw.returnJson(True, '申请成功!', data)
# tmp_well_know = auth_to + '/.well-known'
# if os.path.exists(tmp_well_know):
# mw.execShell('rm -rf ' + tmp_well_know)
# if os.path.exists(dst_path):
# choose_file = self.__file['ssl']
# mw.writeFile(choose_file, 'nginx')
# data = self.getPanelSslData()
# if is_already_apply:
# return mw.returnJson(True, '重复申请!', data)
# return mw.returnJson(True, '申请成功!', data)
def setPanelDomainApi(self):
domain = request.form.get('domain', '')
panel_tpl = mw.getRunDir() + "/data/tpl/nginx_panel.conf"
dst_panel_path = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
cfg_domain = self.__file['bind_domain']
port = mw.readFile('data/port.pl').strip()
ip = mw.getLocalIp()
if domain == '':
os.remove(cfg_domain)
os.remove(dst_panel_path)
mw.restartWeb()
return mw.returnJson(True, '清空域名成功!')
if os.path.exists(cfg_domain):
os.remove(cfg_domain)
reg = r"^([\w\-\*]{1,100}\.){1,4}(\w{1,10}|\w{1,10}\.\w{1,10})$"
if not re.match(reg, domain):
return mw.returnJson(False, '主域名格式不正确')
op_dir = mw.getServerDir() + "/openresty"
if not os.path.exists(op_dir):
return mw.returnJson(False, '依赖OpenResty,先安装启动它!')
content = mw.readFile(panel_tpl)
content = content.replace("{$PORT}", "80")
content = content.replace("{$SERVER_NAME}", domain)
content = content.replace("{$PANAL_PORT}", mw.readFile('data/port.pl'))
content = content.replace("{$LOGPATH}", mw.getRunDir() + '/logs')
content = content.replace("{$PANAL_ADDR}", mw.getRunDir())
mw.writeFile(dst_panel_path, content)
mw.restartWeb()
to_panel_url = 'http://'+ip+":"+port+'/config'
mw.restartMw()
return mw.returnJson(True, '清空域名成功!', to_panel_url)
mw.writeFile(cfg_domain, domain)
return mw.returnJson(True, '设置域名成功!')
to_panel_url = 'http://'+domain+":"+port+'/config'
mw.restartMw()
return mw.returnJson(True, '设置域名成功!',to_panel_url)
# 设置面板SSL
def setPanelSslApi(self):
sslConf = mw.getRunDir() + '/' + self.__file['ssl']
# def setPanelSslApi(self):
# sslConf = mw.getRunDir() + '/' + self.__file['ssl']
panel_tpl = mw.getRunDir() + "/data/tpl/nginx_panel.conf"
dst_panel_path = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
if os.path.exists(sslConf):
os.system('rm -f ' + sslConf)
# panel_tpl = mw.getRunDir() + "/data/tpl/nginx_panel.conf"
# dst_panel_path = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
# if os.path.exists(sslConf):
# os.system('rm -f ' + sslConf)
conf = mw.readFile(dst_panel_path)
if conf:
rep = "\\s+ssl_certificate\\s+.+;\\s+ssl_certificate_key\\s+.+;"
conf = re.sub(rep, '', conf)
rep = "\\s+ssl_protocols\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\\s+ssl_ciphers\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\\s+ssl_prefer_server_ciphers\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\\s+ssl_session_cache\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\\s+ssl_session_timeout\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\\s+ssl_ecdh_curve\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\\s+ssl_session_tickets\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\\s+ssl_stapling\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\\s+ssl_stapling_verify\\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\\s+ssl\\s+on;"
conf = re.sub(rep, '', conf)
rep = "\\s+error_page\\s497.+;"
conf = re.sub(rep, '', conf)
rep = "\\s+if.+server_port.+\n.+\n\\s+\\s*}"
conf = re.sub(rep, '', conf)
rep = "\\s+listen\\s+443.*;"
conf = re.sub(rep, '', conf)
rep = "\\s+listen\\s+\\[\\:\\:\\]\\:443.*;"
conf = re.sub(rep, '', conf)
mw.writeFile(dst_panel_path, conf)
# conf = mw.readFile(dst_panel_path)
# if conf:
# rep = "\\s+ssl_certificate\\s+.+;\\s+ssl_certificate_key\\s+.+;"
# conf = re.sub(rep, '', conf)
# rep = "\\s+ssl_protocols\\s+.+;\n"
# conf = re.sub(rep, '', conf)
# rep = "\\s+ssl_ciphers\\s+.+;\n"
# conf = re.sub(rep, '', conf)
# rep = "\\s+ssl_prefer_server_ciphers\\s+.+;\n"
# conf = re.sub(rep, '', conf)
# rep = "\\s+ssl_session_cache\\s+.+;\n"
# conf = re.sub(rep, '', conf)
# rep = "\\s+ssl_session_timeout\\s+.+;\n"
# conf = re.sub(rep, '', conf)
# rep = "\\s+ssl_ecdh_curve\\s+.+;\n"
# conf = re.sub(rep, '', conf)
# rep = "\\s+ssl_session_tickets\\s+.+;\n"
# conf = re.sub(rep, '', conf)
# rep = "\\s+ssl_stapling\\s+.+;\n"
# conf = re.sub(rep, '', conf)
# rep = "\\s+ssl_stapling_verify\\s+.+;\n"
# conf = re.sub(rep, '', conf)
# rep = "\\s+ssl\\s+on;"
# conf = re.sub(rep, '', conf)
# rep = "\\s+error_page\\s497.+;"
# conf = re.sub(rep, '', conf)
# rep = "\\s+if.+server_port.+\n.+\n\\s+\\s*}"
# conf = re.sub(rep, '', conf)
# rep = "\\s+listen\\s+443.*;"
# conf = re.sub(rep, '', conf)
# rep = "\\s+listen\\s+\\[\\:\\:\\]\\:443.*;"
# conf = re.sub(rep, '', conf)
# mw.writeFile(dst_panel_path, conf)
mw.writeLog('面板配置', '面板SSL关闭成功!')
mw.restartWeb()
return mw.returnJson(True, 'SSL已关闭,请使用http协议访问面板!')
else:
try:
mw.writeFile(sslConf, 'True')
# mw.writeLog('面板配置', '面板SSL关闭成功!')
# mw.restartWeb()
# return mw.returnJson(True, 'SSL已关闭,请使用http协议访问面板!')
# else:
# try:
# mw.writeFile(sslConf, 'True')
keyPath = mw.getRunDir() + '/ssl/private.pem'
certPath = mw.getRunDir() + '/ssl/cert.pem'
# keyPath = mw.getRunDir() + '/ssl/private.pem'
# certPath = mw.getRunDir() + '/ssl/cert.pem'
conf = mw.readFile(dst_panel_path)
if conf:
if conf.find('ssl_certificate') == -1:
sslStr = """#error_page 404/404.html;
ssl_certificate %s;
ssl_certificate_key %s;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
error_page 497 https://$host$request_uri;""" % (certPath, keyPath)
if(conf.find('ssl_certificate') != -1):
return mw.returnJson(True, 'SSL开启成功!')
# conf = mw.readFile(dst_panel_path)
# if conf:
# if conf.find('ssl_certificate') == -1:
# sslStr = """#error_page 404/404.html;
# ssl_certificate %s;
# ssl_certificate_key %s;
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
# ssl_prefer_server_ciphers on;
# ssl_session_cache shared:SSL:10m;
# ssl_session_timeout 10m;
# error_page 497 https://$host$request_uri;""" % (certPath, keyPath)
# if(conf.find('ssl_certificate') != -1):
# return mw.returnJson(True, 'SSL开启成功!')
conf = conf.replace('#error_page 404/404.html;', sslStr)
# conf = conf.replace('#error_page 404/404.html;', sslStr)
rep = "listen\\s+([0-9]+)\\s*[default_server]*;"
tmp = re.findall(rep, conf)
if not mw.inArray(tmp, '443'):
listen = re.search(rep, conf).group()
http_ssl = "\n\tlisten 443 ssl http2;"
http_ssl = http_ssl + "\n\tlisten [::]:443 ssl http2;"
conf = conf.replace(listen, listen + http_ssl)
# rep = "listen\\s+([0-9]+)\\s*[default_server]*;"
# tmp = re.findall(rep, conf)
# if not mw.inArray(tmp, '443'):
# listen = re.search(rep, conf).group()
# http_ssl = "\n\tlisten 443 ssl http2;"
# http_ssl = http_ssl + "\n\tlisten [::]:443 ssl http2;"
# conf = conf.replace(listen, listen + http_ssl)
mw.backFile(dst_panel_path)
mw.writeFile(dst_panel_path, conf)
isError = mw.checkWebConfig()
if(isError != True):
mw.restoreFile(dst_panel_path)
return mw.returnJson(False, '证书错误: <br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>')
except Exception as ex:
return mw.returnJson(False, '开启失败:' + str(ex))
mw.restartWeb()
return mw.returnJson(True, '开启成功,请使用https协议访问面板!')
# mw.backFile(dst_panel_path)
# mw.writeFile(dst_panel_path, conf)
# isError = mw.checkWebConfig()
# if(isError != True):
# mw.restoreFile(dst_panel_path)
# return mw.returnJson(False, '证书错误: <br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>')
# except Exception as ex:
# return mw.returnJson(False, '开启失败:' + str(ex))
# mw.restartWeb()
# return mw.returnJson(True, '开启成功,请使用https协议访问面板!')
def getApi(self):
data = {}
@@ -958,7 +1054,7 @@ class config_api:
mw.writeFile(auth, crypt_data)
ip = mw.getHostAddr()
url = pyotp.totp.TOTP(sec).provisioning_uri(name=ip, issuer_name='mdserver-web')
url = pyotp.totp.TOTP(sec).provisioning_uri(name=ip, issuer_name=tag)
rdata = {}
rdata['secret'] = sec
+5
View File
@@ -42,8 +42,13 @@ class Sql():
self.__DB_CONN = sqlite3.connect(self.__DB_FILE)
self.__DB_CONN.text_factory = str
except Exception as ex:
# print(mw.getTracebackInfo())
return "error: " + str(ex)
def changeTextFactoryToBytes(self):
self.__DB_CONN.text_factory = bytes
return True
def autoTextFactory(self):
if sys.version_info[0] == 3:
self.__DB_CONN.text_factory = lambda x: str(
+15
View File
@@ -121,6 +121,7 @@ class files_api:
def fileAccessApi(self):
filename = request.form.get('filename', '')
data = self.getAccess(filename)
data['sys_users'] = self.getSysUserList()
return mw.getJson(data)
def setFileAccessApi(self):
@@ -933,6 +934,20 @@ class files_api:
data['chown'] = 'www'
return data
def getSysUserList(self):
pwd_file = '/etc/passwd'
if os.path.exists(pwd_file):
content = mw.readFile(pwd_file)
clist = content.split('\n')
sys_users = []
for line in clist:
if line.find(":")<0:
continue
lines = line.split(":",1)
sys_users.append(lines[0])
return sys_users
return ['root','mysql','www']
# 计算文件数量
def getCount(self, path, search):
i = 0
+68 -24
View File
@@ -79,10 +79,11 @@ def getRootDir():
def getPluginDir():
return getRunDir() + '/plugins'
def getPanelDataDir():
return getRunDir() + '/data'
def getMWLogs():
return getRunDir() + '/logs'
def getPanelTmp():
return getRunDir() + '/tmp'
@@ -346,6 +347,9 @@ def restartMw():
import system_api
system_api.system_api().restartMw()
def restartNginx(self):
writeFile('data/restart_nginx.pl', 'True')
return True
def checkWebConfig():
op_dir = getServerDir() + '/openresty/nginx'
@@ -1287,25 +1291,46 @@ def checkDomainPanel():
domain = readFile('data/bind_domain.pl')
port = readFile('data/port.pl').strip()
npid = getServerDir() + "/openresty/nginx/logs/nginx.pid"
if not os.path.exists(npid):
scheme = 'http'
choose_file = getRunDir()+'/ssl/choose.pl'
if os.path.exists(choose_file):
choose = readFile(choose_file).strip()
if not inArray(['local','nginx'], choose):
return False
else:
return False
nconf = getServerDir() + "/web_conf/nginx/vhost/panel.conf"
if os.path.exists(nconf):
port = "80"
local_ssl = getRunDir()+'/ssl/local'
if choose == 'local':
scheme = 'https'
if domain:
client_ip = getClientIp()
if client_ip in ['127.0.0.1', 'localhost', '::1']:
if choose == 'nginx':
# print(port)
npid = getServerDir() + "/openresty/nginx/logs/nginx.pid"
if not os.path.exists(npid):
return False
if tmp.strip().lower() != domain.strip().lower():
from flask import Flask, redirect, request, url_for
to = "http://" + domain + ":" + str(port)
return redirect(to, code=302)
nconf = getServerDir() + "/web_conf/nginx/vhost/panel.conf"
if os.path.exists(nconf):
port = "80"
if not domain:
return False
client_ip = getClientIp()
if client_ip in ['127.0.0.1', 'localhost', '::1']:
return False
if tmp.strip().lower() != domain.strip().lower():
from flask import Flask, redirect, request, url_for
to = scheme + "://" + domain + ":" + str(port)
# print(to)
return redirect(to, code=302)
return False
def createLinuxUser(user, group):
execShell("groupadd {}".format(group))
execShell('useradd -s /sbin/nologin -g {} {}'.format(user, group))
@@ -1441,7 +1466,7 @@ def makeConf():
file = getRunDir() + '/data/json/config.json'
if not os.path.exists(file):
c = {}
c['title'] = '老子面板'
c['title'] = '后羿面板'
c['home'] = 'http://github/midoks/mdserver-web'
c['recycle_bin'] = True
c['template'] = 'default'
@@ -1810,28 +1835,38 @@ def getCertName(certPath):
return None
def createSSL():
def createLocalSSL():
if not os.path.exists('ssl/local'):
execShell('mkdir -p ssl/local')
# 自签证书
if os.path.exists('ssl/input.pl'):
return True
# if os.path.exists('ssl/local/input.pl'):
# return True
client_ip = getClientIp()
import OpenSSL
key = OpenSSL.crypto.PKey()
key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
cert = OpenSSL.crypto.X509()
cert.set_serial_number(0)
cert.get_subject().CN = getLocalIp()
if client_ip == '127.0.0.1':
cert.get_subject().CN = '127.0.0.1'
else:
cert.get_subject().CN = getLocalIp()
cert.set_issuer(cert.get_subject())
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(86400 * 3650)
cert.set_pubkey(key)
cert.sign(key, 'md5')
cert_ca = OpenSSL.crypto.dump_certificate(
OpenSSL.crypto.FILETYPE_PEM, cert)
private_key = OpenSSL.crypto.dump_privatekey(
OpenSSL.crypto.FILETYPE_PEM, key)
cert_ca = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
private_key = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key)
if len(cert_ca) > 100 and len(private_key) > 100:
writeFile('ssl/cert.pem', cert_ca, 'wb+')
writeFile('ssl/private.pem', private_key, 'wb+')
writeFile('ssl/local/cert.pem', cert_ca, 'wb+')
writeFile('ssl/local/private.pem', private_key, 'wb+')
return True
return False
@@ -2075,6 +2110,15 @@ def notifyMessage(msg, stype='common', trigger_time=300, is_write_log=True):
##################### notify end #########################################
def getGlibcVersion():
try:
cmd_result = execShell("ldd --version")[0]
if not cmd_result: return ''
glibc_version = cmd_result.split("\n")[0].split()[-1]
except:
return ''
return glibc_version
##################### ssh start #########################################
def getSshDir():
if isAppleSystem():
+17 -6
View File
@@ -1960,6 +1960,19 @@ class site_api:
proxy_site_path) if os.path.exists(proxy_site_path) else ""
data = json.loads(data_content) if data_content != "" else []
proxy_action = 'add'
if _id == "":
_id = mw.md5("{}".format(_name))
else:
proxy_action = 'edit'
if proxy_action == "add":
for item in data:
if item["name"] == _name:
return mw.returnJson(False, "名称重复!!")
if item["from"] == _from:
return mw.returnJson(False, "代理目录已存在!!")
tpl = "#PROXY-START\n\
location ^~ {from} {\n\
proxy_pass {to};\n\
@@ -2016,15 +2029,9 @@ location ^~ {from} {\n\
else:
tpl = tpl.replace("{proxy_cache}", tpl_proxy_nocache, 999)
proxy_action = 'add'
if _id == "":
_id = mw.md5("{}".format(_name))
else:
proxy_action = 'edit'
conf_proxy = "{}/{}.conf".format(self.getProxyPath(_siteName), _id)
conf_bk = "{}/{}.conf.txt".format(self.getProxyPath(_siteName), _id)
mw.writeFile(conf_proxy, tpl)
rule_test = mw.checkWebConfig()
@@ -2655,6 +2662,10 @@ location ^~ {from} {\n\
mw.writeFile(rewrite_file, '')
def add(self, webname, port, ps, path, version):
site_root_dir = mw.getWwwDir()
if site_root_dir == path.rstrip('/'):
return mw.returnJson(False, '不要以网站根目录创建站点!')
siteMenu = json.loads(webname)
self.siteName = self.toPunycode(
siteMenu['domain'].strip().split(':')[0]).strip()
+120
View File
@@ -0,0 +1,120 @@
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# SSH终端操作
# ---------------------------------------------------------------------------------
import json
import time
import os
import sys
import socket
import threading
import re
from io import BytesIO, StringIO
import mw
import paramiko
from flask_socketio import SocketIO, emit, send
class ssh_local(object):
__debug_file = 'logs/ssh_local.log'
__log_type = 'SSH终端'
__ssh = None
# lock
_instance_lock = threading.Lock()
def __init__(self):
pass
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(ssh_local, "_instance"):
with ssh_local._instance_lock:
if not hasattr(ssh_local, "_instance"):
ssh_local._instance = ssh_local(*args, **kwargs)
return ssh_local._instance
def debug(self, msg):
msg = "{} - {}:{} => {} \n".format(mw.formatDate(),
self.__host, self.__port, msg)
if not mw.isDebugMode():
return
mw.writeFile(self.__debug_file, msg, 'a+')
def returnMsg(self, status, msg):
return {'status': status, 'msg': msg}
def connectSsh(self):
import paramiko
ssh = paramiko.SSHClient()
mw.createSshInfo()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
port = mw.getSSHPort()
try:
ssh.connect('127.0.0.1', port, timeout=5)
except Exception as e:
ssh.connect('localhost', port, timeout=5)
except Exception as e:
ssh.connect(mw.getHostAddr(), port, timeout=30)
except Exception as e:
return False
shell = ssh.invoke_shell(term='xterm', width=83, height=21)
shell.setblocking(0)
return shell
def send(self):
pass
def close(self):
try:
if self.__ssh:
self.__ssh.close()
except:
pass
def wsSend(self, recv):
try:
t = recv.decode("utf-8")
return emit('server_response', {'data': t})
except Exception as e:
return emit('server_response', {'data': recv})
def wsSendConnect(self):
return emit('connect', {'data': 'ok'})
def wsSendReConnect(self):
return emit('reconnect', {'data': 'ok'})
def run(self, info):
if not self.__ssh:
self.__ssh = self.connectSsh()
if self.__ssh.exit_status_ready():
self.__ssh = self.connectSsh()
self.__ssh.send(info)
try:
time.sleep(0.005)
recv = self.__ssh.recv(8192)
return self.wsSend(recv)
except Exception as ex:
return self.wsSend('')
+13 -2
View File
@@ -28,9 +28,9 @@ import paramiko
from flask_socketio import SocketIO, emit, send
class ssh_terminal:
class ssh_terminal(object):
__debug_file = 'logs/terminal.log'
__debug_file = 'logs/ssh_terminal.log'
__log_type = 'SSH终端'
# websocketio 唯一标识
@@ -55,10 +55,21 @@ class ssh_terminal:
__ssh_list = {}
__ssh_last_request_time = {}
# lock
_instance_lock = threading.Lock()
def __init__(self):
ht = threading.Thread(target=self.heartbeat)
ht.start()
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(ssh_terminal, "_instance"):
with ssh_terminal._instance_lock:
if not hasattr(ssh_terminal, "_instance"):
ssh_terminal._instance = ssh_terminal(*args, **kwargs)
return ssh_terminal._instance
def debug(self, msg):
msg = "{} - {}:{} => {} \n".format(mw.formatDate(),
self.__host, self.__port, msg)
+168 -25
View File
@@ -44,10 +44,11 @@ def mw_async(f):
class system_api:
setupPath = None
pids = None
cache = {}
def __init__(self):
self.setupPath = mw.getServerDir()
##### ----- start ----- ###
def networkApi(self):
data = self.getNetWork()
@@ -254,8 +255,7 @@ class system_api:
data['load_average'] = self.GetLoadAverage(get)
data['title'] = self.GetTitle()
data['network'] = self.GetNetWorkApi(get)
data['panel_status'] = not os.path.exists(
'/www/server/mdserver-web/data/close.pl')
data['panel_status'] = not os.path.exists('/www/server/mdserver-web/data/close.pl')
import firewalls
ssh_info = firewalls.firewalls().GetSshInfo(None)
data['enable_ssh_status'] = ssh_info['status']
@@ -488,7 +488,7 @@ class system_api:
shutil.rmtree(filename)
else:
os.remove(filename)
print('mail clear ok')
# print('mail clear ok')
num += 1
total += size
count += num
@@ -547,38 +547,181 @@ class system_api:
def getNetWork(self):
# 取网络流量信息
try:
# 取网络流量信息
networkIo = self.psutilNetIoCounters()
if not "otime" in session:
session['up'] = networkIo[0]
session['down'] = networkIo[1]
session['otime'] = time.time()
ntime = time.time()
networkInfo = {}
networkInfo['upTotal'] = networkIo[0]
networkInfo['downTotal'] = networkIo[1]
networkInfo['up'] = round(float(
networkIo[0] - session['up']) / (ntime - session['otime']), 2)
networkInfo['down'] = round(
float(networkIo[1] - session['down']) / (ntime - session['otime']), 2)
networkInfo['downPackets'] = networkIo[3]
networkInfo['upPackets'] = networkIo[2]
# 取网络流量信息
# networkIo = self.psutilNetIoCounters()
# if not "otime" in session:
# session['up'] = networkIo[0]
# session['down'] = networkIo[1]
# session['otime'] = time.time()
# print networkIo[1], session['down'], ntime, session['otime']
session['up'] = networkIo[0]
session['down'] = networkIo[1]
session['otime'] = time.time()
# ntime = time.time()
# print("source",ntime - session['otime'])
# networkInfo['upTotal'] = networkIo[0]
# networkInfo['downTotal'] = networkIo[1]
# networkInfo['up'] = round(float(
# networkIo[0] - session['up']) / (ntime - session['otime']), 2)
# networkInfo['down'] = round(
# float(networkIo[1] - session['down']) / (ntime - session['otime']), 2)
# networkInfo['downPackets'] = networkIo[3]
# networkInfo['upPackets'] = networkIo[2]
# # print networkIo[1], session['down'], ntime, session['otime']
# session['up'] = networkIo[0]
# session['down'] = networkIo[1]
# session['otime'] = time.time()
networkInfo['cpu'] = self.getCpuInfo()
networkInfo['load'] = self.getLoadAverage()
networkInfo['mem'] = self.getMemInfo()
networkInfo['iostat'] = self.getDiskIostat()
networkInfo['network'] = self.getNetWorkIostat()
return networkInfo
except Exception as e:
print("getNetWork error:", e)
print(mw.getTracebackInfo())
return None
def getNetWorkIostat(self):
netInfo = {}
netInfo['ALL'] = {}
netInfo['ALL']['up'] = 0
netInfo['ALL']['down'] = 0
netInfo['ALL']['upTotal'] = 0
netInfo['ALL']['downTotal'] = 0
netInfo['ALL']['upPackets'] = 0
netInfo['ALL']['downPackets'] = 0
mtime = time.time()
iokey = 'netstat'
netio = None
if iokey in self.cache:
netio = self.cache[iokey]
if not netio:
netio = {}
netio['info'] = None
netio['all_io'] = None
netio['time'] = mtime
stime = mtime - netio['time']
if not stime: stime = 1
# print("new:",stime)
netio_group = psutil.net_io_counters(pernic=True).keys()
netio_cache = netio['info']
allio_cache = netio['all_io']
if not netio_cache:
netio_cache = {}
netio_group_t = {}
for name in netio_group:
netInfo[name] = {}
io_data = psutil.net_io_counters(pernic=True).get(name)
if not name in netio_cache:
netio_cache[name] = io_data
netio_group_t[name] = io_data
netInfo[name]['up'] = round(float((io_data[0] - netio_cache[name][0]) / stime), 2)
netInfo[name]['down'] = round(float((io_data[1] - netio_cache[name][1])/ stime), 2)
netInfo[name]['upTotal'] = io_data[0]
netInfo[name]['downTotal'] = io_data[1]
netInfo[name]['upPackets'] = io_data[2]
netInfo[name]['downPackets'] = io_data[3]
all_io = psutil.net_io_counters()[:4]
if not allio_cache:
allio_cache = all_io
netInfo['ALL']['up'] = round(float((all_io[0] - allio_cache[0]) /stime), 2)
netInfo['ALL']['down'] = round(float((all_io[1] - allio_cache[1]) /stime), 2)
netInfo['ALL']['upTotal'] = all_io[0]
netInfo['ALL']['downTotal'] = all_io[1]
netInfo['ALL']['upPackets'] = all_io[2]
netInfo['ALL']['downPackets'] = all_io[3]
self.cache[iokey] = {'info':netio_group_t,'all_io':all_io,'time':mtime}
return netInfo
def getDiskIostat(self):
iokey = 'iostat'
diskInfo = {}
diskInfo['ALL'] = {}
diskInfo['ALL']['read_count'] = 0
diskInfo['ALL']['write_count'] = 0
diskInfo['ALL']['read_bytes'] = 0
diskInfo['ALL']['write_bytes'] = 0
diskInfo['ALL']['read_time'] = 0
diskInfo['ALL']['write_time'] = 0
diskInfo['ALL']['read_merged_count'] = 0
diskInfo['ALL']['write_merged_count'] = 0
try:
diskio = None
if iokey in self.cache:
diskio = self.cache[iokey]
mtime = int(time.time())
if not diskio:
diskio = {}
diskio['info'] = None
diskio['time'] = mtime
diskio_cache = diskio['info']
stime = mtime - diskio['time']
if not stime: stime = 1
diskio_group = psutil.disk_io_counters(perdisk=True)
if not diskio_cache:
diskio_cache = diskio_group
for disk_name in diskio_group.keys():
diskInfo[disk_name] = {}
# print('disk_name',disk_name)
# print(diskio_group[disk_name].write_time , diskio_cache[disk_name].write_time)
# print(diskio_group[disk_name].write_count , diskio_cache[disk_name].write_count)
diskInfo[disk_name]['read_count'] = int((diskio_group[disk_name].read_count - diskio_cache[disk_name].read_count) / stime)
diskInfo[disk_name]['write_count'] = int((diskio_group[disk_name].write_count - diskio_cache[disk_name].write_count) / stime)
diskInfo[disk_name]['read_bytes'] = int((diskio_group[disk_name].read_bytes - diskio_cache[disk_name].read_bytes) / stime)
diskInfo[disk_name]['write_bytes'] = int((diskio_group[disk_name].write_bytes - diskio_cache[disk_name].write_bytes) / stime)
diskInfo[disk_name]['read_time'] = int((diskio_group[disk_name].read_time - diskio_cache[disk_name].read_time) / stime)
diskInfo[disk_name]['write_time'] = int((diskio_group[disk_name].write_time - diskio_cache[disk_name].write_time) / stime)
if 'read_merged_count' in diskio_group[disk_name] and 'read_merged_count' in diskio_cache[disk_name]:
diskInfo[disk_name]['read_merged_count'] = int((diskio_group[disk_name].read_merged_count - diskio_cache[disk_name].read_merged_count) / stime)
if 'write_merged_count' in diskio_group[disk_name] and 'write_merged_count' in diskio_cache[disk_name]:
diskInfo[disk_name]['write_merged_count'] = int((diskio_group[disk_name].write_merged_count - diskio_cache[disk_name].write_merged_count) / stime)
diskInfo['ALL']['read_count'] += diskInfo[disk_name]['read_count']
diskInfo['ALL']['write_count'] += diskInfo[disk_name]['write_count']
diskInfo['ALL']['read_bytes'] += diskInfo[disk_name]['read_bytes']
diskInfo['ALL']['write_bytes'] += diskInfo[disk_name]['write_bytes']
if diskInfo['ALL']['read_time'] < diskInfo[disk_name]['read_time']:
diskInfo['ALL']['read_time'] = diskInfo[disk_name]['read_time']
if diskInfo['ALL']['write_time'] < diskInfo[disk_name]['write_time']:
diskInfo['ALL']['write_time'] = diskInfo[disk_name]['write_time']
if 'read_merged_count' in diskInfo[disk_name] and 'read_merged_count' in diskInfo[disk_name]:
diskInfo['ALL']['read_merged_count'] += diskInfo[disk_name]['read_merged_count']
if 'write_merged_count' in diskInfo[disk_name] and 'write_merged_count' in diskInfo[disk_name]:
diskInfo['ALL']['write_merged_count'] += diskInfo[disk_name]['write_merged_count']
self.cache[iokey] = {'info':diskio_group,'time':mtime}
except Exception as e:
# print(mw.getTracebackInfo())
pass
return diskInfo
def getNetWorkIoData(self, start, end):
# 取指定时间段的网络Io
data = mw.M('network').dbfile('system').where("addtime>=? AND addtime<=?", (start, end)).field(
+29 -5
View File
@@ -17,37 +17,50 @@ class ORM:
__DB_CUR = None
__DB_ERR = None
__DB_CNF = '/etc/my.cnf'
__DB_TIMEOUT=1
__DB_SOCKET = '/www/server/mysql/mysql.sock'
__DB_CHARSET = "utf8"
def __Conn(self):
# print(self.__DB_HOST, self.__DB_USER)
'''连接数据库'''
try:
if os.path.exists(self.__DB_SOCKET):
if self.__DB_HOST != 'localhost':
try:
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
database=self.__DB_NAME,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=self.__DB_TIMEOUT,
cursorclass=pymysql.cursors.DictCursor)
except Exception as e:
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
database=self.__DB_NAME,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=self.__DB_TIMEOUT,
cursorclass=pymysql.cursors.DictCursor)
elif os.path.exists(self.__DB_SOCKET):
try:
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
database=self.__DB_NAME,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=self.__DB_TIMEOUT,
unix_socket=self.__DB_SOCKET, cursorclass=pymysql.cursors.DictCursor)
except Exception as e:
self.__DB_HOST = '127.0.0.1'
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
database=self.__DB_NAME,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=self.__DB_TIMEOUT,
unix_socket=self.__DB_SOCKET, cursorclass=pymysql.cursors.DictCursor)
else:
try:
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
database=self.__DB_NAME,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=self.__DB_TIMEOUT,
cursorclass=pymysql.cursors.DictCursor)
except Exception as e:
self.__DB_HOST = '127.0.0.1'
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
database=self.__DB_NAME,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=self.__DB_TIMEOUT,
cursorclass=pymysql.cursors.DictCursor)
self.__DB_CUR = self.__DB_CONN.cursor()
@@ -80,6 +93,10 @@ class ORM:
def getPwd(self):
return self.__DB_PASS
def setTimeout(self, timeout = 1):
self.__DB_TIMEOUT = timeout
return True
def setDbName(self, name):
self.__DB_NAME = name
@@ -95,6 +112,13 @@ class ORM:
except Exception as ex:
return ex
def ping(self):
try:
self.__DB_CONN.ping()
except Exception as e:
print(e)
return True
def query(self, sql):
# 执行SQL语句返回数据集
if not self.__Conn():
+9
View File
@@ -64,6 +64,11 @@ mw_start_debug2(){
gunicorn -b :7200 -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 app:app
}
mw_start_debug3(){
gunicorn -c setting.py app:app
python3 task.py
}
mw_stop()
{
@@ -96,4 +101,8 @@ case "$1" in
mw_stop
mw_start_debug2
;;
'debug3')
mw_stop
mw_start_debug3
;;
esac
+2 -1
View File
@@ -5,7 +5,8 @@
```
/etc/init.d/mw default | 显示登录信息
/etc/init.d/mw db | 快捷连接数据库
/etc/init.d/mw db | 快捷连接MySQL
/etc/init.d/mw redis | 快捷连接Redis
----------------------------------------
mw open | 开启面板
mw close | 关闭面板
+1 -1
View File
@@ -17,7 +17,7 @@ pluginService('clean');
function pRead(){
var readme = '<ul class="help-info-text c7">';
readme += '<li>启动后,加入到计划中[2:30]执行。</li>';
readme += '<li>启动后,加入到计划任务每隔7天[0:15]执行。</li>';
readme += '<li>【*】代表要删除。</li>';
readme += '<li>添加/删除清除日志,可在`配置修改`中添加/删除。</li>';
readme += '<li>如果是目录,会寻找【.log】后缀的文件清空。</li>';
+21 -1
View File
@@ -99,7 +99,27 @@ def initConf():
"/var/log/secure",
"/var/log/lastlog",
"/var/log/cron",
"/www/server/cron"
"/www/server/rsyncd",
"/www/server/sphinx/index",
"/www/server/mongodb/logs",
"/www/server/php/53/var/log",
"/www/server/php/54/var/log",
"/www/server/php/55/var/log",
"/www/server/php/56/var/log",
"/www/server/php/70/var/log",
"/www/server/php/71/var/log",
"/www/server/php/72/var/log",
"/www/server/php/73/var/log",
"/www/server/php/74/var/log",
"/www/server/php/80/var/log",
"/www/server/php/81/var/log",
"/www/server/php/82/var/log",
"/www/server/php/83/var/log",
"/www/server/php/84/var/log",
"/www/server/openresty/nginx/logs",
"/www/server/phpmyadmin",
"/www/server/redis/data",
"/www/server/cron",
]
for i in clogcom:
if os.path.exists(i):
+30 -57
View File
@@ -37,57 +37,36 @@ def getConfigData():
return json.loads(mw.readFile(getTaskConf()))
except:
pass
return []
def getConfigTpl():
tpl = {
"name": "",
return {
"task_id": -1,
"period": "day-n",
"where1": "7",
"hour": "0",
"minute": "15",
}
return tpl
def createBgTask():
removeBgTask()
args = {
"period": "day",
"hour": "0",
"minute": "15",
}
createBgTaskByName(getPluginName(), args)
createBgTaskByName(getPluginName())
def createBgTaskByName(name, args):
cfg = getConfigTpl()
def createBgTaskByName(name):
args = getConfigData()
_name = "[勿删]日志清理[" + name + "]"
res = mw.M("crontab").field("id, name").where("name=?", (_name,)).find()
if res:
return True
if "task_id" in cfg.keys() and cfg["task_id"] > 0:
if "task_id" in args and args["task_id"] > 0:
res = mw.M("crontab").field("id, name").where(
"id=?", (cfg["task_id"],)).find()
if res and res["id"] == cfg["task_id"]:
"id=?", (args["task_id"],)).find()
if res and res["id"] == args["task_id"]:
print("计划任务已经存在!")
return True
import crontab_api
api = crontab_api.crontab_api()
period = args['period']
_hour = ''
_minute = ''
_where1 = ''
_type_day = "day"
if period == 'day':
_type_day = 'day'
_hour = args['hour']
_minute = args['minute']
elif period == 'minute-n':
_type_day = 'minute-n'
_where1 = args['minute-n']
_minute = ''
mw_dir = mw.getRunDir()
cmd = '''
mw_dir=%s
@@ -105,11 +84,11 @@ logs_file=$plugin_path/${rname}.log
params = {
'name': _name,
'type': _type_day,
'type': args['period'],
'week': "",
'where1': _where1,
'hour': _hour,
'minute': _minute,
'where1': args['where1'],
'hour': args['hour'],
'minute': args['minute'],
'save': "",
'backup_to': "",
'stype': "toShell",
@@ -120,30 +99,24 @@ logs_file=$plugin_path/${rname}.log
task_id = api.add(params)
if task_id > 0:
cfg["task_id"] = task_id
cfg["name"] = name
_dd = getConfigData()
_dd.append(cfg)
mw.writeFile(getTaskConf(), json.dumps(_dd))
args["task_id"] = task_id
args["name"] = name
mw.writeFile(getTaskConf(), json.dumps(args))
def removeBgTask():
cfg_list = getConfigData()
for x in range(len(cfg_list)):
cfg = cfg_list[x]
if "task_id" in cfg.keys() and cfg["task_id"] > 0:
res = mw.M("crontab").field("id, name").where(
"id=?", (cfg["task_id"],)).find()
if res and res["id"] == cfg["task_id"]:
import crontab_api
api = crontab_api.crontab_api()
data = api.delete(cfg["task_id"])
if data[0]:
cfg["task_id"] = -1
cfg_list[x] = cfg
mw.writeFile(getTaskConf(), '[]')
return True
cfg = getConfigData()
if "task_id" in cfg and cfg["task_id"] > 0:
res = mw.M("crontab").field("id, name").where(
"id=?", (cfg["task_id"],)).find()
if res and res["id"] == cfg["task_id"]:
import crontab_api
api = crontab_api.crontab_api()
data = api.delete(cfg["task_id"])
if data[0]:
cfg["task_id"] = -1
mw.writeFile(getTaskConf(), json.loads(cfg))
return True
return False
+10
View File
@@ -5,6 +5,16 @@
white-space: nowrap;
vertical-align: middle;
}
#select_db xm-select{
min-height: 30px;
line-height: 30px;
}
#select_db xm-select *{
font-size: 12px;
}
</style>
<div class="bt-form">
+10 -3
View File
@@ -123,9 +123,16 @@
<input name="mongodb_field_value" type="text" class="bt-input-text" placeholder="请输入查找内容">
</div>
<button type="button" class="mongodb_find btn btn-success btn-sm mr5 ml5" style="float:right;">
<span>查找</span>
</button>
<div style="float:right;">
<button type="button" class="mongodb_find btn btn-success btn-sm mr5 ml5" >
<span>查找</span>
</button>
<button type="button" class="mongodb_refresh btn btn-success btn-sm mr5 ml5">
<span>刷新</span>
</button>
</div>
</div>
<div class="pull-right" style="padding-top: 5px;">
+5 -1
View File
@@ -738,6 +738,10 @@ function mongodbInitField(f, data){
}
mongodbDataList(1);
});
$('#mongodb .mongodb_refresh').unbind('click').click(function(){
mongodbDataList(1);
});
}
var mogodb_db_list;
@@ -1252,7 +1256,7 @@ function redisBatchClear(){
xm_db_list = xmSelect.render({
el: '#select_db',
repeat: true,
repeat: false,
toolbar: {show: true},
data: idx_db,
});
+349 -7
View File
@@ -1948,7 +1948,7 @@ def addMasterRepSlaveUser(version=''):
if isError != None:
return isError
sql_select = "grant select,lock tables,PROCESS on *.* to " + username + "@'%';"
sql_select = "grant select,reload,REPLICATION CLIENT,PROCESS on *.* to " + username + "@'%';"
pdb.execute(sql_select)
pdb.execute('FLUSH PRIVILEGES;')
@@ -2583,6 +2583,293 @@ def dumpMysqlData(version=''):
return 'ok'
return 'fail'
############### --- 重要 数据补足同步 ---- ###########
def getSyncMysqlDB(dbname,sign = ''):
conn = pSqliteDb('slave_sync_user')
if sign != '':
data = conn.field('ip,port,user,pass,mode,cmd').where('ip=?', (sign,)).find()
else:
data = conn.field('ip,port,user,pass,mode,cmd').find()
user = data['user']
apass = data['pass']
port = data['port']
ip = data['ip']
# 远程数据
sync_db = mw.getMyORM()
# MySQLdb |
sync_db.setPort(port)
sync_db.setHost(ip)
sync_db.setUser(user)
sync_db.setPwd(apass)
sync_db.setDbName(dbname)
sync_db.setTimeout(60)
return sync_db
def syncDatabaseRepairTempFile():
tmp_log = mw.getMWLogs()+ '/mariadb-check.log'
return tmp_log
def syncDatabaseRepairLog(version=''):
import subprocess
args = getArgs()
data = checkArgs(args, ['db','sign','op'])
if not data[0]:
return data[1]
sync_args_db = args['db']
sync_args_sign = args['sign']
op = args['op']
tmp_log = syncDatabaseRepairTempFile()
cmd = 'cd '+mw.getServerDir()+'/mdserver-web && source bin/activate && python3 plugins/mariadb/index.py sync_database_repair {"db":"'+sync_args_db+'","sign":"'+sync_args_sign+'"}'
# print(cmd)
if op == 'get':
log = mw.getLastLine(tmp_log, 15)
return mw.returnJson(True, log)
if op == 'cmd':
return mw.returnJson(True, 'ok', cmd)
if op == 'do':
os.system(' echo "开始执行" > '+ tmp_log)
os.system(cmd +' >> '+ tmp_log +' &')
# time.sleep(10)
# mw.execShell('rm -rf '+tmp_log)
return mw.returnJson(True, 'ok')
return mw.returnJson(False, '无效请求!')
def syncDatabaseRepair(version=''):
time_stats_s = time.time()
tmp_log = syncDatabaseRepairTempFile()
from pymysql.converters import escape_string
args = getArgs()
data = checkArgs(args, ['db','sign'])
if not data[0]:
return data[1]
sync_args_db = args['db']
sync_args_sign = args['sign']
# 本地数据
local_db = pMysqlDb()
# 远程数据
sync_db = getSyncMysqlDB(sync_args_db,sync_args_sign)
tables = local_db.query('show tables from `%s`' % sync_args_db)
table_key = "Tables_in_" + sync_args_db
inconsistent_table = []
tmp_dir = '/tmp/sync_db_repair'
mw.execShell('mkdir -p '+tmp_dir)
for tb in tables:
table_name = sync_args_db+'.'+tb[table_key]
table_check_file = tmp_dir+'/'+table_name+'.txt'
if os.path.exists(table_check_file):
# print(table_name+', 已检查OK')
continue
primary_key_sql = "SHOW INDEX FROM "+table_name+" WHERE Key_name = 'PRIMARY';";
primary_key_data = local_db.query(primary_key_sql)
# print(primary_key_sql,primary_key_data)
pkey_name = '*'
if len(primary_key_data) == 1:
pkey_name = primary_key_data[0]['Column_name']
# print(pkey_name)
if pkey_name != '*' :
# 智能校验(由于服务器同步可能会慢,比较总数总是对不上)
cmd_local_newpk_sql = 'select ' + pkey_name + ' from ' + table_name + " order by " + pkey_name + " desc limit 1"
cmd_local_newpk_data = local_db.query(cmd_local_newpk_sql)
# print(cmd_local_newpk_data)
if len(cmd_local_newpk_data) == 1:
# 比较总数
cmd_count_sql = 'select count('+pkey_name+') as num from '+table_name + ' where '+pkey_name + ' <= '+ str(cmd_local_newpk_data[0][pkey_name])
local_count_data = local_db.query(cmd_count_sql)
sync_count_data = sync_db.query(cmd_count_sql)
if local_count_data != sync_count_data:
print(cmd_count_sql)
print("all data compare: ",local_count_data, sync_count_data)
else:
print(table_name+' smart compare check ok.')
mw.writeFile(tmp_log, table_name+' smart compare check ok.\n','a+')
mw.execShell("echo 'ok' > "+table_check_file)
continue
# 比较总数
cmd_count_sql = 'select count('+pkey_name+') as num from '+table_name
local_count_data = local_db.query(cmd_count_sql)
sync_count_data = sync_db.query(cmd_count_sql)
if local_count_data != sync_count_data:
print("all data compare: ",local_count_data, sync_count_data)
inconsistent_table.append(table_name)
diff = sync_count_data[0]['num'] - local_count_data[0]['num']
print(table_name+', need sync. diff,'+str(diff))
mw.writeFile(tmp_log, table_name+', need sync. diff,'+str(diff)+'\n','a+')
else:
print(table_name+' check ok.')
mw.writeFile(tmp_log, table_name+' check ok.\n','a+')
mw.execShell("echo 'ok' > "+table_check_file)
# inconsistent_table = ['xx.xx']
# 数据对齐
for table_name in inconsistent_table:
is_break = False
while not is_break:
local_db.ping()
# 远程数据
sync_db.ping()
print("check table:"+table_name)
mw.writeFile(tmp_log, "check table:"+table_name+'\n','a+')
table_name_pos = 0
table_name_pos_file = tmp_dir+'/'+table_name+'.pos.txt'
primary_key_sql = "SHOW INDEX FROM "+table_name+" WHERE Key_name = 'PRIMARY';";
primary_key_data = local_db.query(primary_key_sql)
pkey_name = primary_key_data[0]['Column_name']
if os.path.exists(table_name_pos_file):
table_name_pos = mw.readFile(table_name_pos_file)
data_select_sql = 'select * from '+table_name + ' where '+pkey_name+' > '+str(table_name_pos)+' limit 10000'
print(data_select_sql)
local_select_data = local_db.query(data_select_sql)
time_s = time.time()
sync_select_data = sync_db.query(data_select_sql)
print(f'sync query cos:{time.time() - time_s:.4f}s')
mw.writeFile(tmp_log, f'sync query cos:{time.time() - time_s:.4f}s\n','a+')
# print(local_select_data)
# print(sync_select_data)
# print(len(local_select_data))
# print(len(sync_select_data))
print('pos:',str(table_name_pos),'local compare sync,',local_select_data == sync_select_data)
cmd_count_sql = 'select count('+pkey_name+') as num from '+table_name
local_count_data = local_db.query(cmd_count_sql)
time_s = time.time()
sync_count_data = sync_db.query(cmd_count_sql)
print(f'sync count data cos:{time.time() - time_s:.4f}s')
print(local_count_data,sync_count_data)
# 数据同步有延迟,相等即任务数据补足完成
if local_count_data[0]['num'] == sync_count_data[0]['num']:
is_break = True
break
diff = sync_count_data[0]['num'] - local_count_data[0]['num']
print("diff," + str(diff)+' line data!')
if local_select_data == sync_select_data:
data_count = len(local_select_data)
if data_count == 0:
# mw.writeFile(table_name_pos_file, '0')
print(table_name+",data is equal ok..")
is_break = True
break
# print(table_name,data_count)
pos = local_select_data[data_count-1][pkey_name]
print('pos',pos)
progress = pos/sync_count_data[0]['num']
print('progress,%.2f' % progress+'%')
mw.writeFile(table_name_pos_file, str(pos))
else:
sync_select_data_len = len(sync_select_data)
skip_idx = 0
# 主库PK -> 查询本地 | 保证一致
if sync_select_data_len > 0:
for idx in range(sync_select_data_len):
sync_idx_data = sync_select_data[idx]
local_idx_data = None
if idx in local_select_data:
local_idx_data = local_select_data[idx]
if sync_select_data[idx] == local_idx_data:
skip_idx = idx
pos = local_select_data[idx][pkey_name]
mw.writeFile(table_name_pos_file, str(pos))
# print(insert_data)
local_inquery_sql = 'select * from ' + table_name+ ' where ' +pkey_name+' = '+ str(sync_idx_data[pkey_name])
# print(local_inquery_sql)
ldata = local_db.query(local_inquery_sql)
# print('ldata:',ldata)
if len(ldata) == 0:
print("id:"+ str(sync_idx_data[pkey_name])+ " no exists, insert")
insert_sql = 'insert into ' + table_name
field_str = ''
value_str = ''
for field in sync_idx_data:
field_str += '`'+field+'`,'
value_str += '\''+escape_string(str(sync_idx_data[field]))+'\','
field_str = '(' +field_str.strip(',')+')'
value_str = '(' +value_str.strip(',')+')'
insert_sql = insert_sql+' '+field_str+' values'+value_str+';'
print(insert_sql)
r = local_db.execute(insert_sql)
print(r)
else:
# print('compare sync->local:',sync_idx_data == ldata[0] )
if ldata[0] == sync_idx_data:
continue
print("id:"+ str(sync_idx_data[pkey_name])+ " data is not equal, update")
update_sql = 'update ' + table_name
field_str = ''
value_str = ''
for field in sync_idx_data:
if field == pkey_name:
continue
field_str += '`'+field+'`=\''+escape_string(str(sync_idx_data[field]))+'\','
field_str = field_str.strip(',')
update_sql = update_sql+' set '+field_str+' where '+pkey_name+'=\''+str(sync_idx_data[pkey_name])+'\';'
print(update_sql)
r = local_db.execute(update_sql)
print(r)
# 本地PK -> 查询主库 | 保证一致
# local_select_data_len = len(local_select_data)
# if local_select_data_len > 0:
# for idx in range(local_select_data_len):
# if idx < skip_idx:
# continue
# local_idx_data = local_select_data[idx]
# print('local idx check', idx, skip_idx)
# local_inquery_sql = 'select * from ' + table_name+ ' where ' +pkey_name+' = '+ str(local_idx_data[pkey_name])
# print(local_inquery_sql)
# sdata = sync_db.query(local_inquery_sql)
# sdata_len = len(sdata)
# print('sdata:',sdata,sdata_len)
# if sdata_len == 0:
# delete_sql = 'delete from ' + table_name + ' where ' +pkey_name+' = '+ str(local_idx_data[pkey_name])
# print(delete_sql)
# r = local_db.execute(delete_sql)
# print(r)
# break
if is_break:
print("break all")
break
time.sleep(3)
print(f'data check cos:{time.time() - time_stats_s:.4f}s')
print("data supplementation completed")
mw.execShell('rm -rf '+tmp_dir)
return 'ok'
############### --- 重要 同步---- ###########
@@ -2647,11 +2934,18 @@ def doFullSync(version=''):
def doFullSyncUser(version=''):
which_pv = mw.execShell('which pv')
is_exist_pv = False
if os.path.exists(which_pv[0]):
is_exist_pv = True
args = getArgs()
data = checkArgs(args, ['db', 'sign'])
if not data[0]:
return data[1]
time_all_s = time.time()
sync_db = args['db']
sync_sign = args['sign']
@@ -2675,23 +2969,67 @@ def doFullSyncUser(version=''):
os.system("rm -rf " + bak_file)
writeDbSyncStatus({'code': 0, 'msg': '开始同步...', 'progress': 0})
dmp_option = ''
mode = recognizeDbMode()
# if mode == 'gtid':
# dmp_option = ' --set-gtid-purged=off '
writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 10})
find_run_dump = mw.execShell('ps -ef | grep mariadb-dump | grep -v grep')
if find_run_dump[0] != "":
print("正在远程导出数据中,别着急...")
writeDbSyncStatus({'code': 3.1, 'msg': '正在远程导出数据中,别着急...', 'progress': 39})
return False
time_s = time.time()
if not os.path.exists(bak_file):
dmp_option += " --master-data=1 --apply-slave-statements --include-master-host-port "
# https://mariadb.com/kb/zh-cn/mariadb-dump/
dump_sql_data = getServerDir() + "/bin/mariadb-dump -f --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
dump_sql_data = getServerDir() + "/bin/mariadb-dump " + dmp_option + " -f --default-character-set=utf8 --single-transaction --compress -q -h" + ip + " -P" + \
port + " -u" + user + " -p'" + apass + "' " + sync_db + ">" + bak_file
print(dump_sql_data)
mw.execShell(dump_sql_data)
writeDbSyncStatus({'code': 2, 'msg': '本地导入数据...', 'progress': 40})
time_e = time.time()
export_cos = time_e - time_s
print("export cos:", export_cos)
writeDbSyncStatus({'code': 3, 'msg': '导出耗时:'+str(int(export_cos))+'秒,正在到本地导入数据中...', 'progress': 40})
find_run_import = mw.execShell('ps -ef | grep mariadb| grep '+ bak_file +' | grep -v grep')
if find_run_import[0] != "":
print("正在导入数据中,别着急...")
writeDbSyncStatus({'code': 4.1, 'msg': '正在导入数据中,别着急...', 'progress': 59})
return False
# if os.path.exists(bak_file):
# db.execute('reset master')
time_s = time.time()
if os.path.exists(bak_file):
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
my_import_cmd = getServerDir() + '/bin/mariadb -S ' + sock + " -uroot -p'" + pwd + \
"' " + sync_db + '<' + bak_file
print(my_import_cmd)
mw.execShell(my_import_cmd)
if is_exist_pv:
my_import_cmd = getServerDir() + '/bin/mariadb -S ' + sock + " -uroot -p'" + pwd + "' " + sync_db
my_import_cmd = "pv -t -p " + bak_file + '|' + my_import_cmd
print(my_import_cmd)
os.system(my_import_cmd)
else:
my_import_cmd = getServerDir() + '/bin/mariadb -S ' + sock + " -uroot -p'" + pwd + \
"' " + sync_db + '<' + bak_file
print(my_import_cmd)
mw.execShell(my_import_cmd)
time_e = time.time()
import_cos = time_e - time_s
print("import cos:", import_cos)
writeDbSyncStatus({'code': 4, 'msg': '导入耗时:'+str(int(import_cos))+'秒', 'progress': 60})
time.sleep(3)
pinfo = parseSlaveSyncCmd(data['cmd'])
# print(pinfo)
@@ -3026,5 +3364,9 @@ if __name__ == "__main__":
print(doFullSync(version))
elif func == 'dump_mysql_data':
print(dumpMysqlData(version))
elif func == 'sync_database_repair':
print(syncDatabaseRepair())
elif func == 'sync_database_repair_log':
print(syncDatabaseRepairLog())
else:
print('error')
+6
View File
@@ -7,6 +7,12 @@ rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
# cd /www/server/mdserver-web/plugins/mariadb && bash install.sh install 8.2
# cd /www/server/mdserver-web && source bin/activate && python3 plugins/mariadb/index.py try_slave_sync_bugfix {}
# cd /www/server/mdserver-web && source bin/activate && python3 plugins/mariadb/index.py do_full_sync {"db":"xxx","sign":"","begin":1}
# cd /www/server/mdserver-web && source bin/activate && python3 plugins/mariadb/index.py sync_database_repair {"db":"xxx","sign":""}
# cd /www/server/mdserver-web && source bin/activate && python3 plugins/mariadb/index.py init_slave_status
# cd /www/server/mdserver-web && source bin/activate && python3 plugins/mariadb/index.py install_pre_inspection
install_tmp=${rootPath}/tmp/mw_install.pl
+81 -2
View File
@@ -874,7 +874,7 @@ function openPhpmyadmin(name,username,password){
}
if (rdata.data['cfg']['choose'] != 'mariadb'){
layer.msg('当前为['+rdata.choose+']模式,若要使用请修改phpMyAdmin访问切换.',{icon:2,shade: [0.3, '#000']});
layer.msg('当前为['+rdata.data['cfg']['choose']+']模式,若要使用请修改phpMyAdmin访问切换.',{icon:2,shade: [0.3, '#000']});
return;
}
var home_page = rdata.data['home_page'];
@@ -1978,6 +1978,84 @@ function getFullSyncStatus(db){
}
function dataSyncVerify(db){
var reqTimer = null;
function requestLogs(layerIndex){
myPostN('sync_database_repair_log', {db:db, sign:'',op:'get'}, function(rdata){
var rdata = $.parseJSON(rdata.data);
if(!rdata.status) {
layer.close(layerIndex);
layer.msg(rdata.msg,{icon:2, time:2000});
clearInterval(reqTimer);
return;
};
if (rdata.msg == ''){
rdata.msg = '暂无数据!';
}
$("#data_verify_log").html(rdata.msg);
//滚动到最低
var ob = document.getElementById('data_verify_log');
ob.scrollTop = ob.scrollHeight;
});
}
layer.open({
type: 1,
title: '同步数据库['+db+']数据校验',
area: '500px',
btn:[ "开始","取消","手动"],
content:"<div class='bt-form'>\
"+'<pre id="data_verify_log" style="overflow: auto; border: 0px none; line-height:23px;padding: 5px; margin: 0px; white-space: pre-wrap; height: 395px; background-color: rgb(51,51,51);color:#f1f1f1;border-radius:0px;font-family:"></pre>'+"\
</div>",
cancel: function(){
if (reqTimer){
clearInterval(reqTimer);
}
},
yes:function(index,layer_index){
myPostN('sync_database_repair_log', {db:db, sign:'',op:'do'}, function(data){});
layer.msg("执行成功");
requestLogs(layer_index);
reqTimer = setInterval(function(){
requestLogs(layer_index);
},3000);
},
success:function(){
},
btn3: function(){
myPostN('sync_database_repair_log', {db:db, sign:'',op:'cmd'}, function(rdata){
var rdata = $.parseJSON(rdata.data);
layer.open({
title: "手动执行命令CMD",
area: ['600px', '180px'],
type:1,
closeBtn: 1,
shadeClose: false,
btn:["复制","取消"],
content: '<div class="pd15">\
<div class="divtable">\
<pre class="layui-code">'+rdata.data+'</pre>\
</div>\
</div>',
success:function(){
copyText(rdata.data);
},
yes:function(){
copyText(rdata.data);
}
});
});
return false;
}
});
}
function addSlaveSSH(ip=''){
myPost('get_slave_ssh_by_ip', {ip:ip}, function(rdata){
@@ -2633,7 +2711,8 @@ function masterOrSlaveConf(version=''){
list += '<td>' + rdata.data[i]['name'] +'</td>';
list += '<td style="text-align:right">' +
'<a href="javascript:;" class="btlink" onclick="setDbSlave(\''+rdata.data[i]['name']+'\')" title="加入|退出">'+(rdata.data[i]['slave']?'退出':'加入')+'</a> | ' +
'<a href="javascript:;" class="btlink" onclick="getFullSyncStatus(\''+rdata.data[i]['name']+'\')" title="同步">同步</a>' +
'<a href="javascript:;" class="btlink" onclick="getFullSyncStatus(\''+rdata.data[i]['name']+'\')" title="同步">同步</a> | ' +
'<a href="javascript:;" class="btlink" onclick="dataSyncVerify(\''+rdata.data[i]['name']+'\')" title="数据校验">数据校验</a>' +
'</td>';
list += '</tr>';
}
+1 -1
View File
@@ -65,7 +65,7 @@ class backupTools:
# mw.execShell(db_path + "/bin/mysqldump --defaults-file=" + my_conf_path + " --skip-lock-tables --default-character-set=utf8 " +
# name + " | gzip > " + filename)
cmd = db_path + "/bin/mysqldump --defaults-file=" + my_conf_path + " --single-transaction --quick --default-character-set=utf8 " + \
cmd = db_path + "/bin/mariadb-dump --defaults-file=" + my_conf_path + " --single-transaction --quick --default-character-set=utf8 " + \
name + " | gzip > " + filename
mw.execShell(cmd)
+1
View File
@@ -63,6 +63,7 @@
<p onclick="mongoStatus();">负载状态</p>
<p onclick="mongoReplStatus();">复制状态</p>
<p onclick="pluginLogs('mongodb','','run_log');">日志</p>
<p onclick="mgdbReadme();">相关说明</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con" style="height:455px;overflow: auto;"></div>
+35 -13
View File
@@ -18,7 +18,6 @@ if mw.isAppleSystem():
# /usr/lib/systemd/system/mongod.service
# /var/lib/mongo
# python3 /www/server/mdserver-web/plugins/mongodb/index.py repl_init
# python3 /www/server/mdserver-web/plugins/mongodb/index.py run_repl_info
@@ -107,6 +106,9 @@ def getConfIp():
data = getConfigData()
return data['net']['bindIp']
def getConfLocalIp():
return '127.0.0.1'
def getConfPort():
data = getConfigData()
return data['net']['port']
@@ -186,7 +188,7 @@ def mongdbClientS():
import pymongo
port = getConfPort()
auth = getConfAuth()
ip = getConfIp()
ip = getConfLocalIp()
mg_root = pSqliteDb('config').where('id=?', (1,)).getField('mg_root')
if auth == 'disabled':
@@ -200,7 +202,7 @@ def mongdbClient():
import pymongo
port = getConfPort()
auth = getConfAuth()
ip = getConfIp()
ip = getConfLocalIp()
mg_root = pSqliteDb('config').where('id=?', (1,)).getField('mg_root')
# print(ip,port,auth,mg_root)
if auth == 'disabled':
@@ -488,15 +490,14 @@ def runDocInfo():
def runReplInfo():
client = mongdbClient()
db = client.admin
result = {}
try:
serverStatus = db.command('serverStatus')
except Exception as e:
return mw.returnJson(False, str(e))
d = getConfigData()
result = {}
if 'replSetName' in d['replication']:
if 'replication' in d and 'replSetName' in d['replication']:
result['repl_name'] = d['replication']['replSetName']
result['status'] = '无'
@@ -518,7 +519,22 @@ def runReplInfo():
hosts = mw.getDefault(repl,'hosts', '')
result['hosts'] = ','.join(hosts)
result['members'] = []
try:
members_list = []
replStatus = db.command('replSetGetStatus')
if 'members' in replStatus:
members = replStatus['members']
for m in members:
t = {}
t['name'] = m['name']
t['stateStr'] = m['stateStr']
t['uptime'] = m['uptime']
members_list.append(t)
result['members'] = members_list
except Exception as e:
pass
return mw.returnJson(True, 'OK', result)
def getDbList():
@@ -602,7 +618,7 @@ def addDb():
username = data_name
client[data_name].chat.insert_one({})
client[data_name].zchat.insert_one({})
user_roles = [{'role': 'dbOwner', 'db': data_name}, {'role': 'userAdmin', 'db': data_name}]
if auth_status:
# db.command("dropUser", username)
@@ -787,7 +803,7 @@ def toDbBase(find):
data_name = find['name']
db = client[data_name]
db.chat.insert_one({})
db.zchat.insert_one({})
user_roles = [{'role': 'dbOwner', 'db': data_name}, {'role': 'userAdmin', 'db': data_name}]
try:
db_admin.command("createUser", find['username'], pwd=find['password'], roles=user_roles)
@@ -1011,10 +1027,6 @@ def replSetNode():
add_node = args['node'].strip()
idx = int(args['idx'])
priority = -1
if 'priority' in args:
priority = args['priority'].strip()
@@ -1505,6 +1517,14 @@ def installPreInspection(version):
return '暂时仅支持{}'.format(','.join(supportOs))
return 'ok'
def uninstallPreInspection(version):
stop()
import plugins_api
plugins_api.plugins_api().removeIndex(getPluginName(), version)
return "请手动删除MongoDB[{}]<br/> rm -rf {}".format(version, getServerDir())
if __name__ == "__main__":
func = sys.argv[1]
@@ -1524,6 +1544,8 @@ if __name__ == "__main__":
print(reload())
elif func == 'install_pre_inspection':
print(installPreInspection(version))
elif func == 'uninstall_pre_inspection':
print(uninstallPreInspection(version))
elif func == 'initd_status':
print(initdStatus())
elif func == 'initd_install':
+1
View File
@@ -6,6 +6,7 @@
"title": "MongoDB",
"shell": "install.sh",
"install_pre_inspection":true,
"uninstall_pre_inspection":true,
"versions":["4.4","5.0","6.0","7.0"],
"tip": "soft",
"checks": "server/mongodb",
+79 -60
View File
@@ -154,11 +154,17 @@ function mongoReplStatus() {
} else{
tbody += '<tr><th>状态</th><td>' + rdata.status + '</td><td>主/从</td></tr>\
<tr><th>同步文档</th><td>' + rdata.setName + '</td><td>文档名</td></tr>\
<tr><th>hosts</th><td><span class="overflow_hide" style="width:260px;" title="'+rdata.hosts+'">' + rdata.hosts + '</span></td><td>服务器所有节点</td></tr>\
<tr><th>hosts</th><td><span class="overflow_hide" style="width:300px;word-wrap: break-word;white-space:pre-wrap;" title="'+rdata.hosts+'">' + rdata.hosts + '</span></td><td>服务器所有节点</td></tr>\
<tr><th>primary</th><td>' + rdata.primary + '</td><td>主节点</td></tr>\
<tr><th>me</th><td>' + rdata.me + '</td><td>本机</td></tr>';
}
var tbody_members = '';
var member_list = rdata['members'];
for (var i = 0; i < member_list.length; i++) {
tbody_members += '<tr><th>'+member_list[i]['name']+'</th><td>' + member_list[i]['stateStr'] + '</td><td>'+member_list[i]['uptime']+'</td></tr>';
}
// console.log(rdata);
var repl_on = 'btn-danger';
var repl_on_title = '未开启';
@@ -176,9 +182,14 @@ function mongoReplStatus() {
con += '<div class="divtable">\
<table class="table table-hover table-bordered" style="width: 660px;">\
<thead><th>字段</th><th>当前值</th><th>说明</th></thead>\
<tbody>\
'+tbody+'\
<tbody>\
<tbody>'+tbody+'<tbody>\
</table>\
</div>';
con += '<div class="divtable" style="margin-top:5px;">\
<table class="table table-hover table-bordered" style="width: 660px;">\
<thead><th>IP</th><th>状态</th><th>在线</th></thead>\
<tbody>'+tbody_members+'<tbody>\
</table>\
</div>';
@@ -188,67 +199,66 @@ function mongoReplStatus() {
//设置副本名称
function mongoReplCfgReplSetName(){
mgPost('run_doc_info', '', '', function(rdata){
var rdata = $.parseJSON(rdata.data);
// <select class='bt-input-text mr5' name='replSetName' style='width:100px'><option value=''></option></select>
layer.open({
type: 1,
area: '300px',
title: '设置副本名称',
closeBtn: 1,
shift: 5,
shadeClose: false,
btn:["提交","关闭"],
content: "<form class='bt-form pd20' id='mod_pwd'>\
<div class='line'>\
<span class='tname'>同步副本名称</span>\
<div class='info-r'>\
<input class='bt-input-text mr5' name='replSetName' style='width:100px' />\
</div>\
</div>\
</form>",
layer.open({
type: 1,
area: '300px',
title: '设置副本名称',
closeBtn: 1,
shift: 5,
shadeClose: false,
btn:["提交","关闭"],
content: "<form class='bt-form pd20' id='mod_pwd'>\
<div class='line'>\
<span class='tname'>同步副本</span>\
<div class='info-r'>\
<select class='bt-input-text mr5' name='replSetName' style='width:100px'>\
<option value=''></option>\
</select>\
</div>\
</div>\
</form>",
success: function(){
// // console.log(rdata);
// var rlist = rdata['dbs'];
// var dbs = [];
// var selectHtml = '';
// for (var i = 0; i < rlist.length; i++) {
// // console.log(rlist[i]['db']);
// var dbname = rlist[i]['db'];
success: function(){
// console.log(rdata);
var rlist = rdata['dbs'];
var dbs = [];
var selectHtml = '';
for (var i = 0; i < rlist.length; i++) {
// console.log(rlist[i]['db']);
var dbname = rlist[i]['db'];
// if (['admin','local','config'].includes(dbname)){
// } else {
// dbs.push(dbname);
// }
// }
if (['admin','local','config'].includes(dbname)){
} else {
dbs.push(dbname);
}
}
// if (dbs.length == 0 ){
// selectHtml += "<option value=''>无</option>";
// }
if (dbs.length == 0 ){
selectHtml += "<option value=''>无</option>";
}
// for (index in dbs) {
// selectHtml += "<option value='"+dbs[index]+"'>"+dbs[index]+"</option>";
// }
for (index in dbs) {
selectHtml += "<option value='"+dbs[index]+"'>"+dbs[index]+"</option>";
}
$('select[name="replSetName"]').html(selectHtml);
},
yes:function(index){
var data = {};
data['name'] = $('select[name=replSetName]').val();
mgPost('repl_set_name', '',data, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
if (rdata['status']){
layer.close(index);
mongoReplCfgInit();
}
},{icon: rdata.status ? 1 : 2});
});
}
});
// $('select[name="replSetName"]').html(selectHtml);
},
yes:function(index){
var data = {};
data['name'] = $('input[name=replSetName]').val();
if (data['name'] == ''){
layer.msg("副本名称不能为空");
return;
}
mgPost('repl_set_name', '',data, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
if (rdata['status']){
layer.close(index);
mongoReplCfgInit();
}
},{icon: rdata.status ? 1 : 2});
});
}
});
}
@@ -1193,3 +1203,12 @@ function importDbExternal(file,name){
});
}
function mgdbReadme(){
var readme = '<ul class="help-info-text c7">';
readme += '<li>认证同步说明</li>';
readme += '<li>root/用户,配置Key完全一致才能同步。</li>';
readme += '</ul>';
$('.soft-man-con').html(readme);
}
+1 -1
View File
@@ -63,7 +63,7 @@ class backupTools:
if len(mycnf) > 100:
mw.writeFile(db_path + '/etc/my.cnf', mycnf)
cmd = db_path + "/bin/usr/bin/mysqldump --defaults-file=" + my_conf_path + " --single-transaction --quick --default-character-set=utf8 " + \
cmd = db_path + "/bin/usr/bin/mysqldump --defaults-file=" + my_conf_path + " --single-transaction -q --default-character-set=utf8 " + \
name + " | gzip > " + filename
mw.execShell(cmd)
+1 -1
View File
@@ -65,7 +65,7 @@ class backupTools:
if len(content) > 100:
mw.writeFile(my_cnf, content)
cmd = db_path + "/bin/usr/bin/mysqldump --defaults-file=" + my_cnf + " --single-transaction --quick --default-character-set=utf8 " + \
cmd = db_path + "/bin/usr/bin/mysqldump --defaults-file=" + my_cnf + " --single-transaction -q --default-character-set=utf8 " + \
name + " | gzip > " + filename
mw.execShell(cmd)
+27
View File
@@ -0,0 +1,27 @@
```
show global variables like '%gtid%';
show global variables like 'server_uuid';
```
```
# 不锁表,需要删除原来数据表
# tables = db.query('show tables from `%s`' % sync_db_import)
# table_key = "Tables_in_" + sync_db_import
# for tname in tables:
# drop_db_cmd = 'drop table if exists '+sync_db_import+'.'+tname[table_key]
# # print(drop_db_cmd)
# db.query(drop_db_cmd)
```
```
# 修改同步位置
# master_info = sync_mdb.query('show master status')
# slave_info = db.query('show slave status')
# if len(master_info)>0:
# channel_name = slave_info[0]['Channel_Name']
# change_cmd = "CHANGE MASTER TO MASTER_LOG_FILE='"+master_info[0]['File']+"', MASTER_LOG_POS="+str(master_info[0]['Position'])+" for channel '"+channel_name+"';"
# print(change_cmd)
# r = db.execute(change_cmd)
# print(r)
```
+2
View File
@@ -50,7 +50,9 @@ CREATE TABLE IF NOT EXISTS `slave_sync_user` (
`pass` TEXT,
`mode` TEXT,
`cmd` TEXT,
`db` TEXT,
`addtime` TEXT
);
ALTER TABLE `slave_sync_user` ADD COLUMN `db` TEXT DEFAULT '';
+631 -56
View File
@@ -63,12 +63,12 @@ def getArgs():
if t.strip() == '':
tmp = []
else:
t = t.split(':', 1)
t = t.split(':',1)
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':', 1)
t = args[i].split(':',1)
tmp[t[0]] = t[1]
return tmp
@@ -745,7 +745,7 @@ def getMyDbPos():
return tmp.groups()[0].strip()
def setMyDbPos():
def setMyDbPos(version):
args = getArgs()
data = checkArgs(args, ['datadir'])
if not data[0]:
@@ -760,7 +760,7 @@ def setMyDbPos():
mw.execShell('mkdir -p ' + t_datadir)
# mw.execShell('/etc/init.d/mysqld stop')
stop()
stop(version)
mw.execShell('cp -rf ' + s_datadir + '/* ' + t_datadir + '/')
mw.execShell('chown -R mysql mysql ' + t_datadir)
mw.execShell('chmod -R 755 ' + t_datadir)
@@ -774,7 +774,7 @@ def setMyDbPos():
mycnf = mycnf.replace(s_datadir, t_datadir)
mw.writeFile(myfile, mycnf)
start()
start(version)
result = mw.execShell(
'ps aux|grep mysqld| grep -v grep|grep -v python')
@@ -784,7 +784,7 @@ def setMyDbPos():
else:
mw.execShell('pkill -9 mysqld')
mw.writeFile(myfile, mw.readFile(path + '/etc/my_backup.cnf'))
start()
start(version)
return mw.returnJson(False, '文件迁移失败!')
@@ -1070,6 +1070,81 @@ def importDbExternal():
return mw.returnJson(True, 'ok')
def importDbExternalProgress():
args = getArgs()
data = checkArgs(args, ['file', 'name'])
if not data[0]:
return data[1]
file = args['file']
name = args['name']
cmd = 'cd '+mw.getServerDir()+'/mdserver-web && source bin/activate && '
cmd += 'python3 '+mw.getServerDir()+'/mdserver-web/plugins/mysql/index.py import_db_external_progress_bar {"file":"'+file+'","name":"'+name+'"}'
return mw.returnJson(True, 'ok',cmd)
def importDbExternalProgressBar():
args = getArgs()
data = checkArgs(args, ['file', 'name'])
if not data[0]:
return data[1]
file = args['file']
name = args['name']
import_dir = mw.getRootDir() + '/backup/import/'
file_path = import_dir + file
if not os.path.exists(file_path):
return mw.returnJson(False, '文件突然消失?')
exts = ['sql', 'gz', 'zip']
ext = mw.getFileSuffix(file)
if ext not in exts:
return mw.returnJson(False, '导入数据库格式不对!')
tmp = file.split('/')
tmpFile = tmp[len(tmp) - 1]
tmpFile = tmpFile.replace('.sql.' + ext, '.sql')
tmpFile = tmpFile.replace('.' + ext, '.sql')
tmpFile = tmpFile.replace('tar.', '')
# print(tmpFile)
import_sql = ""
if file.find("sql.gz") > -1:
cmd = 'cd ' + import_dir + ' && gzip -dc ' + \
file + " > " + import_dir + tmpFile
info = mw.execShell(cmd)
if info[1] == "":
import_sql = import_dir + tmpFile
if file.find(".zip") > -1:
cmd = 'cd ' + import_dir + ' && unzip -o ' + file
mw.execShell(cmd)
import_sql = import_dir + tmpFile
if file.find("tar.gz") > -1:
cmd = 'cd ' + import_dir + ' && tar -zxvf ' + file
mw.execShell(cmd)
import_sql = import_dir + tmpFile
if file.find(".sql") > -1 and file.find(".sql.gz") == -1:
import_sql = import_dir + file
if import_sql == "":
return mw.returnJson(False, '未找SQL文件')
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
my_cnf = getConf()
mysql_cmd = getServerDir() + '/bin/mysql --defaults-file=' + my_cnf + \
' -uroot -p"' + pwd + '" -f ' + name
mysql_cmd_progress_bar = "pv -t -p " + import_sql + '|'+ mysql_cmd
print(mysql_cmd_progress_bar)
rdata = os.system(mysql_cmd_progress_bar)
return ""
def importDbBackup():
args = getArgs()
@@ -1107,6 +1182,53 @@ def importDbBackup():
return mw.returnJson(True, 'ok')
def importDbBackupProgress():
args = getArgs()
data = checkArgs(args, ['file', 'name'])
if not data[0]:
return data[1]
file = args['file']
name = args['name']
cmd = 'cd '+mw.getServerDir()+'/mdserver-web && source bin/activate && '
cmd += 'python3 '+mw.getServerDir()+'/mdserver-web/plugins/mysql/index.py import_db_backup_progress_bar {"file":"'+file+'","name":"'+name+'"}'
return mw.returnJson(True, 'ok',cmd)
return mw.returnJson(True, 'ok')
def importDbBackupProgressBar():
args = getArgs()
data = checkArgs(args, ['file', 'name'])
if not data[0]:
return data[1]
file = args['file']
name = args['name']
file_path = mw.getRootDir() + '/backup/database/' + file
file_path_sql = mw.getRootDir() + '/backup/database/' + file.replace('.gz', '')
if not os.path.exists(file_path_sql):
cmd = 'cd ' + mw.getRootDir() + '/backup/database && gzip -d ' + file
mw.execShell(cmd)
local_mode = recognizeDbMode()
if local_mode == 'gtid':
pdb = pMysqlDb()
pdb.execute('reset master')
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
mysql_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p"' + pwd + \
'" ' + name
mysql_cmd_progress_bar = "pv -t -p " + file_path_sql + '|'+ mysql_cmd
print(mysql_cmd_progress_bar)
rdata = os.system(mysql_cmd_progress_bar)
return ''
def deleteDbBackup():
args = getArgs()
data = checkArgs(args, ['filename', 'path'])
@@ -2227,7 +2349,7 @@ def addMasterRepSlaveUser(version=''):
if isError != None:
return isError
sql_select = "grant select,lock tables,PROCESS on *.* to " + username + "@'%';"
sql_select = "grant select,reload,REPLICATION CLIENT,PROCESS on *.* to " + username + "@'%';"
pdb.execute(sql_select)
pdb.execute('FLUSH PRIVILEGES;')
@@ -2272,29 +2394,31 @@ def getMasterRepSlaveUserCmd(version):
if sid != '':
channel_name = " for channel 'r{}';".format(sid)
if mode == "gtid":
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
clist[0]['username'] + "', MASTER_PASSWORD='" + \
clist[0]['password'] + "', MASTER_AUTO_POSITION=1" + channel_name
if version == '8.0':
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
clist[0]['username'] + "', SOURCE_PASSWORD='" + \
clist[0]['password'] + \
"', MASTER_AUTO_POSITION=1" + channel_name
else:
sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
clist[0]['username'] + "', MASTER_PASSWORD='" + \
clist[0]['password'] + \
"', MASTER_LOG_FILE='" + mstatus[0]["File"] + \
"',MASTER_LOG_POS=" + str(mstatus[0]["Position"]) + channel_name
mdb8 = ['8.0','8.1','8.2','8.3','8.4']
sql = ''
if not mw.inArray(mdb8,version):
base_sql = "CHANGE MASTER TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
clist[0]['username'] + "', MASTER_PASSWORD='" + \
clist[0]['password'] + "'"
if version == "8.0":
sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
sql += base_sql +';'
sql += "<br/><hr/>"
# sql += base_sql + ", MASTER_AUTO_POSITION=1" + channel_name
sql += base_sql + channel_name
sql += "<br/><hr/>"
sql += base_sql + "', MASTER_LOG_FILE='" + mstatus[0]["File"] + "',MASTER_LOG_POS=" + str(mstatus[0]["Position"]) + channel_name
else:
base_sql = "CHANGE REPLICATION SOURCE TO SOURCE_HOST='" + ip + "', SOURCE_PORT=" + port + ", SOURCE_USER='" + \
clist[0]['username'] + "', SOURCE_PASSWORD='" + \
clist[0]['password'] + \
"', SOURCE_LOG_FILE='" + mstatus[0]["File"] + \
"',SOURCE_LOG_POS=" + \
str(mstatus[0]["Position"]) + channel_name
clist[0]['password']+"'"
sql += base_sql +';'
sql += "<br/><hr/>"
# sql += base_sql + ", MASTER_AUTO_POSITION=1" + channel_name
sql += base_sql + channel_name
sql += "<br/><hr/>"
sql += base_sql + "', SOURCE_LOG_FILE='" + mstatus[0]["File"] + "',SOURCE_LOG_POS=" + str(mstatus[0]["Position"]) + channel_name
data = {}
data['cmd'] = sql
@@ -2647,6 +2771,7 @@ def initSlaveStatus(version=''):
return mw.returnJson(False, 'MySQL未启动', [])
mode_file = getSyncModeFile()
# print(mode_file)
if not os.path.exists(mode_file):
return mw.returnJson(False, '需要先设置同步配置')
@@ -2720,7 +2845,7 @@ def initSlaveStatusSyncUser(version=''):
if slave_t['mode'] == '1':
mode_name = 'gtid'
# print(local_mode, mode_name)
if local_mode != mode_name:
msg += base_t + '->同步模式不一致'
continue
@@ -2734,8 +2859,9 @@ def initSlaveStatusSyncUser(version=''):
pinfo = parseSlaveSyncCmd(cmd_sql)
except Exception as e:
return mw.returnJson(False, base_t + '->CMD同步命令不合规范!')
# print(u['cmd'])
# print(cmd_sql)
t = pdb.query(cmd_sql)
# print(t)
isError = isSqlError(t)
if isError:
return isError
@@ -2850,18 +2976,21 @@ def setSlaveStatus(version=''):
return mw.returnJson(True, '设置成功!')
def deleteSlave(version=''):
args = getArgs()
def deleteSlaveFunc(sign = ''):
db = pMysqlDb()
if 'sign' in args:
sign = args['sign']
if sign != '':
db.query("stop slave for channel '{}'".format(sign))
db.query("reset slave all for channel '{}'".format(sign))
else:
db.query('stop slave')
db.query('reset slave all')
def deleteSlave(version=''):
args = getArgs()
sign = ''
if 'sign' in args:
sign = args['sign']
deleteSlaveFunc(sign)
return mw.returnJson(True, '删除成功!')
@@ -2896,6 +3025,291 @@ def dumpMysqlData(version=''):
return 'fail'
############### --- 重要 数据补足同步 ---- ###########
def getSyncMysqlDB(dbname,sign = ''):
conn = pSqliteDb('slave_sync_user')
if sign != '':
data = conn.field('ip,port,user,pass,mode,cmd').where('ip=?', (sign,)).find()
else:
data = conn.field('ip,port,user,pass,mode,cmd').find()
user = data['user']
apass = data['pass']
port = data['port']
ip = data['ip']
# 远程数据
sync_db = mw.getMyORM()
# MySQLdb |
sync_db.setPort(port)
sync_db.setHost(ip)
sync_db.setUser(user)
sync_db.setPwd(apass)
sync_db.setDbName(dbname)
sync_db.setTimeout(60)
return sync_db
def syncDatabaseRepairTempFile():
tmp_log = mw.getMWLogs()+ '/mysql-check.log'
return tmp_log
def syncDatabaseRepairLog(version=''):
import subprocess
args = getArgs()
data = checkArgs(args, ['db','sign','op'])
if not data[0]:
return data[1]
sync_args_db = args['db']
sync_args_sign = args['sign']
op = args['op']
tmp_log = syncDatabaseRepairTempFile()
cmd = 'cd '+mw.getServerDir()+'/mdserver-web && source bin/activate && python3 plugins/mysql/index.py sync_database_repair {"db":"'+sync_args_db+'","sign":"'+sync_args_sign+'"}'
# print(cmd)
if op == 'get':
log = mw.getLastLine(tmp_log, 15)
return mw.returnJson(True, log)
if op == 'cmd':
return mw.returnJson(True, 'ok', cmd)
if op == 'do':
os.system(' echo "开始执行" > '+ tmp_log)
os.system(cmd +' >> '+ tmp_log +' &')
return mw.returnJson(True, 'ok')
return mw.returnJson(False, '无效请求!')
def syncDatabaseRepair(version=''):
time_stats_s = time.time()
tmp_log = syncDatabaseRepairTempFile()
from pymysql.converters import escape_string
args = getArgs()
data = checkArgs(args, ['db','sign'])
if not data[0]:
return data[1]
sync_args_db = args['db']
sync_args_sign = args['sign']
# 本地数据
local_db = pMysqlDb()
# 远程数据
sync_db = getSyncMysqlDB(sync_args_db,sync_args_sign)
tables = local_db.query('show tables from `%s`' % sync_args_db)
table_key = "Tables_in_" + sync_args_db
inconsistent_table = []
tmp_dir = '/tmp/sync_db_repair'
mw.execShell('mkdir -p '+tmp_dir)
for tb in tables:
table_name = sync_args_db+'.'+tb[table_key]
table_check_file = tmp_dir+'/'+table_name+'.txt'
if os.path.exists(table_check_file):
# print(table_name+', 已检查OK')
continue
primary_key_sql = "SHOW INDEX FROM "+table_name+" WHERE Key_name = 'PRIMARY';";
primary_key_data = local_db.query(primary_key_sql)
# print(primary_key_sql,primary_key_data)
pkey_name = '*'
if len(primary_key_data) == 1:
pkey_name = primary_key_data[0]['Column_name']
# print(pkey_name)
if pkey_name != '*' :
# 智能校验(由于服务器同步可能会慢,比较总数总是对不上)
cmd_local_newpk_sql = 'select ' + pkey_name + ' from ' + table_name + " order by " + pkey_name + " desc limit 1"
cmd_local_newpk_data = local_db.query(cmd_local_newpk_sql)
# print(cmd_local_newpk_data)
if len(cmd_local_newpk_data) == 1:
# 比较总数
cmd_count_sql = 'select count('+pkey_name+') as num from '+table_name + ' where '+pkey_name + ' <= '+ str(cmd_local_newpk_data[0][pkey_name])
local_count_data = local_db.query(cmd_count_sql)
sync_count_data = sync_db.query(cmd_count_sql)
if local_count_data != sync_count_data:
print(cmd_count_sql)
print("all data compare: ",local_count_data, sync_count_data)
else:
print(table_name+' smart compare check ok.')
mw.writeFile(tmp_log, table_name+' smart compare check ok.\n','a+')
mw.execShell("echo 'ok' > "+table_check_file)
continue
# 比较总数
cmd_count_sql = 'select count('+pkey_name+') as num from '+table_name
local_count_data = local_db.query(cmd_count_sql)
sync_count_data = sync_db.query(cmd_count_sql)
if local_count_data != sync_count_data:
print("all data compare: ",local_count_data, sync_count_data)
inconsistent_table.append(table_name)
diff = sync_count_data[0]['num'] - local_count_data[0]['num']
print(table_name+', need sync. diff,'+str(diff))
mw.writeFile(tmp_log, table_name+', need sync. diff,'+str(diff)+'\n','a+')
else:
print(table_name+' check ok.')
mw.writeFile(tmp_log, table_name+' check ok.\n','a+')
mw.execShell("echo 'ok' > "+table_check_file)
# inconsistent_table = ['xx.xx']
# 数据对齐
for table_name in inconsistent_table:
is_break = False
while not is_break:
local_db.ping()
# 远程数据
sync_db.ping()
print("check table:"+table_name)
mw.writeFile(tmp_log, "check table:"+table_name+'\n','a+')
table_name_pos = 0
table_name_pos_file = tmp_dir+'/'+table_name+'.pos.txt'
primary_key_sql = "SHOW INDEX FROM "+table_name+" WHERE Key_name = 'PRIMARY';";
primary_key_data = local_db.query(primary_key_sql)
pkey_name = primary_key_data[0]['Column_name']
if os.path.exists(table_name_pos_file):
table_name_pos = mw.readFile(table_name_pos_file)
data_select_sql = 'select * from '+table_name + ' where '+pkey_name+' > '+str(table_name_pos)+' limit 10000'
print(data_select_sql)
local_select_data = local_db.query(data_select_sql)
time_s = time.time()
sync_select_data = sync_db.query(data_select_sql)
print(f'sync query cos:{time.time() - time_s:.4f}s')
mw.writeFile(tmp_log, f'sync query cos:{time.time() - time_s:.4f}s\n','a+')
# print(local_select_data)
# print(sync_select_data)
# print(len(local_select_data))
# print(len(sync_select_data))
print('pos:',str(table_name_pos),'local compare sync,',local_select_data == sync_select_data)
cmd_count_sql = 'select count('+pkey_name+') as num from '+table_name
local_count_data = local_db.query(cmd_count_sql)
time_s = time.time()
sync_count_data = sync_db.query(cmd_count_sql)
print(f'sync count data cos:{time.time() - time_s:.4f}s')
print(local_count_data,sync_count_data)
# 数据同步有延迟,相等即任务数据补足完成
if local_count_data[0]['num'] == sync_count_data[0]['num']:
is_break = True
break
diff = sync_count_data[0]['num'] - local_count_data[0]['num']
print("diff," + str(diff)+' line data!')
if local_select_data == sync_select_data:
data_count = len(local_select_data)
if data_count == 0:
# mw.writeFile(table_name_pos_file, '0')
print(table_name+",data is equal ok..")
is_break = True
break
# print(table_name,data_count)
pos = local_select_data[data_count-1][pkey_name]
print('pos',pos)
progress = pos/sync_count_data[0]['num']
print('progress,%.2f' % progress+'%')
mw.writeFile(table_name_pos_file, str(pos))
else:
sync_select_data_len = len(sync_select_data)
skip_idx = 0
# 主库PK -> 查询本地 | 保证一致
if sync_select_data_len > 0:
for idx in range(sync_select_data_len):
sync_idx_data = sync_select_data[idx]
local_idx_data = None
if idx in local_select_data:
local_idx_data = local_select_data[idx]
if sync_select_data[idx] == local_idx_data:
skip_idx = idx
pos = local_select_data[idx][pkey_name]
mw.writeFile(table_name_pos_file, str(pos))
# print(insert_data)
local_inquery_sql = 'select * from ' + table_name+ ' where ' +pkey_name+' = '+ str(sync_idx_data[pkey_name])
# print(local_inquery_sql)
ldata = local_db.query(local_inquery_sql)
# print('ldata:',ldata)
if len(ldata) == 0:
print("id:"+ str(sync_idx_data[pkey_name])+ " no exists, insert")
insert_sql = 'insert into ' + table_name
field_str = ''
value_str = ''
for field in sync_idx_data:
field_str += '`'+field+'`,'
value_str += '\''+escape_string(str(sync_idx_data[field]))+'\','
field_str = '(' +field_str.strip(',')+')'
value_str = '(' +value_str.strip(',')+')'
insert_sql = insert_sql+' '+field_str+' values'+value_str+';'
print(insert_sql)
r = local_db.execute(insert_sql)
print(r)
else:
# print('compare sync->local:',sync_idx_data == ldata[0] )
if ldata[0] == sync_idx_data:
continue
print("id:"+ str(sync_idx_data[pkey_name])+ " data is not equal, update")
update_sql = 'update ' + table_name
field_str = ''
value_str = ''
for field in sync_idx_data:
if field == pkey_name:
continue
field_str += '`'+field+'`=\''+escape_string(str(sync_idx_data[field]))+'\','
field_str = field_str.strip(',')
update_sql = update_sql+' set '+field_str+' where '+pkey_name+'=\''+str(sync_idx_data[pkey_name])+'\';'
print(update_sql)
r = local_db.execute(update_sql)
print(r)
# 本地PK -> 查询主库 | 保证一致
# local_select_data_len = len(local_select_data)
# if local_select_data_len > 0:
# for idx in range(local_select_data_len):
# if idx < skip_idx:
# continue
# local_idx_data = local_select_data[idx]
# print('local idx check', idx, skip_idx)
# local_inquery_sql = 'select * from ' + table_name+ ' where ' +pkey_name+' = '+ str(local_idx_data[pkey_name])
# print(local_inquery_sql)
# sdata = sync_db.query(local_inquery_sql)
# sdata_len = len(sdata)
# print('sdata:',sdata,sdata_len)
# if sdata_len == 0:
# delete_sql = 'delete from ' + table_name + ' where ' +pkey_name+' = '+ str(local_idx_data[pkey_name])
# print(delete_sql)
# r = local_db.execute(delete_sql)
# print(r)
# break
if is_break:
print("break all")
break
time.sleep(3)
print(f'data check cos:{time.time() - time_stats_s:.4f}s')
print("data supplementation completed")
mw.execShell('rm -rf '+tmp_dir)
return 'ok'
############### --- 重要 同步---- ###########
def asyncTmpfile():
@@ -2906,7 +3320,20 @@ def asyncTmpfile():
def writeDbSyncStatus(data):
path = asyncTmpfile()
mw.writeFile(path, json.dumps(data))
return True
def fullSyncCmd():
time_all_s = time.time()
args = getArgs()
data = checkArgs(args, ['db', 'sign'])
if not data[0]:
return data[1]
db = args['db']
sign = args['sign']
cmd = 'cd '+mw.getServerDir()+'/mdserver-web && source bin/activate && python3 plugins/mysql/index.py do_full_sync {"db":"'+db+'","sign":"'+sign+'"}'
return mw.returnJson(True,'ok',cmd)
def doFullSync(version=''):
mode_file = getSyncModeFile()
@@ -2920,7 +3347,53 @@ def doFullSync(version=''):
return doFullSyncUser(version)
def isSimpleSyncCmd(sql):
new_sql = sql.lower()
if new_sql.find('master_auto_position') > 0:
return False
return True
def getChannelNameForCmd(cmd):
cmd = cmd.lower()
cmd_arr = cmd.split('channel')
if len(cmd_arr) == 2:
cmd_channel_info = cmd_arr[1]
channel_name = cmd_channel_info.strip()
channel_name = channel_name.strip(';')
channel_name = channel_name.strip("'")
return channel_name
return ''
def doFullSyncUserImportContentForChannel(file, channel_name):
# print(file, channel_name)
content = mw.readFile(file)
content = content.replace('STOP SLAVE;', "STOP SLAVE for channel '{}';".format(channel_name))
content = content.replace('START SLAVE;', "START SLAVE for channel '{}';".format(channel_name))
find_head = "CHANGE MASTER TO "
find_re = find_head+"(.*?);"
find_r = re.search(find_re, content, re.I|re.M)
if find_r:
find_rg = find_r.groups()
if len(find_rg)>0:
find_str = find_head+find_rg[0]
if find_str.lower().find('channel')==-1:
content = content.replace(find_str+';', find_str+" for channel '{}';".format(channel_name))
mw.writeFile(file,content)
return True
def doFullSyncUser(version=''):
which_pv = mw.execShell('which pv')
is_exist_pv = False
if os.path.exists(which_pv[0]):
is_exist_pv = True
time_all_s = time.time()
args = getArgs()
data = checkArgs(args, ['db', 'sign'])
if not data[0]:
@@ -2941,6 +3414,9 @@ def doFullSyncUser(version=''):
db = pMysqlDb()
# 重置
# deleteSlaveFunc(sync_sign)
conn = pSqliteDb('slave_sync_user')
if sync_sign != '':
data = conn.field('ip,port,user,pass,mode,cmd').where(
@@ -2948,10 +3424,15 @@ def doFullSyncUser(version=''):
else:
data = conn.field('ip,port,user,pass,mode,cmd').find()
# print(data)
user = data['user']
apass = data['pass']
port = data['port']
ip = data['ip']
cmd = data['cmd']
channel_name = getChannelNameForCmd(cmd)
sync_mdb = getSyncMysqlDB(sync_db,sync_sign)
bak_file = '/tmp/tmp.sql'
if os.path.exists(bak_file):
@@ -2965,41 +3446,111 @@ def doFullSyncUser(version=''):
time.sleep(1)
writeDbSyncStatus({'code': 1, 'msg': '正在停止从库...', 'progress': 15})
if version == '8.0':
mdb8 = ['8.0','8.1','8.2','8.3','8.4']
if mw.inArray(mdb8,version):
db.query("stop slave user='{}' password='{}';".format(user, apass))
else:
db.query("stop slave")
time.sleep(2)
time.sleep(1)
writeDbSyncStatus({'code': 2, 'msg': '远程导出数据...', 'progress': 20})
if not os.path.exists(bak_file):
dump_sql_data = getServerDir() + "/bin/mysqldump " + dmp_option + " --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
port + " -u" + user + " -p'" + apass + \
"' --ssl-mode=DISABLED " + sync_db + " > " + bak_file
print(dump_sql_data)
mw.execShell(dump_sql_data)
# --master-data=2表示在dump过程中记录主库的binlog和pos点,并在dump文件中注释掉这一行
# --master-data=1表示在dump过程中记录主库的binlog和pos点,并在dump文件中不注释掉这一行,即恢复时会执行
# --dump-slave=2表示在dump过程中,在从库dump,mysqldump进程也要在从库执行,记录当时主库的binlog和pos点,并在dump文件中注释掉这一行
# --dump-slave=1表示在dump过程中,在从库dump,mysqldump进程也要在从库执行,记录当时主库的binlog和pos点,并在dump文件中不注释掉这一行
# --force --opt --single-transaction
# --skip-opt --create-options
# --master-data=1
find_run_dump = mw.execShell('ps -ef | grep mysqldump | grep -v grep')
if find_run_dump[0] != "":
print("正在远程导出数据中,别着急...")
writeDbSyncStatus({'code': 3.1, 'msg': '正在远程导出数据中,别着急...', 'progress': 19})
return False
time_s = time.time()
if not os.path.exists(bak_file):
if isSimpleSyncCmd(cmd):
dmp_option += " --master-data=1 --apply-slave-statements --include-master-host-port "
else:
dmp_option += ' '
dump_sql_data = getServerDir() + "/bin/mysqldump --single-transaction --default-character-set=utf8mb4 --compress -q " + dmp_option + " -h" + ip + " -P" + \
port + " -u" + user + " -p'" + apass + "' --ssl-mode=DISABLED " + sync_db + " > " + bak_file
print(dump_sql_data)
time_s = time.time()
r = mw.execShell(dump_sql_data)
print(r)
time_e = time.time()
export_cos = time_e - time_s
print("export cos:", export_cos)
writeDbSyncStatus({'code': 3, 'msg': '正在到本地导入数据中...', 'progress': 40})
writeDbSyncStatus({'code': 3, 'msg': '导出耗时:'+str(int(export_cos))+'秒,正在到本地导入数据中...', 'progress': 40})
find_run_import = mw.execShell('ps -ef | grep mysql| grep '+ bak_file +' | grep -v grep')
if find_run_import[0] != "":
print("正在导入数据中,别着急...")
writeDbSyncStatus({'code': 4.1, 'msg': '正在导入数据中,别着急...', 'progress': 39})
return False
time_s = time.time()
if os.path.exists(bak_file):
# 重置
db.execute('reset master')
# 加快导入 - 开始
# db.execute('set global innodb_flush_log_at_trx_commit = 2')
# db.execute('set global sync_binlog = 2000')
if channel_name != '':
doFullSyncUserImportContentForChannel(bak_file, channel_name)
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
sock = getSocketFile()
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + " -uroot -p'" + pwd + \
"' " + sync_db_import + ' < ' + bak_file
print(my_import_cmd)
mw.execShell(my_import_cmd)
if version == '8.0':
if is_exist_pv:
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + " -uroot -p'" + pwd + "' " + sync_db_import
my_import_cmd = "pv -t -p " + bak_file + '|' + my_import_cmd
print(my_import_cmd)
os.system(my_import_cmd)
else:
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + " -uroot -p'" + pwd + "' " + sync_db_import + ' < ' + bak_file
print(my_import_cmd)
mw.execShell(my_import_cmd)
# 加快导入 - 结束
# db.execute('set global innodb_flush_log_at_trx_commit = 1')
# db.execute('set global sync_binlog = 1')
time_e = time.time()
import_cos = time_e - time_s
print("import cos:", import_cos)
writeDbSyncStatus({'code': 4, 'msg': '导入耗时:'+str(int(import_cos))+'秒', 'progress': 60})
time.sleep(3)
# print(cmd)
# r = db.query(cmd)
# print(r)
mdb8 = ['8.0','8.1','8.2','8.3','8.4']
if mw.inArray(mdb8,version):
db.query("start slave user='{}' password='{}';".format(user, apass))
else:
db.query("start slave")
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
db.query("start all slaves")
time_all_e = time.time()
cos = time_all_e - time_all_s
writeDbSyncStatus({'code': 6, 'msg': '总耗时:'+str(int(cos))+'秒,从库重启完成...', 'progress': 100})
if os.path.exists(bak_file):
os.system("rm -rf " + bak_file)
return True
@@ -3130,10 +3681,13 @@ def doFullSyncSSH(version=''):
print(import_data[0])
writeDbSyncStatus({'code': 5, 'msg': '导入数据失败...', 'progress': 100})
return 'fail'
# "start slave user='{}' password='{}';".format(uinfo['username'], uinfo['password'])
db.query("start slave")
mdb8 = ['8.0','8.1','8.2','8.3','8.4']
if mw.inArray(mdb8,version):
db.query("start slave user='{}' password='{}';".format(uinfo['username'], uinfo['password']))
else:
db.query("start slave")
writeDbSyncStatus({'code': 6, 'msg': '从库重启完成...', 'progress': 100})
os.system("rm -rf " + SSH_PRIVATE_KEY)
@@ -3178,9 +3732,16 @@ def fullSync(version=''):
def installPreInspection(version):
import psutil
mem = psutil.virtual_memory()
memTotal = mem.total
memG = memTotal/1024/1024/1024
if memG > 2:
return 'ok'
swap_path = mw.getServerDir() + "/swap"
if not os.path.exists(swap_path):
return "为了稳定安装MySQL,先安装swap插件!"
return "内存小,为了稳定安装MySQL,先安装swap插件!"
return 'ok'
@@ -3243,7 +3804,7 @@ if __name__ == "__main__":
elif func == 'my_db_pos':
print(getMyDbPos())
elif func == 'set_db_pos':
print(setMyDbPos())
print(setMyDbPos(version))
elif func == 'my_port':
print(getMyPort())
elif func == 'set_my_port':
@@ -3258,8 +3819,16 @@ if __name__ == "__main__":
print(setDbBackup())
elif func == 'import_db_backup':
print(importDbBackup())
elif func == 'import_db_backup_progress':
print(importDbBackupProgress())
elif func == 'import_db_backup_progress_bar':
print(importDbBackupProgressBar())
elif func == 'import_db_external':
print(importDbExternal())
elif func == 'import_db_external_progress':
print(importDbExternalProgress())
elif func == 'import_db_external_progress_bar':
print(importDbExternalProgressBar())
elif func == 'delete_db_backup':
print(deleteDbBackup())
elif func == 'get_db_backup_list':
@@ -3364,7 +3933,13 @@ if __name__ == "__main__":
print(fullSync(version))
elif func == 'do_full_sync':
print(doFullSync(version))
elif func == 'full_sync_cmd':
print(fullSyncCmd())
elif func == 'dump_mysql_data':
print(dumpMysqlData(version))
elif func == 'sync_database_repair':
print(syncDatabaseRepair())
elif func == 'sync_database_repair_log':
print(syncDatabaseRepairLog())
else:
print('error')
+5 -2
View File
@@ -6,8 +6,11 @@ export PATH
# https://www.cnblogs.com/whiteY/p/17331882.html
# cd /www/server/mdserver-web/plugins/mysql && bash install.sh install 8.2
# cd /www/server/mdserver-web && source bin/activate && python3 /www/server/mdserver-web/plugins/mysql/index.py try_slave_sync_bugfix {}
# cd /www/server/mdserver-web && source bin/activate && python3 plugins/mysql/index.py try_slave_sync_bugfix {}
# cd /www/server/mdserver-web && source bin/activate && python3 plugins/mysql/index.py do_full_sync {"db":"xxx","sign":"","begin":1}
# cd /www/server/mdserver-web && source bin/activate && python3 plugins/mysql/index.py sync_database_repair {"db":"xxx","sign":""}
# cd /www/server/mdserver-web && source bin/activate && python3 plugins/mysql/index.py init_slave_status
# cd /www/server/mdserver-web && source bin/activate && python3 plugins/mysql/index.py install_pre_inspection
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
+176 -12
View File
@@ -871,7 +871,7 @@ function openPhpmyadmin(name,username,password){
}
if (rdata.data['cfg']['choose'] != 'mysql'){
layer.msg('当前为['+rdata.choose+']模式,若要使用请修改phpMyAdmin访问切换.',{icon:2,shade: [0.3, '#000']});
layer.msg('当前为['+rdata.data['cfg']['choose'] + ']模式,若要使用请修改phpMyAdmin访问切换.',{icon:2,shade: [0.3, '#000']});
return;
}
var home_page = rdata.data['home_page'];
@@ -929,6 +929,31 @@ function importBackup(file,name){
});
}
function importBackupProgress(file,name){
myPost('import_db_backup_progress',{file:file,name:name}, function(data){
var rdata = $.parseJSON(data.data);
layer.open({
title: "手动导入命令CMD【显示进度】",
area: ['600px', '180px'],
type:1,
closeBtn: 1,
shadeClose: false,
btn:["复制","取消"],
content: '<div class="pd15">\
<div class="divtable">\
<pre class="layui-code">'+rdata.data+'</pre>\
</div>\
</div>',
success:function(){
copyText(rdata.data);
},
yes:function(){
copyText(rdata.data);
}
});
});
}
function importDbExternal(file,name){
myPost('import_db_external',{file:file,name:name}, function(data){
@@ -936,6 +961,31 @@ function importDbExternal(file,name){
});
}
function importDbExternalProgress(file,name){
myPost('import_db_external_progress',{file:file,name:name}, function(data){
var rdata = $.parseJSON(data.data);
layer.open({
title: "手动导入命令CMD【显示进度】",
area: ['600px', '180px'],
type:1,
closeBtn: 1,
shadeClose: false,
btn:["复制","取消"],
content: '<div class="pd15">\
<div class="divtable">\
<pre class="layui-code">'+rdata.data+'</pre>\
</div>\
</div>',
success:function(){
copyText(rdata.data);
},
yes:function(){
copyText(rdata.data);
}
});
});
}
function setLocalImport(db_name){
//上传文件
@@ -991,6 +1041,7 @@ function setLocalImport(db_name){
<td><span> ' + file_list[i]['time'] + '</span></td>\
<td style="text-align: right;">\
<a class="btlink" onclick="importDbExternal(\'' + file_list[i]['name'] + '\',\'' +db_name+ '\')">导入</a> | \
<a class="btlink" onclick="importDbExternalProgress(\'' + file_list[i]['name'] + '\',\'' +db_name+ '\')">导入进度</a> | \
<a class="btlink del" index="'+i+'">删除</a>\
</td>\
</tr>';
@@ -1014,7 +1065,7 @@ function setLocalImport(db_name){
var layerIndex = layer.open({
type: 1,
title: "从文件导入数据",
area: ['600px', '380px'],
area: ['700px', '380px'],
closeBtn: 1,
shadeClose: false,
content: '<div class="pd15">\
@@ -1060,7 +1111,7 @@ function setBackup(db_name){
var layerIndex = layer.open({
type: 1,
title: "数据库备份详情",
area: ['600px', '280px'],
area: ['700px', '280px'],
closeBtn: 1,
shadeClose: false,
content: '<div class="pd15">\
@@ -1114,6 +1165,7 @@ function setBackupReq(db_name, obj){
<td><span> ' + rdata.data[i]['time'] + '</span></td>\
<td style="text-align: right;">\
<a class="btlink" onclick="importBackup(\'' + rdata.data[i]['name'] + '\',\'' +db_name+ '\')">导入</a> | \
<a class="btlink" onclick="importBackupProgress(\'' + rdata.data[i]['name'] + '\',\'' +db_name+ '\')">导入进度</a> | \
<a class="btlink" onclick="downloadBackup(\'' + rdata.data[i]['file'] + '\')">下载</a> | \
<a class="btlink" onclick="delBackup(\'' + rdata.data[i]['name'] + '\',\'' +db_name+ '\')">删除</a>\
</td>\
@@ -1933,6 +1985,7 @@ function getFullSyncStatus(db){
</div>\
<div class='table_toolbar' style='left:0px;'>\
<span data-status='init' class='sync btn btn-default btn-sm' id='begin_full_sync'>开始</span>\
<span data-status='init' class='btn btn-default btn-sm' id='full_sync_cmd'>手动命令</span>\
</div>\
</div>",
cancel: function(){
@@ -1951,10 +2004,36 @@ function getFullSyncStatus(db){
fullSync(db,sign,0);
}, 1000);
$(this).data('status','starting');
$('#begin_full_sync').text("同步中");
} else {
layer.msg("正在同步中..",{icon:0});
}
});
$('#full_sync_cmd').click(function(){
myPostN('full_sync_cmd', {'db':db,'sign':''}, function(rdata){
var rdata = $.parseJSON(rdata.data);
layer.open({
title: "手动执行命令CMD",
area: ['600px', '180px'],
type:1,
closeBtn: 1,
shadeClose: false,
btn:["复制","取消"],
content: '<div class="pd15">\
<div class="divtable">\
<pre class="layui-code">'+rdata.data+'</pre>\
</div>\
</div>',
success:function(){
copyText(rdata.data);
},
yes:function(){
copyText(rdata.data);
}
});
});
});
}
});
});
@@ -1970,12 +2049,91 @@ function getFullSyncStatus(db){
if (rdata['code']==6 ||rdata['code']<0){
layer.msg(rdata['msg']);
clearInterval(timeId);
$('#begin_full_sync').text("同步结束,再次同步?");
$("#begin_full_sync").attr('data-status','init');
}
});
}
}
function dataSyncVerify(db){
var reqTimer = null;
function requestLogs(layerIndex){
myPostN('sync_database_repair_log', {db:db, sign:'',op:'get'}, function(rdata){
var rdata = $.parseJSON(rdata.data);
if(!rdata.status) {
layer.close(layerIndex);
layer.msg(rdata.msg,{icon:2, time:2000});
clearInterval(reqTimer);
return;
};
if (rdata.msg == ''){
rdata.msg = '暂无数据!';
}
$("#data_verify_log").html(rdata.msg);
//滚动到最低
var ob = document.getElementById('data_verify_log');
ob.scrollTop = ob.scrollHeight;
});
}
layer.open({
type: 1,
title: '同步数据库['+db+']数据校验',
area: '500px',
btn:[ "开始","取消","手动"],
content:"<div class='bt-form'>\
"+'<pre id="data_verify_log" style="overflow: auto; border: 0px none; line-height:23px;padding: 5px; margin: 0px; white-space: pre-wrap; height: 395px; background-color: rgb(51,51,51);color:#f1f1f1;border-radius:0px;font-family:"></pre>'+"\
</div>",
cancel: function(){
if (reqTimer){
clearInterval(reqTimer);
}
},
yes:function(index,layer_index){
myPostN('sync_database_repair_log', {db:db, sign:'',op:'do'}, function(data){});
layer.msg("执行成功");
requestLogs(layer_index);
reqTimer = setInterval(function(){
requestLogs(layer_index);
},3000);
},
success:function(){
},
btn3: function(){
myPostN('sync_database_repair_log', {db:db, sign:'',op:'cmd'}, function(rdata){
var rdata = $.parseJSON(rdata.data);
layer.open({
title: "手动执行命令CMD",
area: ['600px', '180px'],
type:1,
closeBtn: 1,
shadeClose: false,
btn:["复制","取消"],
content: '<div class="pd15">\
<div class="divtable">\
<pre class="layui-code">'+rdata.data+'</pre>\
</div>\
</div>',
success:function(){
copyText(rdata.data);
},
yes:function(){
copyText(rdata.data);
}
});
});
return false;
}
});
}
function addSlaveSSH(ip=''){
myPost('get_slave_ssh_by_ip', {ip:ip}, function(rdata){
@@ -2131,7 +2289,7 @@ function addSlaveSyncUser(ip=''){
var index = layer.open({
type: 1,
area: ['500px','470px'],
area: ['500px','510px'],
title: '同步账户',
closeBtn: 1,
shift: 5,
@@ -2142,6 +2300,15 @@ function addSlaveSyncUser(ip=''){
<div class='line'><span class='tname'>端口</span><div class='info-r'><input name='port' class='bt-input-text mr5' type='number' style='width:330px;' value='"+port+"'></div></div>\
<div class='line'><span class='tname'>同步账户</span><div class='info-r'><input name='user' class='bt-input-text mr5' type='text' style='width:330px;' value='"+user+"'></div></div>\
<div class='line'><span class='tname'>同步密码</span><div class='info-r'><input name='pass' class='bt-input-text mr5' type='text' style='width:330px;' value='"+pass+"'></div></div>\
<div class='line'>\
<span class='tname'>同步模式</span>\
<div class='info-r'>\
<select class='bt-input-text mr5' name='mode'>\
<option value='0' "+( mode == '0' ? 'selected="selected"' : '')+">经典</option>\
<option value='1' "+( mode == '1' ? 'selected="selected"' : '')+">GTID</option>\
</select>\
</div>\
</div>\
<div class='line'>\
<span class='tname'>CMD[必须填写]</span>\
<div class='info-r'><textarea class='bt-input-text mr5' row='20' cols='30' name='cmd' style='width:330px;height:150px;'></textarea></div>\
@@ -2152,6 +2319,7 @@ function addSlaveSyncUser(ip=''){
$('textarea[name="cmd"]').html(cmd);
$('textarea[name="cmd"]').change(function(){
var val = $(this).val();
val = val.replace(';','');
var a = {};
if (val.toLowerCase().indexOf('for')>0){
cmd_tmp = val.split('for');
@@ -2178,11 +2346,6 @@ function addSlaveSyncUser(ip=''){
$('input[name="port"]').val(a['MASTER_PORT']);
$('input[name="user"]').val(a['MASTER_USER']);
$('input[name="pass"]').val(a['MASTER_PASSWORD']);
console.log(a['MASTER_AUTO_POSITION'],typeof(a['MASTER_AUTO_POSITION']));
if (typeof(a['MASTER_AUTO_POSITION']) != 'undefined' ){
$('input[name="mode"]').val('1');
}
});
},
yes:function(index){
@@ -2191,7 +2354,7 @@ function addSlaveSyncUser(ip=''){
var user = $('input[name="user"]').val();
var pass = $('input[name="pass"]').val();
var cmd = $('textarea[name="cmd"]').val();
var mode = $('input[name="mode"]').val();
var mode = $('select[name="mode"]').val();
var data = {ip:ip,port:port,cmd:cmd,user:user,pass:pass,mode:mode};
myPost('add_slave_sync_user', data, function(ret_data){
@@ -2469,7 +2632,7 @@ function masterOrSlaveConf(version=''){
for(i in rdata.data){
var v = rdata.data[i];
if ('Channel_Name' in v){
if ('Channel_Name' in v && v['Channel_Name'] !=''){
isHasSign = true;
}
@@ -2640,7 +2803,8 @@ function masterOrSlaveConf(version=''){
list += '<td>' + rdata.data[i]['name'] +'</td>';
list += '<td style="text-align:right">' +
'<a href="javascript:;" class="btlink" onclick="setDbSlave(\''+rdata.data[i]['name']+'\')" title="加入|退出">'+(rdata.data[i]['slave']?'退出':'加入')+'</a> | ' +
'<a href="javascript:;" class="btlink" onclick="getFullSyncStatus(\''+rdata.data[i]['name']+'\')" title="同步">同步</a>' +
'<a href="javascript:;" class="btlink" onclick="getFullSyncStatus(\''+rdata.data[i]['name']+'\')" title="同步">同步</a> | ' +
'<a href="javascript:;" class="btlink" onclick="dataSyncVerify(\''+rdata.data[i]['name']+'\')" title="数据校验">数据校验</a>' +
'</td>';
list += '</tr>';
}
+1 -1
View File
@@ -51,7 +51,7 @@ http
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_comp_level 9;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
+3 -3
View File
@@ -26,7 +26,7 @@ function phpPost(method, version, args,callback){
},'json');
}
function phpPostCallbak(method, version, args,callback){
function phpPostCallback(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
@@ -715,7 +715,7 @@ function getPHPInfo_old(version) {
}
function getPHPInfo(version) {
phpPostCallbak('get_php_info', version, {}, function(data){
phpPostCallback('get_php_info', version, {}, function(data){
if (!data.status){
layer.msg(rdata.msg, { icon: 2 });
return;
@@ -739,7 +739,7 @@ function phpLibConfig(version){
// var rdata = $.parseJSON(rdata.data);
// });
phpPostCallbak('get_lib_conf', version, {}, function(rdata){
phpPostCallback('get_lib_conf', version, {}, function(rdata){
var rdata = rdata.data;
if (!rdata.status){
+2 -2
View File
@@ -16,7 +16,7 @@ function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)"
function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; }
version=8.1.27
version=8.1.28
PHP_VER=81
Install_php()
{
@@ -56,7 +56,7 @@ if [ ! -d $sourcePath/php/php${PHP_VER} ];then
fi
#检测文件是否损坏.
md5_file_ok=479e65c3f05714d4aace1370e617d78e49e996ec7a7579a5be47535be61f0658
md5_file_ok=95d0b2e9466108fd750dab5c30a09e5c67f5ad2cb3b1ffb3625a038a755ad080
if [ -f $sourcePath/php/php-${version}.tar.xz ];then
md5_file=`sha256sum $sourcePath/php/php-${version}.tar.xz | awk '{print $1}'`
if [ "${md5_file}" != "${md5_file_ok}" ]; then
+2 -2
View File
@@ -16,7 +16,7 @@ function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)"
function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; }
version=8.2.17
version=8.2.18
PHP_VER=82
Install_php()
{
@@ -57,7 +57,7 @@ if [ ! -d $sourcePath/php/php${PHP_VER} ];then
fi
#检测文件是否损坏.
md5_file_ok=1cc4ef733ba58f6557db648012471f1916e5bac316303aa165535bedab08ee35
md5_file_ok=44b306fc021e56441f691da6c3108788bd9e450f293b3bc70fcd64b08dd41a50
if [ -f $sourcePath/php/php-${version}.tar.xz ];then
md5_file=`sha256sum $sourcePath/php/php-${version}.tar.xz | awk '{print $1}'`
if [ "${md5_file}" != "${md5_file_ok}" ]; then
+2 -2
View File
@@ -15,7 +15,7 @@ function version_le() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)"
function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" != "$1"; }
function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; }
version=8.3.4
version=8.3.6
PHP_VER=83
Install_php()
{
@@ -56,7 +56,7 @@ if [ ! -d $sourcePath/php/php${PHP_VER} ];then
fi
#检测文件是否损坏.
md5_file_ok=39a337036a546e5c28aea76cf424ac172db5156bd8a8fd85252e389409a5ba63
md5_file_ok=53c8386b2123af97626d3438b3e4058e0c5914cb74b048a6676c57ac647f5eae
if [ -f $sourcePath/php/php-${version}.tar.xz ];then
md5_file=`sha256sum $sourcePath/php/php-${version}.tar.xz | awk '{print $1}'`
if [ "${md5_file}" != "${md5_file_ok}" ]; then
+4
View File
@@ -17,6 +17,10 @@ sysName=`uname`
actionType=$1
version=$2
if [ "$version" -ge '74' ];then
LIBV=1.19.0
fi
if [ "$version" == '71' ];then
LIBV=1.11.1
fi
+6 -2
View File
@@ -210,13 +210,17 @@ def __delete_port(port):
def openPort():
for i in ["888"]:
conf = getCfg()
port = conf['port']
for i in [port]:
__release_port(i)
return True
def delPort():
for i in ["888"]:
conf = getCfg()
port = conf['port']
for i in [port]:
__delete_port(i)
return True
+9 -4
View File
@@ -1,5 +1,5 @@
daemonize yes
pidfile {$SERVER_PATH}/redis/redis_6379.pid
pidfile {$SERVER_PATH}/redis/redis.pid
bind 127.0.0.1
port 6379
@@ -40,15 +40,20 @@ maxclients 10000
#maxmemory-samples 3
maxmemory 218mb
maxmemory-policy volatile-ttl
#maxmemory-policy allkeys-lru
############################## APPEND ONLY MODE ###############################
#appendonly no
# appendonly no
# appendfsync always
#appendfsync everysec
# appendfsync everysec
# appendfsync no
#no-appendfsync-on-rewrite no
# appendfilename "appendonly.aof"
# no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
+1 -1
View File
@@ -23,7 +23,7 @@ if [ "$REDISPASS" != "" ];then
fi
EXEC={$SERVER_PATH}/redis/bin/redis-server
CLIEXEC="{$SERVER_PATH}/redis/bin/redis-cli -p $REDISPORT$REDISPASS"
PIDFILE={$SERVER_PATH}/redis/redis_6379.pid
PIDFILE={$SERVER_PATH}/redis/redis.pid
echo $REDISPASS
echo $REDISPORT
+14 -9
View File
@@ -25,14 +25,16 @@ Install_App()
{
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/source
mkdir -p $serverPath/source/redis
if [ ! -f $serverPath/source/redis-${VERSION}.tar.gz ];then
wget -O $serverPath/source/redis-${VERSION}.tar.gz http://download.redis.io/releases/redis-${VERSION}.tar.gz
FILE_TGZ=redis-${VERSION}.tar.gz
REDIS_DIR=$serverPath/source/redis
if [ ! -f $REDIS_DIR/${FILE_TGZ} ];then
wget -O $REDIS_DIR/${FILE_TGZ} http://download.redis.io/releases/${FILE_TGZ}
fi
cd $serverPath/source && tar -zxvf redis-${VERSION}.tar.gz
cd $REDIS_DIR && tar -zxvf ${FILE_TGZ}
CMD_MAKE=`which gmake`
if [ "$?" == "0" ];then
@@ -55,8 +57,8 @@ Install_App()
echo '安装失败!'
fi
if [ -d $serverPath/source/redis-${VERSION} ];then
rm -rf $serverPath/source/redis-${VERSION}
if [ -d ${REDIS_DIR}/redis-${VERSION} ];then
rm -rf ${REDIS_DIR}/redis-${VERSION}
fi
}
@@ -80,8 +82,11 @@ Uninstall_App()
$serverPath/redis/initd/redis stop
fi
rm -rf $serverPath/redis
echo "Uninstall_redis" > $install_tmp
if [ -d $serverPath/redis ];then
rm -rf $serverPath/redis
fi
echo "卸载redis成功"
}
action=$1
+1 -1
View File
@@ -1,5 +1,5 @@
daemonize yes
pidfile {$SERVER_PATH}/redis/redis_6379.pid
pidfile {$SERVER_PATH}/redis/redis.pid
loglevel notice
logfile {$SERVER_PATH}/redis/data/redis.log
+1 -1
View File
@@ -1,5 +1,5 @@
daemonize yes
pidfile {$SERVER_PATH}/redis/redis_6379.pid
pidfile {$SERVER_PATH}/redis/redis.pid
bind 127.0.0.1
port 6379
+11 -10
View File
@@ -1,17 +1,18 @@
daemonize yes
pidfile {$SERVER_PATH}/redis/redis_6379.pid
loglevel notice
logfile {$SERVER_PATH}/redis/data/redis.log
databases 16
timeout 0
tcp-keepalive 0
pidfile {$SERVER_PATH}/redis/redis.pid
bind 127.0.0.1
port 6379
requirepass {$REDIS_PASS}
timeout 0
tcp-keepalive 0
loglevel notice
logfile {$SERVER_PATH}/redis/data/redis.log
databases 16
################################ SNAPSHOTTING #################################
save 900 1
@@ -33,7 +34,7 @@ slave-priority 100
# 填写主库信息
#slaveof 127.0.0.1 6379
#masterauth master_pwd
#masterauth 123123
################################## SECURITY ###################################
@@ -41,7 +42,7 @@ slave-priority 100
################################### LIMITS ####################################
maxclients 10000
#maxmemory-samples 3
maxmemory 218mb
maxmemory 0mb
maxmemory-policy volatile-ttl
############################## APPEND ONLY MODE ###############################
+75
View File
@@ -0,0 +1,75 @@
daemonize yes
pidfile {$SERVER_PATH}/redis/redis.pid
loglevel notice
logfile {$SERVER_PATH}/redis/data/redis.log
databases 16
timeout 0
tcp-keepalive 0
bind 127.0.0.1
port 6379
requirepass {$REDIS_PASS}
################################ SNAPSHOTTING #################################
save ""
stop-writes-on-bgsave-error no
################################# REPLICATION #################################
slave-serve-stale-data yes
slave-read-only yes
repl-disable-tcp-nodelay no
slave-priority 100
# 填写主库信息
#slaveof 127.0.0.1 6379
#masterauth 123123
################################## SECURITY ###################################
################################### LIMITS ####################################
maxclients 10000
#maxmemory-samples 3
maxmemory 218mb
maxmemory-policy allkeys-lru
############################## APPEND ONLY MODE ###############################
################################ LUA SCRIPTING ###############################
lua-time-limit 5000
################################## SLOW LOG ###################################
slowlog-log-slower-than 10000
slowlog-max-len 128
############################### ADVANCED CONFIG ###############################
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
activerehashing no
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes
+486
View File
@@ -0,0 +1,486 @@
# coding:utf-8
import sys
import io
import os
import time
import subprocess
import re
import json
sys.path.append(os.getcwd() + "/class/core")
import mw
def getServerDir():
return mw.getServerDir() + '/mysql'
def getPluginDir():
return mw.getPluginDir() + '/mysql'
def getConf():
path = getServerDir() + '/etc/my.cnf'
return path
def getDbPort():
file = getConf()
content = mw.readFile(file)
rep = 'port\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getSocketFile():
file = getConf()
content = mw.readFile(file)
rep = 'socket\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def pSqliteDb(dbname='databases'):
file = getServerDir() + '/mysql.db'
name = 'mysql'
conn = mw.M(dbname).dbPos(getServerDir(), name)
return conn
def pMysqlDb():
# pymysql
db = mw.getMyORM()
db.setPort(getDbPort())
db.setSocket(getSocketFile())
# db.setCharset("utf8")
db.setPwd(pSqliteDb('config').where('id=?', (1,)).getField('mysql_root'))
return db
class sphinxMake():
pdb = None
psdb = None
pkey_name_cache = {}
delta = 'sph_counter'
ver = ''
def __init__(self):
self.pdb = pMysqlDb()
def setDeltaName(self, name):
self.delta = name
return True
def setVersion(self, ver):
self.ver = ver
def createSql(self, db):
conf = '''
CREATE TABLE IF NOT EXISTS `{$DB_NAME}`.`{$TABLE_NAME}` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`table` varchar(200) NOT NULL,
`max_id` bigint(20) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `table_uniq` (`table`),
KEY `table` (`table`)
) ENGINE=InnoDB AUTO_INCREMENT=1 CHARSET=utf8mb4;
'''
conf = conf.replace("{$TABLE_NAME}", self.delta)
conf = conf.replace("{$DB_NAME}", db)
return conf
def eqVerField(self, field):
ver = self.ver.replace(".1",'')
if float(ver) >= 3.6:
if field == 'sql_attr_timestamp':
return 'attr_bigint'
if field == 'sql_attr_bigint':
return 'attr_bigint'
if field == 'sql_attr_float':
return 'attr_float'
if field == 'sql_field_string':
return 'field_string'
if float(ver) >= 3.3:
if field == 'sql_attr_timestamp':
return 'sql_attr_bigint'
return field
def pathVerName(self):
ver = self.ver.replace(".1",'')
# if float(ver) >= 3.6:
# return 'datadir'
return 'path'
def getTablePk(self, db, table):
key = db+'_'+table
if key in self.pkey_name_cache:
return self.pkey_name_cache[key]
# SHOW INDEX FROM bbs.bbs_ucenter_vars WHERE Key_name = 'PRIMARY'
pkey_sql = "SHOW INDEX FROM {}.{} WHERE Key_name = 'PRIMARY';".format(db,table,);
pkey_data = self.pdb.query(pkey_sql)
# print(db, table)
# print(pkey_data)
key = ''
if len(pkey_data) == 1:
pkey_name = pkey_data[0]['Column_name']
sql = "select COLUMN_NAME,DATA_TYPE from information_schema.COLUMNS where `TABLE_SCHEMA`='{}' and `TABLE_NAME` = '{}' and `COLUMN_NAME`='{}';"
sql = sql.format(db,table,pkey_name,)
# print(sql)
fields = self.pdb.query(sql)
if len(fields) == 1:
# print(fields[0]['DATA_TYPE'])
if mw.inArray(['bigint','smallint','tinyint','int','mediumint'], fields[0]['DATA_TYPE']):
key = pkey_name
return key
def getTableFieldStr(self, db, table):
sql = "select COLUMN_NAME,DATA_TYPE from information_schema.COLUMNS where `TABLE_SCHEMA`='{}' and `TABLE_NAME` = '{}';"
sql = sql.format(db,table,)
fields = self.pdb.query(sql)
field_str = ''
for x in range(len(fields)):
field_str += '`'+fields[x]['COLUMN_NAME']+'`,'
field_str = field_str.strip(',')
return field_str
def makeSphinxHeader(self):
conf = '''
indexer
{
mem_limit = 128M
}
searchd
{
listen = 9312
listen = 9306:mysql41
log = {$server_dir}/sphinx/index/searchd.log
query_log = {$server_dir}/sphinx/index/query.log
read_timeout = 5
max_children = 0
pid_file = {$server_dir}/sphinx/index/searchd.pid
seamless_rotate = 1
preopen_indexes = 1
unlink_old = 1
#workers = threads # for RT to work
binlog_path = {$server_dir}/sphinx/index/binlog
}
'''
conf = conf.replace("{$server_dir}", mw.getServerDir())
return conf
def makeSphinxDbSourceRangeSql(self, db, table):
pkey_name = self.getTablePk(db,table)
sql = "SELECT min("+pkey_name+"), max("+pkey_name+") FROM "+table
return sql
def makeSphinxDbSourceQuerySql(self, db, table):
pkey_name = self.getTablePk(db,table)
field_str = self.getTableFieldStr(db,table)
# print(field_str)
if pkey_name == 'id':
sql = "SELECT " + field_str + " FROM " + table + " where id >= $start AND id <= $end"
else:
sql = "SELECT `"+pkey_name+'` as `id`,' + field_str + " FROM " + table + " where "+pkey_name+" >= $start AND "+pkey_name+" <= $end"
return sql
def makeSphinxDbSourceDeltaRange(self, db, table):
pkey_name = self.getTablePk(db,table)
conf = "SELECT (SELECT max_id FROM `{$SPH_TABLE}` where `table`='{$TABLE_NAME}') as min, (SELECT max({$PK_NAME}) FROM {$TABLE_NAME}) as max"
conf = conf.replace("{$DB_NAME}", db)
conf = conf.replace("{$TABLE_NAME}", table)
conf = conf.replace("{$SPH_TABLE}", self.delta)
conf = conf.replace("{$PK_NAME}", pkey_name)
return conf
def makeSphinxDbSourcePost(self, db, table):
pkey_name = self.getTablePk(db,table)
conf = "sql_query_post = UPDATE {$SPH_TABLE} SET max_id=(SELECT MAX({$PK_NAME}) FROM {$TABLE_NAME}) where `table`='{$TABLE_NAME}'"
# conf = "REPLACE INTO {$SPH_TABLE} (`table`,`max_id`) VALUES ('{$TABLE_NAME}',(SELECT MAX({$PK_NAME}) FROM {$TABLE_NAME}))"
conf = conf.replace("{$DB_NAME}", db)
conf = conf.replace("{$TABLE_NAME}", table)
conf = conf.replace("{$SPH_TABLE}", self.delta)
conf = conf.replace("{$PK_NAME}", pkey_name)
return conf
def makeSphinxDbSourceDelta(self, db, table):
conf = '''
source {$DB_NAME}_{$TABLE_NAME}_delta:{$DB_NAME}_{$TABLE_NAME}
{
sql_query_pre = SET NAMES utf8
sql_query_range = {$DELTA_RANGE}
sql_query = {$DELTA_QUERY}
{$DELTA_UPDATE}
{$SPH_FIELD}
}
index {$DB_NAME}_{$TABLE_NAME}_delta:{$DB_NAME}_{$TABLE_NAME}
{
source = {$DB_NAME}_{$TABLE_NAME}_delta
{$PATH_NAME} = {$server_dir}/sphinx/index/db/{$DB_NAME}.{$TABLE_NAME}/delta
html_strip = 1
ngram_len = 1
ngram_chars = U+3000..U+2FA1F
{$SPH_FIELD_INDEX}
}
''';
conf = conf.replace("{$server_dir}", mw.getServerDir())
conf = conf.replace("{$PATH_NAME}", self.pathVerName())
conf = conf.replace("{$DB_NAME}", db)
conf = conf.replace("{$TABLE_NAME}", table)
delta_range = self.makeSphinxDbSourceDeltaRange(db, table)
conf = conf.replace("{$DELTA_RANGE}", delta_range)
delta_query = self.makeSphinxDbSourceQuerySql(db, table)
conf = conf.replace("{$DELTA_QUERY}", delta_query)
delta_update = self.makeSphinxDbSourcePost(db, table)
conf = conf.replace("{$DELTA_UPDATE}", delta_update)
sph_field = self.makeSqlToSphinxTable(db, table)
conf = self.makeSphinxDbFieldRepalce(conf, sph_field)
return conf;
def makeSphinxDbSource(self, db, table, create_sphinx_table = False):
db_info = pSqliteDb('databases').field('username,password').where('name=?', (db,)).find()
port = getDbPort()
conf = '''
source {$DB_NAME}_{$TABLE_NAME}
{
type = mysql
sql_host = 127.0.0.1
sql_user = {$DB_USER}
sql_pass = {$DB_PASS}
sql_db = {$DB_NAME}
sql_port = {$DB_PORT}
sql_query_pre = SET NAMES utf8
{$UPDATE}
sql_query_range = {$DB_RANGE_SQL}
sql_range_step = 1000
sql_query = {$DB_QUERY_SQL}
{$SPH_FIELD}
}
index {$DB_NAME}_{$TABLE_NAME}
{
source = {$DB_NAME}_{$TABLE_NAME}
{$PATH_NAME} = {$server_dir}/sphinx/index/db/{$DB_NAME}.{$TABLE_NAME}/index
ngram_len = 1
ngram_chars = U+3000..U+2FA1F
{$SPH_FIELD_INDEX}
}
'''
conf = conf.replace("{$server_dir}", mw.getServerDir())
conf = conf.replace("{$PATH_NAME}", self.pathVerName())
conf = conf.replace("{$DB_NAME}", db)
conf = conf.replace("{$TABLE_NAME}", table)
conf = conf.replace("{$DB_USER}", db_info['username'])
conf = conf.replace("{$DB_PASS}", db_info['password'])
conf = conf.replace("{$DB_PORT}", port)
range_sql = self.makeSphinxDbSourceRangeSql(db, table)
conf = conf.replace("{$DB_RANGE_SQL}", range_sql)
query_sql = self.makeSphinxDbSourceQuerySql(db, table)
conf = conf.replace("{$DB_QUERY_SQL}", query_sql)
sph_field = self.makeSqlToSphinxTable(db, table)
# conf = conf.replace("{$SPH_FIELD}", sph_field)
conf = self.makeSphinxDbFieldRepalce(conf, sph_field)
if create_sphinx_table:
update = self.makeSphinxDbSourcePost(db, table)
conf = conf.replace("{$UPDATE}", update)
else:
conf = conf.replace("{$UPDATE}", '')
if create_sphinx_table:
sph_sql = self.createSql(db)
self.pdb.query(sph_sql)
sql_find = "select * from {}.{} where `table`='{}'".format(db,self.delta,table)
find_data = self.pdb.query(sql_find)
if len(find_data) == 0:
insert_sql = "insert into `{}`.`{}`(`table`,`max_id`) values ('{}',{}) ".format(db,self.delta,table,0)
# print(insert_sql)
self.pdb.execute(insert_sql)
conf += self.makeSphinxDbSourceDelta(db,table)
# print(ver)
# print(conf)
return conf
def makeSphinxDbFieldRepalce(self, content, sph_field):
ver = self.ver.replace(".1",'')
ver = float(ver)
if ver >= 3.6:
content = content.replace("{$SPH_FIELD}", '')
content = content.replace("{$SPH_FIELD_INDEX}", '')
else:
content = content.replace("{$SPH_FIELD}", sph_field)
content = content.replace("{$SPH_FIELD_INDEX}", '')
return content
def makeSqlToSphinxDb(self, db, table = [], is_delta = False):
conf = ''
for tn in table:
pkey_name = self.getTablePk(db,tn)
if pkey_name == '':
continue
conf += self.makeSphinxDbSource(db, tn,is_delta)
if len(table) == 0:
tables = self.pdb.query("show tables in "+ db)
for x in range(len(tables)):
key = 'Tables_in_'+db
table_name = tables[x][key]
pkey_name = self.getTablePk(db, table_name, is_delta)
if pkey_name == '':
continue
if self.makeSqlToSphinxTableIsHaveFulltext(db, table_name):
conf += self.makeSphinxDbSource(db, table_name)
return conf
def makeSqlToSphinxTableIsHaveFulltext(self, db, table):
sql = "select COLUMN_NAME,DATA_TYPE from information_schema.COLUMNS where `TABLE_SCHEMA`='{}' and `TABLE_NAME` = '{}';"
sql = sql.format(db,table,)
cols = self.pdb.query(sql)
cols_len = len(cols)
for x in range(cols_len):
data_type = cols[x]['DATA_TYPE']
column_name = cols[x]['COLUMN_NAME']
if mw.inArray(['varchar'], data_type):
return True
if mw.inArray(['text','mediumtext','tinytext','longtext'], data_type):
return True
return False
def makeSqlToSphinxTable(self,db,table):
pkey_name = self.getTablePk(db,table)
sql = "select COLUMN_NAME,DATA_TYPE from information_schema.COLUMNS where `TABLE_SCHEMA`='{}' and `TABLE_NAME` = '{}';"
sql = sql.format(db,table,)
cols = self.pdb.query(sql)
cols_len = len(cols)
conf = ''
run_pos = 0
for x in range(cols_len):
data_type = cols[x]['DATA_TYPE']
column_name = cols[x]['COLUMN_NAME']
# print(column_name+":"+data_type)
# if mw.inArray(['tinyint'], data_type):
# conf += 'sql_attr_bool = '+ column_name + "\n"
if pkey_name == column_name:
# run_pos += 1
# conf += '\tsql_attr_bigint = '+column_name+"\n"
continue
if mw.inArray(['enum'], data_type):
run_pos += 1
conf += '\t'+self.eqVerField('sql_attr_string')+' = '+ column_name + "\n"
continue
if mw.inArray(['decimal'], data_type):
run_pos += 1
conf += '\t'+self.eqVerField('sql_attr_float')+' = '+ column_name + "\n"
continue
if mw.inArray(['bigint','smallint','tinyint','int','mediumint'], data_type):
run_pos += 1
conf += '\t'+self.eqVerField('sql_attr_bigint')+' = '+ column_name + "\n"
continue
if mw.inArray(['float'], data_type):
run_pos += 1
conf += '\t'+self.eqVerField('sql_attr_float')+' = '+ column_name + "\n"
continue
if mw.inArray(['char'], data_type):
conf += '\t'+self.eqVerField('sql_attr_string')+' = '+ column_name + "\n"
continue
if mw.inArray(['varchar'], data_type):
run_pos += 1
conf += '\t'+self.eqVerField('sql_field_string')+' = '+ column_name + "\n"
continue
if mw.inArray(['text','mediumtext','tinytext','longtext'], data_type):
run_pos += 1
conf += '\t'+self.eqVerField('sql_field_string')+' = '+ column_name + "\n"
continue
if mw.inArray(['datetime','date'], data_type):
run_pos += 1
conf += '\t'+self.eqVerField('sql_attr_timestamp')+' = '+ column_name + "\n"
continue
return conf
def checkDbName(self, db):
filter_db = ['information_schema','performance_schema','sys','mysql']
if db in filter_db:
return False
return True
def makeSqlToSphinx(self, db, tables = [], is_delta = False):
conf = ''
conf += self.makeSphinxHeader()
conf += self.makeSqlToSphinxDb(db, tables, is_delta)
return conf
def makeSqlToSphinxAll(self):
filter_db = ['information_schema','performance_schema','sys','mysql']
dblist = self.pdb.query('show databases')
conf = ''
conf += self.makeSphinxHeader()
# conf += makeSqlToSphinxDb(pdb, 'bbs')
for x in range(len(dblist)):
dbname = dblist[x]['Database']
if mw.inArray(filter_db, dbname):
continue
conf += self.makeSqlToSphinxDb(dbname)
return conf
+17 -3
View File
@@ -1,21 +1,35 @@
<style>
#table xm-select{
min-height: 30px;
line-height: 30px;
}
#table xm-select *{
font-size: 12px;
}
</style>
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('sphinx');">服务</p>
<p onclick="pluginInitD('sphinx');">自启动</p>
<p onclick="pluginConfigTpl('sphinx');">配置修改</p>
<p onclick="pluginConfigTpl('sphinx','', 'conf','config_tpl','read_config_tpl',tryRebuildIndex);">配置修改</p>
<p onclick="pluginLogs('sphinx','','run_log',30);">运行日志</p>
<p onclick="pluginLogs('sphinx','','query_log', 30);">查询日志</p>
<p onclick="runStatus();">运行状态</p>
<p onclick="rebuild();">重建索引</p>
<p onclick="commonFunc();">常用功能</p>
<p onclick="readme();">说明</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
<div class="soft-man-con" style="height:425px;overflow: auto;"></div>
</div>
</div>
</div>
<script type="text/javascript">
resetPluginWinHeight(500);
$.getScript( "/plugins/file?name=sphinx&f=js/sphinx.js", function(){
pluginService('sphinx');
});
+84 -16
View File
@@ -15,14 +15,13 @@ app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'sphinx'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
sys.path.append(getPluginDir() +"/class")
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
@@ -210,9 +209,10 @@ def reload():
def rebuild():
file = initDreplace()
subprocess.Popen(file + ' rebuild &',
stdout=subprocess.PIPE, shell=True)
# data = mw.execShell(file + ' rebuild')
cmd = file + ' rebuild'
data = mw.execShell(cmd)
if data[0].find('successfully')<0:
return data[0].replace("\n","<br/>")
return 'ok'
@@ -295,18 +295,35 @@ def sphinxConfParse():
sindex = re.findall(rep, content)
indexlen = len(sindex)
cmd = {}
if indexlen > 0:
cmd_index = []
cmd_delta = []
for x in range(indexlen):
if sindex[x].find(':') != -1:
cmd_delta.append(sindex[x])
else:
cmd_index.append(sindex[x])
cmd['cmd'] = bin_dir + '/bin/bin/indexer -c ' + bin_dir + '/sphinx.conf'
cmd['index'] = cmd_index
cmd['delta'] = cmd_delta
cmd['cmd'] = bin_dir + '/bin/bin/indexer -c ' + bin_dir + '/sphinx.conf'
cmd['index'] = []
cmd_index = []
cmd_delta = []
if indexlen > 0:
for x in range(indexlen):
name = sindex[x].strip()
if name == '':
continue
if name.find(':') != -1:
cmd_delta.append(name.strip())
else:
cmd_index.append(name.strip())
# print(cmd_index)
# print(cmd_delta)
for ci in cmd_index:
val = {}
val['index'] = ci
for cd in cmd_delta:
cd = cd.replace(" ", '')
if cd.find(":"+ci) > -1:
val['delta'] = cd.split(":")[0].strip()
break
cmd['index'].append(val)
return cmd
@@ -317,6 +334,55 @@ def sphinxCmd():
else:
return mw.returnJson(False, 'no index')
def makeDbToSphinxTest():
conf_file = getConf()
import sphinx_make
sph_make = sphinx_make.sphinxMake()
conf = sph_make.makeSqlToSphinxAll()
mw.writeFile(conf_file,conf)
print(conf)
# makeSqlToSphinxTable()
return True
def makeDbToSphinx():
args = getArgs()
check = checkArgs(args, ['db','tables','is_delta','is_cover'])
if not check[0]:
return check[1]
db = args['db']
tables = args['tables']
is_delta = args['is_delta']
is_cover = args['is_cover']
if is_cover != 'yes':
return mw.returnJson(False,'暂时仅支持覆盖!')
sph_file = getConf()
import sphinx_make
sph_make = sphinx_make.sphinxMake()
version_pl = getServerDir() + "/version.pl"
if os.path.exists(version_pl):
version = mw.readFile(version_pl).strip()
sph_make.setVersion(version)
if not sph_make.checkDbName(db):
return mw.returnJson(False,'保留数据库名称,不可用!')
is_delta_bool = False
if is_delta == 'yes':
is_delta_bool = True
if is_cover == 'yes':
tables = tables.split(',')
content = sph_make.makeSqlToSphinx(db, tables, is_delta_bool)
mw.writeFile(sph_file,content)
return mw.returnJson(True,'设置成功!')
return mw.returnJson(True,'测试中')
if __name__ == "__main__":
func = sys.argv[1]
@@ -352,5 +418,7 @@ if __name__ == "__main__":
print(runStatus())
elif func == 'sphinx_cmd':
print(sphinxCmd())
elif func == 'db_to_sphinx':
print(makeDbToSphinx())
else:
print('error')
+1 -2
View File
@@ -4,8 +4,7 @@
"name": "sphinx",
"title": "sphinx",
"shell": "install.sh",
"versions":["3.1.1"],
"updates":["3.1.1"],
"versions":["3.1.1","3.2.1","3.3.1","3.4.1","3.5.1","3.6.1","3.7.1"],
"tip": "soft",
"checks": "server/sphinx",
"path": "server/sphinx",
+1 -1
View File
@@ -33,7 +33,7 @@ start () {
}
rebuild () {
${APP_PATH}/bin/bin/indexer -c ${APP_CONF} --all --rotate &
${APP_PATH}/bin/bin/indexer -c ${APP_CONF} --all --rotate
}
+98 -22
View File
@@ -7,45 +7,108 @@ rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
sysName=`uname`
sysArch=`arch`
install_tmp=${rootPath}/tmp/mw_install.pl
# cd /www/server/mdserver-web && source bin/activate && python3 plugins/sphinx/index.py rebuild
# cd /www/server/mdserver-web/plugins/sphinx && bash install.sh install 3.6.1
# cd /www/server/mdserver-web && source bin/activate && python3 plugins/sphinx/index.py db_to_sphinx && /www/server/sphinx/bin/bin/indexer -c /www/server/sphinx/sphinx.conf --all --rotate
# /Users/midoks/Desktop/mwdev/server/sphinx/bin/bin/indexer /Users/midoks/Desktop/mwdev/server/sphinx/sphinx.conf --all --rotate
# cd /www/server/mdserver-web && source bin/activate && python3 plugins/sphinx/index.py sphinx_cmd
# /Users/midoks/Desktop/mwdev/server/sphinx/bin/bin/indexer /Users/midoks/Desktop/mwdev/server/sphinx/sphinx.conf --all --rotate
# cd /www/server/mdserver-web && source bin/activate && python3 plugins/sphinx/index.py start
bash ${rootPath}/scripts/getos.sh
OSNAME=`cat ${rootPath}/data/osname.pl`
OSNAME_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
# echo "bash ${rootPath}/scripts/getos.sh"
OSNAME="macos"
if [ -f ${rootPath}/data/osname.pl ];then
OSNAME=`cat ${rootPath}/data/osname.pl`
fi
if [ ${OSNAME} == "centos" ] ||
[ ${OSNAME} == "fedora" ] ||
[ ${OSNAME} == "alma" ]; then
if [ "${OSNAME}" == "centos" ] ||
[ "${OSNAME}" == "fedora" ] ||
[ "${OSNAME}" == "alma" ]; then
yum install -y postgresql-libs unixODBC
fi
# http://sphinxsearch.com/files/sphinx-3.7.1-da9f8a4-linux-amd64.tar.gz
VERSION=$2
# echo $VERSION
if [ "$VERSION" == "3.1.1" ];then
VERSION_NUM=${VERSION}-612d99f
elif [ "$VERSION" == "3.2.1" ]; then
VERSION_NUM=${VERSION}-f152e0b
elif [ "$VERSION" == "3.3.1" ]; then
VERSION_NUM=${VERSION}-b72d67b
elif [ "$VERSION" == "3.4.1" ]; then
VERSION_NUM=${VERSION}-efbcc65
elif [ "$VERSION" == "3.5.1" ]; then
VERSION_NUM=${VERSION}-82c60cb
elif [ "$VERSION" == "3.6.1" ]; then
VERSION_NUM=${VERSION}-c9dbeda
elif [ "$VERSION" == "3.7.1" ]; then
VERSION_NUM=${VERSION}-da9f8a4
fi
# echo $VERSION_NUM
VERSION=3.1.1
Install_sphinx()
{
echo '正在安装Sphinx...'
mkdir -p $serverPath/sphinx
SPHINX_DIR=${serverPath}/source/sphinx
mkdir -p $SPHINX_DIR
if [ ! -f ${SPHINX_DIR}/sphinx-${VERSION}.tar.gz ];then
if [ $sysName == 'Darwin' ]; then
wget -O ${SPHINX_DIR}/sphinx-${VERSION}.tar.gz http://sphinxsearch.com/files/sphinx-${VERSION}-612d99f-darwin-amd64.tar.gz
else
curl -sSLo ${SPHINX_DIR}/sphinx-${VERSION}.tar.gz http://sphinxsearch.com/files/sphinx-${VERSION}-612d99f-linux-amd64.tar.gz
SPH_NAME=amd64
if [ "$sysArch" == "arm64" ];then
SPH_NAME=amd64
elif [ "$sysArch" == "x86_64" ]; then
SPH_NAME=amd64
elif [ "$sysArch" == "aarch64" ]; then
SPH_NAME=aarch64
fi
if [ "$sysName" == "Darwin" ] && [ "$VERSION" == "3.7.1" ];then
SPH_NAME=aarch64
fi
SPH_SYSNAME=linux
if [ $sysName == 'Darwin' ]; then
SPH_SYSNAME=darwin
elif [ "$sysName" == "aarch64" ]; then
SPH_NAME=aarch64
elif [ "$sysName" == "freebsd" ]; then
SPH_NAME=freebsd
fi
if [ "$SPH_SYSNAME" == "linux" ];then
glibc_ver=`ldd --version | grep libc | awk -F ')' '{print $2}'|awk '{gsub(/^\s+|\s+$/, "");print}'`
if [ "$VERSION" == "3.7.1" ] && [ `echo "2.29 > $glibc_ver " | bc` -eq 1 ];then
SPH_NAME=${SPH_NAME}-glibc2.17
fi
if [ "$VERSION" == "3.6.1" ] && [ `echo "2.29 > $glibc_ver " | bc` -eq 1 ];then
SPH_NAME=${SPH_NAME}-glibc2.17
fi
fi
if [ ! -f ${SPHINX_DIR}/sphinx-${VERSION}.tar.gz ];then
curl -sSLo ${SPHINX_DIR}/sphinx-${VERSION}.tar.gz https://github.com/midoks/mdserver-web/releases/download/init/sphinx-${VERSION}.tar.gz
FILE_NAME=sphinx-${VERSION_NUM}-${SPH_SYSNAME}-${SPH_NAME}
FILE_TGZ=${FILE_NAME}.tar.gz
echo $FILE_TGZ
# curl -sSLo ${SPHINX_DIR}/${FILE_TGZ} http://sphinxsearch.com/files/${FILE_TGZ}
if [ ! -f ${SPHINX_DIR}/${FILE_TGZ} ];then
wget --no-check-certificate -O ${SPHINX_DIR}/${FILE_TGZ} http://sphinxsearch.com/files/${FILE_TGZ}
fi
cd ${SPHINX_DIR} && tar -zxvf sphinx-${VERSION}.tar.gz
cd ${SPHINX_DIR} && tar -zxvf ${FILE_TGZ}
if [ "$?" == "0" ];then
mkdir -p $SPHINX_DIR
@@ -56,7 +119,10 @@ Install_sphinx()
echo "${VERSION}" > $serverPath/sphinx/version.pl
echo '安装Sphinx完成'
cd ${rootPath} && python3 ${rootPath}/plugins/sphinx/index.py start
cd ${rootPath} && python3 ${rootPath}/plugins/sphinx/index.py initd_install
if [ $sysName != 'Darwin' ]; then
cd ${rootPath} && python3 ${rootPath}/plugins/sphinx/index.py initd_install
fi
fi
if [ -d ${SPHINX_DIR}/sphinx-${VERSION} ];then
@@ -69,8 +135,14 @@ Uninstall_sphinx()
if [ -f /usr/lib/systemd/system/sphinx.service ] || [ -f /lib/systemd/system/sphinx.service ];then
systemctl stop sphinx
systemctl disable sphinx
rm -rf /usr/lib/systemd/system/sphinx.service
rm -rf /lib/systemd/system/sphinx.service
if [ -f /usr/lib/systemd/system/sphinx.service ];then
rm -rf /usr/lib/systemd/system/sphinx.service
fi
if [ -f /lib/systemd/system/sphinx.service ];then
rm -rf /lib/systemd/system/sphinx.service
fi
systemctl daemon-reload
fi
@@ -78,8 +150,12 @@ Uninstall_sphinx()
$serverPath/sphinx/initd/sphinx stop
fi
rm -rf $serverPath/sphinx
echo "Uninstall_sphinx" > $install_tmp
if [ -d $serverPath/sphinx ];then
echo "rm -rf $serverPath/sphinx"
rm -rf $serverPath/sphinx
fi
echo "卸载sphinx成功"
}
action=$1
+203 -27
View File
@@ -20,6 +20,32 @@ function spPostMin(method, args, callback){
},'json');
}
function myPost(method, args, callback, title){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
var _title = '正在获取...';
if (typeof(title) != 'undefined'){
_title = title;
}
$.post('/plugins/run', {name:'mysql', func:method, args:_args}, function(data) {
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function spPost(method, args, callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
spPostMin(method,args,function(data){
@@ -30,21 +56,168 @@ function spPost(method, args, callback){
});
}
function rebuild(){
var con = '<button class="btn btn-default btn-sm" onclick="rebuildIndex();">重建索引</button>';
function commonFunc(){
var con = '<button class="btn btn-default btn-sm" onclick="confirmRebuildIndex();">重建索引</button>';
con += '&nbsp;&nbsp; <button class="btn btn-default btn-sm" onclick="autoMakeConf();">自动创建配置</button>';
$(".soft-man-con").html(con);
}
function autoMakeConf(){
var xm_db_list;
var con = '<ul class="help-info-text c7">';
con += '<li style="color:red;">如果数据量比较大,第一次启动会失败!(可通过手动建立索引)</li>';
con += '<li style="color:red;">以下内容,需手动加入计划任务。</li>';
layer.open({
type: 1,
area: ['380px','350px'],
title: '自动创建配置',
closeBtn: 1,
shift: 5,
shadeClose: true,
btn:["提交","关闭"],
content: "<form class='bt-form pd20'>\
<div class='line'>\
<span class='tname'>选择数据库</span>\
<div class='info-r'>\
<select class='bt-input-text mr5' name='dbname' style='width:100%'>\
<option value=''>无</option>\
</select>\
</div>\
</div>\
<div class='line'>\
<span class='tname'>选择表</span>\
<div class='info-r'>\
<div id='table'></div>\
</div>\
</div>\
<div class='line'>\
<span class='tname'>是否增量</span>\
<div class='info-r'>\
<select class='bt-input-text mr5' name='is_delta' style='width:100px'>\
<option value='no'>否</option>\
<option value='yes'>是</option>\
</select>\
</div>\
</div>\
<div class='line'>\
<span class='tname'>是否覆盖配置</span>\
<div class='info-r'>\
<select class='bt-input-text mr5' name='is_cover' style='width:100px'>\
<option value='yes'>是</option>\
<option value='no'>否</option>\
</select>\
</div>\
</div>\
<ul class='help-info-text c7'>\
<li style='color:red;'>具体配置,仍须手动修改!!!</li>'\
<li style='color:red;'>增量索引,需要有更新权限,主从分离时,需要主库配置</li>'\
</ul>\
</form>\
",
success:function(l,i){
$(l).find('.layui-layer-content').css('overflow','visible');
xm_db_list = xmSelect.render({
el: '#table',
repeat: false,
toolbar: {show: true},
data: [],
});
myPost('get_db_list', {"page":1,"page_size":20}, function(data){
var rdata = $.parseJSON(data.data);
var dblist = rdata.data;
var db_html = '';
for (var i = 0; i < dblist.length; i++) {
db_html += "<option value='"+dblist[i]['name']+"'>"+dblist[i]['name']+"</option>";
}
if (dblist.length > 0){
initDbSelect(dblist[0]['name']);
}
$('select[name="dbname"]').html(db_html);
});
$('select[name="dbname"]').change(function(){
var db = $('select[name="dbname"]').val();
initDbSelect(db);
});
},
yes:function(index){
var args = {}
args['db'] = $('select[name="dbname"]').val();
args['is_delta'] = $('select[name="is_delta"]').val();
args['is_cover'] = $('select[name="is_cover"]').val();
args['tables'] = xm_db_list.getValue('value').join(',');
// console.log(args);
spPost('db_to_sphinx', args, function(rdata){
var rdata = $.parseJSON(rdata.data);
// console.log(rdata);
showMsg(rdata.msg,function(){
if (rdata.status){
layer.close(index);
confirmRebuildIndex();
}
},{icon: rdata.status ? 1 : 2}, 2000);
});
}
});
function initDbSelect(db){
if (db == ''){
return;
}
getDbInfo(db, function(rdata){
var rdata = $.parseJSON(rdata.data);
var tables = rdata.tables;
var idx_db = [];
for (var i = 0; i < tables.length; i++) {
var t = {};
t['name'] = tables[i]['table_name'];
t['value'] = tables[i]['table_name'];
idx_db.push(t);
}
xm_db_list = xmSelect.render({el: '#table', filterable: true,repeat: false,toolbar: {show: true},data: idx_db,});
});
}
function getDbInfo(db_name, callback){
myPost('get_db_info', {name:db_name}, function(data){
callback(data);
});
}
}
function rebuildIndex(){
spPost('rebuild', '', function(data){
if (data.data == 'ok'){
layer.msg('在重建中..',{icon:1,time:2000,shade: [0.3, '#000']});
layer.msg('重建成功!',{icon:1,time:2000,shade: [0.3, '#000']});
} else {
layer.msg(data.data,{icon:2,time:2000,shade: [0.3, '#000']});
layer.msg(data.data,{icon:2,time:10000,shade: [0.3, '#000']});
}
});
}
function confirmRebuildIndex(){
layer.confirm("是否重建索引?", {icon:3,closeBtn: 1} , function(){
rebuildIndex();
});
}
function tryRebuildIndex(){
layer.confirm("修改配置后,是否尝试重建索引!", {icon:3,closeBtn: 1} , function(){
rebuildIndex();
});
}
function secToTime(s) {
var t;
if(s > -1){
@@ -74,7 +247,12 @@ function runStatus(){
return;
}
var idata = rdata.data;
// console.log(idata);
var tbody = '';
for (var i in idata) {
tbody += '<tr><th>'+i+'</th><td>' + idata[i] + '</td><td colspan="2">'+i+'</td></tr>';
}
var con = '<div class="divtable"><table class="table table-hover table-bordered" style="margin-bottom:10px;background-color:#fafafa">\
<tbody>\
<tr><th>运行时间</th><td>' + secToTime(idata.uptime) + '</td><th>每秒查询</th><td>' + parseInt(parseInt(idata.queries) / parseInt(idata.uptime)) + '</td></tr>\
@@ -84,18 +262,12 @@ function runStatus(){
</tbody>\
</table>\
<table class="table table-hover table-bordered">\
<thead style="display:none;"><th></th><th></th><th></th><th></th></thead>\
<tbody>\
<tr><th>command_delete</th><td>' + idata.command_delete + '</td><td colspan="2">command_delete</td></tr>\
<tr><th>command_excerpt</th><td>' + idata.command_excerpt + '</td><td colspan="2">command_excerpt</td></tr>\
<tr><th>command_flushattrs</th><td>' + idata.command_flushattrs + '</td><td colspan="2">command_flushattrs</td></tr>\
<tr><th>command_keywords</th><td>' + idata.command_keywords + '</td><td colspan="2">command_keywords</td></tr>\
<tr><th>command_persist</th><td>' + idata.command_persist + '</td><td colspan="2">command_persist</td></tr>\
<tr><th>command_search</th><td>' + idata.command_search + '</td><td colspan="2">command_search</td></tr>\
<tr><th>command_status</th><td>' + idata.command_status + '</td><td colspan="2">command_status</td></tr>\
<tr><th>command_update</th><td>' + idata.command_update + '</td><td colspan="2">command_update</td></tr>\
<tbody>\
</table></div>';
<thead style="display:none;"><th></th><th></th><th></th><th></th></thead>\
<tbody>\
'+tbody+'\
<tbody>\
</table>\
</div>';
$(".soft-man-con").html(con);
});
@@ -110,21 +282,25 @@ function readme(){
return;
}
// console.log(rdata['data']);
var con = '<ul class="help-info-text c7">';
con += '<li style="color:red;">如果数据量比较大,第一次启动会失败!(可通过手动建立索引)</li>';
con += '<li style="color:red;">以下内容,需手动加入计划任务。</li>';
con += '<li>全量:' + rdata['data']['cmd'] + ' --all --rotate</li>';
//主索引
for (var i = 0; i < rdata['data']['index'].length; i++) {
var index_t = rdata['data']['index'][i];
con += '<li>主索引:' + rdata['data']['cmd'] + ' '+ index_t +' --rotate</li>';
}
for (var i = 0; i < rdata['data']['delta'].length; i++) {
var delta_t = rdata['data']['delta'][i];
var list = delta_t.split(':');
// console.log(list);
con += '<li>增量索引:' + rdata['data']['cmd'] + ' '+ list[0] +' --rotate</li>';
con += '<li>合并索引:' + rdata['data']['cmd'] + ' --merge '+ list[1] + ' ' + list[0] +' --rotate</li>';
var index_kv = rdata['data']['index'][i];
var index = index_kv['index'];
// console.log(index);
con += '<li>主索引 :' + rdata['data']['cmd'] + ' '+ index +' --rotate</li>';
if (typeof(index_kv['delta']) != 'undefined'){
var delta = index_kv['delta'];
con += '<li>增量索引 :' + rdata['data']['cmd'] + ' '+ delta +' --rotate</li>';
con += '<li>合并索引 :' + rdata['data']['cmd'] + ' --merge '+ index + ' ' + delta +' --rotate</li>';
}
}
con += '</ul>';
Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

+553
View File
@@ -0,0 +1,553 @@
<style>
/*任务管理器*/
.man-menu-sub {
background-color: #fff;
border-bottom: 1px solid #ccc;
height: 50px;
display: flex;
flex-direction: row;
justify-content: space-between;
flex-wrap: nowrap;
align-items: center;
}
.t-mana .table > tbody > tr.active td {
background-color: #E4EEE0;
}
.search-bar {
}
.search-bar .search_input {
height: 30px;
line-height: 30px;
border-radius: 2px;
border: 1px solid #ccc;
outline: none;
padding-left: 8px;
vertical-align: top;
width: 230px;
}
.search-bar .search_input:focus {
border-color: #20a53a;
span.glyphicon-search {
color: #20a53a;
}
}
.search-bar .glyphicon {
position: relative;
top: 1px;
display: inline-block;
font-family: 'Glyphicons Halflings';
font-style: normal;
font-weight: 400;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.search-bar .glyphicon-search {
height: 28px;
line-height: 28px;
padding: 0 10px;
color: #888;
position: absolute;
right: 14px;
top: 11px;
font-size: 14px;
cursor: pointer;
}
.r56 {
right: 56px !important;
}
.man-menu-sub {
background-color: #fff;
border-bottom: 1px solid #ccc;
height: 50px;
}
.man-menu-sub span {
padding: 14px 15px;
cursor: pointer;
display: inline-block;
font-size: 14px;
}
.man-menu-sub .on {
border-bottom: 2px solid #20a53a;
color: #20a53a;
font-weight: bold;
}
.soft-ico-min {
display: inline-block;
width: 16px;
margin-right: 5px;
}
.soft-ico-min img {
width: 16px;
}
.table-cont {
height: 500px;
overflow: auto;
border: #ddd 1px solid;
position: relative;
}
.ts-line {
position: absolute;
top: 99px;
height: 1px;
background-color: #ddd;
left: 16px;
z-index: 2;
}
.t-mana .bt-ico-ask {
height: 14px;
width: 14px;
line-height: 14px;
}
.mini-info {
width: 100%;
border-top: #DBDBEA 1px solid;
background-color: #f6f6f6;
padding: 15px;
}
.mini-info-box {
width: 500px;
margin: 0 auto;
background-color: #fff;
border: #DBDBEA 1px solid;
border-radius: 6px;
height: 66px;
box-shadow: 0 0 40px #eee;
}
.mini-info-con {
float: left;
height: 100%;
width: 33%;
line-height: 26px;
padding: 6px 16px;
}
.mini-info-con:nth-of-type(2) {
border-left: #DBDBEA 1px solid;
border-right: #DBDBEA 1px solid;
width: 34%;
}
.mini-info-con p {
text-align: right;
position: relative;
}
.mini-info-con .tname {
display: inline-block;
position: absolute;
left: 0;
}
.mini-level {
border: #ddd 1px solid;
width: 166px;
background-color: #fff;
border-radius: 6px;
margin: 0 auto;
height: 66px;
line-height: 66px;
text-align: center;
}
.jc-detail .tname {
font-size: 12px;
font-weight: bold;
margin-right: 10px;
}
.jc-detail h3.tname {
margin-bottom: 10px;
margin-top: 15px;
color: #999;
}
.jc-detail .jc-info {
margin: 10px 0;
border-bottom: #ddd 1px solid;
padding-bottom: 10px;
}
#TaskManagement .td-pid {
/* display: flex; */
/* border-top: #ddd 2px solid; */
/* height: 38px; */
/* height: 100%; */
/* margin-top: 1px; */
}
.td-pid img {
/* margin-right: 8px; */
/* display: inline-block; */
float: left;
cursor: pointer;
/* position: relative;
left: -80px;
filter: drop-shadow(#fff 80px 0); */
/* position: relative;
left: -80px;
filter: drop-shadow(#238B37 0 80px); */
}
.td-pid svg {
float: left;
cursor: pointer;
}
.td-pid .colp {
transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-webkit-transform: rotate(-90deg);
}
.td-pid .arrow:hover {
filter: drop-shadow(#999999 0 0)
}
.td-pid .process-child {
margin-left: 50px;
/* display: none; */
}
.td-pid span {
display: inline-block;
float: right;
}
.td-pid a {
display: block;
margin-left: 30px;
}
#TaskManagement th: {
height: 34px;
}
#TaskManagement tr: {
height: 38px;
}
#TaskManagement tr:hover {
/* background-color: rgb(245, 247, 250,0.6); */
background-color: rgb(246, 246, 246, 0.65);
}
#TaskManagement .process-select {
/* background-color: rgb(242, 242, 242); */
/* background-color: rgb(245, 247, 250,0.6); */
background-color: rgb(246, 246, 246, 0.6);
/* background-color: rgb(246, 246, 246,0.65); */
}
#taskResourceTable .process-select {
/* background-color: rgb(242, 242, 242); */
background-color: #F1F9F3;
}
#TaskManagement .process-select:hover {
/* background-color: rgb(211, 210, 210); */
/* background-color: rgb(245, 247, 250); */
background-color: rgb(246, 246, 246);
/* border: 1px solid #ddd;
box-sizing: border-box; */
}
#taskResourceTable .process-select:hover {
/* background-color: rgb(211, 210, 210); */
background-color: #BCE4C4;
}
.resource-panel {
display: none;
width: 100%;
height: 700px;
/* height: 300px; */
}
.resource-tab {
float: left;
width: 100px;
height: 300px;
background-color: thistle;
}
.resource-right {
margin-left: 100px;
/* width: 100%; */
/* background-color: gray; */
/* height: 600px; */
}
.resource-panel-show {
display: block;
}
.divtable-hide {
display: none;
/* visibility: hidden; */
}
.resource-tab span {
display: block;
height: 30px;
line-height: 30px;
text-align: center;
cursor: pointer;
}
.resource-tab span:hover {
background-color: #ccc;
}
.plug_menu {
display: none;
}
.plug_menu .setting_ul::after{
display: none;
}
.plug_menu .setting_ul.undisplay::after {
content: '';
position: absolute;
color: #fff;
width: 12px;
height: 12px;
font-size: 14px;
top: -7px;
right: 8px;
display: inline-block;
background: #fff;
transform: rotate(-45deg);
border-top: 1px solid rgba(0, 0, 0, 0.25);
border-right: 1px solid rgba(0, 0, 0, 0.25);
}
.set_list_fid_dropdown {
display: inline-block;
line-height: 30px;
margin-left: 10px;
position: relative;
vertical-align: bottom;
}
.set_list_fid_dropdown .setting_btn {
border: 1px solid #ccc;
height: 30px;
width: 30px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.set_list_fid_dropdown .setting_btn:hover{
background: #e9f6eb;
border-color: #bce4c4;
}
.set_list_fid_dropdown .icon-setting {
color: rgb(102, 102, 102);
}
.set_list_fid_dropdown .setting_btn:hover .icon-setting {
color: #20a53a;
}
.set_list_fid_dropdown .setting_ul {
position: absolute;
z-index: 99;
background: #fff;
width: 150px;
right: 0;
border-radius: 4px;
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.25);
padding: 10px 0;
margin-top: 10px;
display: none;
}
.set_list_fid_dropdown .setting_ul::after {
content: '';
position: absolute;
color: #fff;
width: 12px;
height: 12px;
font-size: 14px;
top: -7px;
right: 8px;
display: inline-block;
background: #fff;
transform: rotate(-45deg);
border-top: 1px solid rgba(0, 0, 0, 0.25);
border-right: 1px solid rgba(0, 0, 0, 0.25);
}
.setting_ul .setting_ul_li{
display: flex;
align-items: center;
line-height: 27px;
padding: 0 16px;
cursor: pointer;
}
.setting_ul .setting_ul_li:hover{
background: #e9f6eb;
}
.setting_ul .setting_ul_li.disabled {
cursor: not-allowed;
}
.setting_ul .setting_ul_li i {
display: inline-block;
width: 16px;
height: 16px;
border: 1px solid #ccc;
background-color: #fff;
vertical-align: top;
position: relative;
border-radius: 2px;
}
.setting_ul .setting_ul_li.active i {
background-color: #20a53a;
border-color: #20a53a;
}
.setting_ul .setting_ul_li.disabled i {
background-color: #edf2fc;
border-color: #dcdfe6;
}
.setting_ul .setting_ul_li.active.disabled i {
background-color: #f2f6fc;
border-color: #dcdfe6;
}
.setting_ul .setting_ul_li.active.disabled i::after{
border: solid #dcdfe6;
border-width: 0 2px 2px 0;
}
.setting_ul .setting_ul_li.active i::after{
content: '';
position: absolute;
display: block;
left: 50%;
top: 50%;
margin-left: -2px;
margin-top: -6px;
width: 5px;
height: 10px;
border: solid #fff;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
</style>
<div class="t-mana TaskManView">
<div class="man-menu-sub mlr15">
<div>
<span class="p_list on">进程</span>
<span class="p_run">启动项</span>
<span class="p_service">服务</span>
<span class="p_network">网络</span>
<span class="p_user">用户</span>
<span class="p_cron">计划任务</span>
<span class="p_session">会话</span>
</div>
<div style="display: flex;flex-direction: row;align-items: center;justify-content: flex-end;">
<div class="search-bar ">
<input type="text" class="search_input " style="" placeholder="支持名称、字段模糊搜索">
<span class="glyphicon glyphicon-search r56" aria-hidden="true"></span>
</div>
<div class="table_config set_list_fid_dropdown" title="设置表头">
<div class="setting_btn"><i class="glyphicon glyphicon-cog icon-setting"></i></div>
</div>
</div>
</div>
<div class="ts-line"></div>
<div class="divtable taskdivtable pd15">
<div id="table-cont" class="table-cont">
<table id="TaskManagement" class="table table-hover" width="100%" style="border:none"></table>
</div>
</div>
<div class="resource-panel pd15">
<div class="resource-tab">
<span>CPU</span>
<span>内存</span>
<span>磁盘</span>
</div>
<div class="resource-right">
<div class="resource-top"></div>
<div class="resource-middle divtable">
<div id="table-cont" class="table-cont" style="height:100px;">
<table id="taskResourceTable" class="table table-hover" width="100%" style="border:none">
</table>
</div>
</div>
<div class="resource-bottom"></div>
</div>
</div>
<div class="mini-info" id="load_average"></div>
<div class="plug_menu set_list_fid_dropdown">
<ul class="setting_ul" style="display: none;">
<li class="setting_ul_li ps active disabled" name="ps">
<i></i><span class="ml10">应用名称</span>
</li>
<li class="setting_ul_li pid active disabled" name="pid">
<i></i> <span class="ml10">PID</span>
</li>
<li class="setting_ul_li threads active" name="threads">
<i></i> <span class="ml10">线程</span>
</li>
<li class="setting_ul_li user active" name="user">
<i></i> <span class="ml10">用户</span>
</li>
<li class="setting_ul_li cpu_percent active disabled" name="cpu_percent">
<i></i> <span class="ml10">CPU</span>
</li>
<li class="setting_ul_li memory_used active disabled" name="memory_used">
<i></i> <span class="ml10">内存</span>
</li>
<li class="setting_ul_li io_read_bytes active" name="io_read_bytes">
<i></i> <span class="ml10">io读</span>
</li>
<li class="setting_ul_li io_write_bytes active" name="io_write_bytes">
<i></i> <span class="ml10">io写</span>
</li>
<li class="setting_ul_li up active" name="up">
<i></i> <span class="ml10">上行</span>
</li>
<li class="setting_ul_li down active" name="down">
<i></i> <span class="ml10">下行</span>
</li>
<li class="setting_ul_li connects active" name="connects">
<i></i> <span class="ml10">连接</span>
</li>
<li class="setting_ul_li status active" name="status">
<i></i> <span class="ml10">状态</span>
</li>
<li class="setting_ul_li active disabled" name="">
<i></i> <span class="ml10">操作</span>
</li>
</ul>
</div>
</div>
<script type="text/javascript">
$('.layui-layer-page').css({'width': '1000px'});
$.getScript( "/plugins/file?name=task_manager&f=js/task_manager.js", function(){
console.log("load js ok!");
});
</script>
+62
View File
@@ -0,0 +1,62 @@
# coding:utf-8
import sys
import io
import os
import time
import re
sys.path.append(os.getcwd() + "/class/core")
import mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'task_manager'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getArgs():
args = sys.argv[3:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
if t.strip() == '':
tmp = []
else:
t = t.split(':')
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def checkArgs(data, ck=[]):
for i in range(len(ck)):
if not ck[i] in data:
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, mw.returnJson(True, 'ok'))
def status():
return 'start'
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
else:
print('error')
+17
View File
@@ -0,0 +1,17 @@
{
"sort": 7,
"ps": "轻松管理进程、流量监控、启动项、用户、服务、计划任务、会话",
"name": "task_manager",
"title": "任务管理器",
"shell": "install.sh",
"versions":"1.0",
"tip": "soft",
"checks": "server/task_manager",
"path": "server/task_manager",
"display": 1,
"author": "task_manager",
"date": "2024-06-01",
"home": "task_manager",
"type": 0,
"pid": "4"
}
+55
View File
@@ -0,0 +1,55 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=$2
# python3 plugins/task_manager/task_manager_index.py
# /www/server/mdserver-web/bin/python3 /www/server/mdserver-web/plugins/task_manager/process_network_total.py
# ps -ef|grep process_network_total| grep -v grep | awk '{print $2}' | xargs kill -9
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
Install_App()
{
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/task_manager
if [ -f /usr/bin/apt ]; then
apt install libpcap-dev -y
fi
if [ -f /usr/bin/yum ]; then
yum install libpcap-devel -y
fi
if [ -f /usr/bin/dnf ]; then
dnf install libpcap-devel -y
fi
pip3 install pypcap
echo "$VERSION" > $serverPath/task_manager/version.pl
echo "安装任务管理器成功"
}
Uninstall_App()
{
rm -rf $serverPath/task_manager
echo "卸载任务管理器成功"
}
action=$1
if [ "${1}" == 'install' ];then
Install_App
else
Uninstall_App
fi
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,230 @@
#coding: utf-8
import sys
import time
import os
import struct
os.chdir('/www/server/mdserver-web')
if 'class/' in sys.path: sys.path.insert(0,"class/")
import copy
try:
import pcap
except ImportError:
if os.path.exists('/usr/bin/apt'):
os.system("apt install libpcap-dev -y")
elif os.path.exists('/usr/bin/dnf'):
red_file = '/etc/redhat-release'
if os.path.exists(red_file):
f = open(red_file,'r')
red_body = f.read()
f.close()
if red_body.find('CentOS Linux release 8.') != -1:
rpm_file = '/root/libpcap-1.9.1.rpm'
down_url = "wget -O {} https://repo.almalinux.org/almalinux/8/PowerTools/x86_64/os/Packages/libpcap-devel-1.9.1-5.el8.x86_64.rpm --no-check-certificate -T 10".format(rpm_file)
print(down_url)
os.system(down_url)
os.system("rpm -ivh {}".format(rpm_file))
if os.path.exists(rpm_file): os.remove(rpm_file)
else:
os.system("dnf install libpcap-devel -y")
else:
os.system("dnf install libpcap-devel -y")
elif os.path.exists('/usr/bin/yum'):
os.system("yum install libpcap-devel -y")
os.system("pip install pypcap")
try:
import pcap
except ImportError:
print("pypcap module install failed.")
sys.exit()
class process_network_total:
__pid_file = 'logs/process_network_total.pid'
__inode_list = {}
__net_process_list = {}
__net_process_size = {}
__last_stat = 0
__last_write_time = 0
__end_time = 0
def start(self,timeout = 0):
stime = time.time()
self.__end_time = timeout + stime
self.__last_stat = stime
try:
p = pcap.pcap() # 监听所有网卡
p.setfilter('tcp') # 只监听TCP数据包
for p_time,p_data in p:
self.handle_packet(p_data)
# 过期停止监听
if timeout > 0:
if p_time > self.__end_time:
self.rm_pid_file()
break
except:
self.rm_pid_file()
def handle_packet(self, pcap_data):
# 获取IP协议头
ip_header = pcap_data[14:34]
# 解析src/dst地址
src_ip = ip_header[12:16]
dst_ip = ip_header[16:20]
# 解析sport/dport端口
src_port = pcap_data[34:36]
dst_port = pcap_data[36:38]
src = src_ip + b':' + src_port
dst = dst_ip + b':' + dst_port
# 计算数据包长度
pack_size = len(pcap_data)
# 统计进程流量
self.total_net_process(dst,src,pack_size)
def total_net_process(self,dst,src,pack_size):
self.get_tcp_stat()
direction = None
mtime = time.time()
if dst in self.__net_process_list:
pid = self.__net_process_list[dst]
direction = 'down'
elif src in self.__net_process_list:
pid = self.__net_process_list[src]
direction = 'up'
else:
if mtime - self.__last_stat > 3:
self.__last_stat = mtime
self.get_tcp_stat(True)
if dst in self.__net_process_list:
pid = self.__net_process_list[dst]
direction = 'down'
elif src in self.__net_process_list:
pid = self.__net_process_list[src]
direction = 'up'
if not direction: return False
if not pid: return False
if not pid in self.__net_process_size:
self.__net_process_size[pid] = {}
self.__net_process_size[pid]['down'] = 0
self.__net_process_size[pid]['up'] = 0
self.__net_process_size[pid]['up_package'] = 0
self.__net_process_size[pid]['down_package'] = 0
self.__net_process_size[pid][direction] += pack_size
self.__net_process_size[pid][direction + '_package'] += 1
# 写入到文件
if mtime - self.__last_write_time > 1:
self.__last_write_time = mtime
self.write_net_process()
def write_net_process(self):
w_file = '/dev/shm/mw_net_process'
process_size = copy.deepcopy(self.__net_process_size)
net_process = []
for pid in process_size.keys():
net_process.append(str(pid) + " " + str(process_size[pid]['down']) + " " + str(process_size[pid]['up']) + " " + str(process_size[pid]['down_package']) + " " + str(process_size[pid]['up_package']))
f = open(w_file,'w+',encoding='utf-8')
f.write('\n'.join(net_process))
f.close()
def hex_to_ip(self, hex_ip):
hex_ip,hex_port = hex_ip.split(':')
ip = '.'.join([str(int(hex_ip[i:i+2], 16)) for i in range(0, len(hex_ip), 2)][::-1])
port = int(hex_port, 16)
return ip,port
def get_tcp_stat(self,force = False):
if not force and self.__net_process_list: return self.__net_process_list
self.__net_process_list = {}
tcp_stat_file = '/proc/net/tcp'
tcp_stat = open(tcp_stat_file, 'rb')
tcp_stat_list = tcp_stat.read().decode('utf-8').split('\n')
tcp_stat.close()
tcp_stat_list = tcp_stat_list[1:]
if force: self.get_process_inodes(force)
for i in tcp_stat_list:
tcp_tmp = i.split()
if len(tcp_tmp) < 10: continue
inode = tcp_tmp[9]
if inode == '0': continue
local_ip,local_port = self.hex_to_ip(tcp_tmp[1])
if local_ip == '127.0.0.1': continue
remote_ip,remote_port = self.hex_to_ip(tcp_tmp[2])
if local_ip == remote_ip: continue
if remote_ip == '0.0.0.0': continue
pid = self.inode_to_pid(inode,force)
if not pid: continue
key = self.get_ip_pack(local_ip) + b':' + self.get_port_pack(local_port)
self.__net_process_list[key] = pid
return self.__net_process_list
def get_port_pack(self,port):
return struct.pack('H',int(port))[::-1]
def get_ip_pack(self,ip):
ip_arr = ip.split('.')
ip_pack = b''
for i in ip_arr:
ip_pack += struct.pack('B',int(i))
return ip_pack
def inode_to_pid(self,inode,force = False):
inode_list = self.get_process_inodes()
if inode in inode_list:
return inode_list[inode]
return None
def get_process_inodes(self,force = False):
if not force and self.__inode_list: return self.__inode_list
proc_path = '/proc'
inode_list = {}
for pid in os.listdir(proc_path):
try:
if not pid.isdigit(): continue
inode_path = proc_path + '/' + pid + '/fd'
for fd in os.listdir(inode_path):
try:
fd_file = inode_path + '/' + fd
fd_link = os.readlink(fd_file)
if fd_link.startswith('socket:['):
inode = fd_link[8:-1]
inode_list[inode] = pid
except:
continue
except:
continue
self.__inode_list = inode_list
return inode_list
def get_process_name(self,pid):
pid_path = '/proc/' + pid + '/comm'
if not os.path.exists(pid_path): return ''
pid_file = open(pid_path, 'rb')
pid_name = pid_file.read().decode('utf-8').strip()
pid_file.close()
return pid_name
def write_pid(self):
self_pid = os.getpid()
pid_file = open(self.__pid_file,'w')
pid_file.write(str(self_pid))
pid_file.close()
def rm_pid_file(self):
if os.path.exists(self.__pid_file):
os.remove(self.__pid_file)
if __name__ == '__main__':
p = process_network_total()
p.write_pid()
p.start(600)
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -42,10 +42,10 @@ def send_msg(bot, tag='ad', trigger_time=300):
# 信号只在一个周期内执行一次|end
# https://t.me/gjgzs2022 | 22/m | @GJ_gzs
# https://zhaoziyuan1.cc | web | 15/m | 2m | next,5/15 | @baleite
# https://zhaoziyuan1.cc | web | 15/m | 2m | next,7/15 | @baleite
# 综合包网/NG接口开户 | 28/m | 6m | next,10/28 | @aabbcx888
# 实名认证/过人脸🕵️‍♀️各种账号处理✅ | 30/m| next,6/30 | @nngzs
## 海外服务器 高防CDN 解决移动屏蔽 | 19/m | next,4/19 | @YYCDNFW
# 海外服务器 高防CDN 解决移动屏蔽 | 群内置顶AD| 16/m | @YYCDNFW
keyboard = [
[
types.InlineKeyboardButton(
@@ -51,11 +51,9 @@ def send_msg(bot, tag='ad', trigger_time=300):
# 信号只在一个周期内执行一次|end
# https://t.me/gjgzs2022 | 22/m | @GJ_gzs
# https://zhaoziyuan1.cc | web | 15/m | 2m | next,5/15 | @baleite
# https://zhaoziyuan1.cc | web | 15/m | 2m | next,7/15 | @baleite
# 综合包网/NG接口开户 | 28/m | 6m | next,10/28 | @aabbcx888
# 实名认证/过人脸🕵️‍♀️各种账号处理✅ | 30/m| next,6/30 | @nngzs
## 海外服务器 高防CDN 解决移动屏蔽 | 19/m | next,4/19 | @YYCDNFW
# 群内置顶AD| 16/m | @YYCDNFW
keyboard = [
[
types.InlineKeyboardButton(
+2
View File
@@ -31,6 +31,7 @@ CREATE INDEX method_idx ON web_logs (`method`);
CREATE INDEX status_code_idx ON web_logs (`status_code`);
CREATE INDEX request_time_idx ON web_logs (`request_time`);
CREATE INDEX is_spider_idx ON web_logs (`is_spider`);
CREATE INDEX body_length_idx ON web_logs (`body_length`);
CREATE INDEX all_union_idx ON web_logs (`time`,`ip`,`method`,`status_code`,`request_time`,`is_spider`);
@@ -84,6 +85,7 @@ CREATE TABLE `request_stat`(
`status_402` INTEGER DEFAULT 0,
`status_403` INTEGER DEFAULT 0,
`status_404` INTEGER DEFAULT 0,
`status_499` INTEGER DEFAULT 0,
`http_get` INTEGER DEFAULT 0,
`http_post` INTEGER DEFAULT 0,
`http_put` INTEGER DEFAULT 0,
+2 -2
View File
@@ -86,13 +86,13 @@
.indicators-label {
display: inline-block;
width: 95px;
width: 88px;
height: 26px;
line-height: 26px;
cursor: pointer;
}
.indicators-label input {
.indicators-label input[type=radio] {
height: 13px;
margin: 0 5px 0 0;
vertical-align: -2px;
+29 -2
View File
@@ -654,17 +654,19 @@ def getLogsRealtimeInfo():
'''
import datetime
args = getArgs()
check = checkArgs(args, ['site', 'type'])
check = checkArgs(args, ['site', 'type','second'])
if not check[0]:
return check[1]
domain = args['site']
dtype = args['type']
second = int(args['second'])
conn = pSqliteDb('web_logs', domain)
timeInt = time.mktime(datetime.datetime.now().timetuple())
conn = conn.where("time>=?", (int(timeInt) - 10,))
conn = conn.where("time>=?", (int(timeInt) - second,))
field = 'time,body_length'
field_sum = toSumField(field.replace("time,", ""))
@@ -714,6 +716,7 @@ def getLogsList():
method = args['method']
status_code = args['status_code']
request_time = args['request_time']
request_size = args['request_size']
spider_type = args['spider_type']
query_date = args['query_date']
search_uri = args['search_uri']
@@ -752,6 +755,14 @@ def getLogsList():
if len(request_time_s) == 1:
conn = conn.andWhere("request_time>=?", (request_time,))
if request_size != "all":
request_size_s = request_size.strip().split('-')
# print(int(request_size_s[0])*1024)
if len(request_size_s) == 2:
conn = conn.andWhere("body_length>=? and body_length<?", (int(request_size_s[0])*1024,int(request_size_s[1])*1024,))
if len(request_size_s) == 1:
conn = conn.andWhere("body_length>=?", (int(request_size_s[0])*1024,))
if spider_type == "normal":
pass
elif spider_type == "only_spider":
@@ -780,7 +791,23 @@ def getLogsList():
attacHistoryLogHack(conn, domain, query_date)
conn.changeTextFactoryToBytes()
clist = conn.limit(limit).order('time desc').inquiry()
for x in range(len(clist)):
req_line = clist[x]
for cx in req_line:
v = req_line[cx]
if type(v) == bytes:
try:
clist[x][cx] = v.decode('utf-8')
except Exception as e:
v = str(v)
v = v.replace("b'",'').strip("'")
clist[x][cx] = v
else:
clist[x][cx] = v
# print(clist)
count_key = "count(*) as num"
count = conn.field(count_key).limit('').order('').inquiry()
+97 -34
View File
@@ -192,7 +192,7 @@ function wsOverviewRequest(page){
var data = rdata.data.data;
var statData = rdata.data.stat_list;
console.log(statData, data);
// console.log(statData, data);
var stat_pv = statData['pv'] == null?0:statData['pv'];
var stat_uv = statData['uv'] == null?0:statData['uv'];
@@ -383,11 +383,13 @@ function wsOverviewRequest(page){
var select_option = $('.indicators-container input:checked').parent().attr('data-name');
if (select_option != "realtime_traffic" && select_option != 'realtime_request' ){
clearInterval(ovTimer);
console.log("get_logs_realtime_info over:"+select_option);
// console.log("get_logs_realtime_info over:"+select_option);
return;
}
wsOriginPost("get_logs_realtime_info",'',{"site":args["site"], "type":select_option} , function(rdata){
var second = $('#check_realtime_second').val();
wsOriginPost("get_logs_realtime_info",'',{"site":args["site"], "type":select_option,'second':second} , function(rdata){
var rdata = $.parseJSON(rdata.data);
@@ -488,11 +490,11 @@ var html = '<div>\
<p class="ov_num">0</p>\
</div>\
<div class="overview_box">\
<p class="ov_title">实时流量<i class="tips" data-toggle="tooltip" data-placement="top" title="当前10秒内您网站的实时流量大小。包括已排除的请求。">?</i></p>\
<p class="ov_title">实时流量<i class="tips" data-toggle="tooltip" data-placement="top" title="当前X秒内您网站的实时流量大小。包括已排除的请求。">?</i></p>\
<p class="ov_num">0</p>\
</div>\
<div class="overview_box">\
<p class="ov_title">每秒请求<i class="tips" data-toggle="tooltip" data-placement="top" title="当前10秒内您网站的实时请求数量。包括已排除的请求。">?</i></p>\
<p class="ov_title"><span id="ov_title_req_second">每秒请求<span><i class="tips" data-toggle="tooltip" data-placement="top" title="当前1-10秒内您网站的实时请求数量。包括已排除的请求。">?</i></p>\
<p class="ov_num">0</p>\
</div>\
</div>\
@@ -525,7 +527,11 @@ var html = '<div>\
</div>\
<div class="indicators-label" bt-event-click="indicatorsType" data-name="realtime_request">\
<input type="radio" id="check_realtime_request" name="check_realtime_request">\
<span class="check_realtime_request" style="font-weight:normal">每秒请求</span>\
<span class="check_realtime_request" style="font-weight:normal">每X秒请求</span>\
</div>\
<div class="indicators-label" bt-event-click="indicatorsType">\
<input class="bt-input-text mr5" type="number" id="check_realtime_second" name="check_realtime_second" value="1" style="width:40px;outline:none;height:23px;border-radius:3px;">\
<span style="font-weight:normal">秒</span>\
</div>\
</div>\
</div>\
@@ -592,8 +598,34 @@ $('#search_time button').click(function(){
});
$('.indicators-container input').click(function(){
$('.indicators-container input').each(function(){
function initRealtimeTraffic(){
var check_realtime_second = $('#check_realtime_second').val();
if (check_realtime_second<1){
check_realtime_second = 1;
$('#check_realtime_second').val(check_realtime_second);
}
if (check_realtime_second>10){
check_realtime_second = 10;
$('#check_realtime_second').val(check_realtime_second);
}
var title = "每秒请求";
if (check_realtime_second > 1){
title = '每'+check_realtime_second+'秒请求'
}
$('#ov_title_req_second').text(title)
$('.check_realtime_request').text(title);
}
initRealtimeTraffic();
$('#check_realtime_second').change(function(){
initRealtimeTraffic();
});
$('.indicators-container input[type=radio]').click(function(){
$('.indicators-container input[type=radio]').each(function(){
$(this).removeAttr('checked');
});
$(this).prop({'checked':true});
@@ -651,8 +683,7 @@ function wsSitesListRequest(page){
var stat_length = 0;
var stat_req = 0;
console.log(rdata, data);
// console.log(rdata, data);
var list = '';
if (data.length > 0){
for(i in data){
@@ -2081,6 +2112,7 @@ var html = '<div>\
<option value="503">503</option>\
<option value="403">403</option>\
<option value="404">404</option>\
<option value="499">499</option>\
</select>\
<span style="margin-left:10px">时间: </span>\
<div class="input-group" style="margin-left:10px;width:350px;display: inline-table;vertical-align: top;">\
@@ -2179,6 +2211,7 @@ function wsTableLogRequest(page){
args['method'] = $('select[name="method"]').val();
args['status_code'] = $('select[name="status_code"]').val();
args['request_time'] = $('select[name="request_time"]').val();
args['request_size'] = $('select[name="request_size"]').val();
args['spider_type'] = $('select[name="spider_type"]').val();
args['referer'] = $('select[name="referer"]').val();
args['ip'] = $('input[name="ip"]').val();
@@ -2213,11 +2246,23 @@ function wsTableLogRequest(page){
"12":"其他",
}
var req_status = $('#logs_search').attr('req');
// console.log(req_status);
if (typeof(req_status) != 'undefined'){
if (req_status == 'start'){
layer.msg("正在请求中,请稍候!");
return;
}
}
$('#logs_search').attr('req','start');
// wsPost('get_logs_list', '' ,args, function(rdata){
wsPostCallbak('get_logs_list', '' ,args, function(rdata){
$('#logs_search').attr('req','end');
var rdata = $.parseJSON(rdata.data);
var list = '';
var data = rdata.data.data;
// console.log(data);
if (data.length > 0){
for(i in data){
@@ -2267,22 +2312,6 @@ function wsTableLogRequest(page){
$('#ws_table').html(table);
$('#wsPage').html(rdata.data.page);
$('input[name="ip"]').bind('focus', function(e){
$(this).keyup(function(e){
if(e.keyCode == 13) {
wsTableLogRequest(1);
}
});
});
$('input[name="search_uri"]').bind('focus', function(e){
$(this).keyup(function(e){
if(e.keyCode == 13) {
wsTableLogRequest(1);
}
});
});
$(".tablescroll .details").click(function(){
var index = $(this).attr('data-id');
var res = data[index];
@@ -2318,20 +2347,23 @@ function wsTableLogRequest(page){
var index = $(this).attr('data-id');
var res = data[index];
var request_headers = res.request_headers;
var req_data = $.parseJSON(request_headers);
var req_data_html = res.method +' ' + res.uri + '<br/>';
for (var d in req_data) {
if (d == 'payload'){
req_data_html += '<b style="color:red;">'+d +"</b>:"+req_data[d]+"<br/>";
} else{
req_data_html += d+":"+req_data[d]+"<br/>";
try {
var req_data = $.parseJSON(request_headers);
for (var d in req_data) {
if (d == 'payload'){
req_data_html += '<b style="color:red;">'+d +"</b>:"+req_data[d]+"<br/>";
} else{
req_data_html += d+":"+req_data[d]+"<br/>";
}
}
} catch (error) {
req_data_html += request_headers;
}
layer.open({
type: 1,
title: "【"+res.domain + "】HTTP详情",
@@ -2388,7 +2420,9 @@ var html = '<div>\
<option value="500">500</option>\
<option value="502">502</option>\
<option value="503">503</option>\
<option value="400">400</option>\
<option value="404">404</option>\
<option value="499">499</option>\
<option value="301">301</option>\
<option value="302">302</option>\
<option value="200">200</option>\
@@ -2432,6 +2466,15 @@ var html = '<div>\
<option value="500-1000">500ms-1s</option>\
<option value="1000">大于1s</option>\
</select>\
<span style="margin-left:10px;">大小: </span>\
<select class="bt-input-text" name="request_size" style="margin-left:5px;">\
<option value="all">所有</option>\
<option value="0-1">0-1(kb)</option>\
<option value="1-20">1-20(kb)</option>\
<option value="20-50">20-50(kb)</option>\
<option value="50-100">50-100(kb)</option>\
<option value="100">大于100kb</option>\
</select>\
<span style="margin-left:10px;">URL过滤: </span>\
<div class="input-group" style="width:210px;display:inline-flex;">\
<input type="text" name="search_uri" class="form-control btn-group-sm" autocomplete="off" placeholder="URI搜索" style="font-size: 12px;padding: 0 10px;height:30px;">\
@@ -2444,6 +2487,22 @@ var html = '<div>\
</div>';
$(".soft-man-con").html(html);
$('input[name="ip"]').bind('focus', function(e){
$(this).keyup(function(e){
if(e.keyCode == 13) {
wsTableLogRequest(1);
}
});
});
$('input[name="search_uri"]').bind('focus', function(e){
$(this).keyup(function(e){
if(e.keyCode == 13) {
wsTableLogRequest(1);
}
});
});
//日期范围
laydate.render({
elem: '#time_choose',
@@ -2507,6 +2566,10 @@ $('select[name="request_time"]').change(function(){
wsTableLogRequest(1);
});
$('select[name="request_size"]').change(function(){
wsTableLogRequest(1);
});
$('#logs_search').click(function(){
wsTableLogRequest(1);
});
+25
View File
@@ -616,7 +616,32 @@ function _M.statistics_request(self, ip, is_spider, body_length)
-- 计算pv uv
local pvc = 0
local uvc = 0
local request_header = ngx.req.get_headers()
if not is_spider and ngx.status == 200 and body_length > 0 then
local ua = ''
if request_header['user-agent'] then
ua = string.lower(request_header['user-agent'])
end
pvc = 1
if ua then
local today = ngx.today()
local uv_token = ngx.md5(ip .. ua .. today)
if not cache:get(uv_token) then
uvc = 1
cache:set(uv_token,1, self:get_end_time())
end
end
end
return pvc, uvc
end
-- 仅计算GET/HTML
function _M.statistics_request_old(self, ip, is_spider, body_length)
-- 计算pv uv
local pvc = 0
local uvc = 0
local method = ngx.req.get_method()
if not is_spider and method == 'GET' and ngx.status == 200 and body_length > 512 then
local ua = ''
if request_header['user-agent'] then
+2 -2
View File
@@ -260,7 +260,7 @@ log_by_lua_block {
end
end
if ngx.re.find("500,501,502,503,504,505,506,507,509,510,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,421,422,423,424,425,426,449,451", tostring(status_code), "jo") then
if ngx.re.find("500,501,502,503,504,505,506,507,509,510,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,421,422,423,424,425,426,449,451,499", tostring(status_code), "jo") then
local field = "status_"..status_code
request_stat_fields = request_stat_fields .. ","..field.."="..field.."+1"
end
@@ -392,7 +392,7 @@ log_by_lua_block {
end
end
if ngx.re.find("500,501,502,503,504,505,506,507,509,510,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,421,422,423,424,425,426,449,451", tostring(status_code), "jo") then
if ngx.re.find("500,501,502,503,504,505,506,507,509,510,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,421,422,423,424,425,426,449,451,499", tostring(status_code), "jo") then
local field = "status_"..status_code
request_stat_fields[field] = 1
end
+27 -4
View File
@@ -705,7 +705,7 @@ def get_logs_list(args):
start_time = time.time()
check = checkArgs(args, ['page', 'page_size','site', 'method',
'status_code', 'spider_type', 'request_time', 'query_date', 'search_uri'])
'status_code', 'spider_type', 'request_time', 'request_size', 'query_date', 'search_uri'])
if not check[0]:
return check[1]
@@ -716,6 +716,7 @@ def get_logs_list(args):
method = args['method']
status_code = args['status_code']
request_time = args['request_time']
request_size = args['request_size']
spider_type = args['spider_type']
query_date = args['query_date']
search_uri = args['search_uri']
@@ -726,7 +727,7 @@ def get_logs_list(args):
limit = str(page_size) + ' offset ' + str(page_size * (page - 1))
conn = pSqliteDb('web_logs', domain)
field = 'time,ip,domain,server_name,method,is_spider,protocol,status_code,request_headers,ip_list,client_port,body_length,user_agent,referer,request_time,uri,body_length'
field = 'time,ip,domain,server_name,method,is_spider,protocol,status_code,request_headers,ip_list,client_port,body_length,user_agent,referer,request_time,uri'
condition = ''
conn = conn.field(field)
conn = conn.where("1=1", ())
@@ -762,6 +763,14 @@ def get_logs_list(args):
if len(request_time_s) == 1:
conn = conn.andWhere("request_time>=?", (request_time,))
if request_size != "all":
request_size_s = request_size.strip().split('-')
# print(int(request_size_s[0])*1024)
if len(request_size_s) == 2:
conn = conn.andWhere("body_length>=? and body_length<?", (int(request_size_s[0])*1024,int(request_size_s[1])*1024,))
if len(request_size_s) == 1:
conn = conn.andWhere("body_length>=?", (int(request_size_s[0])*1024,))
if spider_type == "normal":
pass
elif spider_type == "only_spider":
@@ -782,8 +791,22 @@ def get_logs_list(args):
attacHistoryLogHack(conn, domain, query_date)
conn.changeTextFactoryToBytes()
clist = conn.limit(limit).order('time desc').inquiry()
# print(clist)
for x in range(len(clist)):
req_line = clist[x]
for cx in req_line:
v = req_line[cx]
if type(v) == bytes:
try:
clist[x][cx] = v.decode('utf-8')
except Exception as e:
v = str(v)
v = v.replace("b'",'').strip("'")
clist[x][cx] = v
else:
clist[x][cx] = v
count_key = "count(*) as num"
count = conn.field(count_key).limit('').order('').inquiry()
# print(count)
@@ -824,7 +847,7 @@ def getLogsErrorList():
limit = str(page_size) + ' offset ' + str(page_size * (page - 1))
conn = pSqliteDb('web_logs', domain)
field = 'time,ip,domain,server_name,method,protocol,status_code,ip_list,client_port,body_length,user_agent,referer,request_time,uri,body_length'
field = 'time,ip,domain,server_name,method,protocol,status_code,ip_list,client_port,body_length,user_agent,referer,request_time,uri'
conn = conn.field(field)
conn = conn.where("1=1", ())
+2 -2
View File
@@ -1,7 +1,7 @@
setuptools>=33.1.1
Werkzeug>=1.0.1,<3.0.0
wheel>=0.37.1
gunicorn==22.0.0
gunicorn>=21.2.0
requests>=2.27.1
urllib3>=1.21.1
flask>=2.0.3,<3.0.0
@@ -29,7 +29,7 @@ pymemcache
redis
pillow
Jinja2>=2.11.2
PyMySQL==1.0.2
PyMySQL>=1.0.2
whitenoise==5.3.0
pyotp
pytz
+8 -29
View File
@@ -60,8 +60,7 @@ try:
sdb.create_all()
except:
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_FILE_DIR'] = '/tmp/py_mw_session_' + \
str(sys.version_info[0])
app.config['SESSION_FILE_DIR'] = '/tmp/py_mw_session_' + str(sys.version_info[0])
app.config['SESSION_FILE_THRESHOLD'] = 1024
app.config['SESSION_FILE_MODE'] = 384
@@ -296,9 +295,6 @@ def code():
out = io.BytesIO()
codeImage[0].save(out, "png")
# print(codeImage[1])
session['code'] = mw.md5(''.join(codeImage[1]).lower())
img = Response(out.getvalue(), headers={'Content-Type': 'image/png'})
@@ -599,9 +595,6 @@ def index(reqClass=None, reqAction=None, reqData=None):
##################### ssh start ###########################
shell = None
shell_client = None
@socketio.on('webssh_websocketio')
def webssh_websocketio(data):
@@ -609,35 +602,21 @@ def webssh_websocketio(data):
emit('server_response', {'data': '会话丢失,请重新登陆面板!\r\n'})
return
global shell_client
if not shell_client:
import ssh_terminal
shell_client = ssh_terminal.ssh_terminal()
import ssh_terminal
shell_client = ssh_terminal.ssh_terminal.instance()
shell_client.run(request.sid, data)
return
@socketio.on('webssh')
def webssh(msg):
global shell
def webssh(data):
if not isLogined():
emit('server_response', {'data': '会话丢失,请重新登陆面板!\r\n'})
return None
if not shell:
shell = mw.connectSsh()
if shell.exit_status_ready():
shell = mw.connectSsh()
if shell:
shell.send(msg)
try:
time.sleep(0.005)
recv = shell.recv(4096)
emit('server_response', {'data': recv.decode("utf-8")})
except Exception as ex:
emit('server_response', {'data': str(ex)})
import ssh_local
shell = ssh_local.ssh_local.instance()
shell.run(data)
return
##################### ssh end ###########################
+222 -58
View File
@@ -75,16 +75,106 @@ $('input[name="bind_domain"]').change(function(){
$('.btn_bind_domain').removeAttr('disabled');
$('.btn_bind_domain').unbind().click(function(){
$.post('/config/set_panel_domain','domain='+domain, function(rdata){
showMsg(rdata.msg,function(){window.location.reload();},{icon:rdata.status?1:2},2000);
showMsg(rdata.msg,function(){
window.location.href = rdata.data;
},{icon:rdata.status?1:2},5000);
},'json');
});
});
$('input[name="bind_ssl"]').click(function(){
var open_ssl = $(this).prop("checked");
$.post('/config/set_panel_ssl',{}, function(rdata){
showMsg(rdata.msg,function(){window.location.reload();},{icon:rdata.status?1:2},2000);
},'json');
var panel_ssl = $(this).prop("checked");
$(this).prop("checked",!panel_ssl);
//开启证书
if (panel_ssl){
// <option value="1">ACME</option>
layer.open({
type:1,
closeBtn: 1,
title:"开启SSL证书",
area: ['600px','440px'],
btn: ["开启SSL证书访问"],
maxmin:false,
shadeClose: true,
content: '<div class="bt-form" style="padding: 25px 40px;">\
<div style="text-align: center;">\
<h3 style="font-size: 20px;color: #333;margin-left: 5px;">【开启SSL证书】保护面板访问安全</h3>\
</div>\
<ul class="help-info-text c7 pd15" style="color: #333;font-size: 14px;background: #F5F7FA;margin-top: 24px;padding: 10px 20px 10px 20px;border-radius: 2px;">\
<li>自签证书访问步骤:</li>\
<li>1. 部署SSL证书</li>\
<li>2. 浏览器地址栏修改为https://访问</li>\
<li>3. 如提醒风险(正常现象)点击【高级】或【详情】</li>\
<li>4.【继续访问】或【接收风险并继续】</li>\
</ul>\
<div class="pt10" style="margin-top: 20px;">\
<div class="line" style="font-size: 14px;">\
<span class="tname" style="width: 78px;">类型</span>\
<div class="info-r" style="margin-left: 78px;">\
<select class="bt-input-text mr5" name="cert_type" style="width: 440px;">\
<option value="0">自签证书 (推荐,浏览器会提示不安全。可忽略,请放心开启)</option>\
</select>\
</div>\
</div>\
<ul class="help-info-text c7 sslSafeTips">\
<li><span>开启后导致面板不能访问,可以点击查看</span></li>\
<li>自签证书不被浏览器信任,显示不安全是正常现象</li>\
</ul>\
</div>\
</div>',
yes: function(){
var cert_type = $('select[name=cert_type]').val();
$.post('/config/set_panel_local_ssl',{'cert_type':cert_type}, function(rdata){
// console.log(rdata);
var to_https = window.location.href.replace('http','https');
showMsg(rdata.msg,function(){
if (rdata.status){
window.location.href = to_https;
}
},{icon:rdata.status?1:2},5000);
},'json');
}
});
} else {
//关闭SSL
layer.open({
type:1,
closeBtn: 1,
title:"关闭SSL证书",
area: ['480px','280px'],
btn: ["确定","取消"],
shadeClose: true,
content: '<div class="bt-form" style="padding: 25px 40px;">\
<div class="hint_title" style="font-size: 15px;color: #111;text-align:center;">\
<div class="hint_con">关闭SSL极易被抓包攻击导致账号密码泄露,请勿关闭</div>\
</div>\
<div class="confirm-info-box" style="background-color: #f0f0f0;clear: both;font-size: 14px;height: 105px;line-height: 26px;padding: 20px 20px;margin-top: 20px;">\
<div>请手动输入【<span style="color: #fc6d26;">我要关闭</span>】,完成验证</div>\
<input onpaste="return false;" id="prompt_input_box" style="height: 30px;line-height: 30px;margin-top: 5px;width: 360px;color: #444;outline: none;border: 1px solid #ccc;padding: 0 5px;" type="text" value="" autocomplete="off">\
</div>\
</div>',
yes: function(index){
var val = $('#prompt_input_box').val();
if (val != '我要关闭'){
layer.msg("关闭SSL失败!");
return;
}
$.post('/config/close_panel_ssl',{}, function(rdata){
var to_http = window.location.href.replace('https','http');
showMsg(rdata.msg,function(){
if (rdata.status){
window.location.href = to_http;
}
},{icon:rdata.status?1:2},5000);
},'json');
}
});
}
});
/** op **/
@@ -714,8 +804,30 @@ function getPanelSSL(){
$.post('/config/get_panel_ssl',{},function(cert){
layer.close(loadT);
// console.log(cert);
var choose = cert['choose'];
var choose_local = '';
var choose_nginx = '';
if (choose == 'local'){
cert = cert['local'];
choose_local = 'selected="selected"';
} else if (choose == 'nginx') {
cert = cert['nginx'];
choose_nginx = 'selected="selected"';
} else {
cert = cert['local'];
}
var cert_data = '';
// <div class='state_item'>\
// <span>强制HTTPS:</span>\
// <span class='switch'>\
// <input class='btswitch btswitch-ios' id='toHttps' type='checkbox' "+cert['is_https']+">\
// <label class='btswitch-btn set_panel_http_to_https' for='toHttps'></label>\
// </span>\
// </div>\
if (cert['info']){
cert_data = "<div class='ssl_state_info'><div class='state_info_flex'>\
<div class='state_item'><span>证书品牌:</span>\
@@ -726,16 +838,11 @@ function getPanelSSL(){
<div class='state_info_flex'>\
<div class='state_item'><span>认证域名:</span>\
<span class='ellipsis_text ssl_subject'>"+cert['info']['subject']+"</span></div>\
<div class='state_item'>\
<span>强制HTTPS:</span>\
<span class='switch'>\
<input class='btswitch btswitch-ios' id='toHttps' type='checkbox' "+cert['is_https']+">\
<label class='btswitch-btn set_panel_http_to_https' for='toHttps'></label>\
</span>\
</div>\
</div></div>";
}
// <button class="btn btn-success btn-sm apply-lets-ssl">申请ACME证书</button>\
// <option value="nginx" '+choose_nginx+'>OpenResty</option>\
var certBody = '<div class="tab-con">\
<div class="myKeyCon ptb15">\
'+cert_data+'\
@@ -750,7 +857,9 @@ function getPanelSSL(){
<div class="ssl-btn pull-left mtb15" style="width:100%">\
<button class="btn btn-success btn-sm save-panel-ssl">保存</button>\
<button class="btn btn-success btn-sm del-panel-ssl">删除</button>\
<button class="btn btn-success btn-sm apply-lets-ssl">申请Lets证书</button>\
<select class="bt-input-text" name="choose" style="width:100px;">\
<option value="local" '+choose_local+'>本地</option>\
</select>\
</div>\
</div>\
<ul class="help-info-text c7 pull-left">\
@@ -768,65 +877,120 @@ function getPanelSSL(){
content:certBody,
success:function(layero, layer_id){
//保存SSL
$('.save-panel-ssl').click(function(){
var data = {
privateKey:$("#key").val(),
certPem:$("#csr").val()
}
var loadT = layer.msg('正在安装并设置SSL组件,这需要几分钟时间...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/config/save_panel_ssl',data,function(rdata){
layer.close(loadT);
if(rdata.status){
layer.closeAll();
}
layer.msg(rdata.msg,{icon:rdata.status?1:2});
},'json');
layer.confirm('选择保存面板SSL方式?',
{
title:'提示',
shade:0.001,
btn: ['本地SSL', '取消'],//'OpenResty'
btn3:function(){
data['choose'] = 'nginx';
var loadT = layer.msg('正在安装并设置SSL组件,这需要几分钟时间...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/config/save_panel_ssl',data,function(rdata){
layer.close(loadT);
if(rdata.status){
layer.closeAll();
}
layer.msg(rdata.msg,{icon:rdata.status?1:2});
},'json');
},
},
function(index) {
data['choose'] = 'local';
var loadT = layer.msg('正在安装并设置SSL组件,这需要几分钟时间...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/config/save_panel_ssl',data,function(rdata){
layer.close(loadT);
if(rdata.status){
layer.closeAll();
}
layer.msg(rdata.msg,{icon:rdata.status?1:2});
},'json');
},
function(index) {
layer.close(index);
});
});
//删除SSL
$('.del-panel-ssl').click(function(){
var loadT = layer.msg('正在删除SSL...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/config/del_panel_ssl',data,function(rdata){
layer.close(loadT);
if(rdata.status){
layer.closeAll();
}
layer.msg(rdata.msg,{icon:rdata.status?1:2});
},'json');
});
// 设置面板SSL的Http
$('.set_panel_http_to_https').click(function(){
var https = $('#toHttps').prop('checked');
$.post('/config/set_panel_http_to_https',{'https':https},function(rdata){
layer.close(loadT);
if(rdata.status){
layer.closeAll();
}
layer.msg(rdata.msg,{icon:rdata.status?1:2});
},'json');
});
//申请Lets证书
$('.apply-lets-ssl').click(function(){
showSpeedWindow('正在申请...', 'site.get_let_logs', function(layers,index){
$.post('/config/apply_panel_let_ssl',{},function(rdata){
layer.confirm('选择删除面板SSL方式?',
{
title:'提示',
shade:0.001,
btn: ['本地SSL', '取消'],//, 'OpenResty'
btn3:function(){
var data = {};
data['choose'] = 'nginx';
var loadT = layer.msg('正在删除面板SSL【nginx】...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/config/del_panel_ssl',data,function(rdata){
layer.close(loadT);
if(rdata.status){
layer.closeAll();
}
layer.msg(rdata.msg,{icon:rdata.status?1:2});
},'json');
},
},
function(index) {
var data = {};
data['choose'] = 'local';
var loadT = layer.msg('正在删除面板SSL【本地】...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/config/del_panel_ssl',data,function(rdata){
console.log(rdata);
layer.close(loadT);
if(rdata.status){
layer.close(index);
var tdata = rdata['data'];
$('.ssl_issue').text(tdata['info']['issuer']);
$('.ssl_endtime').text("剩余"+tdata['info']['endtime']+"天到期");
$('.ssl_subject').text(tdata['info']['subject']);
$('textarea[name="key"]').val(tdata['info']['privateKey']);
$('textarea[name="csr"]').val(tdata['info']['certPem']);
}
layer.msg(rdata.msg,{icon:rdata.status?1:2});
showMsg(rdata.msg, function(){
if(rdata.status){
location.href = rdata.data;
}
},{icon:rdata.status?1:2},3000);
},'json');
});
},
function(index) {
layer.close(index);
});
});
// // 设置面板SSL的Http
// $('.set_panel_http_to_https').click(function(){
// var https = $('#toHttps').prop('checked');
// $.post('/config/set_panel_http_to_https',{'https':https},function(rdata){
// layer.close(loadT);
// if(rdata.status){
// layer.closeAll();
// }
// layer.msg(rdata.msg,{icon:rdata.status?1:2});
// },'json');
// });
// //申请Lets证书
// $('.apply-lets-ssl').click(function(){
// showSpeedWindow('正在申请...', 'site.get_let_logs', function(layers,index){
// $.post('/config/apply_panel_acme_ssl',{},function(rdata){
// layer.close(loadT);
// if(rdata.status){
// layer.close(index);
// var tdata = rdata['data'];
// $('.ssl_issue').text(tdata['info']['issuer']);
// $('.ssl_endtime').text("剩余"+tdata['info']['endtime']+"天到期");
// $('.ssl_subject').text(tdata['info']['subject']);
// $('textarea[name="key"]').val(tdata['info']['privateKey']);
// $('textarea[name="csr"]').val(tdata['info']['certPem']);
// }
// layer.msg(rdata.msg,{icon:rdata.status?1:2});
// },'json');
// });
// });
}
});
},'json');
+19 -5
View File
@@ -294,7 +294,7 @@ function openFilename(obj){
onlineEditFile(0, path);
}
if (inArray(ext,['png','jpeg','gif','jpg','ico'])){
if (inArray(ext,['png','jpeg','jpg','gif','webp','bmp','ico'])){
getImage(path);
}
@@ -1592,6 +1592,22 @@ function setChmod(action,fileName){
var toExec = fileName == lan.files.all?'batch(3,1)':'setChmod(1,\''+fileName+'\')';
$.post('/files/file_access','filename='+encodeURIComponent(fileName),function(rdata){
// console.log(rdata);
var sys_users = rdata.sys_users;
var own_html = '';
var is_find_own_option = false;
for (var i = 0; i < sys_users.length; i++) {
var own = sys_users[i];
if (rdata.chown==own){
is_find_own_option = true;
own_html += '<option value="'+own+'" selected="selected">'+own+'</option>';
} else {
own_html += '<option value="'+own+'">'+own+'</option>';
}
}
if (!is_find_own_option){
own_html += '<option value="'+rdata.chown+'" selected="selected">'+rdata.chown+'</option>';
}
layer.open({
type:1,
closeBtn: 1,
@@ -1619,10 +1635,8 @@ function setChmod(action,fileName){
</fieldset>\
<div class="setchmodnum"><input class="bt-input-text" type="text" id="access" maxlength="3" value="'+rdata.chmod+'">权限,\
<span>所有者\
<select id="chown" class="bt-input-text">\
<option value="www" '+(rdata.chown=='www'?'selected="selected"':'')+'>www</option>\
<option value="mysql" '+(rdata.chown=='mysql'?'selected="selected"':'')+'>mysql</option>\
<option value="root" '+(rdata.chown=='root'?'selected="selected"':'')+'>root</option>\
<select id="chown" class="bt-input-text" style="width:100px;">\
'+own_html+'\
</select></span></div>\
<div class="bt-form-submit-btn">\
<button type="button" class="btn btn-danger btn-sm btn-title" onclick="layer.closeAll()">关闭</button>\
+601 -53
View File
@@ -1,35 +1,3 @@
$(function() {
$(".mem-release").hover(function() {
$(this).addClass("shine_green");
if (!($(this).hasClass("mem-action"))) {
$(this).find(".mem-re-min").hide();
$(this).find(".mask").css({ "color": "#d2edd8" });
$(this).find(".mem-re-con").css({ "display": "block" });
$(this).find(".mem-re-con").animate({ "top": "0", opacity: 1 });
$("#memory").text('内存释放');
}
}, function() {
$(this).removeClass("shine_green");
$(this).find(".mask").css({ "color": "#20a53a" });
$(this).find(".mem-re-con").css({ "top": "15px", opacity: 1, "display": "none" });
$("#memory").text(getCookie("mem-before"));
$(this).find(".mem-re-min").hide();
}).click(function() {
$(this).find(".mem-re-min").hide();
if (!($(this).hasClass("mem-action"))) {
reMemory();
var btlen = $(".mem-release").find(".mask span").text();
$(this).addClass("mem-action");
$(this).find(".mask").css({ "color": "#20a53a" });
$(this).find(".mem-re-con").animate({ "top": "-400px", opacity: 0 });
$(this).find(".pie_right .right").css({ "transform": "rotate(3deg)" });
for (var i = 0; i < btlen; i++) {
setTimeout("rocket(" + btlen + "," + i + ")", i * 30);
}
}
});
});
//获取负载
function getLoad(data) {
$("#LoadList .mask").html("<span id='Load' style='font-size:14px'>获取中..</span>");
@@ -64,7 +32,7 @@ function getLoad(data) {
}
$('#LoadList .circle').click(function() {
getNet();
// getNet();
});
$('#LoadList .mask').hover(function() {
@@ -81,8 +49,7 @@ $('#LoadList .mask').hover(function() {
function showCpuTips(rdata){
$('#cpuChart .mask').unbind();
$('#cpuChart .mask').hover(function() {
$('#cpuChart .mask').unbind().hover(function() {
var cpuText = '';
if (rdata.cpu[2].length == 1){
var cpuUse = parseFloat(rdata.cpu[2][0] == 0 ? 0 : rdata.cpu[2][0]).toFixed(1);
@@ -284,6 +251,8 @@ function getNet() {
var up, down;
$.get("/system/network", function(net) {
console.log(net);
$("#InterfaceSpeed").html(lan.index.interfacespeed + ": 1.0Gbps");
$("#upSpeed").html(toSize(net.up));
$("#downSpeed").html(toSize(net.down));
@@ -310,9 +279,9 @@ function getNet() {
},'json');
}
//网络Io
//网络IO
function netImg() {
var echartsNetImg = echarts.init(document.getElementById('netImg'));
var xData = [];
var yData = [];
var zData = [];
@@ -359,7 +328,7 @@ function netImg() {
var downNetTmp = toSize(getCookie("downNet"));
var upNetTmpSize = upNetTmp.split(' ')[0];
var downNetTmp = downNetTmp.split(' ')[0]
var downNetTmp = downNetTmp.split(' ')[0];
yData.push(upNetTmpSize);
zData.push(downNetTmp);
@@ -378,12 +347,12 @@ function netImg() {
// 指定图表的配置项和数据
var option = {
title: {
text: lan.index.interface_net,
text: "接口流量实时",
left: 'center',
textStyle: {
color: '#888888',
fontStyle: 'normal',
fontFamily: lan.index.net_font,
fontFamily: "宋体",
fontSize: 16,
}
},
@@ -474,6 +443,8 @@ function netImg() {
}
}]
};
var echartsNetImg = echarts.init(document.getElementById('netImg'));
setInterval(function() {
getNet();
addData(true);
@@ -516,8 +487,7 @@ function setImg() {
};
});
$('.diskbox .mask').unbind();
$('.diskbox .mask').hover(function() {
$('.diskbox .mask').unbind().hover(function() {
layer.closeAll('tips');
var that = this;
var conterError = $(this).attr("data");
@@ -638,7 +608,10 @@ function reBoot() {
area: '330px',
closeBtn: 1,
shadeClose: false,
content: '<div class="rebt-con"><div class="rebt-li"><a data-id="server" href="javascript:;">重启服务器</a></div><div class="rebt-li"><a data-id="panel" href="javascript:;">重启面板</a></div></div>'
content: '<div class="rebt-con">\
<div class="rebt-li"><a data-id="server" href="javascript:;">重启服务器</a></div>\
<div class="rebt-li"><a data-id="panel" href="javascript:;">重启面板</a></div>\
</div>'
});
$('.rebt-con a').click(function () {
@@ -779,17 +752,18 @@ function showDanger(num, port) {
closeBtn: 1,
shift: 5,
content: '<div class="pd20">\
<table class="f14 showDanger"><tbody>\
<tr><td class="text-right" width="150">风险类型:</td><td class="f16" style="color:red">暴力破解 <a href="https://www.bt.cn/bbs/thread-9562-1-1.html" class="btlink f14" style="margin-left:10px" target="_blank">说明</a></td></tr>\
<tr><td class="text-right">累计遭遇攻击总数:</td><td class="f16" style="color:red">' + num + ' <a href="javascript:showDangerIP();" class="btlink f14" style="margin-left:10px">详细</a><span class="c9 f12" style="margin-left:10px">(数据直接来源本服务器日志)</span></td></tr>\
<tr><td class="text-right">风险等级:</td><td class="f16" style="color:red">较高风险</td></tr>\
<tr><td class="text-right" style="vertical-align:top">风险描述:</td><td style="line-height:20px">' + atxt + '</td></tr>\
<tr><td class="text-right" style="vertical-align:top">可参考解决方案:</td><td><p style="margin-bottom:8px">方案一:修改SSH默认端口,修改SSH验证方式为数字证书,清除近期登陆日志。</p><p>方案二:购买宝塔企业运维版,一键部署安全隔离服务,高效且方便。</p></td></tr>\
</tbody></table>\
<div class="mtb20 text-center"><a href="https://www.bt.cn/admin/index.html" target="_blank" class="btn btn-success">立即部署隔离防护</a></div>\
</div>'
<table class="f14 showDanger">\
<tbody>\
<tr><td class="text-right" width="150">风险类型:</td><td class="f16" style="color:red">暴力破解 <a href="https://www.bt.cn/bbs/thread-9562-1-1.html" class="btlink f14" style="margin-left:10px" target="_blank">说明</a></td></tr>\
<tr><td class="text-right">累计遭遇攻击总数:</td><td class="f16" style="color:red">' + num + ' <a href="javascript:showDangerIP();" class="btlink f14" style="margin-left:10px">详细</a><span class="c9 f12" style="margin-left:10px">(数据直接来源本服务器日志)</span></td></tr>\
<tr><td class="text-right">风险等级:</td><td class="f16" style="color:red">较高风险</td></tr>\
<tr><td class="text-right" style="vertical-align:top">风险描述:</td><td style="line-height:20px">' + atxt + '</td></tr>\
<tr><td class="text-right" style="vertical-align:top">可参考解决方案:</td><td><p style="margin-bottom:8px">方案一:修改SSH默认端口,修改SSH验证方式为数字证书,清除近期登陆日志。</p><p>方案二:购买宝塔企业运维版,一键部署安全隔离服务,高效且方便。</p></td></tr>\
</tbody>\
</table>\
</div>'
});
$(".showDanger td").css("padding", "8px")
$(".showDanger td").css("padding", "8px");
}
function pluginInit(){
@@ -913,3 +887,577 @@ function loadKeyDataCount(){
call(pname);
}
}
$(function() {
$(".mem-release").hover(function() {
$(this).addClass("shine_green");
if (!($(this).hasClass("mem-action"))) {
$(this).find(".mem-re-min").hide();
$(this).find(".mask").css({ "color": "#d2edd8" });
$(this).find(".mem-re-con").css({ "display": "block" });
$(this).find(".mem-re-con").animate({ "top": "0", opacity: 1 });
$("#memory").text('内存释放');
}
}, function() {
$(this).removeClass("shine_green");
$(this).find(".mask").css({ "color": "#20a53a" });
$(this).find(".mem-re-con").css({ "top": "15px", opacity: 1, "display": "none" });
$("#memory").text(getCookie("mem-before"));
$(this).find(".mem-re-min").hide();
}).click(function() {
$(this).find(".mem-re-min").hide();
if (!($(this).hasClass("mem-action"))) {
reMemory();
var btlen = $(".mem-release").find(".mask span").text();
$(this).addClass("mem-action");
$(this).find(".mask").css({ "color": "#20a53a" });
$(this).find(".mem-re-con").animate({ "top": "-400px", opacity: 0 });
$(this).find(".pie_right .right").css({ "transform": "rotate(3deg)" });
for (var i = 0; i < btlen; i++) {
setTimeout("rocket(" + btlen + "," + i + ")", i * 30);
}
}
});
$("select[name='network-io'],select[name='disk-io']").change(function () {
var key = $(this).val(), type = $(this).attr('name');
if (type == 'network-io') {
if (key == 'ALL') {
key = '';
}
setCookie('network_io_key', key);
} else {
if (key == 'ALL') {
key = '';
}
setCookie('disk_io_key', key);
}
});
$('.tabs-nav span').click(function () {
var indexs = $(this).index();
$(this).addClass('active').siblings().removeClass('active');
$('.tabs-content .tabs-item:eq(' + indexs + ')').addClass('tabs-active').siblings().removeClass('tabs-active');
$('.tabs-down select:eq(' + indexs + ')').removeClass('hide').siblings().addClass('hide');
switch (indexs) {
case 0:
index.net.table.resize();
break;
case 1:
index.iostat.table.resize();
break;
}
})
});
var index = {
common:{
ts:function (m) { return m < 10 ? '0' + m : m },
format:function (sjc) {
var time = new Date(sjc);
var h = time.getHours();
var mm = time.getMinutes();
var s = time.getSeconds();
return h+ ':' + mm + ':' +s;
},
getTime:function () {
var now = new Date();
var hour = now.getHours();
var minute = now.getMinutes();
var second = now.getSeconds();
if (minute < 10) {
minute = "0" + minute;
}
if (second < 10) {
second = "0" + second;
}
var nowdate = hour + ":" + minute + ":" + second;
return nowdate;
},
},
net: {
table: null,
data: {
xData: [],
yData: [],
zData: []
},
default_unit : 'KB/s',
init_select : false,
init: function(){
for (var i = 8; i >= 0; i--) {
var time = (new Date()).getTime();
index.net.data.xData.push(index.common.format(time - (i * 3 * 1000)));
index.net.data.yData.push(0);
index.net.data.zData.push(0);
}
index.net.table = echarts.init(document.getElementById('netImg'));
var option = index.net.defaultOption();
index.net.table.setOption(option);
window.addEventListener("resize", function () {
index.net.table.resize();
});
},
render:function(){
index.net.table.setOption({
yAxis: {
name: '单位 '+ index.net.default_unit,
splitLine: { lineStyle: { color: "#eee" } },
axisLine: { lineStyle: { color: "#666" } }
},
xAxis: {
data: index.net.data.xData
},
series: [{
name: lan.index.net_up,
data: index.net.data.yData
}, {
name: lan.index.net_down,
data: index.net.data.zData
}]
});
},
defaultOption:function(){
var option = {
title: {
text: "",
left: 'center',
textStyle: {
color: '#888888',
fontStyle: 'normal',
fontFamily: "宋体",
fontSize: 16,
}
},
tooltip: {
trigger: 'axis',
formatter :function (config) {
var _config = config, _tips = "时间:" + _config[0].axisValue + "<br />";
for (var i = 0; i < config.length; i++) {
if (typeof config[i].data == "undefined") {
return false;
}
_tips += '<span style="display: inline-block;width: 10px;height: 10px;border-radius: 50%;background: ' + config[i].color + ';"></span>&nbsp;&nbsp;<span>' + config[i].seriesName + ':' + config[i].data + ' '+ index.net.default_unit + '</span><br />'
}
return _tips;
}
},
legend: {
data: [lan.index.net_up, lan.index.net_down],
bottom: '2%'
},
xAxis: {
type: 'category',
boundaryGap: false,
data: index.net.data.xData,
axisLine: {
lineStyle: {
color: "#666"
}
}
},
yAxis: {
name: '单位 '+ index.net.default_unit,
splitLine: {
lineStyle: { color: "#eee" }
},
axisLine: {
lineStyle: { color: "#666" }
}
},
series: [{
name: '上行',
type: 'line',
data: index.net.data.yData,
smooth: true,
showSymbol: false,
symbol: 'circle',
symbolSize: 6,
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(255, 140, 0,0.5)'
}, {
offset: 1,
color: 'rgba(255, 140, 0,0.8)'
}], false)
}
},
itemStyle: {
normal: {
color: '#f7b851'
}
},
lineStyle: {
normal: {
width: 1
}
}
},
{
name: '下行',
type: 'line',
data: index.net.data.zData,
smooth: true,
showSymbol: false,
symbol: 'circle',
symbolSize: 6,
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(30, 144, 255,0.5)',
}, {
offset: 1,
color: 'rgba(30, 144, 255,0.8)',
}], false)
}
},
itemStyle: {
normal: {
color: '#52a9ff',
}
},
lineStyle: {
normal: {
width: 1,
}
}
}]
};
return option;
},
add: function (up, down) {
var _net = this;
var limit = 8;
var d = new Date()
if (_net.data.xData.length >= limit) _net.data.xData.splice(0, 1);
if (_net.data.yData.length >= limit) _net.data.yData.splice(0, 1);
if (_net.data.zData.length >= limit) _net.data.zData.splice(0, 1);
_net.data.xData.push(d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds());
if (up>down){
var upTmp = toSizePos(up);
var upTmpSize = upTmp['name'].split(' ')[0];
index.net.default_unit = upTmp['name'].split(' ')[1] + '/s';
var downTmpSize = toSizePos(down,upTmp['pos'])['name'].split(' ')[0];
// console.log('up',upTmp['pos'],toSizePos(down, upTmp['pos']),downTmpSize);
_net.data.zData.push(downTmpSize);
_net.data.yData.push(upTmpSize);
} else {
var downTmp = toSizePos(down);
var downTmpSize = downTmp['name'].split(' ')[0];
index.net.default_unit = downTmp['name'].split(' ')[1] + '/s';
var upTmpSize = toSizePos(up, downTmp['pos'])['name'].split(' ')[0];
// console.log('down',downTmp['pos'],toSizePos(up, downTmp['pos']),upTmpSize);
_net.data.zData.push(downTmpSize);
_net.data.yData.push(upTmpSize);
}
},
renderSelect:function(net){
// console.log(net);
if (!index.net.init_select){
var option = '';
var network = net.network;
var network_io_key = getCookie('network_io_key');
for (var name in network) {
if (name == 'ALL'){
option += '<option value="'+name+'">全部</option>';
} else if (network_io_key == name){
option += '<option value="'+name+'" selected>'+name+'</option>';
} else {
option += '<option value="'+name+'">'+name+'</option>';
}
}
$('select[name="network-io"]').html(option);
index.net.init_select = true;
}
}
},
iostat:{
table: null,
data: {
xData: [],
yData: [],
zData: [],
tipsData: []
},
init_select:false,
default_unit : 'MB/s',
init:function(){
for (var i = 8; i >= 0; i--) {
var time = (new Date()).getTime();
index.iostat.data.xData.push(index.common.format(time - (i * 3 * 1000)));
index.iostat.data.yData.push(0);
index.iostat.data.zData.push(0);
index.iostat.data.tipsData.push({});
}
index.iostat.table = echarts.init(document.getElementById('ioStat'));
var option = index.iostat.defaultOption();
index.iostat.table.setOption(option);
window.addEventListener("resize", function () {
index.iostat.table.resize();
});
},
render:function(){
index.iostat.table.setOption({
tooltip: {
trigger: 'axis',
formatter :function (config) {
var _config = config, _tips = "时间:" + _config[0].axisValue + "<br />", options = {
read_bytes: '读取字节数',
read_count: '读取次数 ',
read_merged_count: '合并读取次数',
read_time: '读取延迟',
write_bytes: '写入字节数',
write_count: '写入次数',
write_merged_count: '合并写入次数',
write_time: '写入延迟',
}, data = index.iostat.data.tipsData[config[0].dataIndex], list = ['read_count', 'write_count', 'read_merged_count', 'write_merged_count', 'read_time', 'write_time',];
for (var i = 0; i < config.length; i++) {
if (typeof config[i].data == "undefined") {
return false;
}
_tips += '<span style="display: inline-block;width: 10px;height: 10px;border-radius: 50%;background: ' + config[i].color + ';"></span>&nbsp;&nbsp;<span>' + config[i].seriesName + ':' + config[i].data + ' MB/s' + '</span><br />'
}
$.each(list, function (index, item) {
if (typeof data[item] != 'undefined'){
_tips += '<span style="display: inline-block;width: 10px;height: 10px;"></span>&nbsp;&nbsp;<span style="' + (item.indexOf('time') > -1 ? ('color:' + ((data[item] > 100 && data[item] < 1000) ? '#ff9900' : (data[item] >= 1000 ? 'red' : '#20a53a'))) : '') + '">' + options[item] + ':' + data[item] + (item.indexOf('time') > -1 ? ' ms' : ' 次/秒') + '</span><br />';
}
})
return _tips;
}
},
yAxis: {
name: '单位 '+ index.iostat.default_unit,
splitLine: { lineStyle: { color: "#eee" } },
axisLine: { lineStyle: { color: "#666" } }
},
xAxis: {
data: index.iostat.data.xData
},
series: [{
name: "读取",
data: index.iostat.data.yData
}, {
name: "写入",
data: index.iostat.data.zData
}]
});
},
defaultOption:function(){
var option = {
title: {
text: "",
left: 'center',
textStyle: {
color: '#888888',
fontStyle: 'normal',
fontFamily: "宋体",
fontSize: 16,
}
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ["读取", "写入"],
bottom: '2%'
},
xAxis: {
type: 'category',
boundaryGap: false,
data: index.iostat.data.xData,
axisLine: {
lineStyle: {
color: "#666"
}
}
},
yAxis: {
name: '单位 '+ index.iostat.default_unit,
splitLine: {
lineStyle: { color: "#eee" }
},
axisLine: {
lineStyle: { color: "#666" }
}
},
series: [{
name: '读取',
type: 'line',
data: index.iostat.data.yData,
smooth: true,
showSymbol: false,
symbol: 'circle',
areaStyle: {
normal: {
color: 'rgb(255, 70, 131)'
}
},
itemStyle: {
normal: {
color: 'rgb(255, 70, 131)'
}
},
lineStyle: {
normal: {
width: 1,
}
}
},
{
name: '写入',
type: 'line',
data: index.iostat.data.zData,
smooth: true,
showSymbol: false,
symbol: 'circle',
symbolSize: 6,
areaStyle: {
normal: {
color: 'rgba(46, 165, 186, .7)'
}
},
itemStyle: {
normal: {
color: 'rgba(46, 165, 186, .7)'
}
},
lineStyle: {
normal: {
width: 1,
}
}
}]
};
return option;
},
renderSelect:function(data){
if (!index.iostat.init_select){
var option = '';
var iostat = data.iostat;
var disk_io_key = getCookie('disk_io_key');
for (var name in iostat) {
if (name == 'ALL'){
option += '<option value="'+name+'">全部</option>';
} else if (disk_io_key == name){
option += '<option value="'+name+'" selected>'+name+'</option>';
} else {
option += '<option value="'+name+'">'+name+'</option>';
}
}
$('select[name="disk-io"]').html(option);
index.iostat.init_select = true;
}
},
add: function (read, write, data) {
var _iostat = this;
var limit = 8;
var d = new Date()
if (_iostat.data.xData.length >= limit) _iostat.data.xData.splice(0, 1);
if (_iostat.data.yData.length >= limit) _iostat.data.yData.splice(0, 1);
if (_iostat.data.zData.length >= limit) _iostat.data.zData.splice(0, 1);
if (_iostat.data.tipsData.length >= limit) _iostat.data.tipsData.splice(0, 1);
var readTmpSize = toSizeMB(read).split(' ')[0];
var writeTmpSize = toSizeMB(write).split(' ')[0];
_iostat.data.zData.push(writeTmpSize);
_iostat.data.yData.push(readTmpSize);
_iostat.data.tipsData.push(data);
_iostat.data.xData.push(d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds());
},
},
getData:function(){
$.get("/system/network", function(net) {
//网络IO
var network_io_key = getCookie('network_io_key');
var network_data = net.network;
var network_select = network_data['ALL'];
if (network_io_key && network_io_key != ''){
network_select = network_data[network_io_key];
}
index.net.add(network_select.up,network_select.down);
index.net.render();
index.net.renderSelect(net);
$("#upSpeed").html(toSize(network_select.up));
$("#downSpeed").html(toSize(network_select.down));
$("#downAll").html(toSize(network_select.downTotal));
$("#downAll").attr('title','数据包:' + network_select.downPackets)
$("#upAll").html(toSize(network_select.upTotal));
$("#upAll").attr('title','数据包:' + network_select.upPackets)
//磁盘IO
var disk_io_key = getCookie('disk_io_key');
var iostat_data = net.iostat;
var iostat_select = iostat_data['ALL'];
if (disk_io_key && disk_io_key != ''){
iostat_select = iostat_data[disk_io_key];
}
index.iostat.add(iostat_select.read_bytes,iostat_select.write_bytes, iostat_select);
index.iostat.render();
index.iostat.renderSelect(net);
$("#readBytes").html(toSize(iostat_select.read_bytes));
$("#writeBytes").html(toSize(iostat_select.write_bytes));
$("#diskIops").html(iostat_select.read_count+":"+iostat_select.write_count+ " 次");
$("#diskTime").html(iostat_select.read_time+":"+iostat_select.write_time +" ms");
$("#core").html(net.cpu[1] + " " + lan.index.cpu_core);
$("#state").html(net.cpu[0]);
setcolor(net.cpu[0], "#state", 30, 70, 90);
//负载
getLoad(net.load);
//内存
setMemImg(net.mem);
//绑定hover事件
setImg();
showCpuTips(net);
},'json');
},
task:function(){
// index.getData();
setInterval(function() {
index.getData();
}, 3000);
},
init: function(){
index.net.init();
index.iostat.init();
index.task();
}
}
+59 -20
View File
@@ -16,6 +16,39 @@ function toSize(a) {
}
}
function toSizePos(a, pos = 0) {
var d = [" B", " KB", " MB", " GB", " TB", " PB"];
var e = 1024;
var r = {};
for(var b = 0; b < d.length; b++) {
if (pos > 0){
if (b == pos){
r['name'] = (b == 0 ? a : a.toFixed(2)) + d[b];
r['pos'] = b;
return r
}
} else {
if( a < e) {
r['name'] = (b == 0 ? a : a.toFixed(2)) + d[b];
r['pos'] = b;
return r
}
}
a /= e;
}
}
function toSizeMB(a) {
var d = [" KB", " MB"];
var e = 1024;
var i = 0;
for(var b = 0; b < d.length; b++) {
a /= e;
i = b;
}
return a.toFixed(2) + d[i]
}
function toTrim(x) {
return x.replace(/^\s+|\s+$/gm,'');
}
@@ -577,7 +610,7 @@ function showMsg(msg, callback ,icon, time){
function openPath(a) {
setCookie("open_dir_path", a);
window.location.href = "/files/"
window.location.href = "/files/";
}
function onlineEditFile(k, f, callback) {
@@ -989,7 +1022,7 @@ function setSelectChecked(c, d) {
function jump() {
layer.closeAll();
window.location.href = "/soft"
window.location.href = "/soft";
}
function installTips() {
@@ -1123,15 +1156,15 @@ function getPanelList(){
var user = $(this).attr("data-user");
var pw = $(this).attr("data-pw");
layer.open({
type: 2,
title: false,
closeBtn: 0, //不显示关闭按钮
shade: [0],
area: ['340px', '215px'],
offset: 'rb', //右下角弹出
time: 5, //2秒后自动关闭
anim: 2,
content: [murl+'/login', 'no']
type: 2,
title: false,
closeBtn: 0, //不显示关闭按钮
shade: [0],
area: ['340px', '215px'],
offset: 'rb', //右下角弹出
time: 5, //2秒后自动关闭
anim: 2,
content: [murl+'/login', 'no']
});
var loginForm ='<div id="btpanelform" style="display:none"><form id="toBtpanel" action="'+murl+'/do_login" method="post" target="btpfrom">\
<input name="username" id="btp_username" value="'+user+'" type="text">\
@@ -1364,7 +1397,7 @@ function remind(a){
<td>\
<div class="titlename c3">'+g.data[d].name+'</span>\
<span class="rs-status">【'+lan.bt.task_ok+'】<span>\
<span class="rs-time">耗时['+ getSFM(g.data[d].end - g.data[d].start) +']</span>\
<span class="rs-time">安装等待中...</span>\
</div>\
</td>\
<td class="text-right c3">'+g.data[d].addtime+'</td>\
@@ -2244,7 +2277,7 @@ function pluginConfig(_name, version, func){
//配置修改模版 --- start
function pluginConfigTpl(_name, version, func, config_tpl_func, read_config_tpl_func){
function pluginConfigTpl(_name, version, func, config_tpl_func, read_config_tpl_func, save_callback_func){
if ( typeof(version) == 'undefined' ){
version = '';
}
@@ -2270,7 +2303,7 @@ function pluginConfigTpl(_name, version, func, config_tpl_func, read_config_tpl_
<textarea class="bt-input-text" style="height: 320px; line-height:18px;" id="textBody"></textarea>\
<button id="onlineEditFileBtn" class="btn btn-success btn-sm" style="margin-top:10px;">保存</button>\
<ul class="help-info-text c7 ptb15">\
<li>此处为'+ _name + version +'主配置文件,若您不了解配置规则,请勿随意修改。</li>\
<li>此处为【'+ _name + version +'】主配置文件,若您不了解配置规则,请勿随意修改。</li>\
</ul>';
$(".soft-man-con").html(con);
@@ -2310,7 +2343,7 @@ function pluginConfigTpl(_name, version, func, config_tpl_func, read_config_tpl_
"Ctrl-H": "replaceAll",
"Ctrl-S": function() {
$("#textBody").text(editor.getValue());
pluginConfigSave(fileName);
pluginConfigSave(fileName,save_callback_func);
}
},
lineNumbers: true,
@@ -2321,7 +2354,7 @@ function pluginConfigTpl(_name, version, func, config_tpl_func, read_config_tpl_
$("#onlineEditFileBtn").unbind('click');
$("#onlineEditFileBtn").click(function(){
$("#textBody").text(editor.getValue());
pluginConfigSave(fileName);
pluginConfigSave(fileName, save_callback_func);
});
},'json');
}
@@ -2350,7 +2383,7 @@ function pluginConfigTpl(_name, version, func, config_tpl_func, read_config_tpl_
"Ctrl-H": "replaceAll",
"Ctrl-S": function() {
$("#textBody").text(editor.getValue());
pluginConfigSave(fileName);
pluginConfigSave(fileName,save_callback_func);
}
},
lineNumbers: true,
@@ -2360,7 +2393,7 @@ function pluginConfigTpl(_name, version, func, config_tpl_func, read_config_tpl_
$(".CodeMirror-scroll").css({"height":"300px","margin":0,"padding":0});
$("#onlineEditFileBtn").click(function(){
$("#textBody").text(editor.getValue());
pluginConfigSave(fileName);
pluginConfigSave(fileName,save_callback_func);
});
},'json');
},'json');
@@ -2487,13 +2520,19 @@ function pluginConfigListTpl(_name, version, config_tpl_func, read_config_tpl_fu
//配置保存
function pluginConfigSave(fileName) {
function pluginConfigSave(fileName, callback) {
var data = encodeURIComponent($("#textBody").val());
var encoding = 'utf-8';
var loadT = layer.msg('保存中...', {icon: 16,time: 0});
$.post('/files/save_body', 'data=' + data + '&path=' + fileName + '&encoding=' + encoding, function(rdata) {
layer.close(loadT);
layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
showMsg(rdata.msg, function(){
if ( rdata.status && typeof(callback) == 'function'){
callback();
}
},{icon: rdata.status ? 1 : 2});
},'json');
}
+113 -1
View File
@@ -9,7 +9,8 @@ input,
textarea,
select {
font-size: 100%;
font-family: inherit
font-family: inherit;
outline: none;
}
body,
@@ -275,6 +276,10 @@ html {
margin-left: 5px;
}
.ml10 {
margin-left: 10px;
}
.mr5 {
margin-right: 5px;
}
@@ -282,6 +287,7 @@ html {
.mr20 {
margin-right: 20px;
}
.ml0{
margin-left: 0;
}
@@ -5096,4 +5102,110 @@ select[disabled]{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.title.tabs-nav {
padding: 0;
position: relative;
}
.title.tabs-nav span {
display: inline-block;
height: 50px;
min-width: 100px;
padding: 0 20px;
line-height: 50px;
font-size: 15px;
cursor: pointer;
position: relative;
text-align: center;
}
.title.tabs-nav span.active {
color: #20a53a;
background: #20a53a08;
}
.title.tabs-nav select {
position: absolute;
right: 5px;
top: 50%;
margin-top: -12px;
}
select[name="network-io"], select[name="disk-io"] {
font-size: 13px;
height: 24px;
line-height: 24px;
padding: 2px;
border-radius: 0;
border-color: #ececec;
}
.tabs-content .tabs-item {
display: none;
height: 100%;
width: 100%;
background-color: #fff;
}
.tabs-content .tabs-active.tabs-item {
display: inline-block;
}
.bw-info {
height: 80px;
}
.bw-info>div {
float: left;
padding-top: 35px;
text-align: center;
}
.bw-info>div p {
margin-bottom: 7px;
}
.bw-info>div a {
font-size: 14px;
color: #666;
}
.bw-info .ico-down,
.bw-info .ico-up,
.bw-info .ico-write,
.bw-info .ico-read {
width: 10px;
height: 10px;
display: inline-block;
margin-right: 3px;
border-radius: 5px;
}
.bw-info .ico-down {
background-color: #52a9ff;
}
.bw-info .ico-up {
background-color: #f7b851;
}
.bw-info .ico-write {
background-color: #6CC0CF;
}
.bw-info .ico-read {
background-color: #FF4683;
}
.bw-info ul li {
height: 56px;
line-height: 56px;
}
.bw-info ul li.bi-line {
border-bottom: #ddd solid 1px;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

+1 -1
View File
@@ -54,7 +54,7 @@
<p class="mtb15">
<span class="set-tit text-right">面板端口</span>
<input data-port="{{data['port']}}" id="banport" name="port" class="inputtxt bt-input-text" type="numner" value="{{data['port']}}" maxlength="5">
<input data-port="{{data['port']}}" id="banport" name="port" class="inputtxt bt-input-text" type="number" value="{{data['port']}}" maxlength="5">
<button type="button" class="btn btn-success btn-sm ml5 btn_port" disabled>保存</button>
<span class="set-info c7">建议端口范围7200 - 65535</span>
</p>
+40 -10
View File
@@ -99,15 +99,45 @@
<div class="col-xs-12 col-sm-12 col-md-6 pull-left pd0">
<div class="pl7">
<div class="bgw" style="height:491px">
<div class="title c6 f16 plr15">流量</div>
<div class="bw-info">
<div class="col-sm-6 col-md-3"><p class="c9"><span class="ico-up"></span>上行</p><a id="upSpeed">0</a></div>
<div class="col-sm-6 col-md-3"><p class="c9"><span class="ico-down"></span>下行</p><a id="downSpeed">0</a></div>
<div class="col-sm-6 col-md-3"><p class="c9">总发送</p><a id="upAll">0</a></div>
<div class="col-sm-6 col-md-3"><p class="c9">总接收</p><a id="downAll">0</a></div>
<div class="bgw radius4" style="height:491px">
<div class="title c6 f16 plr15 tabs-nav">
<div class="tab-list">
<span class="tabs-item active">流量</span>
<span class="tabs-item">磁盘IO</span>
</div>
<div class="tabs-down">
<select class="bt-input-text" name="network-io" style="font-size: 12px;">
<option value="ALL">全部</option>
</select>
<select class="bt-input-text hide" name="disk-io" style="font-size: 12px;">
<option value="ALL">全部</option>
</select>
</div>
</div>
<div id="netImg" style="width:100%;height:330px;"></div>
<div class="tabs-content">
<div class="tabs-active radius4 tabs-item">
<div class="bw-info">
<div class="col-sm-6 col-md-3"><p class="c9"><span class="ico-up"></span>上行</p><a id="upSpeed">0</a></div>
<div class="col-sm-6 col-md-3"><p class="c9"><span class="ico-down"></span>下行</p><a id="downSpeed">0</a></div>
<div class="col-sm-6 col-md-3"><p class="c9">总发送</p><a id="upAll">0</a></div>
<div class="col-sm-6 col-md-3"><p class="c9">总接收</p><a id="downAll">0</a></div>
</div>
<div id="netImg" style="width:100%;height:330px;"></div>
</div>
<div class="radius4 tabs-item">
<div class="bw-info">
<div class="col-sm-6 col-md-3"><p class="c9"><span class="ico-read"></span>读取</p><a id="readBytes">0</a></div>
<div class="col-sm-6 col-md-3"><p class="c9"><span class="ico-write"></span>写入</p><a id="writeBytes">0</a></div>
<div class="col-sm-6 col-md-3"><p class="c9">每秒读写</p><a id="diskIops">0</a></div>
<div class="col-sm-6 col-md-3"><p class="c9">读写IO延迟</p><a id="diskTime" style="color: rgb(32, 165, 58);">0</a></div>
</div>
<div id="ioStat" style="width:100%;height:330px;"></div>
</div>
</div>
</div>
</div>
</div>
@@ -119,8 +149,8 @@
<script type="text/javascript" src="/static/app/index.js?v={{config.version}}"></script>
<script type="text/javascript">
netImg();
setImg();
index.init();
pluginInit();
//加载关键数据总数
loadKeyDataCount();
+26 -9
View File
@@ -14,15 +14,6 @@
<!--[if lte IE 9]>
<script src="/static/js/requestAnimationFrame.js"></script>
<![endif]-->
<!-- 统计一下用户量,让我的开发更有激情 -->
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-FC74BB2RGD"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-FC74BB2RGD');
</script>
{% for menu in data['hook_menu'] %}
@@ -188,4 +179,30 @@ if (thisPath.indexOf('?')>-1){
{% endif %}
{% endfor %}
<!-- 统计一下用户量,让我的开发更有激情 -->
<script type="text/javascript">
$(document).ready(function(){
setTimeout(function(){
$.getScript('https://www.googletagmanager.com/gtag/js?id=G-FC74BB2RGD', function(){
console.log("load google ad!");
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-FC74BB2RGD');
});
},3000);
});
</script>
<!-- Google tag (gtag.js) -->
<!-- <script async src="https://www.googletagmanager.com/gtag/js?id=G-FC74BB2RGD"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-FC74BB2RGD');
</script> -->
</html>
+23 -4
View File
@@ -87,6 +87,18 @@ class backupTools:
path = mw.getServerDir() + '/' + mtype + '/etc/my.cnf'
return path
def recognizeDbMode(self, mtype='mysql'):
conf = self.getConf(mtype)
con = mw.readFile(conf)
rep = r"!include %s/(.*)?\.cnf" % (mw.getServerDir() +'/'+ mtype +"/etc/mode",)
mode = 'none'
try:
data = re.findall(rep, con, re.M)
mode = data[0]
except Exception as e:
pass
return mode
# 数据库密码处理
def mypass(self, act, root):
conf_file = self.getConf('mysql')
@@ -134,13 +146,20 @@ class backupTools:
# mw.execShell(db_path + "/bin/mysqldump --opt --default-character-set=utf8 " +
# name + " | gzip > " + filename)
# mw.execShell(db_path + "/bin/mysqldump --skip-lock-tables --default-character-set=utf8 " +
# name + " | gzip > " + filename)
# mw.execShell(db_path + "/bin/mysqldump --single-transaction --quick --default-character-set=utf8 " +
# name + " | gzip > " + filename)
cmd = db_path + "/bin/mysqldump --defaults-file=" + my_cnf + " --force --opt --default-character-set=utf8 " + \
# 开启一致性事务 会lock表
# cmd = db_path + "/bin/mysqldump --defaults-file=" + my_cnf + " --force --opt --default-character-set=utf8 " + \
# name + " | gzip > " + filename
option = ''
mode = self.recognizeDbMode('mysql')
if mode == 'gtid':
option = ' --set-gtid-purged=off '
# skip-opt 不会lock表
# --skip-opt --create-options
cmd = db_path + "/bin/mysqldump --defaults-file=" + my_cnf +" " + option +" --single-transaction -q --default-character-set=utf8mb4 " + \
name + " | gzip > " + filename
# print(cmd)
mw.execShell(cmd)
+56 -14
View File
@@ -209,6 +209,21 @@ mw_unbind_domain()
fi
}
mw_unbind_ssl()
{
if [ -f $mw_path/local ];then
rm -rf $mw_path/local
fi
if [ -f $mw_path/nginx ];then
rm -rf $mw_path/nginx
fi
if [ -f $mw_path/ssl/choose.pl ];then
rm -rf $mw_path/ssl/choose.pl
fi
}
error_logs()
{
tail -n 100 $mw_path/logs/error.log
@@ -258,7 +273,7 @@ mw_mirror()
else
bash <(curl --insecure -sSL https://gitee.com/SuperManito/LinuxMirrors/raw/main/ChangeMirrors.sh)
fi
cd /www/server/mdserver-web
cd ${ROOT_PATH}/mdserver-web
}
mw_install_app()
@@ -297,8 +312,8 @@ mw_debug(){
port=$(cat $mw_path/data/port.pl)
fi
if [ -d /www/server/mdserver-web ];then
cd /www/server/mdserver-web
if [ -d ${ROOT_PATH}/mdserver-web ];then
cd ${ROOT_PATH}/mdserver-web
fi
gunicorn -b :$port -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 app:app
}
@@ -373,7 +388,8 @@ mw_connect_mysql(){
INPUT_KEY=${SOURCE_LIST_KEY[$INPUT]}
CHOICE_DB=${DB_TYPE[$INPUT_KEY]}
echo "login to ${CHOICE_DB}:"
pwd=$(cd /www/server/mdserver-web && python3 /www/server/mdserver-web/plugins/${CHOICE_DB}/index.py root_pwd)
pwd=$(cd ${ROOT_PATH}/mdserver-web && python3 ${ROOT_PATH}/mdserver-web/plugins/${CHOICE_DB}/index.py root_pwd)
if [ "$CHOICE_DB" == "mysql" ];then
${ROOT_PATH}/mysql/bin/mysql -uroot -p"${pwd}"
fi
@@ -392,15 +408,34 @@ mw_connect_mysql(){
}
mw_redis(){
CONF="${ROOT_PATH}/redis/redis.conf"
if [ ! -f "$CONF" ]; then
echo -e "not install redis!"
exit 1
fi
REDISPORT=$(cat $CONF |grep port|grep -v '#'|awk '{print $2}')
REDISPASS=$(cat $CONF |grep requirepass|grep -v '#'|awk '{print $2}')
if [ "$REDISPASS" != "" ];then
REDISPASS=" -a $REDISPASS"
fi
CLIEXEC="${ROOT_PATH}/redis/bin/redis-cli -p $REDISPORT$REDISPASS"
echo $CLIEXEC
${CLIEXEC}
}
mw_venv(){
cd /www/server/mdserver-web && source bin/activate
cd ${ROOT_PATH}/mdserver-web && source bin/activate
}
mw_clean_lib(){
cd /www/server/mdserver-web && rm -rf lib
cd /www/server/mdserver-web && rm -rf lib64
cd /www/server/mdserver-web && rm -rf bin
cd /www/server/mdserver-web && rm -rf include
cd ${ROOT_PATH}/mdserver-web && rm -rf lib
cd ${ROOT_PATH}/mdserver-web && rm -rf lib64
cd ${ROOT_PATH}/mdserver-web && rm -rf bin
cd ${ROOT_PATH}/mdserver-web && rm -rf include
}
case "$1" in
@@ -425,14 +460,21 @@ case "$1" in
'install_app') mw_install_app;;
'close_admin_path') mw_close_admin_path;;
'unbind_domain') mw_unbind_domain;;
'unbind_ssl') mw_unbind_domain;;
'debug') mw_debug;;
'mirror') mw_mirror;;
'db') mw_connect_mysql;;
'redis') mw_redis;;
'venv') mw_venv;;
'clean_lib') mw_clean_lib;;
'default')
cd $mw_path
port=7200
scheme=http
if [ -f $mw_path/ssl/choose.pl ];then
scheme=https
fi
if [ -f $mw_path/data/port.pl ];then
port=$(cat $mw_path/data/port.pl)
@@ -463,9 +505,9 @@ case "$1" in
mw_start
fi
address="MW-Panel-Url-Ipv4: http://$v4:$port$auth_path \nMW-Panel-Url-Ipv6: http://[$v6]:$port$auth_path"
address="MW-Panel-Url-Ipv4: ${scheme}://$v4:$port$auth_path \nMW-Panel-Url-Ipv6: ${scheme}://[$v6]:$port$auth_path"
elif [ "$v4" != "" ]; then
address="MW-Panel-Url: http://$v4:$port$auth_path"
address="MW-Panel-Url: ${scheme}://$v4:$port$auth_path"
elif [ "$v6" != "" ]; then
if [ ! -f $mw_path/data/ipv6.pl ];then
@@ -474,12 +516,12 @@ case "$1" in
mw_stop
mw_start
fi
address="MW-Panel-Url: http://[$v6]:$port$auth_path"
address="MW-Panel-Url: ${scheme}://[$v6]:$port$auth_path"
else
address="MW-Panel-Url: http://you-network-ip:$port$auth_path"
address="MW-Panel-Url: ${scheme}://you-network-ip:$port$auth_path"
fi
else
address="MW-Panel-Url: http://$address:$port$auth_path"
address="MW-Panel-Url: ${scheme}://$address:$port$auth_path"
fi
show_panel_ip="$port|"
+2
View File
@@ -14,6 +14,7 @@ dnf install -y python3-devel
dnf install -y python-devel
dnf install -y crontabs
dnf install -y mysql-devel
dnf install -y pv
SSH_PORT=`netstat -ntpl|grep sshd|grep -v grep | sed -n "1,1p" | awk '{print $4}' | awk -F : '{print $2}'`
if [ "$SSH_PORT" == "" ];then
@@ -94,6 +95,7 @@ yum install -y bison re2c cmake
yum install -y cmake3
yum install -y autoconf
yum install -y expect
yum install -y bc
yum install -y curl curl-devel
yum install -y zlib zlib-devel
+2
View File
@@ -21,6 +21,8 @@ yum install -y python-devel
yum install -y curl-devel libmcrypt libmcrypt-devel
yum install -y mysql-devel
yum install -y expect
yum install -y pv
yum install -y bc
SSH_PORT=`netstat -ntpl|grep sshd|grep -v grep | sed -n "1,1p" | awk '{print $4}' | awk -F : '{print $2}'`
if [ "$SSH_PORT" == "" ];then
+3
View File
@@ -40,6 +40,9 @@ echo y | pacman -Sy rpcsvc-proto
echo y | pacman -Sy lemon
echo y | pacman -Sy which
echo y | pacman -Sy expect
echo y | pacman -Sy pv
echo y | pacman -Sy bc
## gd start
echo y | pacman -Sy gd
+2
View File
@@ -31,6 +31,8 @@ yum install -y libmcrypt
yum install -y libmcrypt-devel
yum install -y mysql-devel
yum install -y expect
yum install -y pv
yum install -y bc
# if [ -f /usr/sbin/iptables ];then
+2
View File
@@ -56,6 +56,8 @@ apt-get update -y
apt install -y wget curl lsof unzip tar cron expect locate lrzsz
apt install -y rar
apt install -y unrar
apt install -y pv
apt install -y bc
apt install -y python3-pip python3-dev python3-venv
+2
View File
@@ -31,6 +31,8 @@ yum install -y libmcrypt
yum install -y libmcrypt-devel
yum install -y mysql-devel
yum install -y expect
yum install -y pv
yum install -y bc
# if [ -f /usr/sbin/iptables ];then
+2
View File
@@ -73,6 +73,8 @@ yum install -y epel-release
yum install -y libevent libevent-devel zip libmcrypt libmcrypt-devel
yum install -y rar unrar
yum install -y pv
yum install -y bc
yum install -y gcc libffi-devel python-devel openssl-devel
yum install -y libmcrypt libmcrypt-devel python3-devel
+2
View File
@@ -60,6 +60,8 @@ pkg install -y harfbuzz
pkg install -y libevent
pkg install -y pidof
pkg install -y pstree
pkg install -y pv
pkg install -y bc
# curl https://sh.rustup.rs -sSf | sh
pkg install -y rust
+1 -1
View File
@@ -22,7 +22,7 @@ if [ "$?" != "0" ];then
brew install mysql
fi
brew install pv
brew install libzip bzip2 gcc openssl re2c cmake
brew install librdkafka
brew install coreutils libxml2 xml2

Some files were not shown because too many files have changed in this diff Show More