├── .gitignore ├── README.md ├── client ├── .DS_Store ├── app.js ├── app.json ├── app.wxss ├── pages │ ├── index │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ ├── map │ │ ├── map.js │ │ ├── map.json │ │ ├── map.wxml │ │ └── map.wxss │ └── result │ │ ├── result.js │ │ ├── result.json │ │ ├── result.wxml │ │ └── result.wxss ├── source │ └── icon.png └── utils │ └── util.js ├── restart_service.sh ├── server ├── .vscode │ ├── launch.json │ └── settings.json └── server.py ├── uwsgi_config.ini └── wsgi.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | 91 | #macos 92 | .DS_Store 93 | .vscode/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # net_tool_wechat_xiaochengxu 2 | 3 | ### Glance 4 | ![screenshot](http://i.imgur.com/rAqtJ2v.jpg) 5 | ### Dependency 6 | - CentOS 7.x 7 | - python3.x, flask 8 | - nginx, uwsgi, supervisord 9 | 10 | ### IP API 11 | - ip api : https://freegeoip.net/json/ 12 | 13 | ### install & configuration 14 | 1. supervisord file :/etc/supervisord.d/nettool.ini 15 | ``` 16 | [supervisord] 17 | [program:nettool] 18 | command=uwsgi uwsgi_config.ini 19 | directory=/home/www/source 20 | user=root 21 | 22 | autostart=true 23 | autorestart=true 24 | ``` 25 | 26 | `you may need to comment 'server' block in /etc/nginx/nginx.conf` 27 | 28 | 2. niginx configuration file : /etc/nginx/conf.d/nettool.conf 29 | ``` 30 | server { 31 | listen 80; 32 | server_name server_domain_or_IP; 33 | return 301 https://$server_name$request_uri; 34 | } 35 | server { 36 | listen 443 ssl; 37 | server_name server_domain_or_IP; 38 | ssl_certificate /etc/letsencrypt/live/example.com/cert.pem; 39 | ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; 40 | 41 | location / { 42 | include uwsgi_params; 43 | uwsgi_pass unix:/home/user/myproject/myproject.sock; 44 | } 45 | } 46 | 47 | ``` 48 | 3. run `sh restart_service.sh` 49 | -------------------------------------------------------------------------------- /client/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heemoe/net_tool_wechat_xiaochengxu/8538f79a9d13d8654ad02139b5cfeca786ca21f7/client/.DS_Store -------------------------------------------------------------------------------- /client/app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch: function () { 4 | } 5 | }) -------------------------------------------------------------------------------- /client/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages":[ 3 | "pages/index/index", 4 | "pages/result/result" 5 | ], 6 | "window":{ 7 | "backgroundTextStyle":"light", 8 | "navigationBarBackgroundColor": "#fff", 9 | "navigationBarTitleText": "NetTool", 10 | "navigationBarTextStyle":"black" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /client/app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | .view-center{ 3 | text-align: center; 4 | } -------------------------------------------------------------------------------- /client/pages/index/index.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | //获取应用实例 3 | var app = getApp() 4 | var input_value = "" 5 | const baseIpUrl = "https://freegeoip.net/json/" 6 | 7 | Page({ 8 | data: { 9 | focus : true, 10 | input_placeholder : "输入你要查询的URL~" 11 | }, 12 | endInputting: function(e){ 13 | console.log(e.detail.value) 14 | input_value = e.detail.value; 15 | }, 16 | pingBtnClick: function() { 17 | if (!checkInputValue()){ 18 | return 19 | } 20 | wx.navigateTo({ 21 | url: '../result/result?type=ping' + inputValueParameter() 22 | }) 23 | }, 24 | digBtnClick: function() { 25 | if (!checkInputValue()){ 26 | return 27 | } 28 | wx.navigateTo({ 29 | url: '../result/result?type=dig' + inputValueParameter() 30 | }) 31 | }, 32 | whoisBtnClick: function() { 33 | if (!checkInputValue()){ 34 | return 35 | } 36 | wx.navigateTo({ 37 | url: '../result/result?type=whois' + inputValueParameter() 38 | }) 39 | }, 40 | ipBtnClick: function() { 41 | if (!checkInputValue()){ 42 | return 43 | } 44 | wx.navigateTo({ 45 | url: '../result/result?type=ip' + inputValueParameter() 46 | }) 47 | }, 48 | ipv6BtnClick: function() { 49 | if (!checkInputValue()){ 50 | return 51 | } 52 | wx.request({ 53 | url: baseIpUrl + input_value, 54 | success: function(res) { 55 | console.log(res) 56 | if (res.statusCode != 200){ 57 | wx.showModal({ 58 | title: "请输入正确的URL或者IP地址!", 59 | showCancel: false, 60 | }) 61 | } 62 | var obj = res.data 63 | wx.openLocation({ 64 | latitude: obj.latitude, 65 | longitude: obj.longitude, 66 | scale: 14 67 | }) 68 | }, 69 | fail: function() { 70 | wx.showModal({ 71 | title: "请求失败!", 72 | showCancel: false 73 | }) 74 | } 75 | }) 76 | } 77 | }) 78 | function checkInputValue() { 79 | if (!input_value.includes(".")){ 80 | wx.showModal({ 81 | title: "请输入正确的URL或者IP地址!", 82 | showCancel: false 83 | }) 84 | return false 85 | } 86 | return true 87 | } 88 | 89 | function inputValueParameter(){ 90 | return "&value=" + input_value; 91 | } -------------------------------------------------------------------------------- /client/pages/index/index.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /client/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /client/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | /**index.wxss**/ 2 | .head_view{ 3 | text-align: center; 4 | } 5 | .head_img { 6 | width:50px; 7 | height:50px; 8 | } 9 | .kwd_view { 10 | margin-top:30px 11 | } 12 | .kwd_view_input { 13 | height:60px; 14 | border-bottom:solid; 15 | border-top:solid; 16 | border-color:#05ce0e; 17 | border-width:1px 18 | } 19 | .buttons { 20 | margin-top: 30px 21 | } 22 | .button { 23 | height: 44px; 24 | width: 70%; 25 | margin-bottom: 10px; 26 | } -------------------------------------------------------------------------------- /client/pages/map/map.js: -------------------------------------------------------------------------------- 1 | const baseIpUrl = "https://freegeoip.net/json/" 2 | Page({ 3 | data: { 4 | lon: "23.099994", 5 | lat: "113.324520" 6 | }, 7 | onLoad: function(options){ 8 | const that = this 9 | // console.log(options) 10 | wx.setNavigationBarTitle({ 11 | title: options.type 12 | }) 13 | wx.request({ 14 | url: baseIpUrl + options.value, 15 | success: function(res) { 16 | console.log(res) 17 | if (res.statusCode != 200){ 18 | wx.showModal({ 19 | title: "请输入正确的URL或者IP地址!", 20 | showCancel: false, 21 | success: function(res) { 22 | if (res.confirm){ 23 | wx.navigateBack() 24 | } 25 | } 26 | }) 27 | } 28 | var obj = res.data 29 | wx.openLocation({ 30 | latitude: obj.latitude, 31 | longitude: obj.longitude, 32 | scale: 28 33 | }) 34 | return 35 | that.setData({ 36 | lon: obj.longitude, 37 | lat: obj.latitude 38 | }) 39 | }, 40 | fail: function() { 41 | wx.showModal({ 42 | title: "请求失败!", 43 | showCancel: false, 44 | success: function(res) { 45 | if (res.confirm){ 46 | wx.navigateBack() 47 | } 48 | } 49 | }) 50 | } 51 | }) 52 | } 53 | }) 54 | 55 | -------------------------------------------------------------------------------- /client/pages/map/map.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /client/pages/map/map.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/pages/map/map.wxss: -------------------------------------------------------------------------------- 1 | .map { 2 | width: 100%; 3 | height: 736px; 4 | } -------------------------------------------------------------------------------- /client/pages/result/result.js: -------------------------------------------------------------------------------- 1 | const baseServerUrl = "https://DOMAIN/api/v1.0/nettool/" 2 | const baseIpUrl = "https://freegeoip.net/json/" 3 | Page({ 4 | data: { 5 | result: "..." 6 | }, 7 | onLoad: function(options){ 8 | const that = this 9 | // console.log(options) 10 | wx.setNavigationBarTitle({ 11 | title: options.type 12 | }) 13 | 14 | if (options.type == "ip"){ 15 | wx.request({ 16 | url: baseIpUrl + options.value, 17 | success: function(res) { 18 | console.log(res.data) 19 | if (!isSucucessCode(res.statusCode)){ 20 | return; 21 | } 22 | var obj = res.data 23 | that.setData({ 24 | result: "ip:" + obj.ip + "\n" + 25 | "country_code: " + obj.country_code + "\n" + 26 | "country_name: " + obj.country_name + "\n" + 27 | "region_code: " + obj.region_code + "\n" + 28 | "region_name: " + obj.region_name + "\n" + 29 | "city: " + obj.city + "\n" + 30 | "zip_code: " + obj.zip_code + "\n" + 31 | "time_zone: " + obj.time_zone + "\n" 32 | }) 33 | }, 34 | fail: function() { 35 | that.setData({ 36 | result: "数据获取失败..." 37 | }) 38 | } 39 | }) 40 | return 41 | } 42 | 43 | wx.request({ 44 | url: baseServerUrl + options.type + "/" + options.value, 45 | success: function(res) { 46 | console.log(res.data) 47 | if (!isSucucessCode(res.statusCode)){ 48 | return; 49 | } 50 | that.setData({ 51 | result: res.data 52 | }) 53 | }, 54 | fail: function() { 55 | that.setData({ 56 | result: "数据获取失败..." 57 | }) 58 | } 59 | }) 60 | } 61 | }) 62 | function isSucucessCode(code){ 63 | if (code != 200){ 64 | wx.showModal({ 65 | title: "请输入正确的URL或者IP地址!", 66 | showCancel: false, 67 | success: function(res) { 68 | if (res.confirm){ 69 | wx.navigateBack() 70 | } 71 | } 72 | }) 73 | return false 74 | } 75 | return true 76 | } 77 | 78 | -------------------------------------------------------------------------------- /client/pages/result/result.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /client/pages/result/result.wxml: -------------------------------------------------------------------------------- 1 | 2 | {{result}} 3 | -------------------------------------------------------------------------------- /client/pages/result/result.wxss: -------------------------------------------------------------------------------- 1 | .result_view { 2 | margin: 200px,200px,200px,200px 3 | } 4 | .result_content_label { 5 | margin-top: 60px; 6 | font-size: 14px; 7 | } -------------------------------------------------------------------------------- /client/source/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heemoe/net_tool_wechat_xiaochengxu/8538f79a9d13d8654ad02139b5cfeca786ca21f7/client/source/icon.png -------------------------------------------------------------------------------- /client/utils/util.js: -------------------------------------------------------------------------------- 1 | function formatTime(date) { 2 | var year = date.getFullYear() 3 | var month = date.getMonth() + 1 4 | var day = date.getDate() 5 | 6 | var hour = date.getHours() 7 | var minute = date.getMinutes() 8 | var second = date.getSeconds() 9 | 10 | 11 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') 12 | } 13 | 14 | function formatNumber(n) { 15 | n = n.toString() 16 | return n[1] ? n : '0' + n 17 | } 18 | 19 | module.exports = { 20 | formatTime: formatTime 21 | } 22 | -------------------------------------------------------------------------------- /restart_service.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sh 2 | killall supervisord 3 | supervisord -c /etc/supervisord.d/nettool.ini 4 | service nginx restart -------------------------------------------------------------------------------- /server/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Flask", 6 | "type": "python", 7 | "request": "launch", 8 | "stopOnEntry": false, 9 | "pythonPath":"${config:python.pythonPath}", 10 | "program": "${workspaceRoot}/wsgi.py", 11 | "cwd": "${workspaceRoot}", 12 | "args": [], 13 | "env": {}, 14 | "envFile": "${workspaceRoot}/.env", 15 | "debugOptions": [ 16 | "WaitOnAbnormalExit", 17 | "WaitOnNormalExit", 18 | "RedirectOutput" 19 | ] 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /server/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | } -------------------------------------------------------------------------------- /server/server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | from flask import Flask 3 | from flask import jsonify 4 | from flask import request 5 | from flask import abort 6 | import subprocess 7 | 8 | app = Flask(__name__) 9 | 10 | 11 | @app.route('/', methods=['GET']) 12 | def get_home(): 13 | return "

Hello World!

" 14 | 15 | 16 | @app.route('/api/v1.0/nettool//', methods=['GET']) 17 | def get_net_tool(type, keyword): 18 | # print(request.args.get('summary')) 19 | # print(request.args.get('charge')) 20 | print(type + keyword) 21 | if type == "dig" or type == "whois" or type == "ping" and keyword and "." in keyword: 22 | value = data_from_type(type, keyword) 23 | return value 24 | else: 25 | abort(400) 26 | return None 27 | 28 | 29 | def data_from_type(cmd, kwd): 30 | cmds = [cmd, kwd] 31 | if cmd == "ping": 32 | cmds = [cmd, "-c", "3", kwd] 33 | # value = subprocess.run(cmds, stdout=subprocess.PIPE).stdout 34 | print(cmds) 35 | proc = subprocess.Popen(cmds, stdout=subprocess.PIPE) 36 | value = '' 37 | for line in proc.stdout: 38 | value += line.decode() + '\n' 39 | print(value) 40 | return value 41 | -------------------------------------------------------------------------------- /uwsgi_config.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | module = wsgi 3 | callable = app 4 | master = true 5 | processes = 1 6 | chdir = /home/www/source/ 7 | 8 | socket = nettool.sock 9 | chmod-socket = 666 10 | vacuum = true 11 | 12 | die-on-term = true -------------------------------------------------------------------------------- /wsgi.py: -------------------------------------------------------------------------------- 1 | from server.server import app 2 | 3 | if __name__ == "__main__": 4 | app.run() 5 | --------------------------------------------------------------------------------