├── .editorconfig ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .travis.yml ├── Dockerfile ├── LICENSE ├── README.md ├── nginx.conf ├── package.json ├── public ├── index.html └── manifest.json ├── src ├── App.css ├── App.js ├── Footbar.js ├── Navbar.js ├── PingCard.js ├── base64.js ├── index.css ├── index.js ├── serverList.json └── utils.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | end_of_line = lf 3 | indent_size = 4 4 | indent_style = space 5 | insert_final_newline = true 6 | charset = utf-8 7 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "babel", 3 | "parserOptions": { 4 | "ecmaVersion": 7, 5 | "sourceType": "module" 6 | }, 7 | "plugins": [ 8 | "react" 9 | ], 10 | "ecmaFeatures": { 11 | "jsx": true 12 | }, 13 | "env": { 14 | "jest": true 15 | }, 16 | "rules": { 17 | "react/jsx-uses-vars": [ 2 ], 18 | "react/jsx-uses-react": [ 2 ], 19 | "quotes": [ 20 | "error", 21 | "single" 22 | ], 23 | "indent": [ 24 | "error", 25 | 4, 26 | { 27 | "SwitchCase": 1 28 | } 29 | ], 30 | "comma-dangle": [ 31 | "error", 32 | "always-multiline" 33 | ], 34 | "newline-after-var": "error", 35 | "semi": [ 36 | "error", 37 | "never" 38 | ], 39 | "eqeqeq": [ 40 | "error", 41 | "always" 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js -crlf 2 | *.json -crlf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | .idea/ 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | - "lts/*" 5 | 6 | install: 7 | - yarn 8 | 9 | script: 'true' 10 | 11 | cache: 12 | directories: 13 | - "node_modules" 14 | 15 | after_success: 16 | - yarn build 17 | - echo "torch.njs.app" > build/CNAME 18 | 19 | deploy: 20 | provider: pages 21 | skip_cleanup: true 22 | github_token: $GITHUB_TOKEN 23 | target_branch: gh-pages 24 | email: jiduye@gmail.com 25 | local-dir: build 26 | name: Travis Automatically Bot 27 | on: 28 | branch: master 29 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.8 as builder 2 | ADD . /app 3 | RUN apk --no-cache add nodejs yarn && \ 4 | cd /app && yarn && yarn build 5 | 6 | FROM alpine:3.8 7 | RUN apk --no-cache add ca-certificates nginx 8 | COPY --from=builder /app/build /app 9 | COPY nginx.conf /etc/nginx/nginx.conf 10 | 11 | EXPOSE 80 12 | WORKDIR /app 13 | 14 | CMD nginx -g "daemon off;" 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Indexyz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Torch-Web

2 | 3 | > Simple and useful tcping tools 4 | 5 |

6 | Version 7 | Author 8 | React 9 | node.js 10 | status 11 |

12 | 13 | 14 | ## Quick start 15 | ```bash 16 | # Install deps 17 | yarn 18 | 19 | # Run it 20 | yarn run start 21 | ``` 22 | 23 | ## Build 24 | 25 | * Replace `src/serverList.json` first if necessary 26 | 27 | ``` 28 | cd Torch-Web 29 | docker build torch-web . 30 | ``` 31 | 32 | ## License 33 | 34 | [MIT](https://github.com/Indexyz/Torch-Web/blob/master/LICENSE) 35 | -------------------------------------------------------------------------------- /nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes auto; 2 | pid /var/run/nginx.pid; 3 | 4 | events { 5 | worker_connections 4096; 6 | use epoll; 7 | } 8 | 9 | http { 10 | sendfile on; 11 | tcp_nopush on; 12 | tcp_nodelay on; 13 | access_log /dev/stderr; 14 | server_tokens off; 15 | keepalive_timeout 15; 16 | keepalive_requests 100; 17 | keepalive_disable msie6; 18 | include /etc/nginx/mime.types; 19 | default_type application/octet-stream; 20 | error_log /dev/stderr error; 21 | gzip on; 22 | gzip_comp_level 6; 23 | gzip_min_length 512; 24 | gzip_buffers 4 8k; 25 | gzip_proxied any; 26 | gzip_vary on; 27 | gzip_disable "msie6"; 28 | gzip_types 29 | text/css 30 | text/javascript 31 | text/xml 32 | text/plain 33 | text/x-component 34 | application/javascript 35 | application/x-javascript 36 | application/json 37 | application/xml 38 | application/rss+xml 39 | application/vnd.ms-fontobject 40 | font/truetype 41 | font/opentype 42 | image/svg+xml 43 | image/jpg 44 | image/png 45 | image/webp; 46 | 47 | server { 48 | listen 80; 49 | root /app; 50 | charset utf-8; 51 | index index.html; 52 | client_max_body_size 1000m; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "torch-web", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "antd": "3.19.2", 7 | "axios": "^0.19.0", 8 | "react": "^16.8.6", 9 | "react-dom": "^16.8.6", 10 | "react-flexbox-grid": "^2.1.2", 11 | "react-helmet": "^5.2.1", 12 | "react-scripts": "3.0.1", 13 | "uuid": "^3.3.2" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "eject": "react-scripts eject", 19 | "lint": "eslint src" 20 | }, 21 | "devDependencies": { 22 | "eslint": "^5.16.0", 23 | "eslint-config-babel": "^9.0.0", 24 | "eslint-plugin-flowtype": "^3.9.1", 25 | "eslint-plugin-react": "^7.13.0" 26 | }, 27 | "browserslist": { 28 | "production": [ 29 | ">0.2%", 30 | "not dead", 31 | "not op_mini all" 32 | ], 33 | "development": [ 34 | "last 1 chrome version", 35 | "last 1 firefox version", 36 | "last 1 safari version" 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Torch 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Torch", 3 | "name": "Simple and useful tcping tools", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | @import '~antd/dist/antd.css'; 2 | 3 | .siteContext { 4 | min-height: calc(100vh - 64px - 69px); 5 | } 6 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Navbar from './Navbar' 3 | import Footbar from './Footbar' 4 | import PingCard from './PingCard' 5 | import { Row, Col } from 'react-flexbox-grid' 6 | import { parseLink } from './utils' 7 | import { 8 | Layout, 9 | Input, 10 | Button, 11 | InputNumber, 12 | Modal, 13 | message } from 'antd' 14 | import uuid from 'uuid' 15 | import './App.css' 16 | import { Helmet } from 'react-helmet' 17 | 18 | const { TextArea } = Input 19 | 20 | class App extends Component { 21 | state = { 22 | hosts: [], 23 | input: { 24 | host: 'www.baidu.com', 25 | port: 443, 26 | }, 27 | text: '', 28 | displayModal: false, 29 | } 30 | 31 | addHost = (docs) => { 32 | this.setState(pre => { 33 | pre.hosts = [Object.assign({}, docs, { 34 | uuid: uuid.v4(), 35 | }), ...pre.hosts] 36 | return pre 37 | }) 38 | } 39 | 40 | updateHost(event) { 41 | const value = event.target.value 42 | 43 | this.setState(pre => { 44 | pre.input.host = value 45 | return pre 46 | }) 47 | } 48 | 49 | updateText(event) { 50 | const value = event.target.value 51 | 52 | this.setState(pre => { 53 | pre.text = value 54 | return pre 55 | }) 56 | } 57 | 58 | showModal = () => { 59 | this.setState({ 60 | displayModal: true, 61 | }) 62 | } 63 | 64 | reTest = () => { 65 | const action = async () => { 66 | const oldTests = this.state.hosts 67 | let counter = 0 68 | 69 | this.setState(state => { 70 | state.hosts = [] 71 | return state 72 | }) 73 | 74 | for (const item of oldTests.reverse()) { 75 | counter += 1 76 | item.uuid = null 77 | this.addHost(item) 78 | message.loading(`Processing ${counter} of ${oldTests.length}`, 0.9) 79 | await new Promise(resolve => setTimeout(resolve, 1000)) 80 | } 81 | } 82 | 83 | action().catch(err => { console.log(err) }) 84 | } 85 | 86 | handleCancel = () => { 87 | this.setState({ 88 | displayModal: false, 89 | }) 90 | } 91 | 92 | handleMultiAdd = () => { 93 | this.handleCancel() 94 | 95 | message.info('Processing links, please wait') 96 | 97 | const action = async () => { 98 | let counter = 0 99 | const lines = (await Promise.all(this.state.text.split('\n') 100 | .map(item => item.trim()) 101 | .map(parseLink))) 102 | .reduce((previous, current) => { 103 | console.log(current) 104 | if (current === null) { 105 | message.error('在解析部分链接时出现问题,请检查键入信息', 5) 106 | } 107 | if (Array.isArray(current)) { 108 | return [...current, ...previous] 109 | } 110 | return [current, ...previous] 111 | }, []) 112 | .filter(link => link !== null) 113 | 114 | for (const line of lines) { 115 | counter += 1 116 | this.addHost(line) 117 | message.loading(`Processing ${counter} of ${lines.length}`, 0.9) 118 | await new Promise(resolve => setTimeout(resolve, 1000)) 119 | } 120 | message.success('节点添加完毕!部分检测可能尚未完成,请耐心等待……', 3) 121 | } 122 | 123 | action() 124 | } 125 | 126 | updatePort(value) { 127 | this.setState(pre => { 128 | pre.input.port = value 129 | return pre 130 | }) 131 | } 132 | 133 | render() { 134 | window.dataLayer = window.dataLayer || [] 135 | function gtag(){ 136 | window.dataLayer.push(arguments) 137 | } 138 | gtag('js', new Date()) 139 | gtag('config', 'UA-97074604-2') 140 | 141 | return ( 142 |
143 | 144 |