mirror of
https://github.com/ehang-io/nps.git
synced 2025-07-04 22:00:43 +00:00
Compare commits
No commits in common. "master" and "v0.25.2" have entirely different histories.
163
.github/workflows/release.yml
vendored
163
.github/workflows/release.yml
vendored
@ -1,163 +0,0 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
|
||||
build_assets:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.15
|
||||
id: go
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
- name: Get dependencies
|
||||
run: |
|
||||
go get -v -t -d ./...
|
||||
if [ -f Gopkg.toml ]; then
|
||||
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
||||
dep ensure
|
||||
fi
|
||||
- name: Build
|
||||
run: |
|
||||
chmod +x build.assets.sh
|
||||
./build.assets.sh
|
||||
- name: Upload
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
files: |
|
||||
freebsd_386_client.tar.gz
|
||||
freebsd_386_server.tar.gz
|
||||
freebsd_amd64_client.tar.gz
|
||||
freebsd_amd64_server.tar.gz
|
||||
freebsd_arm_client.tar.gz
|
||||
freebsd_arm_server.tar.gz
|
||||
linux_386_client.tar.gz
|
||||
linux_386_server.tar.gz
|
||||
linux_amd64_client.tar.gz
|
||||
linux_amd64_server.tar.gz
|
||||
linux_arm64_client.tar.gz
|
||||
linux_arm64_server.tar.gz
|
||||
linux_arm_v5_client.tar.gz
|
||||
linux_arm_v6_client.tar.gz
|
||||
linux_arm_v7_client.tar.gz
|
||||
linux_arm_v5_server.tar.gz
|
||||
linux_arm_v6_server.tar.gz
|
||||
linux_arm_v7_server.tar.gz
|
||||
linux_mips64le_client.tar.gz
|
||||
linux_mips64le_server.tar.gz
|
||||
linux_mips64_client.tar.gz
|
||||
linux_mips64_server.tar.gz
|
||||
linux_mipsle_client.tar.gz
|
||||
linux_mipsle_server.tar.gz
|
||||
linux_mips_client.tar.gz
|
||||
linux_mips_server.tar.gz
|
||||
darwin_amd64_client.tar.gz
|
||||
darwin_amd64_server.tar.gz
|
||||
windows_386_client.tar.gz
|
||||
windows_386_server.tar.gz
|
||||
windows_amd64_client.tar.gz
|
||||
windows_amd64_server.tar.gz
|
||||
npc_sdk.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build_android:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: |
|
||||
chmod +x build.android.sh
|
||||
docker run --rm -i -w /app -v $(pwd):/app -e ANDROID_HOME=/usr/local/android_sdk -e GOPROXY=direct fyneio/fyne-cross:android-latest /app/build.android.sh
|
||||
- name: Upload
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
files: |
|
||||
android_client.apk
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build_spk:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
- name: Set env
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
- name: Build
|
||||
run: |
|
||||
git clone https://github.com/cnlh/spksrc.git ~/spksrc
|
||||
mkdir ~/spksrc/nps && cp -rf ./* ~/spksrc/nps/
|
||||
docker run -id --name spksrc --env VERSION=${{ env.RELEASE_VERSION }} -e GOPROXY=direct -v ~/spksrc:/spksrc synocommunity/spksrc /bin/bash
|
||||
docker exec spksrc /bin/bash -c 'cd /spksrc && make setup && cd /spksrc/spk/npc && make'
|
||||
cp ~/spksrc/packages/npc_noarch-all_${{ env.RELEASE_VERSION }}-1.spk ./npc_syno.spk
|
||||
- name: Upload
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
files: |
|
||||
npc_syno.spk
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build_docker:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
- name: Set env
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push nps
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.nps
|
||||
platforms: linux/amd64,linux/arm,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/nps:latest
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/nps:${{ env.RELEASE_VERSION }}
|
||||
- name: Build and push npc
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.npc
|
||||
platforms: linux/amd64,linux/arm,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/npc:latest
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/npc:${{ env.RELEASE_VERSION }}
|
11
.travis.yml
11
.travis.yml
@ -1,11 +1,12 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.14.x
|
||||
- "1.13"
|
||||
- master
|
||||
services:
|
||||
- docker
|
||||
script:
|
||||
- GOPROXY=direct go test -v ./cmd/nps/
|
||||
- go test -v ./cmd/nps/
|
||||
os:
|
||||
- linux
|
||||
before_deploy:
|
||||
@ -13,9 +14,9 @@ before_deploy:
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
edge: true
|
||||
token: ${GH_TOKEN}
|
||||
cleanup: false
|
||||
api_key:
|
||||
secure: ${TOKEN}
|
||||
skip_cleanup: true
|
||||
file:
|
||||
- freebsd_386_client.tar.gz
|
||||
- freebsd_386_server.tar.gz
|
||||
|
@ -1,11 +1,10 @@
|
||||
FROM golang:1.15 as builder
|
||||
ARG GOPROXY=direct
|
||||
WORKDIR /go/src/ehang.io/nps
|
||||
FROM golang as builder
|
||||
WORKDIR /go/src/github.com/cnlh/nps
|
||||
COPY . .
|
||||
RUN go get -d -v ./...
|
||||
RUN CGO_ENABLED=0 go build -ldflags="-w -s -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder /go/src/ehang.io/nps/npc /
|
||||
COPY --from=builder /go/src/github.com/cnlh/nps/npc /
|
||||
VOLUME /conf
|
||||
ENTRYPOINT ["/npc"]
|
||||
|
@ -1,12 +1,11 @@
|
||||
FROM golang:1.15 as builder
|
||||
ARG GOPROXY=direct
|
||||
WORKDIR /go/src/ehang.io/nps
|
||||
FROM golang as builder
|
||||
WORKDIR /go/src/github.com/cnlh/nps
|
||||
COPY . .
|
||||
RUN go get -d -v ./...
|
||||
RUN CGO_ENABLED=0 go build -ldflags="-w -s -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder /go/src/ehang.io/nps/nps /
|
||||
COPY --from=builder /go/src/ehang.io/nps/web /web
|
||||
COPY --from=builder /go/src/github.com/cnlh/nps/nps /
|
||||
COPY --from=builder /go/src/github.com/cnlh/nps/web /web
|
||||
VOLUME /conf
|
||||
CMD ["/nps"]
|
||||
|
100
README.md
100
README.md
@ -1,86 +1,66 @@
|
||||
|
||||
# NPS
|
||||
 
|
||||
# nps
|
||||
 
|
||||
[](https://gitter.im/cnlh-nps/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||

|
||||

|
||||
[](https://travis-ci.org/cnlh/nps)
|
||||
|
||||
[README](https://github.com/ehang-io/nps/blob/master/README.md)|[中文文档](https://github.com/ehang-io/nps/blob/master/README_zh.md)
|
||||
|
||||
NPS is a lightweight, high-performance, powerful **intranet penetration** proxy server, with a powerful web management terminal.
|
||||
nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务器。目前支持**tcp、udp流量转发**,可支持任何**tcp、udp**上层协议(访问内网网站、本地支付接口调试、ssh访问、远程桌面,内网dns解析等等……),此外还**支持内网http代理、内网socks5代理**、**p2p等**,并带有功能强大的web管理端。
|
||||
|
||||
|
||||

|
||||
## 背景
|
||||

|
||||
|
||||
## Feature
|
||||
1. 做微信公众号开发、小程序开发等----> 域名代理模式
|
||||
|
||||
- Comprehensive protocol support, compatible with almost all commonly used protocols, such as tcp, udp, http(s), socks5, p2p, http proxy ...
|
||||
- Full platform compatibility (linux, windows, macos, Synology, etc.), support installation as a system service simply.
|
||||
- Comprehensive control, both client and server control are allowed.
|
||||
- Https integration, support to convert backend proxy and web services to https, and support multiple certificates.
|
||||
- Just simple configuration on web ui can complete most requirements.
|
||||
- Complete information display, such as traffic, system information, real-time bandwidth, client version, etc.
|
||||
- Powerful extension functions, everything is available (cache, compression, encryption, traffic limit, bandwidth limit, port reuse, etc.)
|
||||
- Domain name resolution has functions such as custom headers, 404 page configuration, host modification, site protection, URL routing, and pan-resolution.
|
||||
- Multi-user and user registration support on server.
|
||||
2. 想在外网通过ssh连接内网的机器,做云服务器到内网服务器端口的映射,----> tcp代理模式
|
||||
|
||||
**Didn't find the feature you want? It doesn't matter, click [Enter the document](https://ehang-io.github.io/nps/) to find it!**
|
||||
3. 在非内网环境下使用内网dns,或者需要通过udp访问内网机器等----> udp代理模式
|
||||
|
||||
## Quick start
|
||||
4. 在外网使用HTTP代理访问内网站点----> http代理模式
|
||||
|
||||
### Installation
|
||||
5. 搭建一个内网穿透ss,在外网如同使用内网vpn一样访问内网资源或者设备----> socks5代理模式
|
||||
|
||||
> [releases](https://github.com/ehang-io/nps/releases)
|
||||
## 快速开始
|
||||
|
||||
Download the corresponding system version, the server and client are separate.
|
||||
### 安装
|
||||
> [releases](https://github.com/cnlh/nps/releases)
|
||||
|
||||
### Server start
|
||||
下载对应的系统版本即可,服务端和客户端是单独的
|
||||
|
||||
After downloading the server compressed package, unzip it, and then enter the unzipped folder.
|
||||
### 服务端启动
|
||||
下载完服务器压缩包后,解压,然后进入解压后的文件夹
|
||||
|
||||
- execute installation command
|
||||
- 执行安装命令
|
||||
|
||||
For linux、darwin ```sudo ./nps install```
|
||||
对于linux|darwin ```sudo ./nps install```
|
||||
|
||||
For windows, run cmd as administrator and enter the installation directory ```nps.exe install```
|
||||
对于windows,管理员身份运行cmd,进入安装目录 ```nps.exe install```
|
||||
|
||||
- default ports
|
||||
- 启动
|
||||
|
||||
The default configuration file of nps use 80,443,8080,8024 ports
|
||||
对于linux|darwin ```sudo nps start```
|
||||
|
||||
80 and 443 ports for host mode default ports
|
||||
对于windows,管理员身份运行cmd,进入程序目录 ```nps.exe start```
|
||||
|
||||
8080 for web management access port
|
||||
停止和重启可用,stop和restart
|
||||
|
||||
8024 for net bridge port, to communicate between server and client
|
||||
**如果发现没有启动成功,可以查看日志(Windows日志文件位于当前运行目录下,linux和darwin位于/var/log/nps.log)**
|
||||
- 访问服务端ip:web服务端口(默认为8080)
|
||||
- 使用用户名和密码登陆(默认admin/123,正式使用一定要更改)
|
||||
- 创建客户端
|
||||
|
||||
- start up
|
||||
### 客户端连接
|
||||
- 点击web管理中客户端前的+号,复制启动命令
|
||||
- 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用cmd执行
|
||||
|
||||
For linux、darwin ```sudo nps start```
|
||||
如果需要注册到系统服务可查看[注册到系统服务](https://cnlh.github.io/nps/#/use?id=注册到系统服务)
|
||||
|
||||
For windows, run cmd as administrator and enter the program directory ```nps.exe start```
|
||||
### 配置
|
||||
- 客户端连接后,在web中配置对应穿透服务即可
|
||||
- 更多高级用法见[完整文档](https://cnlh.github.io/nps/)
|
||||
|
||||
```After installation, the windows configuration file is located at C:\Program Files\nps, linux or darwin is located at /etc/nps```
|
||||
|
||||
**If you don't find it started successfully, you can check the log (Windows log files are located in the current running directory, linux and darwin are located in /var/log/nps.log).**
|
||||
|
||||
- Access server IP:web service port (default is 8080).
|
||||
- Login with username and password (default is admin/123, must be modified when officially used).
|
||||
- Create a client.
|
||||
|
||||
### Client connection
|
||||
- Click the + sign in front of the client in web management and copy the startup command.
|
||||
- Execute the startup command, Linux can be executed directly, Windows will replace ./npc with npc.exe and execute it with cmd.
|
||||
|
||||
|
||||
If you need to register to the system service, you can check [Register to the system service](https://ehang-io.github.io/nps/#/use?id=注册到系统服务)
|
||||
|
||||
### Configuration
|
||||
- After the client connects, configure the corresponding penetration service in the web.
|
||||
- For more advanced usage, see [Complete Documentation](https://ehang-io.github.io/nps/)
|
||||
|
||||
## Contribution
|
||||
- If you encounter a bug, you can submit it to the dev branch directly.
|
||||
- If you encounter a problem, you can feedback through the issue.
|
||||
- The project is under development, and there is still a lot of room for improvement. If you can contribute code, please submit PR to the dev branch.
|
||||
- If there is feedback on new features, you can feedback via issues or qq group.
|
||||
## 贡献
|
||||
- 如果遇到bug可以直接提交至dev分支
|
||||
- 使用遇到问题可以通过issues反馈
|
||||
- 项目处于开发阶段,还有很多待完善的地方,如果可以贡献代码,请提交 PR 至 dev 分支
|
||||
- 如果有新的功能特性反馈,可以通过issues或者qq群反馈
|
||||
|
90
README_zh.md
90
README_zh.md
@ -1,90 +0,0 @@
|
||||
|
||||
# nps
|
||||
 
|
||||
[](https://gitter.im/cnlh-nps/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||

|
||||

|
||||
|
||||
[README](https://github.com/ehang-io/nps/blob/master/README.md)|[中文文档](https://github.com/ehang-io/nps/blob/master/README_zh.md)
|
||||
|
||||
nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务器。目前支持**tcp、udp流量转发**,可支持任何**tcp、udp**上层协议(访问内网网站、本地支付接口调试、ssh访问、远程桌面,内网dns解析等等……),此外还**支持内网http代理、内网socks5代理**、**p2p等**,并带有功能强大的web管理端。
|
||||
|
||||
|
||||
## 背景
|
||||

|
||||
|
||||
1. 做微信公众号开发、小程序开发等----> 域名代理模式
|
||||
|
||||
2. 想在外网通过ssh连接内网的机器,做云服务器到内网服务器端口的映射,----> tcp代理模式
|
||||
|
||||
3. 在非内网环境下使用内网dns,或者需要通过udp访问内网机器等----> udp代理模式
|
||||
|
||||
4. 在外网使用HTTP代理访问内网站点----> http代理模式
|
||||
|
||||
5. 搭建一个内网穿透ss,在外网如同使用内网vpn一样访问内网资源或者设备----> socks5代理模式
|
||||
## 特点
|
||||
- 协议支持全面,兼容几乎所有常用协议,例如tcp、udp、http(s)、socks5、p2p、http代理...
|
||||
- 全平台兼容(linux、windows、macos、群辉等),支持一键安装为系统服务
|
||||
- 控制全面,同时支持服务端和客户端控制
|
||||
- https集成,支持将后端代理和web服务转成https,同时支持多证书
|
||||
- 操作简单,只需简单的配置即可在web ui上完成其余操作
|
||||
- 展示信息全面,流量、系统信息、即时带宽、客户端版本等
|
||||
- 扩展功能强大,该有的都有了(缓存、压缩、加密、流量限制、带宽限制、端口复用等等)
|
||||
- 域名解析具备自定义header、404页面配置、host修改、站点保护、URL路由、泛解析等功能
|
||||
- 服务端支持多用户和用户注册功能
|
||||
|
||||
**没找到你想要的功能?不要紧,点击[进入文档](https://ehang-io.github.io/nps)查找吧**
|
||||
## 快速开始
|
||||
|
||||
### 安装
|
||||
> [releases](https://github.com/ehang-io/nps/releases)
|
||||
|
||||
下载对应的系统版本即可,服务端和客户端是单独的
|
||||
|
||||
### 服务端启动
|
||||
下载完服务器压缩包后,解压,然后进入解压后的文件夹
|
||||
|
||||
- 执行安装命令
|
||||
|
||||
对于linux|darwin ```sudo ./nps install```
|
||||
|
||||
对于windows,管理员身份运行cmd,进入安装目录 ```nps.exe install```
|
||||
|
||||
- 默认端口
|
||||
|
||||
nps默认配置文件使用了80,443,8080,8024端口
|
||||
|
||||
80与443端口为域名解析模式默认端口
|
||||
|
||||
8080为web管理访问端口
|
||||
|
||||
8024为网桥端口,用于客户端与服务器通信
|
||||
|
||||
- 启动
|
||||
|
||||
对于linux|darwin ```sudo nps start```
|
||||
|
||||
对于windows,管理员身份运行cmd,进入程序目录 ```nps.exe start```
|
||||
|
||||
```安装后windows配置文件位于 C:\Program Files\nps,linux和darwin位于/etc/nps```
|
||||
|
||||
**如果发现没有启动成功,可以查看日志(Windows日志文件位于当前运行目录下,linux和darwin位于/var/log/nps.log)**
|
||||
- 访问服务端ip:web服务端口(默认为8080)
|
||||
- 使用用户名和密码登陆(默认admin/123,正式使用一定要更改)
|
||||
- 创建客户端
|
||||
|
||||
### 客户端连接
|
||||
- 点击web管理中客户端前的+号,复制启动命令
|
||||
- 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用cmd执行
|
||||
|
||||
如果需要注册到系统服务可查看[注册到系统服务](https://ehang-io.github.io/nps/#/use?id=注册到系统服务)
|
||||
|
||||
### 配置
|
||||
- 客户端连接后,在web中配置对应穿透服务即可
|
||||
- 更多高级用法见[完整文档](https://ehang-io.github.io/nps/)
|
||||
|
||||
## 贡献
|
||||
- 如果遇到bug可以直接提交至dev分支
|
||||
- 使用遇到问题可以通过issues反馈
|
||||
- 项目处于开发阶段,还有很多待完善的地方,如果可以贡献代码,请提交 PR 至 dev 分支
|
||||
- 如果有新的功能特性反馈,可以通过issues或者qq群反馈
|
@ -1,7 +1,6 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"ehang.io/nps-mux"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -12,26 +11,27 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/conn"
|
||||
"ehang.io/nps/lib/crypt"
|
||||
"ehang.io/nps/lib/file"
|
||||
"ehang.io/nps/lib/version"
|
||||
"ehang.io/nps/server/connection"
|
||||
"ehang.io/nps/server/tool"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/crypt"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/lib/mux"
|
||||
"github.com/cnlh/nps/lib/version"
|
||||
"github.com/cnlh/nps/server/connection"
|
||||
"github.com/cnlh/nps/server/tool"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
tunnel *nps_mux.Mux
|
||||
tunnel *mux.Mux
|
||||
signal *conn.Conn
|
||||
file *nps_mux.Mux
|
||||
file *mux.Mux
|
||||
Version string
|
||||
retryTime int // it will be add 1 when ping not ok until to 3 will close the client
|
||||
}
|
||||
|
||||
func NewClient(t, f *nps_mux.Mux, s *conn.Conn, vs string) *Client {
|
||||
func NewClient(t, f *mux.Mux, s *conn.Conn, vs string) *Client {
|
||||
return &Client{
|
||||
signal: s,
|
||||
tunnel: t,
|
||||
@ -41,30 +41,28 @@ func NewClient(t, f *nps_mux.Mux, s *conn.Conn, vs string) *Client {
|
||||
}
|
||||
|
||||
type Bridge struct {
|
||||
TunnelPort int //通信隧道端口
|
||||
Client sync.Map
|
||||
Register sync.Map
|
||||
tunnelType string //bridge type kcp or tcp
|
||||
OpenTask chan *file.Tunnel
|
||||
CloseTask chan *file.Tunnel
|
||||
CloseClient chan int
|
||||
SecretChan chan *conn.Secret
|
||||
ipVerify bool
|
||||
runList sync.Map //map[int]interface{}
|
||||
disconnectTime int
|
||||
TunnelPort int //通信隧道端口
|
||||
Client sync.Map
|
||||
Register sync.Map
|
||||
tunnelType string //bridge type kcp or tcp
|
||||
OpenTask chan *file.Tunnel
|
||||
CloseTask chan *file.Tunnel
|
||||
CloseClient chan int
|
||||
SecretChan chan *conn.Secret
|
||||
ipVerify bool
|
||||
runList map[int]interface{}
|
||||
}
|
||||
|
||||
func NewTunnel(tunnelPort int, tunnelType string, ipVerify bool, runList sync.Map, disconnectTime int) *Bridge {
|
||||
func NewTunnel(tunnelPort int, tunnelType string, ipVerify bool, runList map[int]interface{}) *Bridge {
|
||||
return &Bridge{
|
||||
TunnelPort: tunnelPort,
|
||||
tunnelType: tunnelType,
|
||||
OpenTask: make(chan *file.Tunnel),
|
||||
CloseTask: make(chan *file.Tunnel),
|
||||
CloseClient: make(chan int),
|
||||
SecretChan: make(chan *conn.Secret),
|
||||
ipVerify: ipVerify,
|
||||
runList: runList,
|
||||
disconnectTime: disconnectTime,
|
||||
TunnelPort: tunnelPort,
|
||||
tunnelType: tunnelType,
|
||||
OpenTask: make(chan *file.Tunnel),
|
||||
CloseTask: make(chan *file.Tunnel),
|
||||
CloseClient: make(chan int),
|
||||
SecretChan: make(chan *conn.Secret),
|
||||
ipVerify: ipVerify,
|
||||
runList: runList,
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,12 +231,6 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int, vs string) {
|
||||
c.Close()
|
||||
return
|
||||
}
|
||||
tcpConn, ok := c.Conn.(*net.TCPConn)
|
||||
if ok {
|
||||
// add tcp keep alive option for signal connection
|
||||
_ = tcpConn.SetKeepAlive(true)
|
||||
_ = tcpConn.SetKeepAlivePeriod(5 * time.Second)
|
||||
}
|
||||
//the vKey connect by another ,close the client of before
|
||||
if v, ok := s.Client.LoadOrStore(id, NewClient(nil, nil, c, vs)); ok {
|
||||
if v.(*Client).signal != nil {
|
||||
@ -250,7 +242,7 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int, vs string) {
|
||||
go s.GetHealthFromClient(id, c)
|
||||
logs.Info("clientId %d connection succeeded, address:%s ", id, c.Conn.RemoteAddr())
|
||||
case common.WORK_CHAN:
|
||||
muxConn := nps_mux.NewMux(c.Conn, s.tunnelType, s.disconnectTime)
|
||||
muxConn := mux.NewMux(c.Conn, s.tunnelType)
|
||||
if v, ok := s.Client.LoadOrStore(id, NewClient(muxConn, nil, nil, vs)); ok {
|
||||
v.(*Client).tunnel = muxConn
|
||||
}
|
||||
@ -271,7 +263,7 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int, vs string) {
|
||||
logs.Error("secret error, failed to match the key successfully")
|
||||
}
|
||||
case common.WORK_FILE:
|
||||
muxConn := nps_mux.NewMux(c.Conn, s.tunnelType, s.disconnectTime)
|
||||
muxConn := mux.NewMux(c.Conn, s.tunnelType)
|
||||
if v, ok := s.Client.LoadOrStore(id, NewClient(nil, muxConn, nil, vs)); ok {
|
||||
v.(*Client).file = muxConn
|
||||
}
|
||||
@ -329,7 +321,7 @@ func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (ta
|
||||
}
|
||||
}
|
||||
}
|
||||
var tunnel *nps_mux.Mux
|
||||
var tunnel *mux.Mux
|
||||
if t != nil && t.Mode == "file" {
|
||||
tunnel = v.(*Client).file
|
||||
} else {
|
||||
@ -415,8 +407,7 @@ loop:
|
||||
})
|
||||
file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
|
||||
v := value.(*file.Tunnel)
|
||||
//if _, ok := s.runList[v.Id]; ok && v.Client.Id == id {
|
||||
if _, ok := s.runList.Load(v.Id); ok && v.Client.Id == id {
|
||||
if _, ok := s.runList[v.Id]; ok && v.Client.Id == id {
|
||||
str += v.Remark + common.CONN_DATA_SEQ
|
||||
}
|
||||
return true
|
||||
|
33
build.android.sh
Executable file → Normal file
33
build.android.sh
Executable file → Normal file
@ -1,34 +1,17 @@
|
||||
#/bin/bash
|
||||
#sudo apt-get install libgl1-mesa-dev xorg-dev
|
||||
#go get github.com/ffdfgdfg/fyne-cross
|
||||
#fyne-cross --targets=linux/amd64,windows/amd64,darwin/amd64 gui/npc/npc.go
|
||||
|
||||
cd /go
|
||||
apt-get install libegl1-mesa-dev libgles2-mesa-dev libx11-dev xorg-dev -y
|
||||
go get -u fyne.io/fyne/v2/cmd/fyne fyne.io/fyne/v2
|
||||
#mkdir -p /go/src/fyne.io
|
||||
#cd src/fyne.io
|
||||
#git clone https://github.com/fyne-io/fyne.git
|
||||
#cd fyne
|
||||
#git checkout v1.2.0
|
||||
#go install -v ./cmd/fyne
|
||||
#fyne package -os android fyne.io/fyne/cmd/hello
|
||||
echo "fyne install success"
|
||||
mkdir -p /go/src/ehang.io/nps
|
||||
cp -R /app/* /go/src/ehang.io/nps
|
||||
cd /go/src/ehang.io/nps
|
||||
#go get -u fyne.io/fyne fyne.io/fyne/cmd/fyne
|
||||
rm cmd/npc/sdk.go
|
||||
#go get -u ./...
|
||||
#go mod tidy
|
||||
#rm -rf /go/src/golang.org/x/mobile
|
||||
echo "tidy success"
|
||||
cd /go/src/ehang.io/nps
|
||||
mkdir -p /go/src/github.com/cnlh/nps
|
||||
cp -R * /go/src/github.com/cnlh/nps
|
||||
cd /go/src/github.com/cnlh/nps
|
||||
go get -u fyne.io/fyne fyne.io/fyne/cmd/fyne
|
||||
go mod vendor
|
||||
cd vendor
|
||||
cp -R * /go/src
|
||||
cd ..
|
||||
rm -rf vendor
|
||||
#rm -rf ~/.cache/*
|
||||
echo "vendor success"
|
||||
cd gui/npc
|
||||
fyne package -appID org.nps.client -os android -icon ../../docs/logo.png
|
||||
fyne package -os android -appID org.nps.client -icon ../../docs/logo.png
|
||||
mv npc.apk /app/android_client.apk
|
||||
echo "android build success"
|
||||
|
156
build.assets.sh
156
build.assets.sh
@ -1,156 +0,0 @@
|
||||
export GOPROXY=direct
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-mingw-w64-i686 gcc-multilib
|
||||
env GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.dll cmd/npc/sdk.go
|
||||
env GOOS=linux GOARCH=386 CGO_ENABLED=1 CC=gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.so cmd/npc/sdk.go
|
||||
tar -czvf npc_sdk.tar.gz npc_sdk.dll npc_sdk.so npc_sdk.h
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_386_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf freebsd_386_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf freebsd_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf freebsd_arm_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_arm_v7_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_arm_v6_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_arm_v5_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_arm64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_mips64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_mips64le_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_mipsle_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_mips_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf windows_386_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf windows_amd64_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf darwin_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_arm_v5_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_arm_v6_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_arm_v7_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_arm64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf freebsd_arm_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf freebsd_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf freebsd_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_mips_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_mips64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_mips64le_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_mipsle_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf darwin_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf windows_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf windows_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
|
75
build.sh
75
build.sh
@ -1,150 +1,161 @@
|
||||
#/bash/sh
|
||||
export VERSION=0.26.10
|
||||
export GOPROXY=direct
|
||||
export VERSION=0.25.2
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-mingw-w64-i686 gcc-multilib
|
||||
sudo apt-get install gcc-mingw-w64-i686
|
||||
env GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.dll cmd/npc/sdk.go
|
||||
env GOOS=linux GOARCH=386 CGO_ENABLED=1 CC=gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.so cmd/npc/sdk.go
|
||||
tar -czvf npc_sdk.tar.gz npc_sdk.dll npc_sdk.so npc_sdk.h
|
||||
tar -czvf npc_sdk.tar.gz npc_sdk.dll npc_sdk.h
|
||||
|
||||
wget https://github.com/upx/upx/releases/download/v3.95/upx-3.95-amd64_linux.tar.xz
|
||||
tar -xvf upx-3.95-amd64_linux.tar.xz
|
||||
cp upx-3.95-amd64_linux/upx ./
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_386_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf freebsd_386_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf freebsd_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf freebsd_arm_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_arm_v7_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_arm_v6_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_arm_v5_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_arm64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_mips64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_mips64le_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_mipsle_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf linux_mips_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf windows_386_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf windows_amd64_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
|
||||
tar -czvf darwin_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
|
||||
tar -czvf darwin_arm64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_arm_v5_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_arm_v6_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_arm_v7_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_arm64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf freebsd_arm_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf freebsd_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf freebsd_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_mips_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_mips64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_mips64le_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf linux_mipsle_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf darwin_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
tar -czvf darwin_arm64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf windows_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
|
||||
|
||||
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
|
||||
|
||||
tar -czvf windows_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key conf/server.pem web/views web/static nps.exe
|
||||
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
||||
@ -152,17 +163,17 @@ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubun
|
||||
sudo apt-get update
|
||||
sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||
docker --version
|
||||
docker run --rm -i -w /app -v $(pwd):/app -e ANDROID_HOME=/usr/local/android_sdk -e GOPROXY=direct lucor/fyne-cross:android-latest /app/build.android.sh
|
||||
docker run --rm -i -w /app -v $(pwd):/app -e ANDROID_HOME=/usr/local/android_sdk ffdfgdfg/fyne-cross:android /app/build.android.sh
|
||||
git clone https://github.com/cnlh/spksrc.git ~/spksrc
|
||||
mkdir ~/spksrc/nps && cp -rf ./* ~/spksrc/nps/
|
||||
docker run -itd --name spksrc --env VERSION=$VERSION -e GOPROXY=direct -v ~/spksrc:/spksrc synocommunity/spksrc /bin/bash
|
||||
docker exec -it spksrc /bin/bash -c 'cd /spksrc && make setup && cd /spksrc/spk/npc && make arch-x64-7.0'
|
||||
cp ~/spksrc/packages/npc_x64-7.0_$VERSION-1.spk ./npc_syno.spk
|
||||
docker run -itd --name spksrc --env VERSION=$VERSION -v ~/spksrc:/spksrc synocommunity/spksrc /bin/bash
|
||||
docker exec -it spksrc /bin/bash -c 'cd /spksrc && make setup && cd /spksrc/spk/npc && make'
|
||||
cp ~/spksrc/packages/npc_noarch-all_$VERSION-1.spk ./npc_syno.spk
|
||||
|
||||
|
||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d
|
||||
docker buildx create --use --name mybuilder
|
||||
docker buildx build --tag ffdfgdfg/nps:$VERSION --tag ffdfgdfg/nps:latest --output type=image,push=true --file Dockerfile.nps --platform=linux/amd64,linux/arm64,linux/386,linux/arm .
|
||||
docker buildx build --tag ffdfgdfg/npc:$VERSION --tag ffdfgdfg/npc:latest --output type=image,push=true --file Dockerfile.npc --platform=linux/amd64,linux/arm64,linux/386,linux/arm .
|
||||
docker buildx build --tag ffdfgdfg/nps:$VERSION --output type=image,push=true --file Dockerfile.nps --platform=linux/amd64,linux/arm64,linux/386,linux/arm .
|
||||
docker buildx build --tag ffdfgdfg/npc:$VERSION --output type=image,push=true --file Dockerfile.npc --platform=linux/amd64,linux/arm64,linux/386,linux/arm .
|
||||
|
@ -3,20 +3,19 @@ package client
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"ehang.io/nps-mux"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/xtaci/kcp-go"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/config"
|
||||
"ehang.io/nps/lib/conn"
|
||||
"ehang.io/nps/lib/crypt"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/config"
|
||||
"github.com/cnlh/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/crypt"
|
||||
"github.com/cnlh/nps/lib/mux"
|
||||
)
|
||||
|
||||
type TRPClient struct {
|
||||
@ -25,16 +24,14 @@ type TRPClient struct {
|
||||
proxyUrl string
|
||||
vKey string
|
||||
p2pAddr map[string]string
|
||||
tunnel *nps_mux.Mux
|
||||
tunnel *mux.Mux
|
||||
signal *conn.Conn
|
||||
ticker *time.Ticker
|
||||
cnf *config.Config
|
||||
disconnectTime int
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
//new client
|
||||
func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl string, cnf *config.Config, disconnectTime int) *TRPClient {
|
||||
func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl string, cnf *config.Config) *TRPClient {
|
||||
return &TRPClient{
|
||||
svrAddr: svraddr,
|
||||
p2pAddr: make(map[string]string, 0),
|
||||
@ -42,14 +39,11 @@ func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl st
|
||||
bridgeConnType: bridgeConnType,
|
||||
proxyUrl: proxyUrl,
|
||||
cnf: cnf,
|
||||
disconnectTime: disconnectTime,
|
||||
once: sync.Once{},
|
||||
}
|
||||
}
|
||||
|
||||
var NowStatus int
|
||||
var CloseClient bool
|
||||
|
||||
//start
|
||||
func (s *TRPClient) Start() {
|
||||
CloseClient = false
|
||||
@ -143,7 +137,7 @@ func (s *TRPClient) newUdpConn(localAddr, rAddr string, md5Password string) {
|
||||
conn.SetUdpSession(udpTunnel)
|
||||
logs.Trace("successful connection with client ,address %s", udpTunnel.RemoteAddr().String())
|
||||
//read link info from remote
|
||||
conn.Accept(nps_mux.NewMux(udpTunnel, s.bridgeConnType, s.disconnectTime), func(c net.Conn) {
|
||||
conn.Accept(mux.NewMux(udpTunnel, s.bridgeConnType), func(c net.Conn) {
|
||||
go s.handleChan(c)
|
||||
})
|
||||
break
|
||||
@ -151,14 +145,14 @@ func (s *TRPClient) newUdpConn(localAddr, rAddr string, md5Password string) {
|
||||
}
|
||||
}
|
||||
|
||||
//pmux tunnel
|
||||
//mux tunnel
|
||||
func (s *TRPClient) newChan() {
|
||||
tunnel, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_CHAN, s.proxyUrl)
|
||||
if err != nil {
|
||||
logs.Error("connect to ", s.svrAddr, "error:", err)
|
||||
return
|
||||
}
|
||||
s.tunnel = nps_mux.NewMux(tunnel.Conn, s.bridgeConnType, s.disconnectTime)
|
||||
s.tunnel = mux.NewMux(tunnel.Conn, s.bridgeConnType)
|
||||
for {
|
||||
src, err := s.tunnel.Accept()
|
||||
if err != nil {
|
||||
@ -221,12 +215,12 @@ func (s *TRPClient) handleChan(src net.Conn) {
|
||||
func (s *TRPClient) handleUdp(serverConn net.Conn) {
|
||||
// bind a local udp port
|
||||
local, err := net.ListenUDP("udp", nil)
|
||||
defer local.Close()
|
||||
defer serverConn.Close()
|
||||
if err != nil {
|
||||
logs.Error("bind local udp port error ", err.Error())
|
||||
return
|
||||
}
|
||||
defer local.Close()
|
||||
go func() {
|
||||
defer serverConn.Close()
|
||||
b := common.BufPoolUdp.Get().([]byte)
|
||||
@ -293,17 +287,13 @@ loop:
|
||||
}
|
||||
|
||||
func (s *TRPClient) Close() {
|
||||
s.once.Do(s.closing)
|
||||
}
|
||||
|
||||
func (s *TRPClient) closing() {
|
||||
CloseClient = true
|
||||
NowStatus = 0
|
||||
if s.tunnel != nil {
|
||||
_ = s.tunnel.Close()
|
||||
s.tunnel.Close()
|
||||
}
|
||||
if s.signal != nil {
|
||||
_ = s.signal.Close()
|
||||
s.signal.Close()
|
||||
}
|
||||
if s.ticker != nil {
|
||||
s.ticker.Stop()
|
||||
|
@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
@ -12,6 +11,7 @@ import (
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -19,12 +19,12 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/config"
|
||||
"ehang.io/nps/lib/conn"
|
||||
"ehang.io/nps/lib/crypt"
|
||||
"ehang.io/nps/lib/version"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/config"
|
||||
"github.com/cnlh/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/crypt"
|
||||
"github.com/cnlh/nps/lib/version"
|
||||
"github.com/xtaci/kcp-go"
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
@ -175,7 +175,7 @@ re:
|
||||
} else {
|
||||
logs.Notice("web access login username:%s password:%s", cnf.CommonConfig.Client.WebUserName, cnf.CommonConfig.Client.WebPassword)
|
||||
}
|
||||
NewRPClient(cnf.CommonConfig.Server, vkey, cnf.CommonConfig.Tp, cnf.CommonConfig.ProxyUrl, cnf, cnf.CommonConfig.DisconnectTime).Start()
|
||||
NewRPClient(cnf.CommonConfig.Server, vkey, cnf.CommonConfig.Tp, cnf.CommonConfig.ProxyUrl, cnf).Start()
|
||||
CloseLocalServer()
|
||||
goto re
|
||||
}
|
||||
@ -253,28 +253,30 @@ func NewConn(tp string, vkey string, server string, connType string, proxyUrl st
|
||||
|
||||
//http proxy connection
|
||||
func NewHttpProxyConn(url *url.URL, remoteAddr string) (net.Conn, error) {
|
||||
req, err := http.NewRequest("CONNECT", "http://"+remoteAddr, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
req := &http.Request{
|
||||
Method: "CONNECT",
|
||||
URL: url,
|
||||
Host: remoteAddr,
|
||||
Header: http.Header{},
|
||||
Proto: "HTTP/1.1",
|
||||
}
|
||||
password, _ := url.User.Password()
|
||||
req.Header.Set("Authorization", "Basic "+basicAuth(strings.Trim(url.User.Username(), " "), password))
|
||||
// we make a http proxy request
|
||||
b, err := httputil.DumpRequest(req, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
proxyConn, err := net.Dial("tcp", url.Host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := req.Write(proxyConn); err != nil {
|
||||
if _, err := proxyConn.Write(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := http.ReadResponse(bufio.NewReader(proxyConn), req)
|
||||
if err != nil {
|
||||
buf := make([]byte, 1024)
|
||||
if _, err := proxyConn.Read(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = res.Body.Close()
|
||||
if res.StatusCode != 200 {
|
||||
return nil, errors.New("Proxy error " + res.Status)
|
||||
}
|
||||
return proxyConn, nil
|
||||
}
|
||||
|
||||
|
@ -7,10 +7,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"ehang.io/nps/lib/conn"
|
||||
"ehang.io/nps/lib/file"
|
||||
"ehang.io/nps/lib/sheap"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/lib/sheap"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"ehang.io/nps-mux"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
@ -9,20 +8,21 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/config"
|
||||
"ehang.io/nps/lib/conn"
|
||||
"ehang.io/nps/lib/crypt"
|
||||
"ehang.io/nps/lib/file"
|
||||
"ehang.io/nps/server/proxy"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/config"
|
||||
"github.com/cnlh/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/crypt"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/lib/mux"
|
||||
"github.com/cnlh/nps/server/proxy"
|
||||
"github.com/xtaci/kcp-go"
|
||||
)
|
||||
|
||||
var (
|
||||
LocalServer []*net.TCPListener
|
||||
udpConn net.Conn
|
||||
muxSession *nps_mux.Mux
|
||||
muxSession *mux.Mux
|
||||
fileServer []*http.Server
|
||||
p2pNetBridge *p2pBridge
|
||||
lock sync.RWMutex
|
||||
@ -73,7 +73,7 @@ func startLocalFileServer(config *config.CommonConfig, t *file.Tunnel, vkey stri
|
||||
}
|
||||
logs.Info("start local file system, local path %s, strip prefix %s ,remote port %s ", t.LocalPath, t.StripPre, t.Ports)
|
||||
fileServer = append(fileServer, srv)
|
||||
listener := nps_mux.NewMux(remoteConn.Conn, common.CONN_TCP, config.DisconnectTime)
|
||||
listener := mux.NewMux(remoteConn.Conn, common.CONN_TCP)
|
||||
logs.Error(srv.Serve(listener))
|
||||
}
|
||||
|
||||
@ -214,6 +214,6 @@ func newUdpConn(localAddr string, config *config.CommonConfig, l *config.LocalSe
|
||||
logs.Trace("successful create a connection with server", remoteAddress)
|
||||
conn.SetUdpSession(udpTunnel)
|
||||
udpConn = udpTunnel
|
||||
muxSession = nps_mux.NewMux(udpConn, "kcp", config.DisconnectTime)
|
||||
muxSession = mux.NewMux(udpConn, "kcp")
|
||||
p2pNetBridge = &p2pBridge{}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
)
|
||||
|
||||
func RegisterLocalIp(server string, vKey string, tp string, proxyUrl string, hour int) {
|
||||
|
129
cmd/npc/npc.go
129
cmd/npc/npc.go
@ -1,44 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"ehang.io/nps/client"
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/config"
|
||||
"ehang.io/nps/lib/file"
|
||||
"ehang.io/nps/lib/install"
|
||||
"ehang.io/nps/lib/version"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/ccding/go-stun/stun"
|
||||
"github.com/cnlh/nps/client"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/config"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/lib/install"
|
||||
"github.com/cnlh/nps/lib/version"
|
||||
"github.com/kardianos/service"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
serverAddr = flag.String("server", "", "Server addr (ip:port)")
|
||||
configPath = flag.String("config", "", "Configuration file path")
|
||||
verifyKey = flag.String("vkey", "", "Authentication key")
|
||||
logType = flag.String("log", "stdout", "Log output mode(stdout|file)")
|
||||
connType = flag.String("type", "tcp", "Connection type with the server(kcp|tcp)")
|
||||
proxyUrl = flag.String("proxy", "", "proxy socks5 url(eg:socks5://111:222@127.0.0.1:9007)")
|
||||
logLevel = flag.String("log_level", "7", "log level 0~7")
|
||||
registerTime = flag.Int("time", 2, "register time long /h")
|
||||
localPort = flag.Int("local_port", 2000, "p2p local port")
|
||||
password = flag.String("password", "", "p2p password flag")
|
||||
target = flag.String("target", "", "p2p target")
|
||||
localType = flag.String("local_type", "p2p", "p2p target")
|
||||
logPath = flag.String("log_path", "", "npc log path")
|
||||
debug = flag.Bool("debug", true, "npc debug")
|
||||
pprofAddr = flag.String("pprof", "", "PProf debug addr (ip:port)")
|
||||
stunAddr = flag.String("stun_addr", "stun.stunprotocol.org:3478", "stun server address (eg:stun.stunprotocol.org:3478)")
|
||||
ver = flag.Bool("version", false, "show current version")
|
||||
disconnectTime = flag.Int("disconnect_timeout", 60, "not receiving check packet times, until timeout will disconnect the client")
|
||||
serverAddr = flag.String("server", "", "Server addr (ip:port)")
|
||||
configPath = flag.String("config", "", "Configuration file path")
|
||||
verifyKey = flag.String("vkey", "", "Authentication key")
|
||||
logType = flag.String("log", "stdout", "Log output mode(stdout|file)")
|
||||
connType = flag.String("type", "tcp", "Connection type with the server(kcp|tcp)")
|
||||
proxyUrl = flag.String("proxy", "", "proxy socks5 url(eg:socks5://111:222@127.0.0.1:9007)")
|
||||
logLevel = flag.String("log_level", "7", "log level 0~7")
|
||||
registerTime = flag.Int("time", 2, "register time long /h")
|
||||
localPort = flag.Int("local_port", 2000, "p2p local port")
|
||||
password = flag.String("password", "", "p2p password flag")
|
||||
target = flag.String("target", "", "p2p target")
|
||||
localType = flag.String("local_type", "p2p", "p2p target")
|
||||
logPath = flag.String("log_path", "", "npc log path")
|
||||
debug = flag.Bool("debug", true, "npc debug")
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -46,10 +40,6 @@ func main() {
|
||||
logs.Reset()
|
||||
logs.EnableFuncCallDepth(true)
|
||||
logs.SetLogFuncCallDepth(3)
|
||||
if *ver {
|
||||
common.PrintVersion()
|
||||
return
|
||||
}
|
||||
if *logPath == "" {
|
||||
*logPath = common.GetNpcLogPath()
|
||||
}
|
||||
@ -64,6 +54,8 @@ func main() {
|
||||
|
||||
// init service
|
||||
options := make(service.KeyValue)
|
||||
options["Restart"] = "on-success"
|
||||
options["SuccessExitStatus"] = "1 2 8 SIGKILL"
|
||||
svcConfig := &service.Config{
|
||||
Name: "Npc",
|
||||
DisplayName: "nps内网穿透客户端",
|
||||
@ -74,8 +66,6 @@ func main() {
|
||||
svcConfig.Dependencies = []string{
|
||||
"Requires=network.target",
|
||||
"After=network-online.target syslog.target"}
|
||||
svcConfig.Option["SystemdScript"] = install.SystemdScript
|
||||
svcConfig.Option["SysvScript"] = install.SysvScript
|
||||
}
|
||||
for _, v := range os.Args[1:] {
|
||||
switch v {
|
||||
@ -92,12 +82,7 @@ func main() {
|
||||
}
|
||||
s, err := service.New(prg, svcConfig)
|
||||
if err != nil {
|
||||
logs.Error(err, "service function disabled")
|
||||
run()
|
||||
// run without service
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
wg.Wait()
|
||||
logs.Error(err)
|
||||
return
|
||||
}
|
||||
if len(os.Args) >= 2 {
|
||||
@ -114,55 +99,20 @@ func main() {
|
||||
install.UpdateNpc()
|
||||
return
|
||||
case "nat":
|
||||
c := stun.NewClient()
|
||||
c.SetServerAddr(*stunAddr)
|
||||
nat, host, err := c.Discover()
|
||||
nat, host, err := stun.NewClient().Discover()
|
||||
if err != nil || host == nil {
|
||||
logs.Error("get nat type error", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("nat type: %s \npublic address: %s\n", nat.String(), host.String())
|
||||
os.Exit(0)
|
||||
case "start", "stop", "restart":
|
||||
// support busyBox and sysV, for openWrt
|
||||
if service.Platform() == "unix-systemv" {
|
||||
logs.Info("unix-systemv service")
|
||||
cmd := exec.Command("/etc/init.d/"+svcConfig.Name, os.Args[1])
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
}
|
||||
return
|
||||
case "install", "start", "stop", "uninstall", "restart":
|
||||
if os.Args[1] == "install" {
|
||||
install.InstallNpc()
|
||||
}
|
||||
err := service.Control(s, os.Args[1])
|
||||
if err != nil {
|
||||
logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
|
||||
}
|
||||
return
|
||||
case "install":
|
||||
service.Control(s, "stop")
|
||||
service.Control(s, "uninstall")
|
||||
install.InstallNpc()
|
||||
err := service.Control(s, os.Args[1])
|
||||
if err != nil {
|
||||
logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
|
||||
}
|
||||
if service.Platform() == "unix-systemv" {
|
||||
logs.Info("unix-systemv service")
|
||||
confPath := "/etc/init.d/" + svcConfig.Name
|
||||
os.Symlink(confPath, "/etc/rc.d/S90"+svcConfig.Name)
|
||||
os.Symlink(confPath, "/etc/rc.d/K02"+svcConfig.Name)
|
||||
}
|
||||
return
|
||||
case "uninstall":
|
||||
err := service.Control(s, os.Args[1])
|
||||
if err != nil {
|
||||
logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
|
||||
}
|
||||
if service.Platform() == "unix-systemv" {
|
||||
logs.Info("unix-systemv service")
|
||||
os.Remove("/etc/rc.d/S90" + svcConfig.Name)
|
||||
os.Remove("/etc/rc.d/K02" + svcConfig.Name)
|
||||
logs.Error("Valid actions: %q\n", service.ControlAction, err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -195,16 +145,6 @@ func (p *npc) run() error {
|
||||
logs.Warning("npc: panic serving %v: %v\n%s", err, string(buf))
|
||||
}
|
||||
}()
|
||||
run()
|
||||
select {
|
||||
case <-p.exit:
|
||||
logs.Warning("stop...")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func run() {
|
||||
common.InitPProfFromArg(*pprofAddr)
|
||||
//p2p or secret command
|
||||
if *password != "" {
|
||||
commonConfig := new(config.CommonConfig)
|
||||
@ -219,7 +159,7 @@ func run() {
|
||||
commonConfig.Client = new(file.Client)
|
||||
commonConfig.Client.Cnf = new(file.Config)
|
||||
go client.StartLocalServer(localServer, commonConfig)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
env := common.GetEnvMap()
|
||||
if *serverAddr == "" {
|
||||
@ -232,15 +172,20 @@ func run() {
|
||||
if *verifyKey != "" && *serverAddr != "" && *configPath == "" {
|
||||
go func() {
|
||||
for {
|
||||
client.NewRPClient(*serverAddr, *verifyKey, *connType, *proxyUrl, nil, *disconnectTime).Start()
|
||||
logs.Info("Client closed! It will be reconnected in five seconds")
|
||||
client.NewRPClient(*serverAddr, *verifyKey, *connType, *proxyUrl, nil).Start()
|
||||
logs.Info("It will be reconnected in five seconds")
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
if *configPath == "" {
|
||||
*configPath = common.GetConfigPath()
|
||||
*configPath = "conf/npc.conf"
|
||||
}
|
||||
go client.StartFromFile(*configPath)
|
||||
}
|
||||
select {
|
||||
case <-p.exit:
|
||||
logs.Warning("stop...")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -2,22 +2,25 @@ package main
|
||||
|
||||
import (
|
||||
"C"
|
||||
"ehang.io/nps/client"
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/version"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/client"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/version"
|
||||
)
|
||||
|
||||
var cl *client.TRPClient
|
||||
|
||||
//export StartClientByVerifyKey
|
||||
func StartClientByVerifyKey(serverAddr, verifyKey, connType, proxyUrl *C.char) int {
|
||||
_ = logs.SetLogger("store")
|
||||
logs.SetLogger("store")
|
||||
if cl != nil {
|
||||
cl.Close()
|
||||
}
|
||||
cl = client.NewRPClient(C.GoString(serverAddr), C.GoString(verifyKey), C.GoString(connType), C.GoString(proxyUrl), nil, 60)
|
||||
cl.Start()
|
||||
cl = client.NewRPClient(C.GoString(serverAddr), C.GoString(verifyKey), C.GoString(connType), C.GoString(proxyUrl), nil)
|
||||
go func() {
|
||||
cl.Start()
|
||||
return
|
||||
}()
|
||||
return 1
|
||||
}
|
||||
|
||||
|
116
cmd/nps/nps.go
116
cmd/nps/nps.go
@ -2,47 +2,39 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/cnlh/nps/lib/install"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"ehang.io/nps/lib/file"
|
||||
"ehang.io/nps/lib/install"
|
||||
"ehang.io/nps/lib/version"
|
||||
"ehang.io/nps/server"
|
||||
"ehang.io/nps/server/connection"
|
||||
"ehang.io/nps/server/tool"
|
||||
"ehang.io/nps/web/routers"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/crypt"
|
||||
"ehang.io/nps/lib/daemon"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/crypt"
|
||||
"github.com/cnlh/nps/lib/daemon"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/lib/version"
|
||||
"github.com/cnlh/nps/server"
|
||||
"github.com/cnlh/nps/server/connection"
|
||||
"github.com/cnlh/nps/server/tool"
|
||||
|
||||
"github.com/cnlh/nps/web/routers"
|
||||
"github.com/kardianos/service"
|
||||
)
|
||||
|
||||
var (
|
||||
level string
|
||||
ver = flag.Bool("version", false, "show current version")
|
||||
level string
|
||||
logType = flag.String("log", "stdout", "Log output mode(stdout|file)")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
// init log
|
||||
if *ver {
|
||||
common.PrintVersion()
|
||||
return
|
||||
}
|
||||
if err := beego.LoadAppConfig("ini", filepath.Join(common.GetRunPath(), "conf", "nps.conf")); err != nil {
|
||||
log.Fatalln("load config file error", err.Error())
|
||||
}
|
||||
common.InitPProfFromFile()
|
||||
if level = beego.AppConfig.String("log_level"); level == "" {
|
||||
level = "7"
|
||||
}
|
||||
@ -56,48 +48,39 @@ func main() {
|
||||
if common.IsWindows() {
|
||||
logPath = strings.Replace(logPath, "\\", "\\\\", -1)
|
||||
}
|
||||
logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+logPath+`","daily":false,"maxlines":100000,"color":true}`)
|
||||
// init service
|
||||
options := make(service.KeyValue)
|
||||
options["Restart"] = "on-success"
|
||||
options["SuccessExitStatus"] = "1 2 8 SIGKILL"
|
||||
svcConfig := &service.Config{
|
||||
Name: "Nps",
|
||||
DisplayName: "nps内网穿透代理服务器",
|
||||
Description: "一款轻量级、功能强大的内网穿透代理服务器。支持tcp、udp流量转发,支持内网http代理、内网socks5代理,同时支持snappy压缩、站点保护、加密传输、多路复用、header修改等。支持web图形化管理,集成多用户模式。",
|
||||
Option: options,
|
||||
}
|
||||
svcConfig.Arguments = append(svcConfig.Arguments, "service")
|
||||
if len(os.Args) > 1 && os.Args[1] == "service" {
|
||||
_ = logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+logPath+`","daily":false,"maxlines":100000,"color":true}`)
|
||||
} else {
|
||||
_ = logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`)
|
||||
}
|
||||
if !common.IsWindows() {
|
||||
svcConfig.Dependencies = []string{
|
||||
"Requires=network.target",
|
||||
"After=network-online.target syslog.target"}
|
||||
svcConfig.Option["SystemdScript"] = install.SystemdScript
|
||||
svcConfig.Option["SysvScript"] = install.SysvScript
|
||||
}
|
||||
prg := &nps{}
|
||||
prg.exit = make(chan struct{})
|
||||
s, err := service.New(prg, svcConfig)
|
||||
if err != nil {
|
||||
logs.Error(err, "service function disabled")
|
||||
run()
|
||||
// run without service
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
wg.Wait()
|
||||
logs.Error(err)
|
||||
return
|
||||
}
|
||||
if len(os.Args) > 1 && os.Args[1] != "service" {
|
||||
if len(os.Args) > 1 {
|
||||
switch os.Args[1] {
|
||||
case "debug":
|
||||
logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`)
|
||||
case "reload":
|
||||
daemon.InitDaemon("nps", common.GetRunPath(), common.GetTmpPath())
|
||||
return
|
||||
case "install":
|
||||
// uninstall before
|
||||
_ = service.Control(s, "stop")
|
||||
_ = service.Control(s, "uninstall")
|
||||
service.Control(s, "uninstall")
|
||||
|
||||
binPath := install.InstallNps()
|
||||
svcConfig.Executable = binPath
|
||||
@ -108,39 +91,13 @@ func main() {
|
||||
}
|
||||
err = service.Control(s, os.Args[1])
|
||||
if err != nil {
|
||||
logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
|
||||
}
|
||||
if service.Platform() == "unix-systemv" {
|
||||
logs.Info("unix-systemv service")
|
||||
confPath := "/etc/init.d/" + svcConfig.Name
|
||||
os.Symlink(confPath, "/etc/rc.d/S90"+svcConfig.Name)
|
||||
os.Symlink(confPath, "/etc/rc.d/K02"+svcConfig.Name)
|
||||
logs.Error("Valid actions: %q\n", service.ControlAction, err.Error())
|
||||
}
|
||||
return
|
||||
case "start", "restart", "stop":
|
||||
if service.Platform() == "unix-systemv" {
|
||||
logs.Info("unix-systemv service")
|
||||
cmd := exec.Command("/etc/init.d/"+svcConfig.Name, os.Args[1])
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
case "start", "restart", "stop", "uninstall":
|
||||
err := service.Control(s, os.Args[1])
|
||||
if err != nil {
|
||||
logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
|
||||
}
|
||||
return
|
||||
case "uninstall":
|
||||
err := service.Control(s, os.Args[1])
|
||||
if err != nil {
|
||||
logs.Error("Valid actions: %q\n%s", service.ControlAction, err.Error())
|
||||
}
|
||||
if service.Platform() == "unix-systemv" {
|
||||
logs.Info("unix-systemv service")
|
||||
os.Remove("/etc/rc.d/S90" + svcConfig.Name)
|
||||
os.Remove("/etc/rc.d/K02" + svcConfig.Name)
|
||||
logs.Error("Valid actions: %q\n", service.ControlAction, err.Error())
|
||||
}
|
||||
return
|
||||
case "update":
|
||||
@ -151,7 +108,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
}
|
||||
_ = s.Run()
|
||||
s.Run()
|
||||
}
|
||||
|
||||
type nps struct {
|
||||
@ -159,12 +116,10 @@ type nps struct {
|
||||
}
|
||||
|
||||
func (p *nps) Start(s service.Service) error {
|
||||
_, _ = s.Status()
|
||||
go p.run()
|
||||
p.run()
|
||||
return nil
|
||||
}
|
||||
func (p *nps) Stop(s service.Service) error {
|
||||
_, _ = s.Status()
|
||||
close(p.exit)
|
||||
if service.Interactive() {
|
||||
os.Exit(0)
|
||||
@ -181,15 +136,6 @@ func (p *nps) run() error {
|
||||
logs.Warning("nps: panic serving %v: %v\n%s", err, string(buf))
|
||||
}
|
||||
}()
|
||||
run()
|
||||
select {
|
||||
case <-p.exit:
|
||||
logs.Warning("stop...")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func run() {
|
||||
routers.Init()
|
||||
task := &file.Tunnel{
|
||||
Mode: "webServer",
|
||||
@ -201,13 +147,13 @@ func run() {
|
||||
}
|
||||
logs.Info("the version of server is %s ,allow client core version to be %s", version.VERSION, version.GetVersion())
|
||||
connection.InitConnectionService()
|
||||
//crypt.InitTls(filepath.Join(common.GetRunPath(), "conf", "server.pem"), filepath.Join(common.GetRunPath(), "conf", "server.key"))
|
||||
crypt.InitTls()
|
||||
crypt.InitTls(filepath.Join(common.GetRunPath(), "conf", "server.pem"), filepath.Join(common.GetRunPath(), "conf", "server.key"))
|
||||
tool.InitAllowPort()
|
||||
tool.StartSystemInfo()
|
||||
timeout, err := beego.AppConfig.Int("disconnect_timeout")
|
||||
if err != nil {
|
||||
timeout = 60
|
||||
go server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type"))
|
||||
select {
|
||||
case <-p.exit:
|
||||
logs.Warning("stop...")
|
||||
}
|
||||
go server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type"), timeout)
|
||||
return nil
|
||||
}
|
||||
|
@ -12,8 +12,6 @@ web_username=user
|
||||
web_password=1234
|
||||
crypt=true
|
||||
compress=true
|
||||
#pprof_addr=0.0.0.0:9999
|
||||
disconnect_timeout=60
|
||||
|
||||
[health_check_test1]
|
||||
health_check_timeout=1
|
||||
|
@ -49,8 +49,7 @@ web_key_file=conf/server.key
|
||||
#web_base_url=/nps
|
||||
|
||||
#Web API unauthenticated IP address(the len of auth_crypt_key must be 16)
|
||||
#Remove comments if needed
|
||||
#auth_key=test
|
||||
auth_key=test
|
||||
auth_crypt_key =1234567812345678
|
||||
|
||||
#allow_ports=9001-9009,10001,11000-12000
|
||||
@ -74,12 +73,4 @@ system_info_display=false
|
||||
http_cache=false
|
||||
http_cache_length=100
|
||||
|
||||
#get origin ip
|
||||
http_add_origin_header=false
|
||||
|
||||
#pprof debug options
|
||||
#pprof_ip=0.0.0.0
|
||||
#pprof_port=9999
|
||||
|
||||
#client disconnect timeout
|
||||
disconnect_timeout=60
|
||||
|
@ -1,13 +1,13 @@
|
||||
# nps
|
||||
 
|
||||
[](https://gitter.im/cnlh-nps/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
[](https://travis-ci.org/cnlh/nps)
|
||||
[](https://travis-ci.org/cnlh/nps)
|
||||
|
||||
nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务器。目前支持**tcp、udp流量转发**,可支持任何**tcp、udp**上层协议(访问内网网站、本地支付接口调试、ssh访问、远程桌面,内网dns解析等等……),此外还**支持内网http代理、内网socks5代理**、**p2p等**,并带有功能强大的web管理端。
|
||||
|
||||
|
||||
## 背景
|
||||

|
||||

|
||||
|
||||
1. 做微信公众号开发、小程序开发等----> 域名代理模式
|
||||
|
||||
|
@ -1,16 +1,14 @@
|
||||

|
||||
|
||||
# NPS <small>0.26.10</small>
|
||||
# NPS <small>0.25.1</small>
|
||||
|
||||
> 一款轻量级、高性能、功能强大的内网穿透代理服务器
|
||||
|
||||
- 几乎支持所有协议
|
||||
- 支持内网http代理、内网socks5代理、p2p等
|
||||
- 简洁但功能强大的WEB管理界面
|
||||
- 支持服务端、客户端同时控制
|
||||
- 扩展功能强大
|
||||
- 全平台兼容,一键注册为服务
|
||||
- 支持tcp、udp流量转发
|
||||
- 支持内网http代理、内网socks5代理、p2p
|
||||
- 简洁方便的WEB管理界面
|
||||
- 服务端控制
|
||||
|
||||
|
||||
[GitHub](https://github.com/ehang-io/nps/)
|
||||
[GitHub](https://github.com/cnlh/nps/)
|
||||
[开始使用](#nps)
|
||||
|
@ -1,3 +0,0 @@
|
||||
* [](https://github.com/ehang-io/nps/stargazers)
|
||||
|
||||
* [](https://github.com/ehang-io/nps/network)
|
@ -19,10 +19,9 @@
|
||||
* [说明](description.md)
|
||||
* [web api](api.md)
|
||||
* [sdk](npc_sdk.md)
|
||||
|
||||
git
|
||||
* 其他
|
||||
|
||||
* [FAQ](faq.md)
|
||||
* [贡献](contribute.md)
|
||||
* [捐助](donate.md)
|
||||
* [致谢](thanks.md)
|
||||
|
@ -1,6 +1,4 @@
|
||||
# web api
|
||||
|
||||
需要开启请先去掉`nps.conf`中`auth_key`的注释并配置一个合适的密钥
|
||||
## webAPI验证说明
|
||||
- 采用auth_key的验证方式
|
||||
- 在提交的每个请求后面附带两个参数,`auth_key` 和`timestamp`
|
||||
@ -42,4 +40,7 @@ POST /auth/getauthkey
|
||||
- 解密串编码方式 十六进制
|
||||
|
||||
## 详细文档
|
||||
- **[详见](webapi.md)** (感谢@avengexyz)
|
||||
- **此文档近期可能更新较慢,建议自行抓包**
|
||||
|
||||
为方便第三方扩展,在web模式下可利用webAPI进行相关操作,详情见
|
||||
[webAPI文档](https://github.com/cnlh/nps/wiki/webAPI%E6%96%87%E6%A1%A3)
|
||||
|
@ -1,6 +1,5 @@
|
||||
# 说明
|
||||
## 获取用户真实ip
|
||||
如需使用需要在`nps.conf`中设置`http_add_origin_header=true`
|
||||
|
||||
在域名代理模式中,可以通过request请求 header 中的 X-Forwarded-For 和 X-Real-IP 来获取用户真实 IP。
|
||||
|
||||
|
@ -2,6 +2,6 @@
|
||||
如果您觉得nps对你有帮助,欢迎给予我们一定捐助,也是帮助nps更好的发展。
|
||||
|
||||
## 支付宝
|
||||

|
||||

|
||||
## 微信
|
||||

|
||||

|
||||
|
@ -1,12 +1,12 @@
|
||||
# 使用示例
|
||||
## 统一准备工作(必做)
|
||||
- 开启服务端,假设公网服务器ip为1.1.1.1,配置文件中`bridge_port`为8024,配置文件中`web_port`为8080
|
||||
- 开启服务端,假设公网服务器ip为1.1.1.1,配置文件中`bridge_port`为8284,配置文件中`web_port`为8080
|
||||
- 访问1.1.1.1:8080
|
||||
- 在客户端管理中创建一个客户端,记录下验证密钥
|
||||
- 内网客户端运行(windows使用cmd运行加.exe)
|
||||
|
||||
```shell
|
||||
./npc -server=1.1.1.1:8024 -vkey=客户端的密钥
|
||||
./npc -server=1.1.1.1:8284 -vkey=客户端的密钥
|
||||
```
|
||||
**注意:运行服务端后,请确保能从客户端设备上正常访问配置文件中所配置的`bridge_port`端口,telnet,netcat这类的来检查**
|
||||
|
||||
@ -14,8 +14,6 @@
|
||||
|
||||
**适用范围:** 小程序开发、微信公众号开发、产品演示
|
||||
|
||||
**注意:域名解析模式为http反向代理,不是dns服务器,在web上能够轻松灵活配置**
|
||||
|
||||
**假设场景:**
|
||||
- 有一个域名proxy.com,有一台公网机器ip为1.1.1.1
|
||||
- 两个内网开发站点127.0.0.1:81,127.0.0.1:82
|
||||
@ -79,8 +77,6 @@
|
||||
- 在刚才创建的客户端隧道管理中添加一条http代理,填写监听的端口(8004),保存。
|
||||
- 在外网环境的本机配置http代理,ip为公网服务器ip(1.1.1.1),端口为填写的监听端口(8004),即可访问了
|
||||
|
||||
**注意:对于私密代理与p2p,除了统一配置的客户端和服务端,还需要一个客户端作为访问端提供一个端口来访问**
|
||||
|
||||
## 私密代理
|
||||
|
||||
**适用范围:** 无需占用多余的端口、安全性要求较高可以防止其他人连接的tcp服务,例如ssh。
|
||||
@ -93,13 +89,13 @@
|
||||
- 在需要连接ssh的机器上以执行命令
|
||||
|
||||
```
|
||||
./npc -server=1.1.1.1:8024 -vkey=vkey -type=tcp -password=secrettest -local_type=secret
|
||||
./npc -server=1.1.1.1:8284 -vkey=vkey -type=tcp -password=secrettest -local_type=secret
|
||||
```
|
||||
如需指定本地端口可加参数`-local_port=xx`,默认为2000
|
||||
|
||||
**注意:** password为web管理上添加的唯一密钥,具体命令可查看web管理上的命令提示
|
||||
|
||||
假设10.1.50.2用户名为root,现在执行`ssh -p 2000 root@127.0.0.1`即可访问ssh
|
||||
假设10.1.50.2用户名为root,现在执行`ssh -p 2000 root@1.1.1.1`即可访问ssh
|
||||
|
||||
|
||||
## p2p服务
|
||||
@ -112,12 +108,11 @@
|
||||
|
||||
**使用步骤**
|
||||
- 在`nps.conf`中设置`p2p_ip`(nps服务器ip)和`p2p_port`(nps服务器udp端口)
|
||||
> 注:若 `p2p_port` 设置为6000,请在防火墙开放6000~6002(额外添加2个端口)udp端口
|
||||
- 在刚才刚才创建的客户端中添加一条p2p代理,并设置唯一密钥p2pssh
|
||||
- 在使用端机器(本机)执行命令
|
||||
|
||||
```
|
||||
./npc -server=1.1.1.1:8024 -vkey=123 -password=p2pssh -target=10.2.50.2:22
|
||||
./npc -server=1.1.1.1:8284 -vkey=123 -password=p2pssh -target=10.2.50.2:22
|
||||
```
|
||||
如需指定本地端口可加参数`-local_port=xx`,默认为2000
|
||||
|
||||
|
20
docs/faq.md
20
docs/faq.md
@ -1,20 +0,0 @@
|
||||
# FAQ
|
||||
|
||||
- 服务端无法启动
|
||||
```
|
||||
服务端默认配置启用了8024,8080,80,443端口,端口冲突无法启动,请修改配置
|
||||
```
|
||||
- 客户端无法连接服务端
|
||||
```
|
||||
请检查配置文件中的所有端口是否在安全组,防火墙放行
|
||||
请检查vkey是否对应
|
||||
请检查版本是否对应
|
||||
```
|
||||
- 服务端配置文件修改无效
|
||||
```
|
||||
install 之后,Linux 配置文件在 /etc/nps
|
||||
```
|
||||
- p2p穿透失败 [p2p服务](https://ehang-io.github.io/nps/#/example?id=p2p%e6%9c%8d%e5%8a%a1)
|
||||
```
|
||||
双方nat类型都是Symmetric Nat一定不成功,建议先查看nat类型。请按照文档操作(标题上有超链接)
|
||||
```
|
@ -16,7 +16,8 @@
|
||||
## 加密传输
|
||||
|
||||
如果公司内网防火墙对外网访问进行了流量识别与屏蔽,例如禁止了ssh协议等,通过设置 配置文件,将服务端与客户端之间的通信内容加密传输,将会有效防止流量被拦截。
|
||||
- nps现在默认每次启动时随机生成tls证书,用于加密传输
|
||||
- nps使用tls加密,所以一定要保留conf目录下的密钥文件,同时也可以自行生成
|
||||
- 在web管理或客户端配置文件中设置
|
||||
|
||||
|
||||
|
||||
@ -78,10 +79,17 @@ target_port=8001-8009,10002,13000-14000
|
||||
target_ip=10.1.50.2
|
||||
```
|
||||
填写target_ip后则表示映射的该地址机器的端口,忽略则便是映射本地127.0.0.1,仅范围映射时有效
|
||||
|
||||
## 守护进程
|
||||
本代理支持守护进程,使用示例如下,服务端客户端所有模式通用,支持linux,darwin,windows。
|
||||
```
|
||||
./(nps|npc) start|stop|restart|status 若有其他参数可加其他参数
|
||||
```
|
||||
```
|
||||
(nps|npc).exe start|stop|restart|status 若有其他参数可加其他参数
|
||||
```
|
||||
## KCP协议支持
|
||||
|
||||
在网络质量非常好的情况下,例如专线,内网,可以开启略微降低延迟。如需使用可在nps.conf中修改`bridge_type`为kcp
|
||||
KCP 是一个快速可靠协议,能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低 30%-40%,在弱网环境下对性能能有一定的提升。可在nps.conf中修改`bridge_type`为kcp
|
||||
,设置后本代理将开启udp端口(`bridge_port`)
|
||||
|
||||
注意:当服务端为kcp时,客户端连接时也需要使用相同配置,无配置文件模式加上参数type=kcp,配置文件模式在配置文件中设置tp=kcp
|
||||
@ -159,7 +167,7 @@ npc支持环境变量渲染以适应在某些特殊场景下的要求。
|
||||
**在无配置文件启动模式下:**
|
||||
设置环境变量
|
||||
```
|
||||
export NPC_SERVER_ADDR=1.1.1.1:8024
|
||||
export NPC_SERVER_ADDR=1.1.1.1:8284
|
||||
export NPC_SERVER_VKEY=xxxxx
|
||||
```
|
||||
直接执行./npc即可运行
|
||||
@ -237,18 +245,3 @@ LevelInformational->6 LevelDebug->7
|
||||
**对于nps:**
|
||||
|
||||
在`nps.conf`中设置相关配置即可
|
||||
|
||||
## pprof性能分析与调试
|
||||
|
||||
可在服务端与客户端配置中开启pprof端口,用于性能分析与调试,注释或留空相应参数为关闭。
|
||||
|
||||
默认为关闭状态
|
||||
|
||||
## 自定义客户端超时检测断开时间
|
||||
|
||||
客户端与服务端间会间隔5s相互发送延迟测量包,这个时间间隔不可修改。
|
||||
可修改延迟测量包丢包的次数,默认为60也就是5分钟都收不到一个延迟测量回包,则会断开客户端连接。
|
||||
值得注意的是需要客户端的socket关闭,才会进行重连,也就是当客户端无法收到服务端的fin包时,只有客户端自行关闭socket才行。
|
||||
也就是假如服务端设置为较低值,而客户端设置较高值,而此时服务端断开连接而客户端无法收到服务端的fin包,客户端也会继续等着直到触发客户端的超时设置。
|
||||
|
||||
在`nps.conf`或`npc.conf`中设置`disconnect_timeout`即可,客户端还可附带`-disconnect_timeout=60`参数启动
|
||||
|
@ -20,7 +20,6 @@
|
||||
repo: '',
|
||||
loadSidebar: true,
|
||||
coverpage: true,
|
||||
loadNavbar: true,
|
||||
subMaxLevel: 2,
|
||||
maxLevel: 4,
|
||||
search: {
|
||||
@ -30,7 +29,7 @@
|
||||
hideOtherSidebarContent: true, // whether or not to hide other sidebar content
|
||||
},
|
||||
plugins: [
|
||||
EditOnGithubPlugin.create("https://github.com/ehang-io/nps/tree/master/docs/", "", "在github上编辑"),
|
||||
EditOnGithubPlugin.create("https://github.com/cnlh/nps/tree/master/docs/", "", "在github上编辑"),
|
||||
]
|
||||
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
# 安装
|
||||
## 安装包安装
|
||||
[releases](https://github.com/ehang-io/nps/releases)
|
||||
[releases](https://github.com/cnlh/nps/releases)
|
||||
|
||||
下载对应的系统版本即可,服务端和客户端是单独的
|
||||
|
||||
## 源码安装
|
||||
- 安装源码
|
||||
```go get -u ehang.io/nps```
|
||||
```go get -u github.com/cnlh/nps...
|
||||
```
|
||||
- 编译
|
||||
|
||||
服务端```go build cmd/nps/nps.go```
|
||||
|
@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
# 介绍
|
||||
|
||||
可在网页上配置和管理各个tcp、udp隧道、内网站点代理,http、https解析等,功能强大,操作方便。
|
||||
|
@ -1,9 +1,9 @@
|
||||
# 增强功能
|
||||
## nat类型检测
|
||||
```
|
||||
./npc nat -stun_addr=stun.stunprotocol.org:3478
|
||||
./npc nat
|
||||
```
|
||||
如果p2p双方都是Symmetric Nat,肯定不能成功,其他组合都有较大成功率。`stun_addr`可以指定stun服务器地址。
|
||||
如果p2p双方都是Symmetric Nat,肯定不能成功,其他组合都有较大成功率。
|
||||
## 状态检查
|
||||
```
|
||||
./npc status -config=npc配置文件路径
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
```
|
||||
命令行模式启动客户端
|
||||
从v0.26.10开始,此函数会阻塞,直到客户端退出返回,请自行管理是否重连
|
||||
p0->连接地址
|
||||
p1->vkey
|
||||
p2->连接类型(tcp or udp)
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
**方式一:** 类似于nginx实现https的处理
|
||||
|
||||
在配置文件中将https_proxy_port设置为443或者其他你想配置的端口,将`https_just_proxy`设置为false,nps 重启后,在web管理界面,域名新增或修改界面中修改域名证书和密钥。
|
||||
在配置文件中将https_proxy_port设置为443或者其他你想配置的端口,和在web中对应域名编辑中设置对应的证书路径,将`https_just_proxy`设置为false,然后就和http代理一样了
|
||||
|
||||
**此外:** 可以在`nps.conf`中设置一个默认的https配置,当遇到未在web中设置https证书的域名解析时,将自动使用默认证书,另还有一种情况就是对于某些请求的clienthello不携带sni扩展信息,nps也将自动使用默认证书
|
||||
|
||||
@ -14,18 +14,18 @@
|
||||
|
||||
## 与nginx配合
|
||||
|
||||
有时候我们还需要在云服务器上运行nginx来保证静态文件缓存等,本代理可和nginx配合使用,在配置文件中将httpProxyPort设置为非80端口,并在nginx中配置代理,例如httpProxyPort为8010时
|
||||
有时候我们还需要在云服务器上运行nginx来保证静态文件缓存等,本代理可和nginx配合使用,在配置文件中将httpProxyPort设置为非80端口,并在nginx中配置代理,例如httpProxyPort为8024时
|
||||
```
|
||||
server {
|
||||
listen 80;
|
||||
server_name *.proxy.com;
|
||||
location / {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_pass http://127.0.0.1:8010;
|
||||
proxy_pass http://127.0.0.1:8024;
|
||||
}
|
||||
}
|
||||
```
|
||||
如需使用https也可在nginx监听443端口并配置ssl,并将本代理的httpsProxyPort设置为空关闭https即可,例如httpProxyPort为8020时
|
||||
如需使用https也可在nginx监听443端口并配置ssl,并将本代理的httpsProxyPort设置为空关闭https即可,例如httpProxyPort为8024时
|
||||
|
||||
```
|
||||
server {
|
||||
@ -40,7 +40,7 @@ server {
|
||||
ssl_prefer_server_ciphers on;
|
||||
location / {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_pass http://127.0.0.1:8020;
|
||||
proxy_pass http://127.0.0.1:8024;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -29,7 +29,7 @@
|
||||
nps.exe stop|restart
|
||||
```
|
||||
## 服务端更新
|
||||
请首先执行 `sudo nps stop` 或者 `nps.exe stop` 停止运行,然后
|
||||
请首先执行`sudo nps stop`或者`nps.exe stop`停止运行,然后
|
||||
|
||||
对于linux
|
||||
```shell
|
||||
@ -40,8 +40,4 @@
|
||||
nps-update.exe update
|
||||
```
|
||||
|
||||
更新完成后,执行执行 `sudo nps start` 或者 `nps.exe start` 重新运行即可完成升级
|
||||
|
||||
如果无法更新成功,可以直接自行下载releases压缩包然后覆盖原有的nps二进制文件和web目录
|
||||
|
||||
注意:`nps install` 之后的 nps 不在原位置,请使用 `whereis nps` 查找具体目录覆盖 nps 二进制文件
|
||||
更新完成后,执行执行`sudo nps start`或者`nps.exe start`重新运行即可完成升级
|
13
docs/run.md
13
docs/run.md
@ -14,11 +14,9 @@
|
||||
|
||||
对于windows,管理员身份运行cmd,进入程序目录 ```nps.exe start```
|
||||
|
||||
```安装后windows配置文件位于 C:\Program Files\nps,linux和darwin位于/etc/nps```
|
||||
|
||||
停止和重启可用,stop和restart
|
||||
|
||||
**如果发现没有启动成功,可以使用`nps(.exe) stop`,然后运行`nps.(exe)`运行调试,或查看日志**(Windows日志文件位于当前运行目录下,linux和darwin位于/var/log/nps.log)
|
||||
**如果发现没有启动成功,可以使用`nps(.exe) debug`运行调试,或查看日志**(Windows日志文件位于当前运行目录下,linux和darwin位于/var/log/nps.log)
|
||||
- 访问服务端ip:web服务端口(默认为8080)
|
||||
- 使用用户名和密码登陆(默认admin/123,正式使用一定要更改)
|
||||
- 创建客户端
|
||||
@ -26,17 +24,10 @@
|
||||
## 客户端
|
||||
- 下载客户端安装包并解压,进入到解压目录
|
||||
- 点击web管理中客户端前的+号,复制启动命令
|
||||
- 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用**cmd执行**
|
||||
|
||||
如果使用`powershell`运行,**请将ip括起来!**
|
||||
- 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用cmd执行
|
||||
|
||||
如果需要注册到系统服务可查看[注册到系统服务](/use?id=注册到系统服务)
|
||||
|
||||
## 版本检查
|
||||
- 对客户端以及服务的均可以使用参数`-version`打印版本
|
||||
- `nps -version`或`./nps -version`
|
||||
- `npc -version`或`./npc -version`
|
||||
|
||||
## 配置
|
||||
- 客户端连接后,在web中配置对应穿透服务即可
|
||||
- 可以查看[使用示例](/example)
|
||||
|
@ -1,5 +1,5 @@
|
||||
# 服务端配置文件
|
||||
- /etc/nps/conf/nps.conf
|
||||
- /conf/nps.conf
|
||||
|
||||
名称 | 含义
|
||||
---|---
|
||||
@ -19,6 +19,3 @@ log_level|日志输出级别
|
||||
auth_crypt_key | 获取服务端authKey时的aes加密密钥,16位
|
||||
p2p_ip| 服务端Ip,使用p2p模式必填
|
||||
p2p_port|p2p模式开启的udp端口
|
||||
pprof_ip|debug pprof 服务端ip
|
||||
pprof_port|debug pprof 端口
|
||||
disconnect_timeout|客户端连接超时,单位 5s,默认值 60,即 300s = 5mins
|
||||
|
46
docs/use.md
46
docs/use.md
@ -2,43 +2,39 @@
|
||||
## 无配置文件模式
|
||||
此模式的各种配置在服务端web管理中完成,客户端除运行一条命令外无需任何其他设置
|
||||
```
|
||||
./npc -server=ip:port -vkey=web界面中显示的密钥
|
||||
./npc -debug=true -server=ip:port -vkey=web界面中显示的密钥
|
||||
```
|
||||
## 注册到系统服务(开机启动、守护进程)
|
||||
## 注册到系统服务
|
||||
对于linux、darwin
|
||||
- 注册:`sudo ./npc install 其他参数(例如-server=xx -vkey=xx或者-config=xxx)`
|
||||
- 启动:`sudo npc start`
|
||||
- 停止:`sudo npc stop`
|
||||
- 如果需要更换命令内容需要先卸载`./npc uninstall`,再重新注册
|
||||
- 启动:`sudo ./npc start`
|
||||
- 停止:`sudo ./npc stop`
|
||||
- 如果需要更换命令内容需要先卸载`./npc -service=uninstall`,再重新注册
|
||||
|
||||
对于windows,使用管理员身份运行cmd
|
||||
|
||||
- 注册:`npc.exe install 其他参数(例如-server=xx -vkey=xx或者-config=xxx)`
|
||||
- 启动:`npc.exe start`
|
||||
- 停止:`npc.exe stop`
|
||||
- 如果需要更换命令内容需要先卸载`npc.exe uninstall`,再重新注册
|
||||
- 如果需要当客户端退出时自动重启客户端,请按照如图所示配置
|
||||

|
||||
- 如果需要更换命令内容需要先卸载`npc.exe -service=uninstall`,再重新注册
|
||||
|
||||
注册到服务后,日志文件windows位于当前目录下,linux和darwin位于/var/log/npc.log
|
||||
|
||||
## 客户端更新
|
||||
首先进入到对于的客户端二进制文件目录
|
||||
|
||||
请首先执行`sudo npc stop`或者`npc.exe stop`停止运行,然后
|
||||
请首先执行`sudo ./npc stop`或者`nps.exe stop`停止运行,然后
|
||||
|
||||
对于linux
|
||||
```shell
|
||||
sudo npc-update update
|
||||
sudo ./npc-update update
|
||||
```
|
||||
对于windows
|
||||
```shell
|
||||
npc-update.exe update
|
||||
```
|
||||
|
||||
更新完成后,执行执行`sudo npc start`或者`npc.exe start`重新运行即可完成升级
|
||||
|
||||
如果无法更新成功,可以直接自行下载releases压缩包然后覆盖原有的npc二进制文件
|
||||
更新完成后,执行执行`sudo nps start`或者`nps.exe start`重新运行即可完成升级
|
||||
|
||||
## 配置文件模式
|
||||
此模式使用nps的公钥或者客户端私钥验证,各种配置在客户端完成,同时服务端web也可以进行管理
|
||||
@ -46,11 +42,11 @@ npc-update.exe update
|
||||
./npc -config=npc配置文件路径
|
||||
```
|
||||
## 配置文件说明
|
||||
[示例配置文件](https://github.com/ehang-io/nps/tree/master/conf/npc.conf)
|
||||
[示例配置文件](https://github.com/cnlh/nps/tree/master/conf/npc.conf)
|
||||
#### 全局配置
|
||||
```ini
|
||||
[common]
|
||||
server_addr=1.1.1.1:8024
|
||||
server_addr=1.1.1.1:8284
|
||||
conn_type=tcp
|
||||
vkey=123
|
||||
username=111
|
||||
@ -61,11 +57,10 @@ rate_limit=10000
|
||||
flow_limit=100
|
||||
remark=test
|
||||
max_conn=10
|
||||
#pprof_addr=0.0.0.0:9999
|
||||
```
|
||||
项 | 含义
|
||||
---|---
|
||||
server_addr | 服务端ip/域名:port
|
||||
server_addr | 服务端ip:port
|
||||
conn_type | 与服务端通信模式(tcp或kcp)
|
||||
vkey|服务端配置文件中的密钥(非web)
|
||||
username|socks5或http(s)密码保护用户名(可忽略)
|
||||
@ -76,12 +71,11 @@ rate_limit|速度限制,可忽略
|
||||
flow_limit|流量限制,可忽略
|
||||
remark|客户端备注,可忽略
|
||||
max_conn|最大连接数,可忽略
|
||||
pprof_addr|debug pprof ip:port
|
||||
#### 域名代理
|
||||
|
||||
```ini
|
||||
[common]
|
||||
server_addr=1.1.1.1:8024
|
||||
server_addr=1.1.1.1:8284
|
||||
vkey=123
|
||||
[web1]
|
||||
host=a.proxy.com
|
||||
@ -101,7 +95,7 @@ header_xxx|请求header修改或添加,header_proxy表示添加header proxy:np
|
||||
|
||||
```ini
|
||||
[common]
|
||||
server_addr=1.1.1.1:8024
|
||||
server_addr=1.1.1.1:8284
|
||||
vkey=123
|
||||
[tcp]
|
||||
mode=tcp
|
||||
@ -118,7 +112,7 @@ tartget_addr|内网目标
|
||||
|
||||
```ini
|
||||
[common]
|
||||
server_addr=1.1.1.1:8024
|
||||
server_addr=1.1.1.1:8284
|
||||
vkey=123
|
||||
[udp]
|
||||
mode=udp
|
||||
@ -134,7 +128,7 @@ target_addr|内网目标
|
||||
|
||||
```ini
|
||||
[common]
|
||||
server_addr=1.1.1.1:8024
|
||||
server_addr=1.1.1.1:8284
|
||||
vkey=123
|
||||
[http]
|
||||
mode=httpProxy
|
||||
@ -148,7 +142,7 @@ server_port | 在服务端的代理端口
|
||||
|
||||
```ini
|
||||
[common]
|
||||
server_addr=1.1.1.1:8024
|
||||
server_addr=1.1.1.1:8284
|
||||
vkey=123
|
||||
[socks5]
|
||||
mode=socks5
|
||||
@ -164,7 +158,7 @@ multi_account | socks5多账号配置文件(可选),配置后使用basic_usern
|
||||
|
||||
```ini
|
||||
[common]
|
||||
server_addr=1.1.1.1:8024
|
||||
server_addr=1.1.1.1:8284
|
||||
vkey=123
|
||||
[secret_ssh]
|
||||
mode=secret
|
||||
@ -181,7 +175,7 @@ target_addr|内网目标
|
||||
|
||||
```ini
|
||||
[common]
|
||||
server_addr=1.1.1.1:8024
|
||||
server_addr=1.1.1.1:8284
|
||||
vkey=123
|
||||
[p2p_ssh]
|
||||
mode=p2p
|
||||
@ -200,7 +194,7 @@ target_addr|内网目标
|
||||
|
||||
```ini
|
||||
[common]
|
||||
server_addr=1.1.1.1:8024
|
||||
server_addr=1.1.1.1:8284
|
||||
vkey=123
|
||||
[file]
|
||||
mode=file
|
||||
|
233
docs/webapi.md
233
docs/webapi.md
@ -1,233 +0,0 @@
|
||||
获取客户端列表
|
||||
|
||||
```
|
||||
POST /client/list/
|
||||
```
|
||||
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| search | 搜索 |
|
||||
| order | 排序asc 正序 desc倒序 |
|
||||
| offset | 分页(第几页) |
|
||||
| limit | 条数(分页显示的条数) |
|
||||
|
||||
***
|
||||
获取单个客户端
|
||||
|
||||
```
|
||||
POST /client/getclient/
|
||||
```
|
||||
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| id | 客户端id |
|
||||
|
||||
***
|
||||
添加客户端
|
||||
|
||||
```
|
||||
POST /client/add/
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| remark | 备注 |
|
||||
| u | basic权限认证用户名 |
|
||||
| p | basic权限认证密码 |
|
||||
| limit | 条数(分页显示的条数) |
|
||||
| vkey | 客户端验证密钥 |
|
||||
| config\_conn\_allow | 是否允许客户端以配置文件模式连接 1允许 0不允许 |
|
||||
| compress | 压缩1允许 0不允许 |
|
||||
| crypt | 是否加密(1或者0)1允许 0不允许 |
|
||||
| rate\_limit | 带宽限制 单位KB/S 空则为不限制 |
|
||||
| flow\_limit | 流量限制 单位M 空则为不限制 |
|
||||
| max\_conn | 客户端最大连接数量 空则为不限制 |
|
||||
| max\_tunnel | 客户端最大隧道数量 空则为不限制 |
|
||||
|
||||
***
|
||||
修改客户端
|
||||
|
||||
```
|
||||
POST /client/edit/
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| remark | 备注 |
|
||||
| u | basic权限认证用户名 |
|
||||
| p | basic权限认证密码 |
|
||||
| limit | 条数(分页显示的条数) |
|
||||
| vkey | 客户端验证密钥 |
|
||||
| config\_conn\_allow | 是否允许客户端以配置文件模式连接 1允许 0不允许 |
|
||||
| compress | 压缩1允许 0不允许 |
|
||||
| crypt | 是否加密(1或者0)1允许 0不允许 |
|
||||
| rate\_limit | 带宽限制 单位KB/S 空则为不限制 |
|
||||
| flow\_limit | 流量限制 单位M 空则为不限制 |
|
||||
| max\_conn | 客户端最大连接数量 空则为不限制 |
|
||||
| max\_tunnel | 客户端最大隧道数量 空则为不限制 |
|
||||
| id | 要修改的客户端id |
|
||||
|
||||
***
|
||||
删除客户端
|
||||
|
||||
```
|
||||
POST /client/del/
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| id | 要删除的客户端id |
|
||||
|
||||
***
|
||||
获取域名解析列表
|
||||
|
||||
```
|
||||
POST /index/hostlist/
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| search | 搜索(可以搜域名/备注什么的) |
|
||||
| offset | 分页(第几页) |
|
||||
| limit | 条数(分页显示的条数) |
|
||||
|
||||
***
|
||||
添加域名解析
|
||||
|
||||
```
|
||||
POST /index/addhost/
|
||||
```
|
||||
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| remark | 备注 |
|
||||
| host | 域名 |
|
||||
| scheme | 协议类型(三种 all http https) |
|
||||
| location | url路由 空则为不限制 |
|
||||
| client\_id | 客户端id |
|
||||
| target | 内网目标(ip:端口) |
|
||||
| header | request header 请求头 |
|
||||
| hostchange | request host 请求主机 |
|
||||
|
||||
***
|
||||
修改域名解析
|
||||
|
||||
```
|
||||
POST /index/edithost/
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| remark | 备注 |
|
||||
| host | 域名 |
|
||||
| scheme | 协议类型(三种 all http https) |
|
||||
| location | url路由 空则为不限制 |
|
||||
| client\_id | 客户端id |
|
||||
| target | 内网目标(ip:端口) |
|
||||
| header | request header 请求头 |
|
||||
| hostchange | request host 请求主机 |
|
||||
| id | 需要修改的域名解析id |
|
||||
|
||||
***
|
||||
删除域名解析
|
||||
|
||||
```
|
||||
POST /index/delhost/
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| id | 需要删除的域名解析id |
|
||||
|
||||
***
|
||||
获取单条隧道信息
|
||||
|
||||
```
|
||||
POST /index/getonetunnel/
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| id | 隧道的id |
|
||||
|
||||
***
|
||||
获取隧道列表
|
||||
|
||||
```
|
||||
POST /index/gettunnel/
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| client\_id | 穿透隧道的客户端id |
|
||||
| type | 类型tcp udp httpProx socks5 secret p2p |
|
||||
| search | 搜索 |
|
||||
| offset | 分页(第几页) |
|
||||
| limit | 条数(分页显示的条数) |
|
||||
|
||||
***
|
||||
添加隧道
|
||||
|
||||
```
|
||||
POST /index/add/
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| type | 类型tcp udp httpProx socks5 secret p2p |
|
||||
| remark | 备注 |
|
||||
| port | 服务端端口 |
|
||||
| target | 目标(ip:端口) |
|
||||
| client\_id | 客户端id |
|
||||
|
||||
***
|
||||
修改隧道
|
||||
|
||||
```
|
||||
POST /index/edit/
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| type | 类型tcp udp httpProx socks5 secret p2p |
|
||||
| remark | 备注 |
|
||||
| port | 服务端端口 |
|
||||
| target | 目标(ip:端口) |
|
||||
| client\_id | 客户端id |
|
||||
| id | 隧道id |
|
||||
|
||||
***
|
||||
删除隧道
|
||||
|
||||
```
|
||||
POST /index/del/
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| id | 隧道id |
|
||||
|
||||
***
|
||||
隧道停止工作
|
||||
|
||||
```
|
||||
POST /index/stop/
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| id | 隧道id |
|
||||
|
||||
***
|
||||
隧道开始工作
|
||||
|
||||
```
|
||||
POST /index/start/
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
| --- | --- |
|
||||
| id | 隧道id |
|
Binary file not shown.
Before Width: | Height: | Size: 26 KiB |
37
go.mod
37
go.mod
@ -1,34 +1,33 @@
|
||||
module ehang.io/nps
|
||||
module github.com/cnlh/nps
|
||||
|
||||
go 1.15
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
ehang.io/nps-mux v0.0.0-20210407130203-4afa0c10c992
|
||||
fyne.io/fyne/v2 v2.0.2
|
||||
fyne.io/fyne v1.2.0
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
|
||||
github.com/astaxie/beego v1.12.0
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
||||
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c // indirect
|
||||
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c
|
||||
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d
|
||||
github.com/dsnet/compress v0.0.1 // indirect
|
||||
github.com/golang/snappy v0.0.3
|
||||
github.com/go-ole/go-ole v1.2.4 // indirect
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db
|
||||
github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 // indirect
|
||||
github.com/kardianos/service v1.2.0
|
||||
github.com/klauspost/cpuid v1.3.1 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.6 // indirect
|
||||
github.com/kardianos/service v1.0.0
|
||||
github.com/klauspost/cpuid v1.2.1 // indirect
|
||||
github.com/klauspost/pgzip v1.2.1 // indirect
|
||||
github.com/klauspost/reedsolomon v1.9.12 // indirect
|
||||
github.com/panjf2000/ants/v2 v2.4.2
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/klauspost/reedsolomon v1.9.2 // indirect
|
||||
github.com/panjf2000/ants/v2 v2.2.2
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.21.3
|
||||
github.com/shirou/gopsutil v2.19.11+incompatible
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
|
||||
github.com/tjfoc/gmsm v1.4.0 // indirect
|
||||
github.com/xtaci/kcp-go v5.4.20+incompatible
|
||||
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect
|
||||
github.com/tjfoc/gmsm v1.0.1 // indirect
|
||||
github.com/xtaci/kcp-go v5.4.4+incompatible
|
||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3
|
||||
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect
|
||||
)
|
||||
|
||||
replace github.com/astaxie/beego => github.com/exfly/beego v1.12.0-export-init
|
||||
|
221
go.sum
221
go.sum
@ -1,9 +1,5 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
ehang.io/nps-mux v0.0.0-20210407130203-4afa0c10c992 h1:LvlcB+8JveSBprHnva0g+OyLwAH8CRxEwtWzTe6ocoE=
|
||||
ehang.io/nps-mux v0.0.0-20210407130203-4afa0c10c992/go.mod h1:v54y/8ICChiM/aVUuKxGIcWwjm4HGNRyyAwbgLBoMbI=
|
||||
fyne.io/fyne/v2 v2.0.2 h1:6pDvFuCmL1odyT/fPI+2L54hMJW1Zt9Dno41HmLInRs=
|
||||
fyne.io/fyne/v2 v2.0.2/go.mod h1:3+FYmLJVgeb8EvTPJ5YzZeo7LkAq4bbuY3Zrir6xHbg=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
fyne.io/fyne v1.2.0 h1:mdp7Cs7QmSJTeazYxEDa9wWeJNig7paBcjm0dooFtLE=
|
||||
fyne.io/fyne v1.2.0/go.mod h1:Ab+3DIB/FVteW0y4DXfmZv4N3JdnCBh2lHkINI02BOU=
|
||||
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I=
|
||||
github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM=
|
||||
@ -13,251 +9,124 @@ github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkK
|
||||
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
|
||||
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
|
||||
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c h1:FUUopH4brHNO2kJoNN3pV+OBEYmgraLT/KHZrMM69r0=
|
||||
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
||||
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c h1:aprLqMn7gSPT+vdDSl+/E6NLEuArwD/J7IWd8bJt5lQ=
|
||||
github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c/go.mod h1:Ie6SubJv/NTO9Q0UBH0QCl3Ve50lu9hjbi5YJUw03TE=
|
||||
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
|
||||
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d h1:As4937T5NVbJ/DmZT9z33pyLEprMd6CUSfhbmMY57Io=
|
||||
github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d/go.mod h1:3FK1bMar37f7jqVY7q/63k3OMX1c47pGCufzt3X0sYE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
|
||||
github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
|
||||
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
|
||||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
|
||||
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
|
||||
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/exfly/beego v1.12.0-export-init h1:VQNYKdXhAwZGUaFmQv8Aj921O3rQJZRIF8xeGrhsjrI=
|
||||
github.com/exfly/beego v1.12.0-export-init/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o=
|
||||
github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8vlzI4mm59llRvNzrFg6/LAA=
|
||||
github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f h1:rguJ/t99j/6zRSFzsBKlsmmyl+vOvCeTJ+2uTBvuXFI=
|
||||
github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw=
|
||||
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48 h1:QrUfZrT8n72FUuiABt4tbu8PwDnOPAbnj3Mql1UhdRI=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw v0.0.0-20181213070059-819e8ce5125f h1:7MsFMbSn8Lcw0blK4+NEOf8DuHoOBDhJsHz04yh13pM=
|
||||
github.com/go-gl/glfw v0.0.0-20181213070059-819e8ce5125f/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
|
||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8=
|
||||
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 h1:WgfvpuKg42WVLkxNwzfFraXkTXPK36bMqXvMFN67clI=
|
||||
github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214/go.mod h1:kj6hFWqfwSjFjLnYW5PK1DoxZ4O0uapwHRmd9jhln4E=
|
||||
github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc=
|
||||
github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE=
|
||||
github.com/kardianos/service v1.2.0 h1:bGuZ/epo3vrt8IPC7mnKQolqFeYJb7Cs8Rk4PSOBB/g=
|
||||
github.com/kardianos/service v1.2.0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
||||
github.com/josephspurrier/goversioninfo v0.0.0-20190124120936-8611f5a5ff3f/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE=
|
||||
github.com/kardianos/service v1.0.0 h1:HgQS3mFfOlyntWX8Oke98JcJLqt1DBcHR4kxShpYef0=
|
||||
github.com/kardianos/service v1.0.0/go.mod h1:8CzDhVuCuugtsHyZoTvsOBuvonN/UDBvl0kH+BUxvbo=
|
||||
github.com/klauspost/compress v1.4.1 h1:8VMb5+0wMgdBykOV96DwNwKFQ+WTI4pzYURP99CcB9E=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
|
||||
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.2 h1:pd2FBxFydtPn2ywTLStbFg9CJKrojATnpeJWSP7Ys4k=
|
||||
github.com/klauspost/cpuid/v2 v2.0.2/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.6 h1:dQ5ueTiftKxp0gyjKSx5+8BtPWkyQbd95m8Gys/RarI=
|
||||
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
|
||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM=
|
||||
github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/klauspost/reedsolomon v1.9.12 h1:EyOucRmcrLH+2hqKGdoA5SM8pwPKR6BJsf3r6zpYOA0=
|
||||
github.com/klauspost/reedsolomon v1.9.12/go.mod h1:nLvuzNvy1ZDNQW30IuMc2ZWCbiqrJgdLoUS2X8HAUVg=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/klauspost/reedsolomon v1.9.2 h1:E9CMS2Pqbv+C7tsrYad4YC9MfhnMVWhMRsTi7U0UB18=
|
||||
github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lucor/goinfo v0.0.0-20200401173949-526b5363a13a/go.mod h1:ORP3/rB5IsulLEBwQZCJyyV6niqmI7P4EWSmkug+1Ng=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/panjf2000/ants/v2 v2.4.2 h1:kesjjo8JipN3vNNg1XaiXaeSs6xJweBTgenkBtsrHf8=
|
||||
github.com/panjf2000/ants/v2 v2.4.2/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A=
|
||||
github.com/panjf2000/ants/v2 v2.2.2 h1:TWzusBjq/IflXhy+/S6u5wmMLCBdJnB9tPIx9Zmhvok=
|
||||
github.com/panjf2000/ants/v2 v2.2.2/go.mod h1:1GFm8bV8nyCQvU5K4WvBCTG1/YBFOD2VzjffD8fV55A=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
|
||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
|
||||
github.com/shirou/gopsutil/v3 v3.21.3 h1:wgcdAHZS2H6qy4JFewVTtqfiYxFzCeEJod/mLztdPG8=
|
||||
github.com/shirou/gopsutil/v3 v3.21.3/go.mod h1:ghfMypLDrFSWN2c9cDYFLHyynQ+QUht0cv/18ZqVczw=
|
||||
github.com/shirou/gopsutil v2.19.11+incompatible h1:lJHR0foqAjI4exXqWsU3DbH7bX1xvdhGdnXTIARA9W4=
|
||||
github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
|
||||
github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg=
|
||||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQOVpMmj5MQnGnv+e8uZNu3xFLgyM=
|
||||
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4=
|
||||
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM=
|
||||
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
|
||||
github.com/srwiley/oksvg v0.0.0-20190829233741-58e08c8fe40e h1:LJUrNHytcMXWKxnULIHPe5SCb1jDpO9o672VB1x2EuQ=
|
||||
github.com/srwiley/oksvg v0.0.0-20190829233741-58e08c8fe40e/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4=
|
||||
github.com/srwiley/rasterx v0.0.0-20181219215540-696f7edb7a7e h1:FFotfUvew9Eg02LYRl8YybAnm0HCwjjfY5JlOI1oB00=
|
||||
github.com/srwiley/rasterx v0.0.0-20181219215540-696f7edb7a7e/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
|
||||
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709 h1:Ko2LQMrRU+Oy/+EDBwX7eZ2jp3C47eDBB8EIhKTun+I=
|
||||
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI=
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
|
||||
github.com/tjfoc/gmsm v1.4.0 h1:8nbaiZG+iVdh+fXVw0DZoZZa7a4TGm3Qab+xdrdzj8s=
|
||||
github.com/tjfoc/gmsm v1.4.0/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/tklauser/go-sysconf v0.3.4 h1:HT8SVixZd3IzLdfs/xlpq0jeSfTX57g1v6wB1EuzV7M=
|
||||
github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek=
|
||||
github.com/tklauser/numcpus v0.2.1 h1:ct88eFm+Q7m2ZfXJdan1xYoXKlmwsfP+k88q05KvlZc=
|
||||
github.com/tklauser/numcpus v0.2.1/go.mod h1:9aU+wOc6WjUIZEwWMP62PL/41d65P+iks1gBkr4QyP8=
|
||||
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b h1:mnG1fcsIB1d/3vbkBak2MM0u+vhGhlQwpeimUi7QncM=
|
||||
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
|
||||
github.com/tjfoc/gmsm v1.0.1 h1:R11HlqhXkDospckjZEihx9SW/2VW0RgdwrykyWMFOQU=
|
||||
github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc=
|
||||
github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8=
|
||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
|
||||
github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg=
|
||||
github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.4.4+incompatible h1:QIJ0a0Q0N1G20yLHL2+fpdzyy2v/Cb3PI+xiwx/KK9c=
|
||||
github.com/xtaci/kcp-go v5.4.4+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
|
||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI=
|
||||
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8 h1:idBdZTd9UioThJp8KpM/rTSinK/ChZFBE43/WtIy8zg=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw=
|
||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88=
|
||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3 h1:eH6Eip3UpmR+yM/qI9Ijluzb1bNv/cAU/n+6l8tRSis=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M=
|
||||
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200328031815-3db5fc6bac03/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.nps.client"
|
||||
android:versionCode="1"
|
||||
android:versionName="0.26.10">
|
||||
|
||||
<application android:label="Npc" android:debuggable="true">
|
||||
<activity android:name="org.golang.app.GoNativeActivity"
|
||||
android:label="Npc"
|
||||
android:configChanges="orientation|keyboardHidden">
|
||||
<meta-data android:name="android.app.lib_name" android:value="npc"/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
101
gui/npc/npc.go
101
gui/npc/npc.go
@ -1,17 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"ehang.io/nps/client"
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/daemon"
|
||||
"ehang.io/nps/lib/version"
|
||||
"fmt"
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/app"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"fyne.io/fyne"
|
||||
"fyne.io/fyne/app"
|
||||
"fyne.io/fyne/layout"
|
||||
"fyne.io/fyne/widget"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/client"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/daemon"
|
||||
"github.com/cnlh/nps/lib/version"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
@ -33,12 +32,10 @@ func main() {
|
||||
}
|
||||
|
||||
var (
|
||||
start bool
|
||||
closing bool
|
||||
status = "Start!"
|
||||
connType = "tcp"
|
||||
cl = new(client.TRPClient)
|
||||
refreshCh = make(chan struct{})
|
||||
start bool
|
||||
status = "Start!"
|
||||
connType = "tcp"
|
||||
cl = new(client.TRPClient)
|
||||
)
|
||||
|
||||
func WidgetScreen() fyne.CanvasObject {
|
||||
@ -47,17 +44,38 @@ func WidgetScreen() fyne.CanvasObject {
|
||||
)
|
||||
}
|
||||
|
||||
func makeMainTab() *fyne.Container {
|
||||
func makeMainTab() fyne.Widget {
|
||||
serverPort := widget.NewEntry()
|
||||
serverPort.SetPlaceHolder("Server:Port")
|
||||
|
||||
vKey := widget.NewEntry()
|
||||
vKey.SetPlaceHolder("Vkey")
|
||||
radio := widget.NewRadioGroup([]string{"tcp", "kcp"}, func(s string) { connType = s })
|
||||
|
||||
radio := widget.NewRadio([]string{"tcp", "kcp"}, func(s string) { connType = s })
|
||||
radio.Horizontal = true
|
||||
|
||||
refreshCh := make(chan struct{})
|
||||
button := widget.NewButton(status, func() {
|
||||
onclick(serverPort.Text, vKey.Text, connType)
|
||||
start = !start
|
||||
if start {
|
||||
status = "Stop!"
|
||||
// init the npc
|
||||
fmt.Println("submit", serverPort.Text, vKey.Text, connType)
|
||||
sp, vk, ct := loadConfig()
|
||||
if sp != serverPort.Text || vk != vKey.Text || ct != connType {
|
||||
saveConfig(serverPort.Text, vKey.Text, connType)
|
||||
}
|
||||
cl = client.NewRPClient(serverPort.Text, vKey.Text, connType, "", nil)
|
||||
go cl.Start()
|
||||
} else {
|
||||
// close the npc
|
||||
status = "Start!"
|
||||
if cl != nil {
|
||||
go cl.Close()
|
||||
cl = nil
|
||||
}
|
||||
}
|
||||
refreshCh <- struct{}{}
|
||||
})
|
||||
go func() {
|
||||
for {
|
||||
@ -67,9 +85,9 @@ func makeMainTab() *fyne.Container {
|
||||
}()
|
||||
|
||||
lo := widget.NewMultiLineEntry()
|
||||
lo.Disable()
|
||||
lo.SetReadOnly(true)
|
||||
lo.Resize(fyne.NewSize(910, 250))
|
||||
slo := container.NewScroll(lo)
|
||||
slo := widget.NewScrollContainer(lo)
|
||||
slo.Resize(fyne.NewSize(910, 250))
|
||||
go func() {
|
||||
for {
|
||||
@ -85,10 +103,9 @@ func makeMainTab() *fyne.Container {
|
||||
vKey.SetText(vk)
|
||||
connType = ct
|
||||
radio.SetSelected(ct)
|
||||
onclick(sp, vk, ct)
|
||||
}
|
||||
|
||||
return container.NewVBox(
|
||||
return widget.NewVBox(
|
||||
widget.NewLabel("Npc "+version.VERSION),
|
||||
serverPort,
|
||||
vKey,
|
||||
@ -98,44 +115,6 @@ func makeMainTab() *fyne.Container {
|
||||
)
|
||||
}
|
||||
|
||||
func onclick(s, v, c string) {
|
||||
start = !start
|
||||
if start {
|
||||
closing = false
|
||||
status = "Stop!"
|
||||
// init the npc
|
||||
fmt.Println("submit", s, v, c)
|
||||
sp, vk, ct := loadConfig()
|
||||
if sp != s || vk != v || ct != c {
|
||||
saveConfig(s, v, c)
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
cl = client.NewRPClient(s, v, c, "", nil, 60)
|
||||
status = "Stop!"
|
||||
refreshCh <- struct{}{}
|
||||
cl.Start()
|
||||
logs.Warn("client closed, reconnecting in 5 seconds...")
|
||||
if closing {
|
||||
return
|
||||
}
|
||||
status = "Reconnecting..."
|
||||
refreshCh <- struct{}{}
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
// close the npc
|
||||
status = "Start!"
|
||||
closing = true
|
||||
if cl != nil {
|
||||
go cl.Close()
|
||||
cl = nil
|
||||
}
|
||||
}
|
||||
refreshCh <- struct{}{}
|
||||
}
|
||||
|
||||
func getDir() (dir string, err error) {
|
||||
if runtime.GOOS != "android" {
|
||||
dir, err = os.UserConfigDir()
|
||||
@ -163,7 +142,7 @@ func saveConfig(host, vkey, connType string) {
|
||||
return
|
||||
}
|
||||
if _, err := f.Write([]byte(data)); err != nil {
|
||||
_ = f.Close() // ignore error; Write error takes precedence
|
||||
f.Close() // ignore error; Write error takes precedence
|
||||
logs.Error(err)
|
||||
return
|
||||
}
|
||||
|
@ -1,821 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- 由 Microsoft Visio, SVG Export 生成 工作图.svg Page-1 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
|
||||
xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="11.6929in" height="8.26772in"
|
||||
viewBox="0 0 841.89 595.276" xml:space="preserve" color-interpolation-filters="sRGB" class="st17">
|
||||
<v:documentProperties v:langID="2052" v:metric="true" v:viewMarkup="false">
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="msvNoAutoConnect" v:prompt="" v:val="VT0(0):26"/>
|
||||
</v:userDefs>
|
||||
</v:documentProperties>
|
||||
|
||||
<style type="text/css">
|
||||
<![CDATA[
|
||||
.st1 {fill:#5b9bd5;stroke:#ffffff;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.5}
|
||||
.st2 {stroke:#ffffff;stroke-linecap:butt;stroke-width:0.5}
|
||||
.st3 {fill:#1e4a73;font-family:Calibri;font-size:1.5em}
|
||||
.st4 {fill:#aad288;stroke:#ffffff;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.5}
|
||||
.st5 {fill:#ffffff}
|
||||
.st6 {font-size:1em}
|
||||
.st7 {fill:#5b9bd5}
|
||||
.st8 {stroke:#ffffff;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.5}
|
||||
.st9 {fill:#a5a5a5}
|
||||
.st10 {marker-end:url(#mrkr4-135);marker-start:url(#mrkr4-133);stroke:#5592c9;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5}
|
||||
.st11 {fill:#5592c9;fill-opacity:1;stroke:#5592c9;stroke-opacity:1;stroke-width:0.37313432835821}
|
||||
.st12 {fill:#ffffff;stroke:none;stroke-linecap:butt;stroke-width:7.2}
|
||||
.st13 {fill:#41729d;font-family:Calibri;font-size:1.5em}
|
||||
.st14 {fill:none;stroke:#42829e;stroke-dasharray:45,27;stroke-linecap:round;stroke-linejoin:round;stroke-width:3}
|
||||
.st15 {fill:none;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.5}
|
||||
.st16 {fill:#5b9bd5;font-family:Calibri;font-size:1.99999em}
|
||||
.st17 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
|
||||
]]>
|
||||
</style>
|
||||
|
||||
<defs id="Markers">
|
||||
<g id="lend4">
|
||||
<path d="M 2 1 L 0 0 L 2 -1 L 2 1 " style="stroke:none"/>
|
||||
</g>
|
||||
<marker id="mrkr4-133" class="st11" v:arrowType="4" v:arrowSize="2" v:setback="5.12" refX="5.12" orient="auto"
|
||||
markerUnits="strokeWidth" overflow="visible">
|
||||
<use xlink:href="#lend4" transform="scale(2.68) "/>
|
||||
</marker>
|
||||
<marker id="mrkr4-135" class="st11" v:arrowType="4" v:arrowSize="2" v:setback="5.36" refX="-5.36" orient="auto"
|
||||
markerUnits="strokeWidth" overflow="visible">
|
||||
<use xlink:href="#lend4" transform="scale(-2.68,-2.68) "/>
|
||||
</marker>
|
||||
</defs>
|
||||
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="msvThemeOrder" v:val="VT0(0):26"/>
|
||||
</v:userDefs>
|
||||
<title>页-1</title>
|
||||
<v:pageProperties v:drawingScale="0.0393701" v:pageScale="0.0393701" v:drawingUnits="24" v:shadowOffsetX="8.50394"
|
||||
v:shadowOffsetY="-8.50394"/>
|
||||
<v:layer v:name="连接线" v:index="0"/>
|
||||
<g id="group1-1" transform="translate(418.11,-311.811)" v:mID="1" v:groupContext="group">
|
||||
<v:custProps>
|
||||
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
|
||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
|
||||
<v:cp v:nameU="SubShapeType" v:lbl="SubShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(防火墙)"/>
|
||||
</v:custProps>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
||||
</v:userDefs>
|
||||
<title>防火墙</title>
|
||||
<desc>NAT</desc>
|
||||
<g id="shape2-2" v:mID="2" v:groupContext="shape" transform="translate(0.545123,-7.63784)">
|
||||
<title>工作表.2</title>
|
||||
<rect x="0" y="539.685" width="69.7759" height="55.5905" class="st1"/>
|
||||
</g>
|
||||
<g id="shape3-4" v:mID="3" v:groupContext="shape" transform="translate(0.795123,-7.88784)">
|
||||
<title>工作表.3</title>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
|
||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
|
||||
</v:userDefs>
|
||||
<path d="M0 587.41 L69.28 587.41" class="st2"/>
|
||||
<path d="M0 579.54 L69.28 579.54" class="st2"/>
|
||||
<path d="M0 571.67 L69.28 571.67" class="st2"/>
|
||||
<path d="M0 563.8 L69.28 563.8" class="st2"/>
|
||||
<path d="M0 555.93 L69.28 555.93" class="st2"/>
|
||||
<path d="M0 548.06 L69.28 548.06" class="st2"/>
|
||||
<path d="M17.32 595.28 L17.32 587.41" class="st2"/>
|
||||
<path d="M34.64 595.28 L34.64 587.41" class="st2"/>
|
||||
<path d="M51.96 595.28 L51.96 587.41" class="st2"/>
|
||||
<path d="M8.66 587.41 L8.66 579.54" class="st2"/>
|
||||
<path d="M25.98 587.41 L25.98 579.54" class="st2"/>
|
||||
<path d="M43.3 587.41 L43.3 579.54" class="st2"/>
|
||||
<path d="M60.62 587.41 L60.62 579.54" class="st2"/>
|
||||
<path d="M17.32 579.54 L17.32 571.67" class="st2"/>
|
||||
<path d="M34.64 579.54 L34.64 571.67" class="st2"/>
|
||||
<path d="M51.96 579.54 L51.96 571.67" class="st2"/>
|
||||
<path d="M8.66 571.67 L8.66 563.8" class="st2"/>
|
||||
<path d="M25.98 571.67 L25.98 563.8" class="st2"/>
|
||||
<path d="M43.3 571.67 L43.3 563.8" class="st2"/>
|
||||
<path d="M60.62 571.67 L60.62 563.8" class="st2"/>
|
||||
<path d="M17.32 563.8 L17.32 555.93" class="st2"/>
|
||||
<path d="M34.64 563.8 L34.64 555.93" class="st2"/>
|
||||
<path d="M51.96 563.8 L51.96 555.93" class="st2"/>
|
||||
<path d="M8.66 555.93 L8.66 548.06" class="st2"/>
|
||||
<path d="M25.98 555.93 L25.98 548.06" class="st2"/>
|
||||
<path d="M43.3 555.93 L43.3 548.06" class="st2"/>
|
||||
<path d="M60.62 555.93 L60.62 548.06" class="st2"/>
|
||||
<path d="M17.32 548.06 L17.32 540.19" class="st2"/>
|
||||
<path d="M34.64 548.06 L34.64 540.19" class="st2"/>
|
||||
<path d="M51.96 548.06 L51.96 540.19" class="st2"/>
|
||||
</g>
|
||||
<g id="shape1-36" v:mID="1" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="35.4331" cy="610.077" width="42.88" height="29.6036"/>
|
||||
<text x="20.03" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NAT</text> </g>
|
||||
</g>
|
||||
<g id="group4-38" transform="translate(701.575,-311.811)" v:mID="4" v:groupContext="group">
|
||||
<v:custProps>
|
||||
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Memory" v:lbl="内存" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="OperatingSystem" v:lbl="操作系统" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="HardDriveSize" v:lbl="硬盘容量" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
|
||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(服务器)"/>
|
||||
<v:cp v:nameU="BelongsTo" v:lbl="属于" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
</v:custProps>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
||||
</v:userDefs>
|
||||
<title>服务器</title>
|
||||
<desc>Application2 10.0.0.4:PORT</desc>
|
||||
<g id="shape5-39" v:mID="5" v:groupContext="shape" transform="translate(12.8133,0)">
|
||||
<title>工作表.5</title>
|
||||
<rect x="0" y="524.409" width="45.2395" height="70.8661" class="st1"/>
|
||||
</g>
|
||||
<g id="shape6-41" v:mID="6" v:groupContext="shape" transform="translate(46.625,-30.2513)">
|
||||
<title>工作表.6</title>
|
||||
<ellipse cx="2.73472" cy="592.541" rx="2.73472" ry="2.73472" class="st4"/>
|
||||
</g>
|
||||
<g id="shape7-43" v:mID="7" v:groupContext="shape" transform="translate(30.0295,-11.6164)">
|
||||
<title>工作表.7</title>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
|
||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
|
||||
</v:userDefs>
|
||||
<path d="M-0 595.28 L22.06 595.28 L22.06 593.5 L-0 593.5 L-0 595.28 ZM-0 589.9 L22.06 589.9 L22.06 588.13 L-0 588.13
|
||||
L-0 589.9 ZM-0 584.53 L22.06 584.53 L22.06 582.76 L-0 582.76 L-0 584.53 Z" class="st5"/>
|
||||
</g>
|
||||
<g id="shape4-46" v:mID="4" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="35.4331" cy="620.877" width="115.9" height="51.2036"/>
|
||||
<text x="-10.6" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Application2<v:newlineChar/><tspan
|
||||
x="-16.48" dy="1.2em" class="st6">10.0.0.4:PORT</tspan></text> </g>
|
||||
</g>
|
||||
<g id="group8-49" transform="translate(701.575,-496.063)" v:mID="8" v:groupContext="group">
|
||||
<v:custProps>
|
||||
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Memory" v:lbl="内存" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="OperatingSystem" v:lbl="操作系统" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="HardDriveSize" v:lbl="硬盘容量" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
|
||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(服务器)"/>
|
||||
<v:cp v:nameU="BelongsTo" v:lbl="属于" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
</v:custProps>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
||||
</v:userDefs>
|
||||
<title>服务器.8</title>
|
||||
<desc>Application1 10.0.0.3:PORT</desc>
|
||||
<g id="shape9-50" v:mID="9" v:groupContext="shape" transform="translate(12.8133,0)">
|
||||
<title>工作表.9</title>
|
||||
<rect x="0" y="524.409" width="45.2395" height="70.8661" class="st1"/>
|
||||
</g>
|
||||
<g id="shape10-52" v:mID="10" v:groupContext="shape" transform="translate(46.625,-30.2513)">
|
||||
<title>工作表.10</title>
|
||||
<ellipse cx="2.73472" cy="592.541" rx="2.73472" ry="2.73472" class="st4"/>
|
||||
</g>
|
||||
<g id="shape11-54" v:mID="11" v:groupContext="shape" transform="translate(30.0295,-11.6164)">
|
||||
<title>工作表.11</title>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
|
||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
|
||||
</v:userDefs>
|
||||
<path d="M-0 595.28 L22.06 595.28 L22.06 593.5 L-0 593.5 L-0 595.28 ZM-0 589.9 L22.06 589.9 L22.06 588.13 L-0 588.13
|
||||
L-0 589.9 ZM-0 584.53 L22.06 584.53 L22.06 582.76 L-0 582.76 L-0 584.53 Z" class="st5"/>
|
||||
</g>
|
||||
<g id="shape8-57" v:mID="8" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="35.4331" cy="620.877" width="115.9" height="51.2036"/>
|
||||
<text x="-10.6" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Application1<v:newlineChar/><tspan
|
||||
x="-16.48" dy="1.2em" class="st6">10.0.0.3:PORT</tspan></text> </g>
|
||||
</g>
|
||||
<g id="group12-60" transform="translate(701.575,-127.559)" v:mID="12" v:groupContext="group">
|
||||
<v:custProps>
|
||||
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="CPU" v:lbl="CPU" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Memory" v:lbl="内存" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="OperatingSystem" v:lbl="操作系统" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="HardDriveSize" v:lbl="硬盘容量" v:prompt="" v:type="0" v:format="" v:sortKey="Workstation"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
|
||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(服务器)"/>
|
||||
<v:cp v:nameU="BelongsTo" v:lbl="属于" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
</v:custProps>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
||||
</v:userDefs>
|
||||
<title>服务器.12</title>
|
||||
<desc>Application3 10.0.0.5:PORT</desc>
|
||||
<g id="shape13-61" v:mID="13" v:groupContext="shape" transform="translate(12.8133,0)">
|
||||
<title>工作表.13</title>
|
||||
<rect x="0" y="524.409" width="45.2395" height="70.8661" class="st1"/>
|
||||
</g>
|
||||
<g id="shape14-63" v:mID="14" v:groupContext="shape" transform="translate(46.625,-30.2513)">
|
||||
<title>工作表.14</title>
|
||||
<ellipse cx="2.73472" cy="592.541" rx="2.73472" ry="2.73472" class="st4"/>
|
||||
</g>
|
||||
<g id="shape15-65" v:mID="15" v:groupContext="shape" transform="translate(30.0295,-11.6164)">
|
||||
<title>工作表.15</title>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
|
||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
|
||||
</v:userDefs>
|
||||
<path d="M-0 595.28 L22.06 595.28 L22.06 593.5 L-0 593.5 L-0 595.28 ZM-0 589.9 L22.06 589.9 L22.06 588.13 L-0 588.13
|
||||
L-0 589.9 ZM-0 584.53 L22.06 584.53 L22.06 582.76 L-0 582.76 L-0 584.53 Z" class="st5"/>
|
||||
</g>
|
||||
<g id="shape12-68" v:mID="12" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="35.4331" cy="620.877" width="115.9" height="51.2036"/>
|
||||
<text x="-10.6" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Application3<v:newlineChar/><tspan
|
||||
x="-16.48" dy="1.2em" class="st6">10.0.0.5:PORT</tspan></text> </g>
|
||||
</g>
|
||||
<g id="group16-71" transform="translate(538.583,-311.811)" v:mID="16" v:groupContext="group">
|
||||
<v:custProps>
|
||||
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Building" v:lbl="建筑物" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
|
||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(计算机)"/>
|
||||
<v:cp v:nameU="SubShapeType" v:lbl="SubShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(大型机)"/>
|
||||
</v:custProps>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
||||
</v:userDefs>
|
||||
<title>主机</title>
|
||||
<desc>NPC Client 10.0.0.2 Dial To: ->10.0.0.3:PORT ->10.0.0.4:PORT ...</desc>
|
||||
<g id="shape17-72" v:mID="17" v:groupContext="shape" transform="translate(5.68158,0)">
|
||||
<title>工作表.17</title>
|
||||
<path d="M0 595.28 L59.5 595.28 L59.5 524.41 L0 524.41 L0 595.28 Z" class="st7"/>
|
||||
<path d="M0 595.28 L59.5 595.28 L59.5 524.41 L0 524.41 L0 595.28" class="st8"/>
|
||||
<path d="M29.75 595.28 L29.75 524.41" class="st8"/>
|
||||
</g>
|
||||
<g id="shape18-76" v:mID="18" v:groupContext="shape" transform="translate(11.5726,-5.14536)">
|
||||
<title>工作表.18</title>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
|
||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
|
||||
</v:userDefs>
|
||||
<path d="M36.09 551.42 L49.23 551.42 L49.23 536.38 L36.09 536.38 L36.09 551.42 ZM14.89 542.47 L16.68 542.47 L16.68
|
||||
536.06 L14.89 536.06 L14.89 542.47 ZM14.89 551.71 L16.68 551.71 L16.68 545.3 L14.89 545.3 L14.89 551.71
|
||||
ZM10.63 542.47 L12.43 542.47 L12.43 536.06 L10.63 536.06 L10.63 542.47 ZM10.63 551.71 L12.43 551.71
|
||||
L12.43 545.3 L10.63 545.3 L10.63 551.71 ZM4.25 542.47 L6.05 542.47 L6.05 536.06 L4.25 536.06 L4.25 542.47
|
||||
ZM4.25 551.71 L6.05 551.71 L6.05 545.3 L4.25 545.3 L4.25 551.71 ZM0 542.47 L1.79 542.47 L1.79 536.06
|
||||
L0 536.06 L0 542.47 ZM0 551.71 L1.79 551.71 L1.79 545.3 L0 545.3 L0 551.71 ZM33.82 586.45 L33.82 587.7
|
||||
L49.39 587.69 L49.39 586.44 L33.82 586.45 ZM33.82 590.24 L33.82 591.49 L49.39 591.48 L49.39 590.24 L33.82
|
||||
590.24 ZM33.82 594.03 L33.82 595.28 L49.39 595.27 L49.39 594.03 L33.82 594.03 ZM2.96 587.7 L18.52 587.7
|
||||
L18.52 586.45 L2.95 586.45 L2.96 587.7 ZM2.96 591.49 L18.52 591.49 L18.52 590.24 L2.95 590.24 L2.96
|
||||
591.49 ZM2.96 595.28 L18.52 595.28 L18.52 594.03 L2.95 594.03 L2.96 595.28 Z" class="st5"/>
|
||||
</g>
|
||||
<g id="shape19-79" v:mID="19" v:groupContext="shape" transform="translate(49.0815,-50.4059)">
|
||||
<title>工作表.19</title>
|
||||
<path d="M8.15 583.79 A1.11073 1.11073 -180 1 0 10.24 584.56 A1.11073 1.11073 -180 1 0 8.15 583.79 ZM8.17 587.08
|
||||
A1.11073 1.11073 -180 1 0 10.22 587.93 A1.11073 1.11073 -180 1 0 8.17 587.08 ZM8.18 590.39 A1.11073
|
||||
1.11073 -180 1 0 10.21 591.28 A1.11073 1.11073 -180 1 0 8.18 590.39 ZM8.18 593.71 A1.11073 1.11073 -180
|
||||
1 0 10.21 594.6 A1.11073 1.11073 -180 1 0 8.18 593.71 ZM4.1 583.84 A1.11073 1.11073 -180 1 0 6.21 584.51
|
||||
A1.11073 1.11073 -180 1 0 4.1 583.84 ZM4.11 587.14 A1.11073 1.11073 -180 1 0 6.2 587.87 A1.11073 1.11073
|
||||
-180 1 0 4.11 587.14 ZM4.11 590.44 A1.11073 1.11073 -180 1 0 6.19 591.22 A1.11073 1.11073 -180 1 0 4.11
|
||||
590.44 ZM4.11 593.77 A1.11073 1.11073 -180 1 0 6.19 594.55 A1.11073 1.11073 -180 1 0 4.11 593.77 ZM0.04
|
||||
583.9 A1.11144 1.11144 -180 1 0 2.19 584.46 A1.11144 1.11144 -180 1 0 0.04 583.9 ZM0.05 587.19 A1.11144
|
||||
1.11144 -180 1 0 2.18 587.82 A1.11144 1.11144 -180 1 0 0.05 587.19 ZM0.05 590.5 A1.11144 1.11144 -180
|
||||
1 0 2.17 591.16 A1.11144 1.11144 -180 1 0 0.05 590.5 ZM0.05 593.83 A1.11144 1.11144 -180 1 0 2.17 594.49
|
||||
A1.11144 1.11144 -180 1 0 0.05 593.83 Z" class="st9"/>
|
||||
</g>
|
||||
<g id="shape16-82" v:mID="16" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="35.4331" cy="674.877" width="130.38" height="159.204"/>
|
||||
<text x="20.18" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NPC<v:newlineChar/><tspan
|
||||
x="14.28" dy="1.2em" class="st6">Client<v:newlineChar/></tspan><tspan x="5.81" dy="1.2em" class="st6">10.0.0.2<v:newlineChar/></tspan><tspan
|
||||
x="7.88" dy="1.2em" class="st6">Dial To:<v:newlineChar/></tspan><tspan x="-23.72" dy="1.2em"
|
||||
class="st6">-</tspan>>10.0.0.3:PORT<v:newlineChar/><tspan x="-23.72" dy="1.2em" class="st6">-</tspan>>10.0.0.4:PORT<v:newlineChar/><tspan
|
||||
x="-23.72" dy="1.2em" class="st6">-</tspan>>10.0.0.5:PORT</text> </g>
|
||||
</g>
|
||||
<g id="group20-90" transform="translate(212.598,-311.811)" v:mID="20" v:groupContext="group">
|
||||
<v:custProps>
|
||||
<v:cp v:nameU="AssetNumber" v:lbl="资产号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="SerialNumber" v:lbl="序列号" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Building" v:lbl="建筑物" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="Asset" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Manufacturer" v:lbl="制造商" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ProductNumber" v:lbl="产品编号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="PartNumber" v:lbl="部件号" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ProductDescription" v:lbl="产品说明" v:prompt="" v:type="0" v:format="" v:sortKey="Equipment"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NetworkName" v:lbl="网络名称" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="IPAddress" v:lbl="IP 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="SubnetMask" v:lbl="子网掩码" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="AdminInterface" v:lbl="管理接口" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NumberofPorts" v:lbl="端口数目" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="CommunityString" v:lbl="团体字符串" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="NetworkDescription" v:lbl="网络说明" v:prompt="" v:type="0" v:format="" v:sortKey="Network"
|
||||
v:invis="false" v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="MACAddress" v:lbl="MAC 地址" v:prompt="" v:type="0" v:format="" v:sortKey="Network" v:invis="false"
|
||||
v:ask="false" v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(设备)"/>
|
||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(计算机)"/>
|
||||
<v:cp v:nameU="SubShapeType" v:lbl="SubShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(大型机)"/>
|
||||
</v:custProps>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
||||
</v:userDefs>
|
||||
<title>主机.20</title>
|
||||
<desc>NPS Server 1.1.1.1 Listen On: 8003->10.0.0.3:PORT 8004->10.0....</desc>
|
||||
<g id="shape21-91" v:mID="21" v:groupContext="shape" transform="translate(5.68158,0)">
|
||||
<title>工作表.21</title>
|
||||
<path d="M0 595.28 L59.5 595.28 L59.5 524.41 L0 524.41 L0 595.28 Z" class="st7"/>
|
||||
<path d="M0 595.28 L59.5 595.28 L59.5 524.41 L0 524.41 L0 595.28" class="st8"/>
|
||||
<path d="M29.75 595.28 L29.75 524.41" class="st8"/>
|
||||
</g>
|
||||
<g id="shape22-95" v:mID="22" v:groupContext="shape" transform="translate(11.5726,-5.14536)">
|
||||
<title>工作表.22</title>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(1)"/>
|
||||
<v:ud v:nameU="SurroundingRegionColor" v:prompt="" v:val="VT5(#5b9bd5)"/>
|
||||
</v:userDefs>
|
||||
<path d="M36.09 551.42 L49.23 551.42 L49.23 536.38 L36.09 536.38 L36.09 551.42 ZM14.89 542.47 L16.68 542.47 L16.68
|
||||
536.06 L14.89 536.06 L14.89 542.47 ZM14.89 551.71 L16.68 551.71 L16.68 545.3 L14.89 545.3 L14.89 551.71
|
||||
ZM10.63 542.47 L12.43 542.47 L12.43 536.06 L10.63 536.06 L10.63 542.47 ZM10.63 551.71 L12.43 551.71
|
||||
L12.43 545.3 L10.63 545.3 L10.63 551.71 ZM4.25 542.47 L6.05 542.47 L6.05 536.06 L4.25 536.06 L4.25 542.47
|
||||
ZM4.25 551.71 L6.05 551.71 L6.05 545.3 L4.25 545.3 L4.25 551.71 ZM0 542.47 L1.79 542.47 L1.79 536.06
|
||||
L0 536.06 L0 542.47 ZM0 551.71 L1.79 551.71 L1.79 545.3 L0 545.3 L0 551.71 ZM33.82 586.45 L33.82 587.7
|
||||
L49.39 587.69 L49.39 586.44 L33.82 586.45 ZM33.82 590.24 L33.82 591.49 L49.39 591.48 L49.39 590.24 L33.82
|
||||
590.24 ZM33.82 594.03 L33.82 595.28 L49.39 595.27 L49.39 594.03 L33.82 594.03 ZM2.96 587.7 L18.52 587.7
|
||||
L18.52 586.45 L2.95 586.45 L2.96 587.7 ZM2.96 591.49 L18.52 591.49 L18.52 590.24 L2.95 590.24 L2.96
|
||||
591.49 ZM2.96 595.28 L18.52 595.28 L18.52 594.03 L2.95 594.03 L2.96 595.28 Z" class="st5"/>
|
||||
</g>
|
||||
<g id="shape23-98" v:mID="23" v:groupContext="shape" transform="translate(49.0815,-50.4059)">
|
||||
<title>工作表.23</title>
|
||||
<path d="M8.15 583.79 A1.11073 1.11073 -180 1 0 10.24 584.56 A1.11073 1.11073 -180 1 0 8.15 583.79 ZM8.17 587.08
|
||||
A1.11073 1.11073 -180 1 0 10.22 587.93 A1.11073 1.11073 -180 1 0 8.17 587.08 ZM8.18 590.39 A1.11073
|
||||
1.11073 -180 1 0 10.21 591.28 A1.11073 1.11073 -180 1 0 8.18 590.39 ZM8.18 593.71 A1.11073 1.11073 -180
|
||||
1 0 10.21 594.6 A1.11073 1.11073 -180 1 0 8.18 593.71 ZM4.1 583.84 A1.11073 1.11073 -180 1 0 6.21 584.51
|
||||
A1.11073 1.11073 -180 1 0 4.1 583.84 ZM4.11 587.14 A1.11073 1.11073 -180 1 0 6.2 587.87 A1.11073 1.11073
|
||||
-180 1 0 4.11 587.14 ZM4.11 590.44 A1.11073 1.11073 -180 1 0 6.19 591.22 A1.11073 1.11073 -180 1 0 4.11
|
||||
590.44 ZM4.11 593.77 A1.11073 1.11073 -180 1 0 6.19 594.55 A1.11073 1.11073 -180 1 0 4.11 593.77 ZM0.04
|
||||
583.9 A1.11144 1.11144 -180 1 0 2.19 584.46 A1.11144 1.11144 -180 1 0 0.04 583.9 ZM0.05 587.19 A1.11144
|
||||
1.11144 -180 1 0 2.18 587.82 A1.11144 1.11144 -180 1 0 0.05 587.19 ZM0.05 590.5 A1.11144 1.11144 -180
|
||||
1 0 2.17 591.16 A1.11144 1.11144 -180 1 0 0.05 590.5 ZM0.05 593.83 A1.11144 1.11144 -180 1 0 2.17 594.49
|
||||
A1.11144 1.11144 -180 1 0 0.05 593.83 Z" class="st9"/>
|
||||
</g>
|
||||
<g id="shape20-101" v:mID="20" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="35.4331" cy="674.877" width="166.87" height="159.204"/>
|
||||
<text x="20.84" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NPS<v:newlineChar/><tspan
|
||||
x="12" dy="1.2em" class="st6">Server<v:newlineChar/></tspan><tspan x="10.37" dy="1.2em" class="st6">1.1.1.1<v:newlineChar/></tspan><tspan
|
||||
x="-1.29" dy="1.2em" class="st6">Listen On:<v:newlineChar/></tspan><tspan x="-41.96" dy="1.2em"
|
||||
class="st6">8003</tspan>->10.0.0.3:PORT<v:newlineChar/><tspan x="-41.96" dy="1.2em" class="st6">8004</tspan>->10.0.0.4:PORT<v:newlineChar/><tspan
|
||||
x="-41.96" dy="1.2em" class="st6">8005</tspan>->10.0.0.5:PORT</text> </g>
|
||||
</g>
|
||||
<g id="group24-109" transform="translate(49.6063,-496.063)" v:mID="24" v:groupContext="group">
|
||||
<v:custProps>
|
||||
<v:cp v:nameU="Name" v:lbl="名称" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(连接性)"/>
|
||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(用户)"/>
|
||||
</v:custProps>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
||||
</v:userDefs>
|
||||
<title>用户</title>
|
||||
<desc>User1 Wants:APP1</desc>
|
||||
<g id="shape25-110" v:mID="25" v:groupContext="shape" transform="translate(18.0575,0)">
|
||||
<title>工作表.25</title>
|
||||
<path d="M26.29 533.22 A8.81 8.81 -180 1 0 8.67 533.22 A8.81 8.81 -180 1 0 26.29 533.22 ZM27.58 544.41 L7.17 544.41
|
||||
C3.22 544.41 0 547.62 0 551.58 L0 576.58 L5.59 576.58 L5.59 562.03 L7.45 562.03 L7.45 595.28 L16.55
|
||||
595.28 L16.55 580.42 C16.55 579.9 16.97 579.48 17.48 579.48 C18 579.48 18.42 579.9 18.42 580.42 L18.42
|
||||
595.28 L28.04 595.28 L28.04 561.98 L29.91 561.98 L29.91 576.58 L34.75 576.58 L34.75 551.58 C34.75 547.62
|
||||
31.54 544.41 27.58 544.41 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape24-112" v:mID="24" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="35.4331" cy="620.877" width="102.19" height="51.2036"/>
|
||||
<text x="13.96" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>User1<v:newlineChar/><tspan
|
||||
x="-9.62" dy="1.2em" class="st6">Wants:APP1</tspan></text> </g>
|
||||
</g>
|
||||
<g id="group26-115" transform="translate(49.6063,-311.811)" v:mID="26" v:groupContext="group">
|
||||
<v:custProps>
|
||||
<v:cp v:nameU="Name" v:lbl="名称" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(连接性)"/>
|
||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(用户)"/>
|
||||
</v:custProps>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
||||
</v:userDefs>
|
||||
<title>用户.26</title>
|
||||
<desc>User2 Wants:APP2</desc>
|
||||
<g id="shape27-116" v:mID="27" v:groupContext="shape" transform="translate(18.0575,0)">
|
||||
<title>工作表.27</title>
|
||||
<path d="M26.29 533.22 A8.81 8.81 -180 1 0 8.67 533.22 A8.81 8.81 -180 1 0 26.29 533.22 ZM27.58 544.41 L7.17 544.41
|
||||
C3.22 544.41 0 547.62 0 551.58 L0 576.58 L5.59 576.58 L5.59 562.03 L7.45 562.03 L7.45 595.28 L16.55
|
||||
595.28 L16.55 580.42 C16.55 579.9 16.97 579.48 17.48 579.48 C18 579.48 18.42 579.9 18.42 580.42 L18.42
|
||||
595.28 L28.04 595.28 L28.04 561.98 L29.91 561.98 L29.91 576.58 L34.75 576.58 L34.75 551.58 C34.75 547.62
|
||||
31.54 544.41 27.58 544.41 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape26-118" v:mID="26" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="35.4331" cy="620.877" width="102.19" height="51.2036"/>
|
||||
<text x="13.96" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>User2<v:newlineChar/><tspan
|
||||
x="-9.62" dy="1.2em" class="st6">Wants:APP2</tspan></text> </g>
|
||||
</g>
|
||||
<g id="group28-121" transform="translate(49.6063,-127.559)" v:mID="28" v:groupContext="group">
|
||||
<v:custProps>
|
||||
<v:cp v:nameU="Name" v:lbl="名称" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Location" v:lbl="位置" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Building" v:lbl="构建" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Room" v:lbl="空间" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="Department" v:lbl="部门" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="false" v:ask="false"
|
||||
v:langID="2052" v:cal="0"/>
|
||||
<v:cp v:nameU="ShapeClass" v:lbl="ShapeClass" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(连接性)"/>
|
||||
<v:cp v:nameU="ShapeType" v:lbl="ShapeType" v:prompt="" v:type="0" v:format="" v:sortKey="" v:invis="true"
|
||||
v:ask="false" v:langID="2052" v:cal="0" v:val="VT4(用户)"/>
|
||||
</v:custProps>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
<v:ud v:nameU="ShapeClass" v:prompt="" v:val="VT0(5):26"/>
|
||||
<v:ud v:nameU="SolSH" v:prompt="" v:val="VT15({BF0433D9-CD73-4EB5-8390-8653BE590246}):41"/>
|
||||
<v:ud v:nameU="visLegendShape" v:prompt="" v:val="VT0(2):26"/>
|
||||
</v:userDefs>
|
||||
<title>用户.28</title>
|
||||
<desc>User3 Wants:APP3</desc>
|
||||
<g id="shape29-122" v:mID="29" v:groupContext="shape" transform="translate(18.0575,0)">
|
||||
<title>工作表.29</title>
|
||||
<path d="M26.29 533.22 A8.81 8.81 -180 1 0 8.67 533.22 A8.81 8.81 -180 1 0 26.29 533.22 ZM27.58 544.41 L7.17 544.41
|
||||
C3.22 544.41 0 547.62 0 551.58 L0 576.58 L5.59 576.58 L5.59 562.03 L7.45 562.03 L7.45 595.28 L16.55
|
||||
595.28 L16.55 580.42 C16.55 579.9 16.97 579.48 17.48 579.48 C18 579.48 18.42 579.9 18.42 580.42 L18.42
|
||||
595.28 L28.04 595.28 L28.04 561.98 L29.91 561.98 L29.91 576.58 L34.75 576.58 L34.75 551.58 C34.75 547.62
|
||||
31.54 544.41 27.58 544.41 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape28-124" v:mID="28" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="35.4331" cy="620.877" width="102.19" height="51.2036"/>
|
||||
<text x="13.96" y="615.48" class="st3" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>User3<v:newlineChar/><tspan
|
||||
x="-9.62" dy="1.2em" class="st6">Wants:APP3</tspan></text> </g>
|
||||
</g>
|
||||
<g id="shape1003-127" v:mID="1003" v:groupContext="shape" v:layerMember="0" transform="translate(99.8466,-514.757)">
|
||||
<title>动态连接线.1003</title>
|
||||
<desc>->8003 Multi Conn</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="56.059" cy="684.836" width="93.29" height="51.2036"/>
|
||||
<path d="M5.09 601.03 L5.33 601.3 L113.11 723.13" class="st10"/>
|
||||
<rect v:rectContext="textBkgnd" x="15.4535" y="663.236" width="81.2109" height="43.1999" class="st12"/>
|
||||
<text x="30.58" y="679.44" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>->8003<v:newlineChar/><tspan
|
||||
x="15.45" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
|
||||
<g id="shape1004-139" v:mID="1004" v:groupContext="shape" v:layerMember="0" transform="translate(102.415,-340.157)">
|
||||
<title>动态连接线.1004</title>
|
||||
<desc>->8004 Multi Conn</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="57.9325" cy="588.189" width="93.29" height="51.2036"/>
|
||||
<path d="M7.68 588.19 L8.04 588.19 L107.83 588.19" class="st10"/>
|
||||
<rect v:rectContext="textBkgnd" x="17.327" y="566.589" width="81.2109" height="43.1999" class="st12"/>
|
||||
<text x="32.45" y="582.79" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>->8004<v:newlineChar/><tspan
|
||||
x="17.33" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
|
||||
<g id="shape1005-149" v:mID="1005" v:groupContext="shape" v:layerMember="0" transform="translate(98.1493,-177.812)">
|
||||
<title>动态连接线.1005</title>
|
||||
<desc>->8005 Multi Conn</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="60.0654" cy="527.376" width="93.29" height="51.2036"/>
|
||||
<path d="M5.09 589.52 L5.33 589.25 L114.8 465.5" class="st10"/>
|
||||
<rect v:rectContext="textBkgnd" x="19.4599" y="505.776" width="81.2109" height="43.1999" class="st12"/>
|
||||
<text x="34.58" y="521.98" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>->8005<v:newlineChar/><tspan
|
||||
x="19.46" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
|
||||
<g id="shape1006-159" v:mID="1006" v:groupContext="shape" v:layerMember="0" transform="translate(277.783,-354.331)">
|
||||
<title>动态连接线.1006</title>
|
||||
<desc>NPS & NPC Multiplexing Connection TCP or KCP Only One Conn Pe...</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="70.4362" cy="602.362" width="103.62" height="159.204"/>
|
||||
<path d="M7.68 602.36 L8.04 602.36 L132.83 602.36" class="st10"/>
|
||||
<rect v:rectContext="textBkgnd" x="24.6671" y="526.762" width="91.5381" height="151.2" class="st12"/>
|
||||
<text x="30.38" y="542.96" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NPS & NPC<v:newlineChar/><tspan
|
||||
x="24.67" dy="1.2em" class="st6">Multiplexing<v:newlineChar/></tspan><tspan x="28.6" dy="1.2em" class="st6">Connection<v:newlineChar/></tspan><tspan
|
||||
x="30.53" dy="1.2em" class="st6">TCP or KCP<v:newlineChar/></tspan><tspan x="36.41" dy="1.2em" class="st6">Only One<v:newlineChar/></tspan><tspan
|
||||
x="32.66" dy="1.2em" class="st6">Conn Peer<v:newlineChar/></tspan><tspan x="55.18" dy="1.2em" class="st6">NPC</tspan></text> </g>
|
||||
<g id="shape1007-174" v:mID="1007" v:groupContext="shape" v:layerMember="0" transform="translate(603.767,-380.876)">
|
||||
<title>动态连接线.1007</title>
|
||||
<desc>->PORT Multi Conn</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="55.0044" cy="550.955" width="93.29" height="51.2036"/>
|
||||
<path d="M5.09 589.52 L5.33 589.25 L105.29 476.25" class="st10"/>
|
||||
<rect v:rectContext="textBkgnd" x="14.3989" y="529.355" width="81.2109" height="43.1999" class="st12"/>
|
||||
<text x="27.89" y="545.56" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>->PORT<v:newlineChar/><tspan
|
||||
x="14.4" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
|
||||
<g id="shape1008-184" v:mID="1008" v:groupContext="shape" v:layerMember="0" transform="translate(603.767,-340.157)">
|
||||
<title>动态连接线.1008</title>
|
||||
<desc>->PORT Multi Conn</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="55.3104" cy="588.189" width="93.29" height="51.2036"/>
|
||||
<path d="M7.68 588.19 L8.04 588.19 L102.58 588.19" class="st10"/>
|
||||
<rect v:rectContext="textBkgnd" x="14.7049" y="566.589" width="81.2109" height="43.1999" class="st12"/>
|
||||
<text x="28.19" y="582.79" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>->PORT<v:newlineChar/><tspan
|
||||
x="14.7" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
|
||||
<g id="shape1009-194" v:mID="1009" v:groupContext="shape" v:layerMember="0" transform="translate(603.767,-313.612)">
|
||||
<title>动态连接线.1009</title>
|
||||
<desc>->PORT Multi Conn</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="68.0438" cy="667.943" width="93.29" height="51.2036"/>
|
||||
<path d="M5.09 601.03 L5.33 601.3 L105.29 714.3" class="st10"/>
|
||||
<rect v:rectContext="textBkgnd" x="27.4383" y="646.343" width="81.2109" height="43.1999" class="st12"/>
|
||||
<text x="40.93" y="662.54" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>->PORT<v:newlineChar/><tspan
|
||||
x="27.44" dy="1.2em" class="st6">Multi Conn</tspan></text> </g>
|
||||
<g id="shape1010-204" v:mID="1010" v:groupContext="shape" v:layerMember="0" transform="translate(488.431,-340.157)">
|
||||
<title>动态连接线.1010</title>
|
||||
<desc>NPS & NPC</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:prompt="" v:val="VT0(15):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="27.9165" cy="588.189" width="90" height="72.8036"/>
|
||||
<path d="M7.68 588.19 L8.04 588.19 L47.79 588.19" class="st10"/>
|
||||
<rect v:rectContext="textBkgnd" x="12.6587" y="555.789" width="30.5156" height="64.7998" class="st12"/>
|
||||
<text x="13.32" y="571.99" class="st13" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>NPS<v:newlineChar/><tspan
|
||||
x="21.78" dy="1.2em" class="st6">&<v:newlineChar/></tspan><tspan x="12.66" dy="1.2em" class="st6">NPC</tspan></text> </g>
|
||||
<g id="shape1011-215" v:mID="1011" v:groupContext="shape" transform="translate(34.0157,-62.8844)">
|
||||
<title>工作表.1011</title>
|
||||
<path d="M0 595.28 L398.27 595.28 L398.27 85.04 L0 85.04 L0 595.28 Z" class="st14"/>
|
||||
</g>
|
||||
<g id="shape1012-217" v:mID="1012" v:groupContext="shape" transform="translate(473.386,-62.8844)">
|
||||
<title>工作表.1012</title>
|
||||
<path d="M0 595.28 L320.31 595.28 L320.31 85.04 L0 85.04 L0 595.28 Z" class="st14"/>
|
||||
</g>
|
||||
<g id="shape1013-219" v:mID="1013" v:groupContext="shape" transform="translate(255.118,-496.063)">
|
||||
<title>工作表.1013</title>
|
||||
<desc>Internet</desc>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="63.7795" cy="559.843" width="127.56" height="70.8661"/>
|
||||
<rect x="0" y="524.409" width="127.559" height="70.8661" class="st15"/>
|
||||
<text x="23.98" y="567.04" class="st16" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Internet</text> </g>
|
||||
<g id="shape1014-222" v:mID="1014" v:groupContext="shape" transform="translate(517.323,-515.866)">
|
||||
<title>工作表.1014</title>
|
||||
<desc>Intranet</desc>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="76" cy="579.646" width="152.01" height="31.2598"/>
|
||||
<rect x="0" y="564.016" width="152" height="31.2598" class="st15"/>
|
||||
<text x="36.43" y="586.85" class="st16" v:langID="2052"><v:paragraph v:horizAlign="1"/><v:tabList/>Intranet</text> </g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 58 KiB |
@ -36,3 +36,19 @@ WWW-Authenticate: Basic realm="easyProxy"
|
||||
|
||||
`
|
||||
)
|
||||
|
||||
const (
|
||||
MUX_PING_FLAG uint8 = iota
|
||||
MUX_NEW_CONN_OK
|
||||
MUX_NEW_CONN_Fail
|
||||
MUX_NEW_MSG
|
||||
MUX_NEW_MSG_PART
|
||||
MUX_MSG_SEND_OK
|
||||
MUX_NEW_CONN
|
||||
MUX_CONN_CLOSE
|
||||
MUX_PING_RETURN
|
||||
MUX_PING int32 = -1
|
||||
MAXIMUM_SEGMENT_SIZE = PoolSizeWindow
|
||||
MAXIMUM_WINDOW_SIZE = 1 << 25 // 1<<31-1 TCP slide window size is very large,
|
||||
// we use 32M, reduce memory usage
|
||||
)
|
||||
|
@ -3,11 +3,13 @@ package common
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type NetPackager interface {
|
||||
@ -15,6 +17,235 @@ type NetPackager interface {
|
||||
UnPack(reader io.Reader) (err error)
|
||||
}
|
||||
|
||||
type BasePackager struct {
|
||||
Length uint16
|
||||
Content []byte
|
||||
}
|
||||
|
||||
func (Self *BasePackager) NewPac(contents ...interface{}) (err error) {
|
||||
Self.clean()
|
||||
for _, content := range contents {
|
||||
switch content.(type) {
|
||||
case nil:
|
||||
Self.Content = Self.Content[:0]
|
||||
case []byte:
|
||||
err = Self.appendByte(content.([]byte))
|
||||
case string:
|
||||
err = Self.appendByte([]byte(content.(string)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = Self.appendByte([]byte(CONN_DATA_SEQ))
|
||||
default:
|
||||
err = Self.marshal(content)
|
||||
}
|
||||
}
|
||||
Self.setLength()
|
||||
if Self.Length > MAXIMUM_SEGMENT_SIZE {
|
||||
err = errors.New("mux:packer: newpack content segment too large")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *BasePackager) appendByte(data []byte) (err error) {
|
||||
m := len(Self.Content)
|
||||
n := m + len(data)
|
||||
if n <= cap(Self.Content) {
|
||||
Self.Content = Self.Content[0:n] // grow the length for copy
|
||||
copy(Self.Content[m:n], data)
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("pack content too large")
|
||||
}
|
||||
}
|
||||
|
||||
//似乎这里涉及到父类作用域问题,当子类调用父类的方法时,其struct仅仅为父类的
|
||||
func (Self *BasePackager) Pack(writer io.Writer) (err error) {
|
||||
err = binary.Write(writer, binary.LittleEndian, Self.Length)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = binary.Write(writer, binary.LittleEndian, Self.Content)
|
||||
return
|
||||
}
|
||||
|
||||
//Unpack 会导致传入的数字类型转化成float64!!
|
||||
//主要原因是json unmarshal并未传入正确的数据类型
|
||||
func (Self *BasePackager) UnPack(reader io.Reader) (n uint16, err error) {
|
||||
Self.clean()
|
||||
n += 2 // uint16
|
||||
err = binary.Read(reader, binary.LittleEndian, &Self.Length)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if int(Self.Length) > cap(Self.Content) {
|
||||
err = errors.New("unpack err, content length too large")
|
||||
return
|
||||
}
|
||||
if Self.Length > MAXIMUM_SEGMENT_SIZE {
|
||||
err = errors.New("mux:packer: unpack content segment too large")
|
||||
return
|
||||
}
|
||||
Self.Content = Self.Content[:int(Self.Length)]
|
||||
//n, err := io.ReadFull(reader, Self.Content)
|
||||
//if n != int(Self.Length) {
|
||||
// err = io.ErrUnexpectedEOF
|
||||
//}
|
||||
err = binary.Read(reader, binary.LittleEndian, Self.Content)
|
||||
n += Self.Length
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *BasePackager) marshal(content interface{}) (err error) {
|
||||
tmp, err := json.Marshal(content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = Self.appendByte(tmp)
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *BasePackager) Unmarshal(content interface{}) (err error) {
|
||||
err = json.Unmarshal(Self.Content, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *BasePackager) setLength() {
|
||||
Self.Length = uint16(len(Self.Content))
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *BasePackager) clean() {
|
||||
Self.Length = 0
|
||||
Self.Content = Self.Content[:0] // reset length
|
||||
}
|
||||
|
||||
func (Self *BasePackager) Split() (strList []string) {
|
||||
n := bytes.IndexByte(Self.Content, 0)
|
||||
strList = strings.Split(string(Self.Content[:n]), CONN_DATA_SEQ)
|
||||
strList = strList[0 : len(strList)-1]
|
||||
return
|
||||
}
|
||||
|
||||
type ConnPackager struct {
|
||||
// Todo
|
||||
ConnType uint8
|
||||
BasePackager
|
||||
}
|
||||
|
||||
func (Self *ConnPackager) NewPac(connType uint8, content ...interface{}) (err error) {
|
||||
Self.ConnType = connType
|
||||
err = Self.BasePackager.NewPac(content...)
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *ConnPackager) Pack(writer io.Writer) (err error) {
|
||||
err = binary.Write(writer, binary.LittleEndian, Self.ConnType)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = Self.BasePackager.Pack(writer)
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *ConnPackager) UnPack(reader io.Reader) (n uint16, err error) {
|
||||
err = binary.Read(reader, binary.LittleEndian, &Self.ConnType)
|
||||
if err != nil && err != io.EOF {
|
||||
return
|
||||
}
|
||||
n, err = Self.BasePackager.UnPack(reader)
|
||||
n += 2
|
||||
return
|
||||
}
|
||||
|
||||
type MuxPackager struct {
|
||||
Flag uint8
|
||||
Id int32
|
||||
Window uint32
|
||||
ReadLength uint32
|
||||
BasePackager
|
||||
}
|
||||
|
||||
func (Self *MuxPackager) NewPac(flag uint8, id int32, content ...interface{}) (err error) {
|
||||
Self.Flag = flag
|
||||
Self.Id = id
|
||||
switch flag {
|
||||
case MUX_PING_FLAG, MUX_PING_RETURN, MUX_NEW_MSG, MUX_NEW_MSG_PART:
|
||||
Self.Content = WindowBuff.Get()
|
||||
err = Self.BasePackager.NewPac(content...)
|
||||
//logs.Warn(Self.Length, string(Self.Content))
|
||||
case MUX_MSG_SEND_OK:
|
||||
// MUX_MSG_SEND_OK contains two data
|
||||
switch content[0].(type) {
|
||||
case int:
|
||||
Self.Window = uint32(content[0].(int))
|
||||
case uint32:
|
||||
Self.Window = content[0].(uint32)
|
||||
}
|
||||
switch content[1].(type) {
|
||||
case int:
|
||||
Self.ReadLength = uint32(content[1].(int))
|
||||
case uint32:
|
||||
Self.ReadLength = content[1].(uint32)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *MuxPackager) Pack(writer io.Writer) (err error) {
|
||||
err = binary.Write(writer, binary.LittleEndian, Self.Flag)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = binary.Write(writer, binary.LittleEndian, Self.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
switch Self.Flag {
|
||||
case MUX_NEW_MSG, MUX_NEW_MSG_PART, MUX_PING_FLAG, MUX_PING_RETURN:
|
||||
err = Self.BasePackager.Pack(writer)
|
||||
WindowBuff.Put(Self.Content)
|
||||
case MUX_MSG_SEND_OK:
|
||||
err = binary.Write(writer, binary.LittleEndian, Self.Window)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = binary.Write(writer, binary.LittleEndian, Self.ReadLength)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *MuxPackager) UnPack(reader io.Reader) (n uint16, err error) {
|
||||
err = binary.Read(reader, binary.LittleEndian, &Self.Flag)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = binary.Read(reader, binary.LittleEndian, &Self.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
switch Self.Flag {
|
||||
case MUX_NEW_MSG, MUX_NEW_MSG_PART, MUX_PING_FLAG, MUX_PING_RETURN:
|
||||
Self.Content = WindowBuff.Get() // need get a window buf from pool
|
||||
Self.BasePackager.clean() // also clean the content
|
||||
n, err = Self.BasePackager.UnPack(reader)
|
||||
//logs.Warn("unpack", Self.Length, string(Self.Content))
|
||||
case MUX_MSG_SEND_OK:
|
||||
err = binary.Read(reader, binary.LittleEndian, &Self.Window)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n += 4 // uint32
|
||||
err = binary.Read(reader, binary.LittleEndian, &Self.ReadLength)
|
||||
n += 4 // uint32
|
||||
}
|
||||
n += 5 //uint8 int32
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
ipV4 = 1
|
||||
domainName = 3
|
||||
|
@ -1,6 +1,7 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@ -8,6 +9,8 @@ const PoolSize = 64 * 1024
|
||||
const PoolSizeSmall = 100
|
||||
const PoolSizeUdp = 1472 + 200
|
||||
const PoolSizeCopy = 32 << 10
|
||||
const PoolSizeBuffer = 4096
|
||||
const PoolSizeWindow = PoolSizeBuffer - 2 - 4 - 4 - 1
|
||||
|
||||
var BufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
@ -83,11 +86,112 @@ func (Self *copyBufferPool) Put(x []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
type windowBufferPool struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
|
||||
func (Self *windowBufferPool) New() {
|
||||
Self.pool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, PoolSizeWindow, PoolSizeWindow)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (Self *windowBufferPool) Get() (buf []byte) {
|
||||
buf = Self.pool.Get().([]byte)
|
||||
return buf[:PoolSizeWindow]
|
||||
}
|
||||
|
||||
func (Self *windowBufferPool) Put(x []byte) {
|
||||
Self.pool.Put(x[:PoolSizeWindow]) // make buf to full
|
||||
}
|
||||
|
||||
type bufferPool struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
|
||||
func (Self *bufferPool) New() {
|
||||
Self.pool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return bytes.NewBuffer(make([]byte, 0, PoolSizeBuffer))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (Self *bufferPool) Get() *bytes.Buffer {
|
||||
return Self.pool.Get().(*bytes.Buffer)
|
||||
}
|
||||
|
||||
func (Self *bufferPool) Put(x *bytes.Buffer) {
|
||||
x.Reset()
|
||||
Self.pool.Put(x)
|
||||
}
|
||||
|
||||
type muxPackagerPool struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
|
||||
func (Self *muxPackagerPool) New() {
|
||||
Self.pool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
pack := MuxPackager{}
|
||||
return &pack
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (Self *muxPackagerPool) Get() *MuxPackager {
|
||||
return Self.pool.Get().(*MuxPackager)
|
||||
}
|
||||
|
||||
func (Self *muxPackagerPool) Put(pack *MuxPackager) {
|
||||
Self.pool.Put(pack)
|
||||
}
|
||||
|
||||
type ListElement struct {
|
||||
Buf []byte
|
||||
L uint16
|
||||
Part bool
|
||||
}
|
||||
|
||||
type listElementPool struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
|
||||
func (Self *listElementPool) New() {
|
||||
Self.pool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
element := ListElement{}
|
||||
return &element
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (Self *listElementPool) Get() *ListElement {
|
||||
return Self.pool.Get().(*ListElement)
|
||||
}
|
||||
|
||||
func (Self *listElementPool) Put(element *ListElement) {
|
||||
element.L = 0
|
||||
element.Buf = nil
|
||||
element.Part = false
|
||||
Self.pool.Put(element)
|
||||
}
|
||||
|
||||
var once = sync.Once{}
|
||||
var BuffPool = bufferPool{}
|
||||
var CopyBuff = copyBufferPool{}
|
||||
var MuxPack = muxPackagerPool{}
|
||||
var WindowBuff = windowBufferPool{}
|
||||
var ListElementPool = listElementPool{}
|
||||
|
||||
func newPool() {
|
||||
BuffPool.New()
|
||||
CopyBuff.New()
|
||||
MuxPack.New()
|
||||
WindowBuff.New()
|
||||
ListElementPool.New()
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -1,29 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
)
|
||||
|
||||
func InitPProfFromFile() {
|
||||
ip := beego.AppConfig.String("pprof_ip")
|
||||
p := beego.AppConfig.String("pprof_port")
|
||||
if len(ip) > 0 && len(p) > 0 && IsPort(p) {
|
||||
runPProf(ip + ":" + p)
|
||||
}
|
||||
}
|
||||
|
||||
func InitPProfFromArg(arg string) {
|
||||
if len(arg) > 0 {
|
||||
runPProf(arg)
|
||||
}
|
||||
}
|
||||
|
||||
func runPProf(ipPort string) {
|
||||
go func() {
|
||||
_ = http.ListenAndServe(ipPort, nil)
|
||||
}()
|
||||
logs.Info("PProf debug listen on", ipPort)
|
||||
}
|
@ -76,14 +76,3 @@ func GetTmpPath() string {
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
//config file path
|
||||
func GetConfigPath() string {
|
||||
var path string
|
||||
if IsWindows() {
|
||||
path = filepath.Join(GetAppPath(), "conf/npc.conf")
|
||||
} else {
|
||||
path = "conf/npc.conf"
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
@ -2,11 +2,9 @@ package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"ehang.io/nps/lib/version"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@ -18,7 +16,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"ehang.io/nps/lib/crypt"
|
||||
"github.com/cnlh/nps/lib/crypt"
|
||||
)
|
||||
|
||||
//Get the corresponding IP address through domain name
|
||||
@ -100,7 +98,7 @@ func Getverifyval(vkey string) string {
|
||||
}
|
||||
|
||||
//Change headers and host of request
|
||||
func ChangeHostAndHeader(r *http.Request, host string, header string, addr string, addOrigin bool) {
|
||||
func ChangeHostAndHeader(r *http.Request, host string, header string, addr string) {
|
||||
if host != "" {
|
||||
r.Host = host
|
||||
}
|
||||
@ -117,10 +115,8 @@ func ChangeHostAndHeader(r *http.Request, host string, header string, addr strin
|
||||
if prior, ok := r.Header["X-Forwarded-For"]; ok {
|
||||
addr = strings.Join(prior, ", ") + ", " + addr
|
||||
}
|
||||
if addOrigin {
|
||||
r.Header.Set("X-Forwarded-For", addr)
|
||||
r.Header.Set("X-Real-IP", addr)
|
||||
}
|
||||
r.Header.Set("X-Forwarded-For", addr)
|
||||
r.Header.Set("X-Real-IP", addr)
|
||||
}
|
||||
|
||||
//Read file content by file path
|
||||
@ -463,7 +459,3 @@ func GetServerIpByClientIp(clientIp net.IP) string {
|
||||
_, ip := GetIntranetIp()
|
||||
return ip
|
||||
}
|
||||
|
||||
func PrintVersion() {
|
||||
fmt.Printf("Version: %s\nCore version: %s\nSame core version of client and server can connect each other\n", version.VERSION, version.GetVersion())
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/file"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
)
|
||||
|
||||
type CommonConfig struct {
|
||||
@ -17,7 +17,6 @@ type CommonConfig struct {
|
||||
AutoReconnection bool
|
||||
ProxyUrl string
|
||||
Client *file.Client
|
||||
DisconnectTime int
|
||||
}
|
||||
|
||||
type LocalServer struct {
|
||||
@ -146,10 +145,6 @@ func dealCommon(s string) *CommonConfig {
|
||||
c.Client.MaxConn = common.GetIntNoErrByStr(item[1])
|
||||
case "remark":
|
||||
c.Client.Remark = item[1]
|
||||
case "pprof_addr":
|
||||
common.InitPProfFromArg(item[1])
|
||||
case "disconnect_timeout":
|
||||
c.DisconnectTime = common.GetIntNoErrByStr(item[1])
|
||||
}
|
||||
}
|
||||
return c
|
||||
@ -246,7 +241,7 @@ func dealTunnel(s string) *file.Tunnel {
|
||||
t.StripPre = item[1]
|
||||
case "multi_account":
|
||||
t.MultiAccount = &file.MultiAccount{}
|
||||
if common.FileExists(item[1]) {
|
||||
if common.FileExists(item[1]){
|
||||
if b, err := common.ReadAllFromFile(item[1]); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
@ -302,7 +297,7 @@ func delLocalService(s string) *LocalServer {
|
||||
|
||||
func getAllTitle(content string) (arr []string, err error) {
|
||||
var re *regexp.Regexp
|
||||
re, err = regexp.Compile(`(?m)^\[[^\[\]\r\n]+\]`)
|
||||
re, err = regexp.Compile(`\[.+?\]`)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -3,25 +3,24 @@ package conn
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"ehang.io/nps/lib/goroutine"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/lib/goroutine"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/crypt"
|
||||
"ehang.io/nps/lib/file"
|
||||
"ehang.io/nps/lib/pmux"
|
||||
"ehang.io/nps/lib/rate"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/crypt"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/lib/mux"
|
||||
"github.com/cnlh/nps/lib/rate"
|
||||
"github.com/xtaci/kcp-go"
|
||||
)
|
||||
|
||||
@ -35,33 +34,11 @@ func NewConn(conn net.Conn) *Conn {
|
||||
return &Conn{Conn: conn}
|
||||
}
|
||||
|
||||
func (s *Conn) readRequest(buf []byte) (n int, err error) {
|
||||
var rd int
|
||||
for {
|
||||
rd, err = s.Read(buf[n:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n += rd
|
||||
if n < 4 {
|
||||
continue
|
||||
}
|
||||
if string(buf[n-4:n]) == "\r\n\r\n" {
|
||||
return
|
||||
}
|
||||
// buf is full, can't contain the request
|
||||
if n == cap(buf) {
|
||||
err = io.ErrUnexpectedEOF
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//get host 、connection type、method...from connection
|
||||
func (s *Conn) GetHost() (method, address string, rb []byte, err error, r *http.Request) {
|
||||
var b [32 * 1024]byte
|
||||
var n int
|
||||
if n, err = s.readRequest(b[:]); err != nil {
|
||||
if n, err = s.Read(b[:]); err != nil {
|
||||
return
|
||||
}
|
||||
rb = b[:n]
|
||||
@ -149,8 +126,8 @@ func (s *Conn) SetAlive(tp string) {
|
||||
conn.SetReadDeadline(time.Time{})
|
||||
//conn.SetKeepAlive(false)
|
||||
//conn.SetKeepAlivePeriod(time.Duration(2 * time.Second))
|
||||
case *pmux.PortConn:
|
||||
s.Conn.(*pmux.PortConn).SetReadDeadline(time.Time{})
|
||||
case *mux.PortConn:
|
||||
s.Conn.(*mux.PortConn).SetReadDeadline(time.Time{})
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,8 +138,8 @@ func (s *Conn) SetReadDeadlineBySecond(t time.Duration) {
|
||||
s.Conn.(*kcp.UDPSession).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second))
|
||||
case *net.TCPConn:
|
||||
s.Conn.(*net.TCPConn).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second))
|
||||
case *pmux.PortConn:
|
||||
s.Conn.(*pmux.PortConn).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second))
|
||||
case *mux.PortConn:
|
||||
s.Conn.(*mux.PortConn).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second))
|
||||
}
|
||||
}
|
||||
|
||||
@ -394,10 +371,7 @@ func CopyWaitGroup(conn1, conn2 net.Conn, crypt bool, snappy bool, rate *rate.Ra
|
||||
//if flow != nil {
|
||||
// flow.Add(in, out)
|
||||
//}
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(1)
|
||||
err := goroutine.CopyConnsPool.Invoke(goroutine.NewConns(connHandle, conn2, flow, wg))
|
||||
wg.Wait()
|
||||
err := goroutine.CopyConnsPool.Invoke(goroutine.NewConns(connHandle, conn2, flow))
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package conn
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
@ -10,14 +9,12 @@ import (
|
||||
type SnappyConn struct {
|
||||
w *snappy.Writer
|
||||
r *snappy.Reader
|
||||
c io.Closer
|
||||
}
|
||||
|
||||
func NewSnappyConn(conn io.ReadWriteCloser) *SnappyConn {
|
||||
c := new(SnappyConn)
|
||||
c.w = snappy.NewBufferedWriter(conn)
|
||||
c.r = snappy.NewReader(conn)
|
||||
c.c = conn.(io.Closer)
|
||||
return c
|
||||
}
|
||||
|
||||
@ -38,16 +35,6 @@ func (s *SnappyConn) Read(b []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
func (s *SnappyConn) Close() error {
|
||||
err := s.w.Close()
|
||||
err2 := s.c.Close()
|
||||
if err != nil && err2 == nil {
|
||||
return err
|
||||
}
|
||||
if err == nil && err2 != nil {
|
||||
return err2
|
||||
}
|
||||
if err != nil && err2 != nil {
|
||||
return errors.New(err.Error() + err2.Error())
|
||||
}
|
||||
return nil
|
||||
s.w.Close()
|
||||
return s.w.Close()
|
||||
}
|
||||
|
@ -1,37 +1,22 @@
|
||||
package crypt
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"log"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego/logs"
|
||||
)
|
||||
|
||||
var (
|
||||
cert tls.Certificate
|
||||
)
|
||||
var pemPath, keyPath string
|
||||
|
||||
func InitTls() {
|
||||
c, k, err := generateKeyPair("NPS Org")
|
||||
if err == nil {
|
||||
cert, err = tls.X509KeyPair(c, k)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalln("Error initializing crypto certs", err)
|
||||
}
|
||||
func InitTls(pem, key string) {
|
||||
pemPath = pem
|
||||
keyPath = key
|
||||
}
|
||||
|
||||
func NewTlsServerConn(conn net.Conn) net.Conn {
|
||||
var err error
|
||||
cert, err := tls.LoadX509KeyPair(pemPath, keyPath)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
os.Exit(0)
|
||||
@ -47,41 +32,3 @@ func NewTlsClientConn(conn net.Conn) net.Conn {
|
||||
}
|
||||
return tls.Client(conn, conf)
|
||||
}
|
||||
|
||||
func generateKeyPair(CommonName string) (rawCert, rawKey []byte, err error) {
|
||||
// Create private key and self-signed certificate
|
||||
// Adapted from https://golang.org/src/crypto/tls/generate_cert.go
|
||||
|
||||
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
validFor := time.Hour * 24 * 365 * 10 // ten years
|
||||
notBefore := time.Now()
|
||||
notAfter := notBefore.Add(validFor)
|
||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
||||
template := x509.Certificate{
|
||||
SerialNumber: serialNumber,
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"My Company Name LTD."},
|
||||
CommonName: CommonName,
|
||||
Country: []string{"US"},
|
||||
},
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
rawCert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
||||
rawKey = pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
)
|
||||
|
||||
func InitDaemon(f string, runPath string, pidPath string) {
|
||||
|
@ -8,8 +8,8 @@ import (
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -4,13 +4,14 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/crypt"
|
||||
"ehang.io/nps/lib/rate"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/crypt"
|
||||
"github.com/cnlh/nps/lib/rate"
|
||||
)
|
||||
|
||||
type DbUtils struct {
|
||||
@ -327,16 +328,13 @@ func (s *DbUtils) GetInfoByHost(host string, r *http.Request) (h *Host, err erro
|
||||
}
|
||||
//Remove http(s) http(s)://a.proxy.com
|
||||
//*.proxy.com *.a.proxy.com Do some pan-parsing
|
||||
if v.Scheme != "all" && v.Scheme != r.URL.Scheme {
|
||||
tmp := strings.Replace(v.Host, "*", `\w+?`, -1)
|
||||
var re *regexp.Regexp
|
||||
if re, err = regexp.Compile(tmp); err != nil {
|
||||
return true
|
||||
}
|
||||
tmpHost := v.Host
|
||||
if strings.Contains(tmpHost, "*") {
|
||||
tmpHost = strings.Replace(tmpHost, "*", "", -1)
|
||||
if strings.Contains(host, tmpHost) {
|
||||
hosts = append(hosts, v)
|
||||
}
|
||||
} else if v.Host == host {
|
||||
if len(re.FindAllString(host, -1)) > 0 && (v.Scheme == "all" || v.Scheme == r.URL.Scheme) {
|
||||
//URL routing
|
||||
hosts = append(hosts, v)
|
||||
}
|
||||
return true
|
||||
|
@ -3,15 +3,14 @@ package file
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/rate"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/rate"
|
||||
)
|
||||
|
||||
func NewJsonDb(runPath string) *JsonDb {
|
||||
@ -100,28 +99,16 @@ func (s *JsonDb) GetClient(id int) (c *Client, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
var hostLock sync.Mutex
|
||||
|
||||
func (s *JsonDb) StoreHostToJsonFile() {
|
||||
hostLock.Lock()
|
||||
storeSyncMapToFile(s.Hosts, s.HostFilePath)
|
||||
hostLock.Unlock()
|
||||
}
|
||||
|
||||
var taskLock sync.Mutex
|
||||
|
||||
func (s *JsonDb) StoreTasksToJsonFile() {
|
||||
taskLock.Lock()
|
||||
storeSyncMapToFile(s.Tasks, s.TaskFilePath)
|
||||
taskLock.Unlock()
|
||||
}
|
||||
|
||||
var clientLock sync.Mutex
|
||||
|
||||
func (s *JsonDb) StoreClientsToJsonFile() {
|
||||
clientLock.Lock()
|
||||
storeSyncMapToFile(s.Clients, s.ClientFilePath)
|
||||
clientLock.Unlock()
|
||||
}
|
||||
|
||||
func (s *JsonDb) GetClientId() int32 {
|
||||
@ -147,11 +134,11 @@ func loadSyncMapFromFile(filePath string, f func(value string)) {
|
||||
}
|
||||
|
||||
func storeSyncMapToFile(m sync.Map, filePath string) {
|
||||
file, err := os.Create(filePath + ".tmp")
|
||||
// first create a temporary file to store
|
||||
file, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
m.Range(func(key, value interface{}) bool {
|
||||
var b []byte
|
||||
var err error
|
||||
@ -190,12 +177,4 @@ func storeSyncMapToFile(m sync.Map, filePath string) {
|
||||
}
|
||||
return true
|
||||
})
|
||||
_ = file.Sync()
|
||||
_ = file.Close()
|
||||
// must close file first, then rename it
|
||||
err = os.Rename(filePath+".tmp", filePath)
|
||||
if err != nil {
|
||||
logs.Error(err, "store to file err, data will lost")
|
||||
}
|
||||
// replace the file, maybe provides atomic operation
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"ehang.io/nps/lib/rate"
|
||||
"github.com/cnlh/nps/lib/rate"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package goroutine
|
||||
|
||||
import (
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/file"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/panjf2000/ants/v2"
|
||||
"io"
|
||||
"net"
|
||||
@ -44,15 +44,13 @@ type Conns struct {
|
||||
conn1 io.ReadWriteCloser // mux connection
|
||||
conn2 net.Conn // outside connection
|
||||
flow *file.Flow
|
||||
wg *sync.WaitGroup
|
||||
}
|
||||
|
||||
func NewConns(c1 io.ReadWriteCloser, c2 net.Conn, flow *file.Flow, wg *sync.WaitGroup) Conns {
|
||||
func NewConns(c1 io.ReadWriteCloser, c2 net.Conn, flow *file.Flow) Conns {
|
||||
return Conns{
|
||||
conn1: c1,
|
||||
conn2: c2,
|
||||
flow: flow,
|
||||
wg: wg,
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +67,6 @@ func copyConns(group interface{}) {
|
||||
if conns.flow != nil {
|
||||
conns.flow.Add(in, out)
|
||||
}
|
||||
conns.wg.Done()
|
||||
}
|
||||
|
||||
var connCopyPool, _ = ants.NewPoolWithFunc(200000, copyConnGroup, ants.WithNonblocking(false))
|
||||
|
@ -1,11 +1,11 @@
|
||||
package install
|
||||
|
||||
import (
|
||||
"ehang.io/nps/lib/common"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/c4milo/unpackit"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
@ -16,124 +16,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Keep it in sync with the template from service_sysv_linux.go file
|
||||
// Use "ps | grep -v grep | grep $(get_pid)" because "ps PID" may not work on OpenWrt
|
||||
const SysvScript = `#!/bin/sh
|
||||
# For RedHat and cousins:
|
||||
# chkconfig: - 99 01
|
||||
# description: {{.Description}}
|
||||
# processname: {{.Path}}
|
||||
### BEGIN INIT INFO
|
||||
# Provides: {{.Path}}
|
||||
# Required-Start:
|
||||
# Required-Stop:
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: {{.DisplayName}}
|
||||
# Description: {{.Description}}
|
||||
### END INIT INFO
|
||||
cmd="{{.Path}}{{range .Arguments}} {{.|cmd}}{{end}}"
|
||||
name=$(basename $(readlink -f $0))
|
||||
pid_file="/var/run/$name.pid"
|
||||
stdout_log="/var/log/$name.log"
|
||||
stderr_log="/var/log/$name.err"
|
||||
[ -e /etc/sysconfig/$name ] && . /etc/sysconfig/$name
|
||||
get_pid() {
|
||||
cat "$pid_file"
|
||||
}
|
||||
is_running() {
|
||||
[ -f "$pid_file" ] && ps | grep -v grep | grep $(get_pid) > /dev/null 2>&1
|
||||
}
|
||||
case "$1" in
|
||||
start)
|
||||
if is_running; then
|
||||
echo "Already started"
|
||||
else
|
||||
echo "Starting $name"
|
||||
{{if .WorkingDirectory}}cd '{{.WorkingDirectory}}'{{end}}
|
||||
$cmd >> "$stdout_log" 2>> "$stderr_log" &
|
||||
echo $! > "$pid_file"
|
||||
if ! is_running; then
|
||||
echo "Unable to start, see $stdout_log and $stderr_log"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
if is_running; then
|
||||
echo -n "Stopping $name.."
|
||||
kill $(get_pid)
|
||||
for i in $(seq 1 10)
|
||||
do
|
||||
if ! is_running; then
|
||||
break
|
||||
fi
|
||||
echo -n "."
|
||||
sleep 1
|
||||
done
|
||||
echo
|
||||
if is_running; then
|
||||
echo "Not stopped; may still be shutting down or shutdown may have failed"
|
||||
exit 1
|
||||
else
|
||||
echo "Stopped"
|
||||
if [ -f "$pid_file" ]; then
|
||||
rm "$pid_file"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "Not running"
|
||||
fi
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
if is_running; then
|
||||
echo "Unable to stop, will not attempt to start"
|
||||
exit 1
|
||||
fi
|
||||
$0 start
|
||||
;;
|
||||
status)
|
||||
if is_running; then
|
||||
echo "Running"
|
||||
else
|
||||
echo "Stopped"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|status}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
`
|
||||
|
||||
const SystemdScript = `[Unit]
|
||||
Description={{.Description}}
|
||||
ConditionFileIsExecutable={{.Path|cmdEscape}}
|
||||
{{range $i, $dep := .Dependencies}}
|
||||
{{$dep}} {{end}}
|
||||
[Service]
|
||||
LimitNOFILE=65536
|
||||
StartLimitInterval=5
|
||||
StartLimitBurst=10
|
||||
ExecStart={{.Path|cmdEscape}}{{range .Arguments}} {{.|cmd}}{{end}}
|
||||
{{if .ChRoot}}RootDirectory={{.ChRoot|cmd}}{{end}}
|
||||
{{if .WorkingDirectory}}WorkingDirectory={{.WorkingDirectory|cmdEscape}}{{end}}
|
||||
{{if .UserName}}User={{.UserName}}{{end}}
|
||||
{{if .ReloadSignal}}ExecReload=/bin/kill -{{.ReloadSignal}} "$MAINPID"{{end}}
|
||||
{{if .PIDFile}}PIDFile={{.PIDFile|cmd}}{{end}}
|
||||
{{if and .LogOutput .HasOutputFileSupport -}}
|
||||
StandardOutput=file:/var/log/{{.Name}}.out
|
||||
StandardError=file:/var/log/{{.Name}}.err
|
||||
{{- end}}
|
||||
Restart=always
|
||||
RestartSec=120
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
`
|
||||
|
||||
func UpdateNps() {
|
||||
destPath := downloadLatest("server")
|
||||
//复制文件到对应目录
|
||||
@ -154,7 +36,7 @@ type release struct {
|
||||
|
||||
func downloadLatest(bin string) string {
|
||||
// get version
|
||||
data, err := http.Get("https://api.github.com/repos/ehang-io/nps/releases/latest")
|
||||
data, err := http.Get("https://api.github.com/repos/cnlh/nps/releases/latest")
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
@ -168,7 +50,7 @@ func downloadLatest(bin string) string {
|
||||
fmt.Println("the latest version is", version)
|
||||
filename := runtime.GOOS + "_" + runtime.GOARCH + "_" + bin + ".tar.gz"
|
||||
// download latest package
|
||||
downloadUrl := fmt.Sprintf("https://ehang.io/nps/releases/download/%s/%s", version, filename)
|
||||
downloadUrl := fmt.Sprintf("https://github.com/cnlh/nps/releases/download/%s/%s", version, filename)
|
||||
fmt.Println("download package from ", downloadUrl)
|
||||
resp, err := http.Get(downloadUrl)
|
||||
if err != nil {
|
||||
@ -209,13 +91,11 @@ func copyStaticFile(srcPath, bin string) string {
|
||||
if _, err := copyFile(filepath.Join(srcPath, bin), "/usr/local/bin/"+bin); err != nil {
|
||||
log.Fatalln(err)
|
||||
} else {
|
||||
copyFile(filepath.Join(srcPath, bin), "/usr/local/bin/"+bin+"-update")
|
||||
chMod("/usr/local/bin/"+bin+"-update", 0755)
|
||||
copyFile(filepath.Join(srcPath, "nps"), "/usr/local/bin/"+bin+"-update")
|
||||
binPath = "/usr/local/bin/" + bin
|
||||
}
|
||||
} else {
|
||||
copyFile(filepath.Join(srcPath, bin), "/usr/bin/"+bin+"-update")
|
||||
chMod("/usr/bin/"+bin+"-update", 0755)
|
||||
copyFile(filepath.Join(srcPath, "nps"), "/usr/bin/"+bin+"-update")
|
||||
binPath = "/usr/bin/" + bin
|
||||
}
|
||||
} else {
|
||||
|
32
lib/mux/bytes.go
Normal file
32
lib/mux/bytes.go
Normal file
@ -0,0 +1,32 @@
|
||||
package mux
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
//write bytes with int32 length
|
||||
func WriteLenBytes(buf []byte, w io.Writer) (int, error) {
|
||||
raw := bytes.NewBuffer([]byte{})
|
||||
if err := binary.Write(raw, binary.LittleEndian, int32(len(buf))); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := binary.Write(raw, binary.LittleEndian, buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return w.Write(raw.Bytes())
|
||||
}
|
||||
|
||||
//read bytes by length
|
||||
func ReadLenBytes(buf []byte, r io.Reader) (int, error) {
|
||||
var l uint32
|
||||
var err error
|
||||
if binary.Read(r, binary.LittleEndian, &l) != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, err = io.ReadFull(r, buf[:l]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(l), nil
|
||||
}
|
644
lib/mux/conn.go
Normal file
644
lib/mux/conn.go
Normal file
@ -0,0 +1,644 @@
|
||||
package mux
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
)
|
||||
|
||||
type conn struct {
|
||||
net.Conn
|
||||
getStatusCh chan struct{}
|
||||
connStatusOkCh chan struct{}
|
||||
connStatusFailCh chan struct{}
|
||||
connId int32
|
||||
isClose bool
|
||||
closeFlag bool // close conn flag
|
||||
receiveWindow *ReceiveWindow
|
||||
sendWindow *SendWindow
|
||||
once sync.Once
|
||||
//label string
|
||||
}
|
||||
|
||||
func NewConn(connId int32, mux *Mux, label ...string) *conn {
|
||||
c := &conn{
|
||||
getStatusCh: make(chan struct{}),
|
||||
connStatusOkCh: make(chan struct{}),
|
||||
connStatusFailCh: make(chan struct{}),
|
||||
connId: connId,
|
||||
receiveWindow: new(ReceiveWindow),
|
||||
sendWindow: new(SendWindow),
|
||||
once: sync.Once{},
|
||||
}
|
||||
//if len(label) > 0 {
|
||||
// c.label = label[0]
|
||||
//}
|
||||
c.receiveWindow.New(mux)
|
||||
c.sendWindow.New(mux)
|
||||
//logm := &connLog{
|
||||
// startTime: time.Now(),
|
||||
// isClose: false,
|
||||
// logs: []string{c.label + "new conn success"},
|
||||
//}
|
||||
//setM(label[0], int(connId), logm)
|
||||
return c
|
||||
}
|
||||
|
||||
func (s *conn) Read(buf []byte) (n int, err error) {
|
||||
if s.isClose || buf == nil {
|
||||
return 0, errors.New("the conn has closed")
|
||||
}
|
||||
if len(buf) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
// waiting for takeout from receive window finish or timeout
|
||||
//now := time.Now()
|
||||
n, err = s.receiveWindow.Read(buf, s.connId)
|
||||
//t := time.Now().Sub(now)
|
||||
//if t.Seconds() > 0.5 {
|
||||
//logs.Warn("conn read long", n, t.Seconds())
|
||||
//}
|
||||
//var errstr string
|
||||
//if err == nil {
|
||||
// errstr = "err:nil"
|
||||
//} else {
|
||||
// errstr = err.Error()
|
||||
//}
|
||||
//d := getM(s.label, int(s.connId))
|
||||
//d.logs = append(d.logs, s.label+"read "+strconv.Itoa(n)+" "+errstr+" "+string(buf[:100]))
|
||||
//setM(s.label, int(s.connId), d)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *conn) Write(buf []byte) (n int, err error) {
|
||||
if s.isClose {
|
||||
return 0, errors.New("the conn has closed")
|
||||
}
|
||||
if s.closeFlag {
|
||||
//s.Close()
|
||||
return 0, errors.New("io: write on closed conn")
|
||||
}
|
||||
if len(buf) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
//logs.Warn("write buf", len(buf))
|
||||
//now := time.Now()
|
||||
n, err = s.sendWindow.WriteFull(buf, s.connId)
|
||||
//t := time.Now().Sub(now)
|
||||
//if t.Seconds() > 0.5 {
|
||||
// logs.Warn("conn write long", n, t.Seconds())
|
||||
//}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *conn) Close() (err error) {
|
||||
s.once.Do(s.closeProcess)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *conn) closeProcess() {
|
||||
s.isClose = true
|
||||
s.receiveWindow.mux.connMap.Delete(s.connId)
|
||||
if !s.receiveWindow.mux.IsClose {
|
||||
// if server or user close the conn while reading, will get a io.EOF
|
||||
// and this Close method will be invoke, send this signal to close other side
|
||||
s.receiveWindow.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil)
|
||||
}
|
||||
s.sendWindow.CloseWindow()
|
||||
s.receiveWindow.CloseWindow()
|
||||
//d := getM(s.label, int(s.connId))
|
||||
//d.isClose = true
|
||||
//d.logs = append(d.logs, s.label+"close "+time.Now().String())
|
||||
//setM(s.label, int(s.connId), d)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *conn) LocalAddr() net.Addr {
|
||||
return s.receiveWindow.mux.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (s *conn) RemoteAddr() net.Addr {
|
||||
return s.receiveWindow.mux.conn.RemoteAddr()
|
||||
}
|
||||
|
||||
func (s *conn) SetDeadline(t time.Time) error {
|
||||
_ = s.SetReadDeadline(t)
|
||||
_ = s.SetWriteDeadline(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *conn) SetReadDeadline(t time.Time) error {
|
||||
s.receiveWindow.SetTimeOut(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *conn) SetWriteDeadline(t time.Time) error {
|
||||
s.sendWindow.SetTimeOut(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
type window struct {
|
||||
remainingWait uint64 // 64bit alignment
|
||||
off uint32
|
||||
maxSize uint32
|
||||
closeOp bool
|
||||
closeOpCh chan struct{}
|
||||
mux *Mux
|
||||
}
|
||||
|
||||
func (Self *window) unpack(ptrs uint64) (remaining, wait uint32) {
|
||||
const mask = 1<<dequeueBits - 1
|
||||
remaining = uint32((ptrs >> dequeueBits) & mask)
|
||||
wait = uint32(ptrs & mask)
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *window) pack(remaining, wait uint32) uint64 {
|
||||
const mask = 1<<dequeueBits - 1
|
||||
return (uint64(remaining) << dequeueBits) |
|
||||
uint64(wait&mask)
|
||||
}
|
||||
|
||||
func (Self *window) New() {
|
||||
Self.closeOpCh = make(chan struct{}, 2)
|
||||
}
|
||||
|
||||
func (Self *window) CloseWindow() {
|
||||
if !Self.closeOp {
|
||||
Self.closeOp = true
|
||||
Self.closeOpCh <- struct{}{}
|
||||
Self.closeOpCh <- struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
type ReceiveWindow struct {
|
||||
window
|
||||
bufQueue ReceiveWindowQueue
|
||||
element *common.ListElement
|
||||
count int8
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindow) New(mux *Mux) {
|
||||
// initial a window for receive
|
||||
Self.bufQueue.New()
|
||||
Self.element = common.ListElementPool.Get()
|
||||
Self.maxSize = common.MAXIMUM_SEGMENT_SIZE * 10
|
||||
Self.mux = mux
|
||||
Self.window.New()
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindow) remainingSize(delta uint16) (n uint32) {
|
||||
// receive window remaining
|
||||
l := int64(atomic.LoadUint32(&Self.maxSize)) - int64(Self.bufQueue.Len())
|
||||
l -= int64(delta)
|
||||
if l > 0 {
|
||||
n = uint32(l)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindow) calcSize() {
|
||||
// calculating maximum receive window size
|
||||
if Self.count == 0 {
|
||||
//logs.Warn("ping, bw", Self.mux.latency, Self.bw.Get())
|
||||
conns := Self.mux.connMap.Size()
|
||||
n := uint32(math.Float64frombits(atomic.LoadUint64(&Self.mux.latency)) *
|
||||
Self.mux.bw.Get() / float64(conns))
|
||||
if n < common.MAXIMUM_SEGMENT_SIZE*10 {
|
||||
n = common.MAXIMUM_SEGMENT_SIZE * 10
|
||||
}
|
||||
bufLen := Self.bufQueue.Len()
|
||||
if n < bufLen {
|
||||
n = bufLen
|
||||
}
|
||||
if n < Self.maxSize/2 {
|
||||
n = Self.maxSize / 2
|
||||
}
|
||||
// set the minimal size
|
||||
if n > 2*Self.maxSize {
|
||||
n = 2 * Self.maxSize
|
||||
}
|
||||
if n > (common.MAXIMUM_WINDOW_SIZE / uint32(conns)) {
|
||||
n = common.MAXIMUM_WINDOW_SIZE / uint32(conns)
|
||||
}
|
||||
// set the maximum size
|
||||
//logs.Warn("n", n)
|
||||
atomic.StoreUint32(&Self.maxSize, n)
|
||||
Self.count = -10
|
||||
}
|
||||
Self.count += 1
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindow) Write(buf []byte, l uint16, part bool, id int32) (err error) {
|
||||
if Self.closeOp {
|
||||
return errors.New("conn.receiveWindow: write on closed window")
|
||||
}
|
||||
element, err := NewListElement(buf, l, part)
|
||||
//logs.Warn("push the buf", len(buf), l, (&element).l)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
Self.calcSize() // calculate the max window size
|
||||
var wait uint32
|
||||
start:
|
||||
ptrs := atomic.LoadUint64(&Self.remainingWait)
|
||||
_, wait = Self.unpack(ptrs)
|
||||
newRemaining := Self.remainingSize(l)
|
||||
// calculate the remaining window size now, plus the element we will push
|
||||
if newRemaining == 0 {
|
||||
//logs.Warn("window full true", remaining)
|
||||
wait = 1
|
||||
}
|
||||
if !atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(0, wait)) {
|
||||
goto start
|
||||
// another goroutine change the status, make sure shall we need wait
|
||||
}
|
||||
Self.bufQueue.Push(element)
|
||||
// status check finish, now we can push the element into the queue
|
||||
if wait == 0 {
|
||||
Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.maxSize, newRemaining)
|
||||
// send the remaining window size, not including zero size
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindow) Read(p []byte, id int32) (n int, err error) {
|
||||
if Self.closeOp {
|
||||
return 0, io.EOF // receive close signal, returns eof
|
||||
}
|
||||
pOff := 0
|
||||
l := 0
|
||||
//logs.Warn("receive window read off, element.l", Self.off, Self.element.l)
|
||||
copyData:
|
||||
if Self.off == uint32(Self.element.L) {
|
||||
// on the first Read method invoked, Self.off and Self.element.l
|
||||
// both zero value
|
||||
common.ListElementPool.Put(Self.element)
|
||||
if Self.closeOp {
|
||||
return 0, io.EOF
|
||||
}
|
||||
Self.element, err = Self.bufQueue.Pop()
|
||||
// if the queue is empty, Pop method will wait until one element push
|
||||
// into the queue successful, or timeout.
|
||||
// timer start on timeout parameter is set up ,
|
||||
// reset to 60s if timeout and data still available
|
||||
Self.off = 0
|
||||
if err != nil {
|
||||
Self.CloseWindow() // also close the window, to avoid read twice
|
||||
return // queue receive stop or time out, break the loop and return
|
||||
}
|
||||
//logs.Warn("pop element", Self.element.l, Self.element.part)
|
||||
}
|
||||
l = copy(p[pOff:], Self.element.Buf[Self.off:Self.element.L])
|
||||
pOff += l
|
||||
Self.off += uint32(l)
|
||||
//logs.Warn("window read length buf len", Self.readLength, Self.bufQueue.Len())
|
||||
n += l
|
||||
l = 0
|
||||
if Self.off == uint32(Self.element.L) {
|
||||
//logs.Warn("put the element end ", string(Self.element.buf[:15]))
|
||||
common.WindowBuff.Put(Self.element.Buf)
|
||||
Self.sendStatus(id, Self.element.L)
|
||||
// check the window full status
|
||||
}
|
||||
if pOff < len(p) && Self.element.Part {
|
||||
// element is a part of the segments, trying to fill up buf p
|
||||
goto copyData
|
||||
}
|
||||
return // buf p is full or all of segments in buf, return
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindow) sendStatus(id int32, l uint16) {
|
||||
var remaining, wait uint32
|
||||
for {
|
||||
ptrs := atomic.LoadUint64(&Self.remainingWait)
|
||||
remaining, wait = Self.unpack(ptrs)
|
||||
remaining += uint32(l)
|
||||
if atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(remaining, 0)) {
|
||||
break
|
||||
}
|
||||
runtime.Gosched()
|
||||
// another goroutine change remaining or wait status, make sure
|
||||
// we need acknowledge other side
|
||||
}
|
||||
// now we get the current window status success
|
||||
if wait == 1 {
|
||||
//logs.Warn("send the wait status", remaining)
|
||||
Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, atomic.LoadUint32(&Self.maxSize), remaining)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindow) SetTimeOut(t time.Time) {
|
||||
// waiting for FIFO queue Pop method
|
||||
Self.bufQueue.SetTimeOut(t)
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindow) Stop() {
|
||||
// queue has no more data to push, so unblock pop method
|
||||
Self.once.Do(Self.bufQueue.Stop)
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindow) CloseWindow() {
|
||||
Self.window.CloseWindow()
|
||||
Self.Stop()
|
||||
Self.release()
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindow) release() {
|
||||
//if Self.element != nil {
|
||||
// if Self.element.Buf != nil {
|
||||
// common.WindowBuff.Put(Self.element.Buf)
|
||||
// }
|
||||
// common.ListElementPool.Put(Self.element)
|
||||
//}
|
||||
for {
|
||||
ele := Self.bufQueue.TryPop()
|
||||
if ele == nil {
|
||||
return
|
||||
}
|
||||
if ele.Buf != nil {
|
||||
common.WindowBuff.Put(ele.Buf)
|
||||
}
|
||||
common.ListElementPool.Put(ele)
|
||||
} // release resource
|
||||
}
|
||||
|
||||
type SendWindow struct {
|
||||
window
|
||||
buf []byte
|
||||
setSizeCh chan struct{}
|
||||
timeout time.Time
|
||||
}
|
||||
|
||||
func (Self *SendWindow) New(mux *Mux) {
|
||||
Self.setSizeCh = make(chan struct{})
|
||||
Self.maxSize = common.MAXIMUM_SEGMENT_SIZE * 10
|
||||
atomic.AddUint64(&Self.remainingWait, uint64(common.MAXIMUM_SEGMENT_SIZE*10)<<dequeueBits)
|
||||
Self.mux = mux
|
||||
Self.window.New()
|
||||
}
|
||||
|
||||
func (Self *SendWindow) SetSendBuf(buf []byte) {
|
||||
// send window buff from conn write method, set it to send window
|
||||
Self.buf = buf
|
||||
Self.off = 0
|
||||
}
|
||||
|
||||
func (Self *SendWindow) SetSize(windowSize, newRemaining uint32) (closed bool) {
|
||||
// set the window size from receive window
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
closed = true
|
||||
}
|
||||
}()
|
||||
if Self.closeOp {
|
||||
close(Self.setSizeCh)
|
||||
return true
|
||||
}
|
||||
//logs.Warn("set send window size to ", windowSize, newRemaining)
|
||||
var remaining, wait, newWait uint32
|
||||
for {
|
||||
ptrs := atomic.LoadUint64(&Self.remainingWait)
|
||||
remaining, wait = Self.unpack(ptrs)
|
||||
if remaining == newRemaining {
|
||||
//logs.Warn("waiting for another window size")
|
||||
return false // waiting for receive another usable window size
|
||||
}
|
||||
if newRemaining == 0 && wait == 1 {
|
||||
newWait = 1 // keep the wait status,
|
||||
// also if newRemaining is not zero, change wait to 0
|
||||
}
|
||||
if atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(newRemaining, newWait)) {
|
||||
break
|
||||
}
|
||||
// anther goroutine change wait status or window size
|
||||
}
|
||||
if wait == 1 {
|
||||
// send window into the wait status, need notice the channel
|
||||
//logs.Warn("send window remaining size is 0")
|
||||
Self.allow()
|
||||
}
|
||||
// send window not into the wait status, so just do slide
|
||||
return false
|
||||
}
|
||||
|
||||
func (Self *SendWindow) allow() {
|
||||
select {
|
||||
case Self.setSizeCh <- struct{}{}:
|
||||
//logs.Warn("send window remaining size is 0 finish")
|
||||
return
|
||||
case <-Self.closeOpCh:
|
||||
close(Self.setSizeCh)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (Self *SendWindow) sent(sentSize uint32) {
|
||||
atomic.AddUint64(&Self.remainingWait, ^(uint64(sentSize)<<dequeueBits - 1))
|
||||
}
|
||||
|
||||
func (Self *SendWindow) WriteTo() (p []byte, sendSize uint32, part bool, err error) {
|
||||
// returns buf segments, return only one segments, need a loop outside
|
||||
// until err = io.EOF
|
||||
if Self.closeOp {
|
||||
return nil, 0, false, errors.New("conn.writeWindow: window closed")
|
||||
}
|
||||
if Self.off == uint32(len(Self.buf)) {
|
||||
return nil, 0, false, io.EOF
|
||||
// send window buff is drain, return eof and get another one
|
||||
}
|
||||
var remaining uint32
|
||||
start:
|
||||
ptrs := atomic.LoadUint64(&Self.remainingWait)
|
||||
remaining, _ = Self.unpack(ptrs)
|
||||
if remaining == 0 {
|
||||
if !atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(0, 1)) {
|
||||
goto start // another goroutine change the window, try again
|
||||
}
|
||||
// into the wait status
|
||||
//logs.Warn("send window into wait status")
|
||||
err = Self.waitReceiveWindow()
|
||||
if err != nil {
|
||||
return nil, 0, false, err
|
||||
}
|
||||
//logs.Warn("rem into wait finish")
|
||||
goto start
|
||||
}
|
||||
// there are still remaining window
|
||||
//logs.Warn("rem", remaining)
|
||||
if len(Self.buf[Self.off:]) > common.MAXIMUM_SEGMENT_SIZE {
|
||||
sendSize = common.MAXIMUM_SEGMENT_SIZE
|
||||
//logs.Warn("cut buf by mss")
|
||||
} else {
|
||||
sendSize = uint32(len(Self.buf[Self.off:]))
|
||||
}
|
||||
if remaining < sendSize {
|
||||
// usable window size is small than
|
||||
// window MAXIMUM_SEGMENT_SIZE or send buf left
|
||||
sendSize = remaining
|
||||
//logs.Warn("cut buf by remainingsize", sendSize, len(Self.buf[Self.off:]))
|
||||
}
|
||||
//logs.Warn("send size", sendSize)
|
||||
if sendSize < uint32(len(Self.buf[Self.off:])) {
|
||||
part = true
|
||||
}
|
||||
p = Self.buf[Self.off : sendSize+Self.off]
|
||||
Self.off += sendSize
|
||||
Self.sent(sendSize)
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *SendWindow) waitReceiveWindow() (err error) {
|
||||
t := Self.timeout.Sub(time.Now())
|
||||
if t < 0 { // not set the timeout, wait for it as long as connection close
|
||||
select {
|
||||
case _, ok := <-Self.setSizeCh:
|
||||
if !ok {
|
||||
return errors.New("conn.writeWindow: window closed")
|
||||
}
|
||||
return nil
|
||||
case <-Self.closeOpCh:
|
||||
return errors.New("conn.writeWindow: window closed")
|
||||
}
|
||||
}
|
||||
timer := time.NewTimer(t)
|
||||
defer timer.Stop()
|
||||
// waiting for receive usable window size, or timeout
|
||||
select {
|
||||
case _, ok := <-Self.setSizeCh:
|
||||
if !ok {
|
||||
return errors.New("conn.writeWindow: window closed")
|
||||
}
|
||||
return nil
|
||||
case <-timer.C:
|
||||
return errors.New("conn.writeWindow: write to time out")
|
||||
case <-Self.closeOpCh:
|
||||
return errors.New("conn.writeWindow: window closed")
|
||||
}
|
||||
}
|
||||
|
||||
func (Self *SendWindow) WriteFull(buf []byte, id int32) (n int, err error) {
|
||||
Self.SetSendBuf(buf) // set the buf to send window
|
||||
//logs.Warn("set the buf to send window")
|
||||
var bufSeg []byte
|
||||
var part bool
|
||||
var l uint32
|
||||
for {
|
||||
bufSeg, l, part, err = Self.WriteTo()
|
||||
//logs.Warn("buf seg", len(bufSeg), part, err)
|
||||
// get the buf segments from send window
|
||||
if bufSeg == nil && part == false && err == io.EOF {
|
||||
// send window is drain, break the loop
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
n += int(l)
|
||||
l = 0
|
||||
if part {
|
||||
Self.mux.sendInfo(common.MUX_NEW_MSG_PART, id, bufSeg)
|
||||
} else {
|
||||
Self.mux.sendInfo(common.MUX_NEW_MSG, id, bufSeg)
|
||||
//logs.Warn("buf seg sent", len(bufSeg), part, err)
|
||||
}
|
||||
// send to other side, not send nil data to other side
|
||||
}
|
||||
//logs.Warn("buf seg write success")
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *SendWindow) SetTimeOut(t time.Time) {
|
||||
// waiting for receive a receive window size
|
||||
Self.timeout = t
|
||||
}
|
||||
|
||||
//type bandwidth struct {
|
||||
// readStart time.Time
|
||||
// lastReadStart time.Time
|
||||
// readEnd time.Time
|
||||
// lastReadEnd time.Time
|
||||
// bufLength int
|
||||
// lastBufLength int
|
||||
// count int8
|
||||
// readBW float64
|
||||
// writeBW float64
|
||||
// readBandwidth float64
|
||||
//}
|
||||
//
|
||||
//func (Self *bandwidth) StartRead() {
|
||||
// Self.lastReadStart, Self.readStart = Self.readStart, time.Now()
|
||||
// if !Self.lastReadStart.IsZero() {
|
||||
// if Self.count == -5 {
|
||||
// Self.calcBandWidth()
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//func (Self *bandwidth) EndRead() {
|
||||
// Self.lastReadEnd, Self.readEnd = Self.readEnd, time.Now()
|
||||
// if Self.count == -5 {
|
||||
// Self.calcWriteBandwidth()
|
||||
// }
|
||||
// if Self.count == 0 {
|
||||
// Self.calcReadBandwidth()
|
||||
// Self.count = -6
|
||||
// }
|
||||
// Self.count += 1
|
||||
//}
|
||||
//
|
||||
//func (Self *bandwidth) SetCopySize(n int) {
|
||||
// // must be invoke between StartRead and EndRead
|
||||
// Self.lastBufLength, Self.bufLength = Self.bufLength, n
|
||||
//}
|
||||
//// calculating
|
||||
//// start end start end
|
||||
//// read read
|
||||
//// write
|
||||
//
|
||||
//func (Self *bandwidth) calcBandWidth() {
|
||||
// t := Self.readStart.Sub(Self.lastReadStart)
|
||||
// if Self.lastBufLength >= 32768 {
|
||||
// Self.readBandwidth = float64(Self.lastBufLength) / t.Seconds()
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//func (Self *bandwidth) calcReadBandwidth() {
|
||||
// // Bandwidth between nps and npc
|
||||
// readTime := Self.readEnd.Sub(Self.readStart)
|
||||
// Self.readBW = float64(Self.bufLength) / readTime.Seconds()
|
||||
// //logs.Warn("calc read bw", Self.readBW, Self.bufLength, readTime.Seconds())
|
||||
//}
|
||||
//
|
||||
//func (Self *bandwidth) calcWriteBandwidth() {
|
||||
// // Bandwidth between nps and user, npc and application
|
||||
// writeTime := Self.readStart.Sub(Self.lastReadEnd)
|
||||
// Self.writeBW = float64(Self.lastBufLength) / writeTime.Seconds()
|
||||
// //logs.Warn("calc write bw", Self.writeBW, Self.bufLength, writeTime.Seconds())
|
||||
//}
|
||||
//
|
||||
//func (Self *bandwidth) Get() (bw float64) {
|
||||
// // The zero value, 0 for numeric types
|
||||
// if Self.writeBW == 0 && Self.readBW == 0 {
|
||||
// //logs.Warn("bw both 0")
|
||||
// return 100
|
||||
// }
|
||||
// if Self.writeBW == 0 && Self.readBW != 0 {
|
||||
// return Self.readBW
|
||||
// }
|
||||
// if Self.readBW == 0 && Self.writeBW != 0 {
|
||||
// return Self.writeBW
|
||||
// }
|
||||
// return Self.readBandwidth
|
||||
//}
|
75
lib/mux/map.go
Normal file
75
lib/mux/map.go
Normal file
@ -0,0 +1,75 @@
|
||||
package mux
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type connMap struct {
|
||||
connMap map[int32]*conn
|
||||
//closeCh chan struct{}
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func NewConnMap() *connMap {
|
||||
connMap := &connMap{
|
||||
connMap: make(map[int32]*conn),
|
||||
//closeCh: make(chan struct{}),
|
||||
}
|
||||
//go connMap.clean()
|
||||
return connMap
|
||||
}
|
||||
|
||||
func (s *connMap) Size() (n int) {
|
||||
s.Lock()
|
||||
n = len(s.connMap)
|
||||
s.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (s *connMap) Get(id int32) (*conn, bool) {
|
||||
s.Lock()
|
||||
v, ok := s.connMap[id]
|
||||
s.Unlock()
|
||||
if ok && v != nil {
|
||||
return v, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (s *connMap) Set(id int32, v *conn) {
|
||||
s.Lock()
|
||||
s.connMap[id] = v
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
func (s *connMap) Close() {
|
||||
//s.closeCh <- struct{}{} // stop the clean goroutine first
|
||||
for _, v := range s.connMap {
|
||||
v.Close() // close all the connections in the mux
|
||||
}
|
||||
}
|
||||
|
||||
func (s *connMap) Delete(id int32) {
|
||||
s.Lock()
|
||||
delete(s.connMap, id)
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
//func (s *connMap) clean() {
|
||||
// ticker := time.NewTimer(time.Minute * 1)
|
||||
// for {
|
||||
// select {
|
||||
// case <-ticker.C:
|
||||
// s.Lock()
|
||||
// for _, v := range s.connMap {
|
||||
// if v.isClose {
|
||||
// delete(s.connMap, v.connId)
|
||||
// }
|
||||
// }
|
||||
// s.Unlock()
|
||||
// case <-s.closeCh:
|
||||
// ticker.Stop()
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
//}
|
509
lib/mux/mux.go
Normal file
509
lib/mux/mux.go
Normal file
@ -0,0 +1,509 @@
|
||||
package mux
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
)
|
||||
|
||||
type Mux struct {
|
||||
latency uint64 // we store latency in bits, but it's float64
|
||||
net.Listener
|
||||
conn net.Conn
|
||||
connMap *connMap
|
||||
newConnCh chan *conn
|
||||
id int32
|
||||
closeChan chan struct{}
|
||||
IsClose bool
|
||||
pingOk uint32
|
||||
counter *latencyCounter
|
||||
bw *bandwidth
|
||||
pingCh chan []byte
|
||||
pingCheckTime uint32
|
||||
connType string
|
||||
writeQueue PriorityQueue
|
||||
newConnQueue ConnQueue
|
||||
}
|
||||
|
||||
func NewMux(c net.Conn, connType string) *Mux {
|
||||
//c.(*net.TCPConn).SetReadBuffer(0)
|
||||
//c.(*net.TCPConn).SetWriteBuffer(0)
|
||||
m := &Mux{
|
||||
conn: c,
|
||||
connMap: NewConnMap(),
|
||||
id: 0,
|
||||
closeChan: make(chan struct{}, 1),
|
||||
newConnCh: make(chan *conn),
|
||||
bw: new(bandwidth),
|
||||
IsClose: false,
|
||||
connType: connType,
|
||||
pingCh: make(chan []byte),
|
||||
counter: newLatencyCounter(),
|
||||
}
|
||||
m.writeQueue.New()
|
||||
m.newConnQueue.New()
|
||||
//read session by flag
|
||||
m.readSession()
|
||||
//ping
|
||||
m.ping()
|
||||
m.pingReturn()
|
||||
m.writeSession()
|
||||
return m
|
||||
}
|
||||
|
||||
func (s *Mux) NewConn() (*conn, error) {
|
||||
if s.IsClose {
|
||||
return nil, errors.New("the mux has closed")
|
||||
}
|
||||
conn := NewConn(s.getId(), s, "nps ")
|
||||
//it must be set before send
|
||||
s.connMap.Set(conn.connId, conn)
|
||||
s.sendInfo(common.MUX_NEW_CONN, conn.connId, nil)
|
||||
//set a timer timeout 30 second
|
||||
timer := time.NewTimer(time.Minute * 2)
|
||||
defer timer.Stop()
|
||||
select {
|
||||
case <-conn.connStatusOkCh:
|
||||
return conn, nil
|
||||
case <-conn.connStatusFailCh:
|
||||
case <-timer.C:
|
||||
}
|
||||
return nil, errors.New("create connection fail,the server refused the connection")
|
||||
}
|
||||
|
||||
func (s *Mux) Accept() (net.Conn, error) {
|
||||
if s.IsClose {
|
||||
return nil, errors.New("accpet error,the mux has closed")
|
||||
}
|
||||
conn := <-s.newConnCh
|
||||
if conn == nil {
|
||||
return nil, errors.New("accpet error,the conn has closed")
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (s *Mux) Addr() net.Addr {
|
||||
return s.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (s *Mux) sendInfo(flag uint8, id int32, data ...interface{}) {
|
||||
if s.IsClose {
|
||||
return
|
||||
}
|
||||
var err error
|
||||
pack := common.MuxPack.Get()
|
||||
err = pack.NewPac(flag, id, data...)
|
||||
if err != nil {
|
||||
common.MuxPack.Put(pack)
|
||||
logs.Error("mux: new pack err", err)
|
||||
s.Close()
|
||||
return
|
||||
}
|
||||
s.writeQueue.Push(pack)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Mux) writeSession() {
|
||||
go s.packBuf()
|
||||
//go s.writeBuf()
|
||||
}
|
||||
|
||||
func (s *Mux) packBuf() {
|
||||
//buffer := common.BuffPool.Get()
|
||||
for {
|
||||
if s.IsClose {
|
||||
break
|
||||
}
|
||||
//buffer.Reset()
|
||||
pack := s.writeQueue.Pop()
|
||||
if s.IsClose {
|
||||
break
|
||||
}
|
||||
//buffer := common.BuffPool.Get()
|
||||
err := pack.Pack(s.conn)
|
||||
common.MuxPack.Put(pack)
|
||||
if err != nil {
|
||||
logs.Error("mux: pack err", err)
|
||||
//common.BuffPool.Put(buffer)
|
||||
s.Close()
|
||||
break
|
||||
}
|
||||
//logs.Warn(buffer.String())
|
||||
//s.bufQueue.Push(buffer)
|
||||
//l := buffer.Len()
|
||||
//n, err := buffer.WriteTo(s.conn)
|
||||
//common.BuffPool.Put(buffer)
|
||||
//if err != nil || int(n) != l {
|
||||
// logs.Error("mux: close from write session fail ", err, n, l)
|
||||
// s.Close()
|
||||
// break
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
//func (s *Mux) writeBuf() {
|
||||
// for {
|
||||
// if s.IsClose {
|
||||
// break
|
||||
// }
|
||||
// buffer, err := s.bufQueue.Pop()
|
||||
// if err != nil {
|
||||
// break
|
||||
// }
|
||||
// l := buffer.Len()
|
||||
// n, err := buffer.WriteTo(s.conn)
|
||||
// common.BuffPool.Put(buffer)
|
||||
// if err != nil || int(n) != l {
|
||||
// logs.Warn("close from write session fail ", err, n, l)
|
||||
// s.Close()
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
func (s *Mux) ping() {
|
||||
go func() {
|
||||
now, _ := time.Now().UTC().MarshalText()
|
||||
s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, now)
|
||||
// send the ping flag and get the latency first
|
||||
ticker := time.NewTicker(time.Second * 5)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
if s.IsClose {
|
||||
break
|
||||
}
|
||||
select {
|
||||
case <-ticker.C:
|
||||
}
|
||||
if atomic.LoadUint32(&s.pingCheckTime) >= 60 {
|
||||
logs.Error("mux: ping time out")
|
||||
s.Close()
|
||||
// more than 5 minutes not receive the ping return package,
|
||||
// mux conn is damaged, maybe a packet drop, close it
|
||||
break
|
||||
}
|
||||
now, _ := time.Now().UTC().MarshalText()
|
||||
s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, now)
|
||||
atomic.AddUint32(&s.pingCheckTime, 1)
|
||||
if atomic.LoadUint32(&s.pingOk) > 10 && s.connType == "kcp" {
|
||||
logs.Error("mux: kcp ping err")
|
||||
s.Close()
|
||||
break
|
||||
}
|
||||
atomic.AddUint32(&s.pingOk, 1)
|
||||
}
|
||||
return
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *Mux) pingReturn() {
|
||||
go func() {
|
||||
var now time.Time
|
||||
var data []byte
|
||||
for {
|
||||
if s.IsClose {
|
||||
break
|
||||
}
|
||||
select {
|
||||
case data = <-s.pingCh:
|
||||
atomic.StoreUint32(&s.pingCheckTime, 0)
|
||||
case <-s.closeChan:
|
||||
break
|
||||
}
|
||||
_ = now.UnmarshalText(data)
|
||||
latency := time.Now().UTC().Sub(now).Seconds() / 2
|
||||
if latency > 0 {
|
||||
atomic.StoreUint64(&s.latency, math.Float64bits(s.counter.Latency(latency)))
|
||||
// convert float64 to bits, store it atomic
|
||||
}
|
||||
//logs.Warn("latency", math.Float64frombits(atomic.LoadUint64(&s.latency)))
|
||||
if cap(data) > 0 {
|
||||
common.WindowBuff.Put(data)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *Mux) readSession() {
|
||||
go func() {
|
||||
var connection *conn
|
||||
for {
|
||||
if s.IsClose {
|
||||
break
|
||||
}
|
||||
connection = s.newConnQueue.Pop()
|
||||
if s.IsClose {
|
||||
break // make sure that is closed
|
||||
}
|
||||
s.connMap.Set(connection.connId, connection) //it has been set before send ok
|
||||
s.newConnCh <- connection
|
||||
s.sendInfo(common.MUX_NEW_CONN_OK, connection.connId, nil)
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
pack := common.MuxPack.Get()
|
||||
var l uint16
|
||||
var err error
|
||||
for {
|
||||
if s.IsClose {
|
||||
break
|
||||
}
|
||||
pack = common.MuxPack.Get()
|
||||
s.bw.StartRead()
|
||||
if l, err = pack.UnPack(s.conn); err != nil {
|
||||
logs.Error("mux: read session unpack from connection err", err)
|
||||
s.Close()
|
||||
break
|
||||
}
|
||||
s.bw.SetCopySize(l)
|
||||
atomic.StoreUint32(&s.pingOk, 0)
|
||||
switch pack.Flag {
|
||||
case common.MUX_NEW_CONN: //new connection
|
||||
connection := NewConn(pack.Id, s)
|
||||
s.newConnQueue.Push(connection)
|
||||
continue
|
||||
case common.MUX_PING_FLAG: //ping
|
||||
s.sendInfo(common.MUX_PING_RETURN, common.MUX_PING, pack.Content)
|
||||
common.WindowBuff.Put(pack.Content)
|
||||
continue
|
||||
case common.MUX_PING_RETURN:
|
||||
//go func(content []byte) {
|
||||
s.pingCh <- pack.Content
|
||||
//}(pack.Content)
|
||||
continue
|
||||
}
|
||||
if connection, ok := s.connMap.Get(pack.Id); ok && !connection.isClose {
|
||||
switch pack.Flag {
|
||||
case common.MUX_NEW_MSG, common.MUX_NEW_MSG_PART: //new msg from remote connection
|
||||
err = s.newMsg(connection, pack)
|
||||
if err != nil {
|
||||
logs.Error("mux: read session connection new msg err", err)
|
||||
connection.Close()
|
||||
}
|
||||
continue
|
||||
case common.MUX_NEW_CONN_OK: //connection ok
|
||||
connection.connStatusOkCh <- struct{}{}
|
||||
continue
|
||||
case common.MUX_NEW_CONN_Fail:
|
||||
connection.connStatusFailCh <- struct{}{}
|
||||
continue
|
||||
case common.MUX_MSG_SEND_OK:
|
||||
if connection.isClose {
|
||||
continue
|
||||
}
|
||||
connection.sendWindow.SetSize(pack.Window, pack.ReadLength)
|
||||
continue
|
||||
case common.MUX_CONN_CLOSE: //close the connection
|
||||
connection.closeFlag = true
|
||||
//s.connMap.Delete(pack.Id)
|
||||
//go func(connection *conn) {
|
||||
connection.receiveWindow.Stop() // close signal to receive window
|
||||
//}(connection)
|
||||
continue
|
||||
}
|
||||
} else if pack.Flag == common.MUX_CONN_CLOSE {
|
||||
continue
|
||||
}
|
||||
common.MuxPack.Put(pack)
|
||||
}
|
||||
common.MuxPack.Put(pack)
|
||||
s.Close()
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *Mux) newMsg(connection *conn, pack *common.MuxPackager) (err error) {
|
||||
if connection.isClose {
|
||||
err = io.ErrClosedPipe
|
||||
return
|
||||
}
|
||||
//logs.Warn("read session receive new msg", pack.Length)
|
||||
//go func(connection *conn, pack *common.MuxPackager) { // do not block read session
|
||||
//insert into queue
|
||||
if pack.Flag == common.MUX_NEW_MSG_PART {
|
||||
err = connection.receiveWindow.Write(pack.Content, pack.Length, true, pack.Id)
|
||||
}
|
||||
if pack.Flag == common.MUX_NEW_MSG {
|
||||
err = connection.receiveWindow.Write(pack.Content, pack.Length, false, pack.Id)
|
||||
}
|
||||
//logs.Warn("read session write success", pack.Length)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Mux) Close() (err error) {
|
||||
logs.Warn("close mux")
|
||||
if s.IsClose {
|
||||
return errors.New("the mux has closed")
|
||||
}
|
||||
s.IsClose = true
|
||||
s.connMap.Close()
|
||||
s.connMap = nil
|
||||
//s.bufQueue.Stop()
|
||||
s.closeChan <- struct{}{}
|
||||
close(s.newConnCh)
|
||||
err = s.conn.Close()
|
||||
s.release()
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Mux) release() {
|
||||
for {
|
||||
pack := s.writeQueue.TryPop()
|
||||
if pack == nil {
|
||||
break
|
||||
}
|
||||
if pack.BasePackager.Content != nil {
|
||||
common.WindowBuff.Put(pack.BasePackager.Content)
|
||||
}
|
||||
common.MuxPack.Put(pack)
|
||||
}
|
||||
for {
|
||||
connection := s.newConnQueue.TryPop()
|
||||
if connection == nil {
|
||||
break
|
||||
}
|
||||
connection = nil
|
||||
}
|
||||
s.writeQueue.Stop()
|
||||
s.newConnQueue.Stop()
|
||||
}
|
||||
|
||||
//get new connId as unique flag
|
||||
func (s *Mux) getId() (id int32) {
|
||||
//Avoid going beyond the scope
|
||||
if (math.MaxInt32 - s.id) < 10000 {
|
||||
atomic.StoreInt32(&s.id, 0)
|
||||
}
|
||||
id = atomic.AddInt32(&s.id, 1)
|
||||
if _, ok := s.connMap.Get(id); ok {
|
||||
return s.getId()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type bandwidth struct {
|
||||
readBandwidth uint64 // store in bits, but it's float64
|
||||
readStart time.Time
|
||||
lastReadStart time.Time
|
||||
bufLength uint32
|
||||
}
|
||||
|
||||
func (Self *bandwidth) StartRead() {
|
||||
if Self.readStart.IsZero() {
|
||||
Self.readStart = time.Now()
|
||||
}
|
||||
if Self.bufLength >= common.MAXIMUM_SEGMENT_SIZE*300 {
|
||||
Self.lastReadStart, Self.readStart = Self.readStart, time.Now()
|
||||
Self.calcBandWidth()
|
||||
}
|
||||
}
|
||||
|
||||
func (Self *bandwidth) SetCopySize(n uint16) {
|
||||
Self.bufLength += uint32(n)
|
||||
}
|
||||
|
||||
func (Self *bandwidth) calcBandWidth() {
|
||||
t := Self.readStart.Sub(Self.lastReadStart)
|
||||
atomic.StoreUint64(&Self.readBandwidth, math.Float64bits(float64(Self.bufLength)/t.Seconds()))
|
||||
Self.bufLength = 0
|
||||
}
|
||||
|
||||
func (Self *bandwidth) Get() (bw float64) {
|
||||
// The zero value, 0 for numeric types
|
||||
bw = math.Float64frombits(atomic.LoadUint64(&Self.readBandwidth))
|
||||
if bw <= 0 {
|
||||
bw = 100
|
||||
}
|
||||
//logs.Warn(bw)
|
||||
return
|
||||
}
|
||||
|
||||
const counterBits = 4
|
||||
const counterMask = 1<<counterBits - 1
|
||||
|
||||
func newLatencyCounter() *latencyCounter {
|
||||
return &latencyCounter{
|
||||
buf: make([]float64, 1<<counterBits, 1<<counterBits),
|
||||
headMin: 0,
|
||||
}
|
||||
}
|
||||
|
||||
type latencyCounter struct {
|
||||
buf []float64 //buf is a fixed length ring buffer,
|
||||
// if buffer is full, new value will replace the oldest one.
|
||||
headMin uint8 //head indicate the head in ring buffer,
|
||||
// in meaning, slot in list will be replaced;
|
||||
// min indicate this slot value is minimal in list.
|
||||
}
|
||||
|
||||
func (Self *latencyCounter) unpack(idxs uint8) (head, min uint8) {
|
||||
head = uint8((idxs >> counterBits) & counterMask)
|
||||
// we set head is 4 bits
|
||||
min = uint8(idxs & counterMask)
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *latencyCounter) pack(head, min uint8) uint8 {
|
||||
return uint8(head<<counterBits) |
|
||||
uint8(min&counterMask)
|
||||
}
|
||||
|
||||
func (Self *latencyCounter) add(value float64) {
|
||||
head, min := Self.unpack(Self.headMin)
|
||||
Self.buf[head] = value
|
||||
if head == min {
|
||||
min = Self.minimal()
|
||||
//if head equals min, means the min slot already be replaced,
|
||||
// so we need to find another minimal value in the list,
|
||||
// and change the min indicator
|
||||
}
|
||||
if Self.buf[min] > value {
|
||||
min = head
|
||||
}
|
||||
head++
|
||||
Self.headMin = Self.pack(head, min)
|
||||
}
|
||||
|
||||
func (Self *latencyCounter) minimal() (min uint8) {
|
||||
var val float64
|
||||
var i uint8
|
||||
for i = 0; i < counterMask; i++ {
|
||||
if Self.buf[i] > 0 {
|
||||
if val > Self.buf[i] {
|
||||
val = Self.buf[i]
|
||||
min = i
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *latencyCounter) Latency(value float64) (latency float64) {
|
||||
Self.add(value)
|
||||
_, min := Self.unpack(Self.headMin)
|
||||
latency = Self.buf[min] * Self.countSuccess()
|
||||
return
|
||||
}
|
||||
|
||||
const lossRatio = 1.6
|
||||
|
||||
func (Self *latencyCounter) countSuccess() (successRate float64) {
|
||||
var success, loss, i uint8
|
||||
_, min := Self.unpack(Self.headMin)
|
||||
for i = 0; i < counterMask; i++ {
|
||||
if Self.buf[i] > lossRatio*Self.buf[min] && Self.buf[i] > 0 {
|
||||
loss++
|
||||
}
|
||||
if Self.buf[i] <= lossRatio*Self.buf[min] && Self.buf[i] > 0 {
|
||||
success++
|
||||
}
|
||||
}
|
||||
// counting all the data in the ring buf, except zero
|
||||
successRate = float64(success) / float64(loss+success)
|
||||
return
|
||||
}
|
447
lib/mux/mux_test.go
Normal file
447
lib/mux/mux_test.go
Normal file
@ -0,0 +1,447 @@
|
||||
package mux
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/goroutine"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
_ "net/http/pprof"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/astaxie/beego/logs"
|
||||
)
|
||||
|
||||
var conn1 net.Conn
|
||||
var conn2 net.Conn
|
||||
|
||||
func TestNewMux(t *testing.T) {
|
||||
go func() {
|
||||
http.ListenAndServe("0.0.0.0:8889", nil)
|
||||
}()
|
||||
logs.EnableFuncCallDepth(true)
|
||||
logs.SetLogFuncCallDepth(3)
|
||||
server()
|
||||
client()
|
||||
//poolConnCopy, _ := ants.NewPoolWithFunc(200000, common.copyConn, ants.WithNonblocking(false))
|
||||
time.Sleep(time.Second * 3)
|
||||
go func() {
|
||||
m2 := NewMux(conn2, "tcp")
|
||||
for {
|
||||
//logs.Warn("npc starting accept")
|
||||
c, err := m2.Accept()
|
||||
if err != nil {
|
||||
logs.Warn(err)
|
||||
continue
|
||||
}
|
||||
//logs.Warn("npc accept success ")
|
||||
c2, err := net.Dial("tcp", "127.0.0.1:80")
|
||||
if err != nil {
|
||||
logs.Warn(err)
|
||||
c.Close()
|
||||
continue
|
||||
}
|
||||
//c2.(*net.TCPConn).SetReadBuffer(0)
|
||||
//c2.(*net.TCPConn).SetReadBuffer(0)
|
||||
_ = goroutine.CopyConnsPool.Invoke(goroutine.NewConns(c, c2, nil))
|
||||
//go func(c2 net.Conn, c *conn) {
|
||||
// wg := new(sync.WaitGroup)
|
||||
// wg.Add(2)
|
||||
// _ = poolConnCopy.Invoke(common.newConnGroup(c2, c, wg))
|
||||
// //go func() {
|
||||
// // _, err = common.CopyBuffer(c2, c)
|
||||
// // if err != nil {
|
||||
// // c2.Close()
|
||||
// // c.Close()
|
||||
// // //logs.Warn("close npc by copy from nps", err, c.connId)
|
||||
// // }
|
||||
// // wg.Done()
|
||||
// //}()
|
||||
// //wg.Add(1)
|
||||
// _ = poolConnCopy.Invoke(common.newConnGroup(c, c2, wg))
|
||||
// //go func() {
|
||||
// // _, err = common.CopyBuffer(c, c2)
|
||||
// // if err != nil {
|
||||
// // c2.Close()
|
||||
// // c.Close()
|
||||
// // //logs.Warn("close npc by copy from server", err, c.connId)
|
||||
// // }
|
||||
// // wg.Done()
|
||||
// //}()
|
||||
// //logs.Warn("npc wait")
|
||||
// wg.Wait()
|
||||
//}(c2, c.(*conn))
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
m1 := NewMux(conn1, "tcp")
|
||||
l, err := net.Listen("tcp", "127.0.0.1:7777")
|
||||
if err != nil {
|
||||
logs.Warn(err)
|
||||
}
|
||||
for {
|
||||
//logs.Warn("nps starting accept")
|
||||
conns, err := l.Accept()
|
||||
if err != nil {
|
||||
logs.Warn(err)
|
||||
continue
|
||||
}
|
||||
//conns.(*net.TCPConn).SetReadBuffer(0)
|
||||
//conns.(*net.TCPConn).SetReadBuffer(0)
|
||||
//logs.Warn("nps accept success starting new conn")
|
||||
tmpCpnn, err := m1.NewConn()
|
||||
if err != nil {
|
||||
logs.Warn("nps new conn err ", err)
|
||||
continue
|
||||
}
|
||||
//logs.Warn("nps new conn success ", tmpCpnn.connId)
|
||||
_ = goroutine.CopyConnsPool.Invoke(goroutine.NewConns(tmpCpnn, conns, nil))
|
||||
//go func(tmpCpnn *conn, conns net.Conn) {
|
||||
// wg := new(sync.WaitGroup)
|
||||
// wg.Add(2)
|
||||
// _ = poolConnCopy.Invoke(common.newConnGroup(tmpCpnn, conns, wg))
|
||||
// //go func() {
|
||||
// // _, err := common.CopyBuffer(tmpCpnn, conns)
|
||||
// // if err != nil {
|
||||
// // conns.Close()
|
||||
// // tmpCpnn.Close()
|
||||
// // //logs.Warn("close nps by copy from user", tmpCpnn.connId, err)
|
||||
// // }
|
||||
// //}()
|
||||
// //wg.Add(1)
|
||||
// _ = poolConnCopy.Invoke(common.newConnGroup(conns, tmpCpnn, wg))
|
||||
// //time.Sleep(time.Second)
|
||||
// //_, err = common.CopyBuffer(conns, tmpCpnn)
|
||||
// //if err != nil {
|
||||
// // conns.Close()
|
||||
// // tmpCpnn.Close()
|
||||
// // //logs.Warn("close nps by copy from npc ", tmpCpnn.connId, err)
|
||||
// //}
|
||||
// wg.Wait()
|
||||
//}(tmpCpnn, conns)
|
||||
}
|
||||
}()
|
||||
|
||||
//go NewLogServer()
|
||||
time.Sleep(time.Second * 5)
|
||||
//for i := 0; i < 1; i++ {
|
||||
// go test_raw(i)
|
||||
//}
|
||||
//test_request()
|
||||
|
||||
for {
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
}
|
||||
|
||||
func server() {
|
||||
var err error
|
||||
l, err := net.Listen("tcp", "127.0.0.1:9999")
|
||||
if err != nil {
|
||||
logs.Warn(err)
|
||||
}
|
||||
go func() {
|
||||
conn1, err = l.Accept()
|
||||
if err != nil {
|
||||
logs.Warn(err)
|
||||
}
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
func client() {
|
||||
var err error
|
||||
conn2, err = net.Dial("tcp", "127.0.0.1:9999")
|
||||
if err != nil {
|
||||
logs.Warn(err)
|
||||
}
|
||||
}
|
||||
|
||||
func test_request() {
|
||||
conn, _ := net.Dial("tcp", "127.0.0.1:7777")
|
||||
for i := 0; i < 1000; i++ {
|
||||
conn.Write([]byte(`GET / HTTP/1.1
|
||||
Host: 127.0.0.1:7777
|
||||
Connection: keep-alive
|
||||
|
||||
|
||||
`))
|
||||
r, err := http.ReadResponse(bufio.NewReader(conn), nil)
|
||||
if err != nil {
|
||||
logs.Warn("close by read response err", err)
|
||||
break
|
||||
}
|
||||
logs.Warn("read response success", r)
|
||||
b, err := httputil.DumpResponse(r, true)
|
||||
if err != nil {
|
||||
logs.Warn("close by dump response err", err)
|
||||
break
|
||||
}
|
||||
fmt.Println(string(b[:20]), err)
|
||||
//time.Sleep(time.Second)
|
||||
}
|
||||
logs.Warn("finish")
|
||||
}
|
||||
|
||||
func test_raw(k int) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
ti := time.Now()
|
||||
conn, err := net.Dial("tcp", "127.0.0.1:7777")
|
||||
if err != nil {
|
||||
logs.Warn("conn dial err", err)
|
||||
}
|
||||
tid := time.Now()
|
||||
conn.Write([]byte(`GET /videojs5/video.js HTTP/1.1
|
||||
Host: 127.0.0.1:7777
|
||||
|
||||
|
||||
`))
|
||||
tiw := time.Now()
|
||||
buf := make([]byte, 3572)
|
||||
n, err := io.ReadFull(conn, buf)
|
||||
//n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
logs.Warn("close by read response err", err)
|
||||
break
|
||||
}
|
||||
logs.Warn(n, string(buf[:50]), "\n--------------\n", string(buf[n-50:n]))
|
||||
//time.Sleep(time.Second)
|
||||
err = conn.Close()
|
||||
if err != nil {
|
||||
logs.Warn("close conn err ", err)
|
||||
}
|
||||
now := time.Now()
|
||||
du := now.Sub(ti).Seconds()
|
||||
dud := now.Sub(tid).Seconds()
|
||||
duw := now.Sub(tiw).Seconds()
|
||||
if du > 1 {
|
||||
logs.Warn("duration long", du, dud, duw, k, i)
|
||||
}
|
||||
if n != 3572 {
|
||||
logs.Warn("n loss", n, string(buf))
|
||||
}
|
||||
}
|
||||
logs.Warn("finish")
|
||||
}
|
||||
|
||||
func TestNewConn(t *testing.T) {
|
||||
buf := common.GetBufPoolCopy()
|
||||
logs.Warn(len(buf), cap(buf))
|
||||
//b := pool.GetBufPoolCopy()
|
||||
//b[0] = 1
|
||||
//b[1] = 2
|
||||
//b[2] = 3
|
||||
b := []byte{1, 2, 3}
|
||||
logs.Warn(copy(buf[:3], b), len(buf), cap(buf))
|
||||
logs.Warn(len(buf), buf[0])
|
||||
}
|
||||
|
||||
func TestDQueue(t *testing.T) {
|
||||
logs.EnableFuncCallDepth(true)
|
||||
logs.SetLogFuncCallDepth(3)
|
||||
d := new(bufDequeue)
|
||||
d.vals = make([]unsafe.Pointer, 8)
|
||||
go func() {
|
||||
time.Sleep(time.Second)
|
||||
for i := 0; i < 10; i++ {
|
||||
logs.Warn(i)
|
||||
logs.Warn(d.popTail())
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
time.Sleep(time.Second)
|
||||
for i := 0; i < 10; i++ {
|
||||
data := "test"
|
||||
go logs.Warn(i, unsafe.Pointer(&data), d.pushHead(unsafe.Pointer(&data)))
|
||||
}
|
||||
}()
|
||||
time.Sleep(time.Second * 3)
|
||||
}
|
||||
|
||||
func TestChain(t *testing.T) {
|
||||
go func() {
|
||||
log.Println(http.ListenAndServe("0.0.0.0:8889", nil))
|
||||
}()
|
||||
logs.EnableFuncCallDepth(true)
|
||||
logs.SetLogFuncCallDepth(3)
|
||||
time.Sleep(time.Second * 5)
|
||||
d := new(bufChain)
|
||||
d.new(256)
|
||||
go func() {
|
||||
time.Sleep(time.Second)
|
||||
for i := 0; i < 30000; i++ {
|
||||
unsa, ok := d.popTail()
|
||||
str := (*string)(unsa)
|
||||
if ok {
|
||||
fmt.Println(i, str, *str, ok)
|
||||
//logs.Warn(i, str, *str, ok)
|
||||
} else {
|
||||
fmt.Println("nil", i, ok)
|
||||
//logs.Warn("nil", i, ok)
|
||||
}
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
time.Sleep(time.Second)
|
||||
for i := 0; i < 3000; i++ {
|
||||
go func(i int) {
|
||||
for n := 0; n < 10; n++ {
|
||||
data := "test " + strconv.Itoa(i) + strconv.Itoa(n)
|
||||
fmt.Println(data, unsafe.Pointer(&data))
|
||||
//logs.Warn(data, unsafe.Pointer(&data))
|
||||
d.pushHead(unsafe.Pointer(&data))
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
}()
|
||||
time.Sleep(time.Second * 100000)
|
||||
}
|
||||
|
||||
func TestFIFO(t *testing.T) {
|
||||
go func() {
|
||||
log.Println(http.ListenAndServe("0.0.0.0:8889", nil))
|
||||
}()
|
||||
logs.EnableFuncCallDepth(true)
|
||||
logs.SetLogFuncCallDepth(3)
|
||||
time.Sleep(time.Second * 5)
|
||||
d := new(ReceiveWindowQueue)
|
||||
d.New()
|
||||
go func() {
|
||||
time.Sleep(time.Second)
|
||||
for i := 0; i < 1001; i++ {
|
||||
data, err := d.Pop()
|
||||
if err == nil {
|
||||
//fmt.Println(i, string(data.buf), err)
|
||||
logs.Warn(i, string(data.Buf), err)
|
||||
common.ListElementPool.Put(data)
|
||||
} else {
|
||||
//fmt.Println("err", err)
|
||||
logs.Warn("err", err)
|
||||
}
|
||||
//logs.Warn(d.Len())
|
||||
}
|
||||
logs.Warn("pop finish")
|
||||
}()
|
||||
go func() {
|
||||
time.Sleep(time.Second * 10)
|
||||
for i := 0; i < 1000; i++ {
|
||||
by := []byte("test " + strconv.Itoa(i) + " ") //
|
||||
data, _ := NewListElement(by, uint16(len(by)), true)
|
||||
//fmt.Println(string((*data).buf), data)
|
||||
//logs.Warn(string((*data).buf), data)
|
||||
d.Push(data)
|
||||
}
|
||||
}()
|
||||
time.Sleep(time.Second * 100000)
|
||||
}
|
||||
|
||||
func TestPriority(t *testing.T) {
|
||||
go func() {
|
||||
log.Println(http.ListenAndServe("0.0.0.0:8889", nil))
|
||||
}()
|
||||
logs.EnableFuncCallDepth(true)
|
||||
logs.SetLogFuncCallDepth(3)
|
||||
time.Sleep(time.Second * 5)
|
||||
d := new(PriorityQueue)
|
||||
d.New()
|
||||
go func() {
|
||||
time.Sleep(time.Second)
|
||||
for i := 0; i < 360050; i++ {
|
||||
data := d.Pop()
|
||||
//fmt.Println(i, string(data.buf), err)
|
||||
logs.Warn(i, string(data.Content), data)
|
||||
}
|
||||
logs.Warn("pop finish")
|
||||
}()
|
||||
go func() {
|
||||
time.Sleep(time.Second * 10)
|
||||
for i := 0; i < 30000; i++ {
|
||||
go func(i int) {
|
||||
for n := 0; n < 10; n++ {
|
||||
data := new(common.MuxPackager)
|
||||
by := []byte("test " + strconv.Itoa(i) + strconv.Itoa(n))
|
||||
_ = data.NewPac(common.MUX_NEW_MSG_PART, int32(i), by)
|
||||
//fmt.Println(string((*data).buf), data)
|
||||
logs.Warn(string((*data).Content), data)
|
||||
d.Push(data)
|
||||
}
|
||||
}(i)
|
||||
go func(i int) {
|
||||
data := new(common.MuxPackager)
|
||||
_ = data.NewPac(common.MUX_NEW_CONN, int32(i), nil)
|
||||
//fmt.Println(string((*data).buf), data)
|
||||
logs.Warn(data)
|
||||
d.Push(data)
|
||||
}(i)
|
||||
go func(i int) {
|
||||
data := new(common.MuxPackager)
|
||||
_ = data.NewPac(common.MUX_NEW_CONN_OK, int32(i), nil)
|
||||
//fmt.Println(string((*data).buf), data)
|
||||
logs.Warn(data)
|
||||
d.Push(data)
|
||||
}(i)
|
||||
}
|
||||
}()
|
||||
time.Sleep(time.Second * 100000)
|
||||
}
|
||||
|
||||
//func TestReceive(t *testing.T) {
|
||||
// go func() {
|
||||
// log.Println(http.ListenAndServe("0.0.0.0:8889", nil))
|
||||
// }()
|
||||
// logs.EnableFuncCallDepth(true)
|
||||
// logs.SetLogFuncCallDepth(3)
|
||||
// time.Sleep(time.Second * 5)
|
||||
// mux := new(Mux)
|
||||
// mux.bw.readBandwidth = float64(1*1024*1024)
|
||||
// mux.latency = float64(1/1000)
|
||||
// wind := new(ReceiveWindow)
|
||||
// wind.New(mux)
|
||||
// wind.
|
||||
// go func() {
|
||||
// time.Sleep(time.Second)
|
||||
// for i := 0; i < 36000; i++ {
|
||||
// data := d.Pop()
|
||||
// //fmt.Println(i, string(data.buf), err)
|
||||
// logs.Warn(i, string(data.Content), data)
|
||||
// }
|
||||
// }()
|
||||
// go func() {
|
||||
// time.Sleep(time.Second*10)
|
||||
// for i := 0; i < 3000; i++ {
|
||||
// go func(i int) {
|
||||
// for n := 0; n < 10; n++{
|
||||
// data := new(common.MuxPackager)
|
||||
// by := []byte("test " + strconv.Itoa(i) + strconv.Itoa(n))
|
||||
// _ = data.NewPac(common.MUX_NEW_MSG_PART, int32(i), by)
|
||||
// //fmt.Println(string((*data).buf), data)
|
||||
// logs.Warn(string((*data).Content), data)
|
||||
// d.Push(data)
|
||||
// }
|
||||
// }(i)
|
||||
// go func(i int) {
|
||||
// data := new(common.MuxPackager)
|
||||
// _ = data.NewPac(common.MUX_NEW_CONN, int32(i), nil)
|
||||
// //fmt.Println(string((*data).buf), data)
|
||||
// logs.Warn(data)
|
||||
// d.Push(data)
|
||||
// }(i)
|
||||
// go func(i int) {
|
||||
// data := new(common.MuxPackager)
|
||||
// _ = data.NewPac(common.MUX_NEW_CONN_OK, int32(i), nil)
|
||||
// //fmt.Println(string((*data).buf), data)
|
||||
// logs.Warn(data)
|
||||
// d.Push(data)
|
||||
// }(i)
|
||||
// }
|
||||
// }()
|
||||
// time.Sleep(time.Second * 100000)
|
||||
//}
|
@ -1,4 +1,4 @@
|
||||
package pmux
|
||||
package mux
|
||||
|
||||
import (
|
||||
"net"
|
@ -1,4 +1,4 @@
|
||||
package pmux
|
||||
package mux
|
||||
|
||||
import (
|
||||
"errors"
|
@ -1,6 +1,6 @@
|
||||
// This module is used for port reuse
|
||||
// Distinguish client, web manager , HTTP and HTTPS according to the difference of protocol
|
||||
package pmux
|
||||
package mux
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
@ -12,8 +12,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@ -139,7 +139,7 @@ func (pMux *PortMux) process(conn net.Conn) {
|
||||
|
||||
func (pMux *PortMux) Close() error {
|
||||
if pMux.isClose {
|
||||
return errors.New("the port pmux has closed")
|
||||
return errors.New("the port mux has closed")
|
||||
}
|
||||
pMux.isClose = true
|
||||
close(pMux.clientConn)
|
@ -1,4 +1,4 @@
|
||||
package pmux
|
||||
package mux
|
||||
|
||||
import (
|
||||
"testing"
|
589
lib/mux/queue.go
Normal file
589
lib/mux/queue.go
Normal file
@ -0,0 +1,589 @@
|
||||
package mux
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"io"
|
||||
"math"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type PriorityQueue struct {
|
||||
highestChain *bufChain
|
||||
middleChain *bufChain
|
||||
lowestChain *bufChain
|
||||
starving uint8
|
||||
stop bool
|
||||
cond *sync.Cond
|
||||
}
|
||||
|
||||
func (Self *PriorityQueue) New() {
|
||||
Self.highestChain = new(bufChain)
|
||||
Self.highestChain.new(4)
|
||||
Self.middleChain = new(bufChain)
|
||||
Self.middleChain.new(32)
|
||||
Self.lowestChain = new(bufChain)
|
||||
Self.lowestChain.new(256)
|
||||
locker := new(sync.Mutex)
|
||||
Self.cond = sync.NewCond(locker)
|
||||
}
|
||||
|
||||
func (Self *PriorityQueue) Push(packager *common.MuxPackager) {
|
||||
//logs.Warn("push start")
|
||||
Self.push(packager)
|
||||
Self.cond.Broadcast()
|
||||
//logs.Warn("push finish")
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *PriorityQueue) push(packager *common.MuxPackager) {
|
||||
switch packager.Flag {
|
||||
case common.MUX_PING_FLAG, common.MUX_PING_RETURN:
|
||||
Self.highestChain.pushHead(unsafe.Pointer(packager))
|
||||
// the ping package need highest priority
|
||||
// prevent ping calculation error
|
||||
case common.MUX_NEW_CONN, common.MUX_NEW_CONN_OK, common.MUX_NEW_CONN_Fail:
|
||||
// the new conn package need some priority too
|
||||
Self.middleChain.pushHead(unsafe.Pointer(packager))
|
||||
default:
|
||||
Self.lowestChain.pushHead(unsafe.Pointer(packager))
|
||||
}
|
||||
}
|
||||
|
||||
const maxStarving uint8 = 8
|
||||
|
||||
func (Self *PriorityQueue) Pop() (packager *common.MuxPackager) {
|
||||
var iter bool
|
||||
for {
|
||||
packager = Self.TryPop()
|
||||
if packager != nil {
|
||||
return
|
||||
}
|
||||
if Self.stop {
|
||||
return
|
||||
}
|
||||
if iter {
|
||||
break
|
||||
// trying to pop twice
|
||||
}
|
||||
iter = true
|
||||
runtime.Gosched()
|
||||
}
|
||||
Self.cond.L.Lock()
|
||||
defer Self.cond.L.Unlock()
|
||||
for packager = Self.TryPop(); packager == nil; {
|
||||
if Self.stop {
|
||||
return
|
||||
}
|
||||
//logs.Warn("queue into wait")
|
||||
Self.cond.Wait()
|
||||
// wait for it with no more iter
|
||||
packager = Self.TryPop()
|
||||
//logs.Warn("queue wait finish", packager)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *PriorityQueue) TryPop() (packager *common.MuxPackager) {
|
||||
ptr, ok := Self.highestChain.popTail()
|
||||
if ok {
|
||||
packager = (*common.MuxPackager)(ptr)
|
||||
return
|
||||
}
|
||||
if Self.starving < maxStarving {
|
||||
// not pop too much, lowestChain will wait too long
|
||||
ptr, ok = Self.middleChain.popTail()
|
||||
if ok {
|
||||
packager = (*common.MuxPackager)(ptr)
|
||||
Self.starving++
|
||||
return
|
||||
}
|
||||
}
|
||||
ptr, ok = Self.lowestChain.popTail()
|
||||
if ok {
|
||||
packager = (*common.MuxPackager)(ptr)
|
||||
if Self.starving > 0 {
|
||||
Self.starving = uint8(Self.starving / 2)
|
||||
}
|
||||
return
|
||||
}
|
||||
if Self.starving > 0 {
|
||||
ptr, ok = Self.middleChain.popTail()
|
||||
if ok {
|
||||
packager = (*common.MuxPackager)(ptr)
|
||||
Self.starving++
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *PriorityQueue) Stop() {
|
||||
Self.stop = true
|
||||
Self.cond.Broadcast()
|
||||
}
|
||||
|
||||
type ConnQueue struct {
|
||||
chain *bufChain
|
||||
starving uint8
|
||||
stop bool
|
||||
cond *sync.Cond
|
||||
}
|
||||
|
||||
func (Self *ConnQueue) New() {
|
||||
Self.chain = new(bufChain)
|
||||
Self.chain.new(32)
|
||||
locker := new(sync.Mutex)
|
||||
Self.cond = sync.NewCond(locker)
|
||||
}
|
||||
|
||||
func (Self *ConnQueue) Push(connection *conn) {
|
||||
Self.chain.pushHead(unsafe.Pointer(connection))
|
||||
Self.cond.Broadcast()
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *ConnQueue) Pop() (connection *conn) {
|
||||
var iter bool
|
||||
for {
|
||||
connection = Self.TryPop()
|
||||
if connection != nil {
|
||||
return
|
||||
}
|
||||
if Self.stop {
|
||||
return
|
||||
}
|
||||
if iter {
|
||||
break
|
||||
// trying to pop twice
|
||||
}
|
||||
iter = true
|
||||
runtime.Gosched()
|
||||
}
|
||||
Self.cond.L.Lock()
|
||||
defer Self.cond.L.Unlock()
|
||||
for connection = Self.TryPop(); connection == nil; {
|
||||
if Self.stop {
|
||||
return
|
||||
}
|
||||
//logs.Warn("queue into wait")
|
||||
Self.cond.Wait()
|
||||
// wait for it with no more iter
|
||||
connection = Self.TryPop()
|
||||
//logs.Warn("queue wait finish", packager)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *ConnQueue) TryPop() (connection *conn) {
|
||||
ptr, ok := Self.chain.popTail()
|
||||
if ok {
|
||||
connection = (*conn)(ptr)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *ConnQueue) Stop() {
|
||||
Self.stop = true
|
||||
Self.cond.Broadcast()
|
||||
}
|
||||
|
||||
func NewListElement(buf []byte, l uint16, part bool) (element *common.ListElement, err error) {
|
||||
if uint16(len(buf)) != l {
|
||||
err = errors.New("ListElement: buf length not match")
|
||||
return
|
||||
}
|
||||
//if l == 0 {
|
||||
// logs.Warn("push zero")
|
||||
//}
|
||||
element = common.ListElementPool.Get()
|
||||
element.Buf = buf
|
||||
element.L = l
|
||||
element.Part = part
|
||||
return
|
||||
}
|
||||
|
||||
type ReceiveWindowQueue struct {
|
||||
chain *bufChain
|
||||
stopOp chan struct{}
|
||||
readOp chan struct{}
|
||||
lengthWait uint64 // really strange ???? need put here
|
||||
// https://golang.org/pkg/sync/atomic/#pkg-note-BUG
|
||||
// On non-Linux ARM, the 64-bit functions use instructions unavailable before the ARMv6k core.
|
||||
// On ARM, x86-32, and 32-bit MIPS, it is the caller's responsibility
|
||||
// to arrange for 64-bit alignment of 64-bit words accessed atomically.
|
||||
// The first word in a variable or in an allocated struct, array, or slice can be relied upon to be 64-bit aligned.
|
||||
timeout time.Time
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindowQueue) New() {
|
||||
Self.readOp = make(chan struct{})
|
||||
Self.chain = new(bufChain)
|
||||
Self.chain.new(64)
|
||||
Self.stopOp = make(chan struct{}, 2)
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindowQueue) Push(element *common.ListElement) {
|
||||
var length, wait uint32
|
||||
for {
|
||||
ptrs := atomic.LoadUint64(&Self.lengthWait)
|
||||
length, wait = Self.chain.head.unpack(ptrs)
|
||||
length += uint32(element.L)
|
||||
if atomic.CompareAndSwapUint64(&Self.lengthWait, ptrs, Self.chain.head.pack(length, 0)) {
|
||||
break
|
||||
}
|
||||
// another goroutine change the length or into wait, make sure
|
||||
}
|
||||
//logs.Warn("window push before", Self.Len(), uint32(element.l), len(element.buf))
|
||||
Self.chain.pushHead(unsafe.Pointer(element))
|
||||
//logs.Warn("window push", Self.Len())
|
||||
if wait == 1 {
|
||||
Self.allowPop()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindowQueue) Pop() (element *common.ListElement, err error) {
|
||||
var length uint32
|
||||
startPop:
|
||||
ptrs := atomic.LoadUint64(&Self.lengthWait)
|
||||
length, _ = Self.chain.head.unpack(ptrs)
|
||||
if length == 0 {
|
||||
if !atomic.CompareAndSwapUint64(&Self.lengthWait, ptrs, Self.chain.head.pack(0, 1)) {
|
||||
goto startPop // another goroutine is pushing
|
||||
}
|
||||
err = Self.waitPush()
|
||||
// there is no more data in queue, wait for it
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
goto startPop // wait finish, trying to get the new status
|
||||
}
|
||||
// length is not zero, so try to pop
|
||||
for {
|
||||
element = Self.TryPop()
|
||||
if element != nil {
|
||||
return
|
||||
}
|
||||
runtime.Gosched() // another goroutine is still pushing
|
||||
}
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindowQueue) TryPop() (element *common.ListElement) {
|
||||
ptr, ok := Self.chain.popTail()
|
||||
if ok {
|
||||
//logs.Warn("window pop before", Self.Len())
|
||||
element = (*common.ListElement)(ptr)
|
||||
atomic.AddUint64(&Self.lengthWait, ^(uint64(element.L)<<dequeueBits - 1))
|
||||
//logs.Warn("window pop", Self.Len(), uint32(element.l))
|
||||
return
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindowQueue) allowPop() (closed bool) {
|
||||
//logs.Warn("allow pop", Self.Len())
|
||||
select {
|
||||
case Self.readOp <- struct{}{}:
|
||||
return false
|
||||
case <-Self.stopOp:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindowQueue) waitPush() (err error) {
|
||||
//logs.Warn("wait push")
|
||||
//defer logs.Warn("wait push finish")
|
||||
t := Self.timeout.Sub(time.Now())
|
||||
if t <= 0 { // not set the timeout, so wait for it without timeout, just like a tcp connection
|
||||
select {
|
||||
case <-Self.readOp:
|
||||
return nil
|
||||
case <-Self.stopOp:
|
||||
err = io.EOF
|
||||
return
|
||||
}
|
||||
}
|
||||
timer := time.NewTimer(t)
|
||||
defer timer.Stop()
|
||||
//logs.Warn("queue into wait")
|
||||
select {
|
||||
case <-Self.readOp:
|
||||
//logs.Warn("queue wait finish")
|
||||
return nil
|
||||
case <-Self.stopOp:
|
||||
err = io.EOF
|
||||
return
|
||||
case <-timer.C:
|
||||
err = errors.New("mux.queue: read time out")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindowQueue) Len() (n uint32) {
|
||||
ptrs := atomic.LoadUint64(&Self.lengthWait)
|
||||
n, _ = Self.chain.head.unpack(ptrs)
|
||||
return
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindowQueue) Stop() {
|
||||
Self.stopOp <- struct{}{}
|
||||
Self.stopOp <- struct{}{}
|
||||
}
|
||||
|
||||
func (Self *ReceiveWindowQueue) SetTimeOut(t time.Time) {
|
||||
Self.timeout = t
|
||||
}
|
||||
|
||||
// https://golang.org/src/sync/poolqueue.go
|
||||
|
||||
type bufDequeue struct {
|
||||
// headTail packs together a 32-bit head index and a 32-bit
|
||||
// tail index. Both are indexes into vals modulo len(vals)-1.
|
||||
//
|
||||
// tail = index of oldest data in queue
|
||||
// head = index of next slot to fill
|
||||
//
|
||||
// Slots in the range [tail, head) are owned by consumers.
|
||||
// A consumer continues to own a slot outside this range until
|
||||
// it nils the slot, at which point ownership passes to the
|
||||
// producer.
|
||||
//
|
||||
// The head index is stored in the most-significant bits so
|
||||
// that we can atomically add to it and the overflow is
|
||||
// harmless.
|
||||
headTail uint64
|
||||
|
||||
// vals is a ring buffer of interface{} values stored in this
|
||||
// dequeue. The size of this must be a power of 2.
|
||||
//
|
||||
// A slot is still in use until *both* the tail
|
||||
// index has moved beyond it and typ has been set to nil. This
|
||||
// is set to nil atomically by the consumer and read
|
||||
// atomically by the producer.
|
||||
vals []unsafe.Pointer
|
||||
starving uint32
|
||||
}
|
||||
|
||||
const dequeueBits = 32
|
||||
|
||||
// dequeueLimit is the maximum size of a bufDequeue.
|
||||
//
|
||||
// This must be at most (1<<dequeueBits)/2 because detecting fullness
|
||||
// depends on wrapping around the ring buffer without wrapping around
|
||||
// the index. We divide by 4 so this fits in an int on 32-bit.
|
||||
const dequeueLimit = (1 << dequeueBits) / 4
|
||||
|
||||
func (d *bufDequeue) unpack(ptrs uint64) (head, tail uint32) {
|
||||
const mask = 1<<dequeueBits - 1
|
||||
head = uint32((ptrs >> dequeueBits) & mask)
|
||||
tail = uint32(ptrs & mask)
|
||||
return
|
||||
}
|
||||
|
||||
func (d *bufDequeue) pack(head, tail uint32) uint64 {
|
||||
const mask = 1<<dequeueBits - 1
|
||||
return (uint64(head) << dequeueBits) |
|
||||
uint64(tail&mask)
|
||||
}
|
||||
|
||||
// pushHead adds val at the head of the queue. It returns false if the
|
||||
// queue is full.
|
||||
func (d *bufDequeue) pushHead(val unsafe.Pointer) bool {
|
||||
var slot *unsafe.Pointer
|
||||
var starve uint8
|
||||
if atomic.LoadUint32(&d.starving) > 0 {
|
||||
runtime.Gosched()
|
||||
}
|
||||
for {
|
||||
ptrs := atomic.LoadUint64(&d.headTail)
|
||||
head, tail := d.unpack(ptrs)
|
||||
if (tail+uint32(len(d.vals)))&(1<<dequeueBits-1) == head {
|
||||
// Queue is full.
|
||||
return false
|
||||
}
|
||||
ptrs2 := d.pack(head+1, tail)
|
||||
if atomic.CompareAndSwapUint64(&d.headTail, ptrs, ptrs2) {
|
||||
slot = &d.vals[head&uint32(len(d.vals)-1)]
|
||||
if starve >= 3 && atomic.LoadUint32(&d.starving) > 0 {
|
||||
atomic.StoreUint32(&d.starving, 0)
|
||||
}
|
||||
break
|
||||
}
|
||||
starve++
|
||||
if starve >= 3 {
|
||||
atomic.StoreUint32(&d.starving, 1)
|
||||
}
|
||||
}
|
||||
// The head slot is free, so we own it.
|
||||
*slot = val
|
||||
return true
|
||||
}
|
||||
|
||||
// popTail removes and returns the element at the tail of the queue.
|
||||
// It returns false if the queue is empty. It may be called by any
|
||||
// number of consumers.
|
||||
func (d *bufDequeue) popTail() (unsafe.Pointer, bool) {
|
||||
ptrs := atomic.LoadUint64(&d.headTail)
|
||||
head, tail := d.unpack(ptrs)
|
||||
if tail == head {
|
||||
// Queue is empty.
|
||||
return nil, false
|
||||
}
|
||||
slot := &d.vals[tail&uint32(len(d.vals)-1)]
|
||||
var val unsafe.Pointer
|
||||
for {
|
||||
val = atomic.LoadPointer(slot)
|
||||
if val != nil {
|
||||
// We now own slot.
|
||||
break
|
||||
}
|
||||
// Another goroutine is still pushing data on the tail.
|
||||
}
|
||||
|
||||
// Tell pushHead that we're done with this slot. Zeroing the
|
||||
// slot is also important so we don't leave behind references
|
||||
// that could keep this object live longer than necessary.
|
||||
//
|
||||
// We write to val first and then publish that we're done with
|
||||
atomic.StorePointer(slot, nil)
|
||||
// At this point pushHead owns the slot.
|
||||
if tail < math.MaxUint32 {
|
||||
atomic.AddUint64(&d.headTail, 1)
|
||||
} else {
|
||||
atomic.AddUint64(&d.headTail, ^uint64(math.MaxUint32-1))
|
||||
}
|
||||
return val, true
|
||||
}
|
||||
|
||||
// bufChain is a dynamically-sized version of bufDequeue.
|
||||
//
|
||||
// This is implemented as a doubly-linked list queue of poolDequeues
|
||||
// where each dequeue is double the size of the previous one. Once a
|
||||
// dequeue fills up, this allocates a new one and only ever pushes to
|
||||
// the latest dequeue. Pops happen from the other end of the list and
|
||||
// once a dequeue is exhausted, it gets removed from the list.
|
||||
type bufChain struct {
|
||||
// head is the bufDequeue to push to. This is only accessed
|
||||
// by the producer, so doesn't need to be synchronized.
|
||||
head *bufChainElt
|
||||
|
||||
// tail is the bufDequeue to popTail from. This is accessed
|
||||
// by consumers, so reads and writes must be atomic.
|
||||
tail *bufChainElt
|
||||
newChain uint32
|
||||
}
|
||||
|
||||
type bufChainElt struct {
|
||||
bufDequeue
|
||||
|
||||
// next and prev link to the adjacent poolChainElts in this
|
||||
// bufChain.
|
||||
//
|
||||
// next is written atomically by the producer and read
|
||||
// atomically by the consumer. It only transitions from nil to
|
||||
// non-nil.
|
||||
//
|
||||
// prev is written atomically by the consumer and read
|
||||
// atomically by the producer. It only transitions from
|
||||
// non-nil to nil.
|
||||
next, prev *bufChainElt
|
||||
}
|
||||
|
||||
func storePoolChainElt(pp **bufChainElt, v *bufChainElt) {
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(pp)), unsafe.Pointer(v))
|
||||
}
|
||||
|
||||
func loadPoolChainElt(pp **bufChainElt) *bufChainElt {
|
||||
return (*bufChainElt)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(pp))))
|
||||
}
|
||||
|
||||
func (c *bufChain) new(initSize int) {
|
||||
// Initialize the chain.
|
||||
// initSize must be a power of 2
|
||||
d := new(bufChainElt)
|
||||
d.vals = make([]unsafe.Pointer, initSize)
|
||||
storePoolChainElt(&c.head, d)
|
||||
storePoolChainElt(&c.tail, d)
|
||||
}
|
||||
|
||||
func (c *bufChain) pushHead(val unsafe.Pointer) {
|
||||
startPush:
|
||||
for {
|
||||
if atomic.LoadUint32(&c.newChain) > 0 {
|
||||
runtime.Gosched()
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
d := loadPoolChainElt(&c.head)
|
||||
|
||||
if d.pushHead(val) {
|
||||
return
|
||||
}
|
||||
|
||||
// The current dequeue is full. Allocate a new one of twice
|
||||
// the size.
|
||||
if atomic.CompareAndSwapUint32(&c.newChain, 0, 1) {
|
||||
newSize := len(d.vals) * 2
|
||||
if newSize >= dequeueLimit {
|
||||
// Can't make it any bigger.
|
||||
newSize = dequeueLimit
|
||||
}
|
||||
|
||||
d2 := &bufChainElt{prev: d}
|
||||
d2.vals = make([]unsafe.Pointer, newSize)
|
||||
d2.pushHead(val)
|
||||
storePoolChainElt(&c.head, d2)
|
||||
storePoolChainElt(&d.next, d2)
|
||||
atomic.StoreUint32(&c.newChain, 0)
|
||||
return
|
||||
}
|
||||
goto startPush
|
||||
}
|
||||
|
||||
func (c *bufChain) popTail() (unsafe.Pointer, bool) {
|
||||
d := loadPoolChainElt(&c.tail)
|
||||
if d == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
for {
|
||||
// It's important that we load the next pointer
|
||||
// *before* popping the tail. In general, d may be
|
||||
// transiently empty, but if next is non-nil before
|
||||
// the TryPop and the TryPop fails, then d is permanently
|
||||
// empty, which is the only condition under which it's
|
||||
// safe to drop d from the chain.
|
||||
d2 := loadPoolChainElt(&d.next)
|
||||
|
||||
if val, ok := d.popTail(); ok {
|
||||
return val, ok
|
||||
}
|
||||
|
||||
if d2 == nil {
|
||||
// This is the only dequeue. It's empty right
|
||||
// now, but could be pushed to in the future.
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// The tail of the chain has been drained, so move on
|
||||
// to the next dequeue. Try to drop it from the chain
|
||||
// so the next TryPop doesn't have to look at the empty
|
||||
// dequeue again.
|
||||
if atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&c.tail)), unsafe.Pointer(d), unsafe.Pointer(d2)) {
|
||||
// We won the race. Clear the prev pointer so
|
||||
// the garbage collector can collect the empty
|
||||
// dequeue and so popHead doesn't back up
|
||||
// further than necessary.
|
||||
storePoolChainElt(&d2.prev, nil)
|
||||
}
|
||||
d = d2
|
||||
}
|
||||
}
|
154
lib/mux/web.go
Normal file
154
lib/mux/web.go
Normal file
@ -0,0 +1,154 @@
|
||||
package mux
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type connLog struct {
|
||||
startTime time.Time
|
||||
isClose bool
|
||||
logs []string
|
||||
}
|
||||
|
||||
var logms map[int]*connLog
|
||||
var logmc map[int]*connLog
|
||||
|
||||
var copyMaps map[int]*connLog
|
||||
var copyMapc map[int]*connLog
|
||||
var stashTimeNow time.Time
|
||||
var mutex sync.Mutex
|
||||
|
||||
func deepCopyMaps() {
|
||||
copyMaps = make(map[int]*connLog)
|
||||
for k, v := range logms {
|
||||
copyMaps[k] = &connLog{
|
||||
startTime: v.startTime,
|
||||
isClose: v.isClose,
|
||||
logs: v.logs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func deepCopyMapc() {
|
||||
copyMapc = make(map[int]*connLog)
|
||||
for k, v := range logmc {
|
||||
copyMapc[k] = &connLog{
|
||||
startTime: v.startTime,
|
||||
isClose: v.isClose,
|
||||
logs: v.logs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
logms = make(map[int]*connLog)
|
||||
logmc = make(map[int]*connLog)
|
||||
}
|
||||
|
||||
type IntSlice []int
|
||||
|
||||
func (s IntSlice) Len() int { return len(s) }
|
||||
|
||||
func (s IntSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
func (s IntSlice) Less(i, j int) bool { return s[i] < s[j] }
|
||||
|
||||
func NewLogServer() {
|
||||
http.HandleFunc("/", index)
|
||||
http.HandleFunc("/detail", detail)
|
||||
http.HandleFunc("/stash", stash)
|
||||
fmt.Println(http.ListenAndServe(":8899", nil))
|
||||
}
|
||||
|
||||
func stash(w http.ResponseWriter, r *http.Request) {
|
||||
stashTimeNow = time.Now()
|
||||
deepCopyMaps()
|
||||
deepCopyMapc()
|
||||
w.Write([]byte("ok"))
|
||||
}
|
||||
|
||||
func getM(label string, id int) (cL *connLog) {
|
||||
label = strings.TrimSpace(label)
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
if label == "nps" {
|
||||
cL = logms[id]
|
||||
}
|
||||
if label == "npc" {
|
||||
cL = logmc[id]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setM(label string, id int, cL *connLog) {
|
||||
label = strings.TrimSpace(label)
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
if label == "nps" {
|
||||
logms[id] = cL
|
||||
}
|
||||
if label == "npc" {
|
||||
logmc[id] = cL
|
||||
}
|
||||
}
|
||||
|
||||
func index(w http.ResponseWriter, r *http.Request) {
|
||||
var keys []int
|
||||
for k := range copyMaps {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Sort(IntSlice(keys))
|
||||
var s string
|
||||
s += "<h1>nps</h1>"
|
||||
for _, v := range keys {
|
||||
connL := copyMaps[v]
|
||||
s += "<a href='/detail?id=" + strconv.Itoa(v) + "&label=nps" + "'>" + strconv.Itoa(v) + "</a>----------"
|
||||
s += strconv.Itoa(int(stashTimeNow.Sub(connL.startTime).Milliseconds())) + "ms----------"
|
||||
s += strconv.FormatBool(connL.isClose)
|
||||
s += "<br>"
|
||||
}
|
||||
|
||||
keys = keys[:0]
|
||||
s += "<h1>npc</h1>"
|
||||
for k := range copyMapc {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Sort(IntSlice(keys))
|
||||
|
||||
for _, v := range keys {
|
||||
connL := copyMapc[v]
|
||||
s += "<a href='/detail?id=" + strconv.Itoa(v) + "&label=npc" + "'>" + strconv.Itoa(v) + "</a>----------"
|
||||
s += strconv.Itoa(int(stashTimeNow.Sub(connL.startTime).Milliseconds())) + "ms----------"
|
||||
s += strconv.FormatBool(connL.isClose)
|
||||
s += "<br>"
|
||||
}
|
||||
w.Write([]byte(s))
|
||||
}
|
||||
|
||||
func detail(w http.ResponseWriter, r *http.Request) {
|
||||
id := r.FormValue("id")
|
||||
label := r.FormValue("label")
|
||||
logs.Warn(label)
|
||||
i, _ := strconv.Atoi(id)
|
||||
var v *connLog
|
||||
if label == "nps" {
|
||||
v, _ = copyMaps[i]
|
||||
}
|
||||
if label == "npc" {
|
||||
v, _ = copyMapc[i]
|
||||
}
|
||||
var s string
|
||||
if v != nil {
|
||||
for i, vv := range v.logs {
|
||||
s += "<p>" + strconv.Itoa(i+1) + ":" + vv + "</p>"
|
||||
}
|
||||
}
|
||||
w.Write([]byte(s))
|
||||
}
|
7
lib/mux/web_test.go
Normal file
7
lib/mux/web_test.go
Normal file
@ -0,0 +1,7 @@
|
||||
package mux
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestWeb(t *testing.T) {
|
||||
NewLogServer()
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package version
|
||||
|
||||
const VERSION = "0.26.10"
|
||||
const VERSION = "0.25.2"
|
||||
|
||||
// Compulsory minimum version, Minimum downward compatibility to this version
|
||||
func GetVersion() string {
|
||||
return "0.26.0"
|
||||
return "0.25.0"
|
||||
}
|
||||
|
@ -5,12 +5,12 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"ehang.io/nps/lib/pmux"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/lib/mux"
|
||||
)
|
||||
|
||||
var pMux *pmux.PortMux
|
||||
var pMux *mux.PortMux
|
||||
var bridgePort string
|
||||
var httpsPort string
|
||||
var httpPort string
|
||||
@ -28,7 +28,7 @@ func InitConnectionService() {
|
||||
logs.Error(err)
|
||||
os.Exit(0)
|
||||
}
|
||||
pMux = pmux.NewPortMux(port, beego.AppConfig.String("web_host"))
|
||||
pMux = mux.NewPortMux(port, beego.AppConfig.String("web_host"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,11 +6,11 @@ import (
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"ehang.io/nps/bridge"
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/conn"
|
||||
"ehang.io/nps/lib/file"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/bridge"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
|
@ -13,13 +13,13 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"ehang.io/nps/bridge"
|
||||
"ehang.io/nps/lib/cache"
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/conn"
|
||||
"ehang.io/nps/lib/file"
|
||||
"ehang.io/nps/server/connection"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/bridge"
|
||||
"github.com/cnlh/nps/lib/cache"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/server/connection"
|
||||
)
|
||||
|
||||
type httpServer struct {
|
||||
@ -30,12 +30,11 @@ type httpServer struct {
|
||||
httpsServer *http.Server
|
||||
httpsListener net.Listener
|
||||
useCache bool
|
||||
addOrigin bool
|
||||
cache *cache.Cache
|
||||
cacheLen int
|
||||
}
|
||||
|
||||
func NewHttp(bridge *bridge.Bridge, c *file.Tunnel, httpPort, httpsPort int, useCache bool, cacheLen int, addOrigin bool) *httpServer {
|
||||
func NewHttp(bridge *bridge.Bridge, c *file.Tunnel, httpPort, httpsPort int, useCache bool, cacheLen int) *httpServer {
|
||||
httpServer := &httpServer{
|
||||
BaseServer: BaseServer{
|
||||
task: c,
|
||||
@ -46,7 +45,6 @@ func NewHttp(bridge *bridge.Bridge, c *file.Tunnel, httpPort, httpsPort int, use
|
||||
httpsPort: httpsPort,
|
||||
useCache: useCache,
|
||||
cacheLen: cacheLen,
|
||||
addOrigin: addOrigin,
|
||||
}
|
||||
if useCache {
|
||||
httpServer.cache = cache.New(cacheLen)
|
||||
@ -57,7 +55,7 @@ func NewHttp(bridge *bridge.Bridge, c *file.Tunnel, httpPort, httpsPort int, use
|
||||
func (s *httpServer) Start() error {
|
||||
var err error
|
||||
if s.errorContent, err = common.ReadAllFromFile(filepath.Join(common.GetRunPath(), "web", "static", "page", "error.html")); err != nil {
|
||||
s.errorContent = []byte("nps 404")
|
||||
s.errorContent = []byte("easyProxy 404")
|
||||
}
|
||||
if s.httpPort > 0 {
|
||||
s.httpServer = s.NewServer(s.httpPort, "http")
|
||||
@ -118,6 +116,7 @@ func (s *httpServer) handleHttp(c *conn.Conn, r *http.Request) {
|
||||
var (
|
||||
host *file.Host
|
||||
target net.Conn
|
||||
lastHost *file.Host
|
||||
err error
|
||||
connClient io.ReadWriteCloser
|
||||
scheme = r.URL.Scheme
|
||||
@ -129,16 +128,11 @@ func (s *httpServer) handleHttp(c *conn.Conn, r *http.Request) {
|
||||
)
|
||||
defer func() {
|
||||
if connClient != nil {
|
||||
connClient.Close()
|
||||
} else {
|
||||
s.writeConnFail(c.Conn)
|
||||
connClient.Close()
|
||||
}
|
||||
c.Close()
|
||||
}()
|
||||
reset:
|
||||
if isReset {
|
||||
host.Client.AddConn()
|
||||
}
|
||||
if host, err = file.GetDb().GetInfoByHost(r.Host, r); err != nil {
|
||||
logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI)
|
||||
return
|
||||
@ -147,13 +141,12 @@ reset:
|
||||
logs.Warn("client id %d, host id %d, error %s, when https connection", host.Client.Id, host.Id, err.Error())
|
||||
return
|
||||
}
|
||||
if !isReset {
|
||||
defer host.Client.AddConn()
|
||||
}
|
||||
defer host.Client.AddConn()
|
||||
if err = s.auth(r, c, host.Client.Cnf.U, host.Client.Cnf.P); err != nil {
|
||||
logs.Warn("auth error", err, r.RemoteAddr)
|
||||
return
|
||||
}
|
||||
reset:
|
||||
if targetAddr, err = host.Target.GetRandomTarget(); err != nil {
|
||||
logs.Warn(err.Error())
|
||||
return
|
||||
@ -164,6 +157,7 @@ reset:
|
||||
return
|
||||
}
|
||||
connClient = conn.GetConn(target, lk.Crypt, lk.Compress, host.Client.Rate, true)
|
||||
lastHost = host
|
||||
|
||||
//read from inc-client
|
||||
go func() {
|
||||
@ -177,8 +171,7 @@ reset:
|
||||
}
|
||||
}()
|
||||
for {
|
||||
if resp, err := http.ReadResponse(bufio.NewReader(connClient), r); err != nil || resp == nil || r == nil {
|
||||
// if there got broken pipe, http.ReadResponse will get a nil
|
||||
if resp, err := http.ReadResponse(bufio.NewReader(connClient), r); err != nil || resp == nil {
|
||||
return
|
||||
} else {
|
||||
//if the cache is start and the response is in the extension,store the response to the cache list
|
||||
@ -221,7 +214,7 @@ reset:
|
||||
}
|
||||
|
||||
//change the host and header and set proxy setting
|
||||
common.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String(), s.addOrigin)
|
||||
common.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String())
|
||||
logs.Trace("%s request, method %s, host %s, url %s, remote address %s, target %s", r.URL.Scheme, r.Method, r.Host, r.URL.Path, c.RemoteAddr().String(), lk.Host)
|
||||
//write
|
||||
lenConn = conn.NewLenConn(connClient)
|
||||
@ -242,8 +235,9 @@ reset:
|
||||
if hostTmp, err := file.GetDb().GetInfoByHost(r.Host, r); err != nil {
|
||||
logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI)
|
||||
break
|
||||
} else if host != hostTmp {
|
||||
} else if host != lastHost {
|
||||
host = hostTmp
|
||||
lastHost = host
|
||||
isReset = true
|
||||
connClient.Close()
|
||||
goto reset
|
||||
|
@ -6,13 +6,13 @@ import (
|
||||
"net/url"
|
||||
"sync"
|
||||
|
||||
"ehang.io/nps/lib/cache"
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/conn"
|
||||
"ehang.io/nps/lib/crypt"
|
||||
"ehang.io/nps/lib/file"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/lib/cache"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/crypt"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -5,8 +5,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
)
|
||||
|
||||
type P2PServer struct {
|
||||
|
@ -7,10 +7,10 @@ import (
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/conn"
|
||||
"ehang.io/nps/lib/file"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -270,7 +270,6 @@ func (s *Sock5ModeServer) handleUDP(c net.Conn) {
|
||||
|
||||
b := common.BufPoolUdp.Get().([]byte)
|
||||
defer common.BufPoolUdp.Put(b)
|
||||
defer target.Close()
|
||||
for {
|
||||
_, err := c.Read(b)
|
||||
if err != nil {
|
||||
|
@ -7,13 +7,13 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"ehang.io/nps/bridge"
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/conn"
|
||||
"ehang.io/nps/lib/file"
|
||||
"ehang.io/nps/server/connection"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/bridge"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/server/connection"
|
||||
)
|
||||
|
||||
type TunnelModeServer struct {
|
||||
|
@ -7,8 +7,8 @@ import (
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/conn"
|
||||
)
|
||||
|
||||
func HandleTrans(c *conn.Conn, s *TunnelModeServer) error {
|
||||
|
@ -3,7 +3,7 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"ehang.io/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/conn"
|
||||
)
|
||||
|
||||
func HandleTrans(c *conn.Conn, s *TunnelModeServer) error {
|
||||
|
@ -1,22 +1,18 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"ehang.io/nps/bridge"
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/conn"
|
||||
"ehang.io/nps/lib/file"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/cnlh/nps/bridge"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/conn"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
)
|
||||
|
||||
type UdpModeServer struct {
|
||||
BaseServer
|
||||
addrMap sync.Map
|
||||
listener *net.UDPConn
|
||||
}
|
||||
|
||||
@ -37,8 +33,8 @@ func (s *UdpModeServer) Start() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf := common.BufPoolUdp.Get().([]byte)
|
||||
for {
|
||||
buf := common.BufPoolUdp.Get().([]byte)
|
||||
n, addr, err := s.listener.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "use of closed network connection") {
|
||||
@ -53,43 +49,26 @@ func (s *UdpModeServer) Start() error {
|
||||
}
|
||||
|
||||
func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
|
||||
if v, ok := s.addrMap.Load(addr.String()); ok {
|
||||
clientConn, ok := v.(io.ReadWriteCloser)
|
||||
if ok {
|
||||
clientConn.Write(data)
|
||||
s.task.Flow.Add(int64(len(data)), 0)
|
||||
}
|
||||
if err := s.CheckFlowAndConnNum(s.task.Client); err != nil {
|
||||
logs.Warn("client id %d, task id %d,error %s, when udp connection", s.task.Client.Id, s.task.Id, err.Error())
|
||||
return
|
||||
}
|
||||
defer s.task.Client.AddConn()
|
||||
link := conn.NewLink(common.CONN_UDP, s.task.Target.TargetStr, s.task.Client.Cnf.Crypt, s.task.Client.Cnf.Compress, addr.String(), s.task.Target.LocalProxy)
|
||||
if target, err := s.bridge.SendLinkInfo(s.task.Client.Id, link, s.task); err != nil {
|
||||
return
|
||||
} else {
|
||||
if err := s.CheckFlowAndConnNum(s.task.Client); err != nil {
|
||||
logs.Warn("client id %d, task id %d,error %s, when udp connection", s.task.Client.Id, s.task.Id, err.Error())
|
||||
return
|
||||
}
|
||||
defer s.task.Client.AddConn()
|
||||
link := conn.NewLink(common.CONN_UDP, s.task.Target.TargetStr, s.task.Client.Cnf.Crypt, s.task.Client.Cnf.Compress, addr.String(), s.task.Target.LocalProxy)
|
||||
if clientConn, err := s.bridge.SendLinkInfo(s.task.Client.Id, link, s.task); err != nil {
|
||||
s.task.Flow.Add(int64(len(data)), 0)
|
||||
buf := common.BufPoolUdp.Get().([]byte)
|
||||
defer common.BufPoolUdp.Put(buf)
|
||||
target.Write(data)
|
||||
s.task.Flow.Add(int64(len(data)), 0)
|
||||
if n, err := target.Read(buf); err != nil {
|
||||
logs.Warn(err)
|
||||
return
|
||||
} else {
|
||||
target := conn.GetConn(clientConn, s.task.Client.Cnf.Crypt, s.task.Client.Cnf.Compress, nil, true)
|
||||
s.addrMap.Store(addr.String(), target)
|
||||
defer target.Close()
|
||||
|
||||
target.Write(data)
|
||||
|
||||
buf := common.BufPoolUdp.Get().([]byte)
|
||||
defer common.BufPoolUdp.Put(buf)
|
||||
|
||||
s.task.Flow.Add(int64(len(data)), 0)
|
||||
for {
|
||||
clientConn.SetReadDeadline(time.Now().Add(time.Minute * 10))
|
||||
if n, err := target.Read(buf); err != nil {
|
||||
s.addrMap.Delete(addr.String())
|
||||
logs.Warn(err)
|
||||
return
|
||||
} else {
|
||||
s.listener.WriteTo(buf[:n], addr)
|
||||
s.task.Flow.Add(0, int64(n))
|
||||
}
|
||||
}
|
||||
s.listener.WriteTo(buf[:n], addr)
|
||||
s.task.Flow.Add(0, int64(n))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,34 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"ehang.io/nps/lib/version"
|
||||
"errors"
|
||||
"github.com/cnlh/nps/lib/version"
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"ehang.io/nps/bridge"
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/file"
|
||||
"ehang.io/nps/server/proxy"
|
||||
"ehang.io/nps/server/tool"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/logs"
|
||||
"github.com/shirou/gopsutil/v3/cpu"
|
||||
"github.com/shirou/gopsutil/v3/load"
|
||||
"github.com/shirou/gopsutil/v3/mem"
|
||||
"github.com/shirou/gopsutil/v3/net"
|
||||
"github.com/cnlh/nps/bridge"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/server/proxy"
|
||||
"github.com/cnlh/nps/server/tool"
|
||||
"github.com/shirou/gopsutil/cpu"
|
||||
"github.com/shirou/gopsutil/load"
|
||||
"github.com/shirou/gopsutil/mem"
|
||||
"github.com/shirou/gopsutil/net"
|
||||
)
|
||||
|
||||
var (
|
||||
Bridge *bridge.Bridge
|
||||
RunList sync.Map //map[int]interface{}
|
||||
RunList map[int]interface{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
RunList = sync.Map{}
|
||||
RunList = make(map[int]interface{})
|
||||
}
|
||||
|
||||
//init task from db
|
||||
@ -38,8 +37,7 @@ func InitFromCsv() {
|
||||
if vkey := beego.AppConfig.String("public_vkey"); vkey != "" {
|
||||
c := file.NewClient(vkey, true, true)
|
||||
file.GetDb().NewClient(c)
|
||||
RunList.Store(c.Id, nil)
|
||||
//RunList[c.Id] = nil
|
||||
RunList[c.Id] = nil
|
||||
}
|
||||
//Initialize services in server-side files
|
||||
file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
|
||||
@ -85,8 +83,8 @@ func DealBridgeTask() {
|
||||
}
|
||||
|
||||
//start a new server
|
||||
func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string, bridgeDisconnect int) {
|
||||
Bridge = bridge.NewTunnel(bridgePort, bridgeType, common.GetBoolByStr(beego.AppConfig.String("ip_limit")), RunList, bridgeDisconnect)
|
||||
func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
|
||||
Bridge = bridge.NewTunnel(bridgePort, bridgeType, common.GetBoolByStr(beego.AppConfig.String("ip_limit")), RunList)
|
||||
go func() {
|
||||
if err := Bridge.StartTunnel(); err != nil {
|
||||
logs.Error("start server bridge error", err)
|
||||
@ -104,8 +102,7 @@ func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string, bridgeD
|
||||
if err := svr.Start(); err != nil {
|
||||
logs.Error(err)
|
||||
}
|
||||
RunList.Store(cnf.Id, svr)
|
||||
//RunList[cnf.Id] = svr
|
||||
RunList[cnf.Id] = svr
|
||||
} else {
|
||||
logs.Error("Incorrect startup mode %s", cnf.Mode)
|
||||
}
|
||||
@ -150,16 +147,14 @@ func NewMode(Bridge *bridge.Bridge, c *file.Tunnel) proxy.Service {
|
||||
httpsPort, _ := beego.AppConfig.Int("https_proxy_port")
|
||||
useCache, _ := beego.AppConfig.Bool("http_cache")
|
||||
cacheLen, _ := beego.AppConfig.Int("http_cache_length")
|
||||
addOrigin, _ := beego.AppConfig.Bool("http_add_origin_header")
|
||||
service = proxy.NewHttp(Bridge, c, httpPort, httpsPort, useCache, cacheLen, addOrigin)
|
||||
service = proxy.NewHttp(Bridge, c, httpPort, httpsPort, useCache, cacheLen)
|
||||
}
|
||||
return service
|
||||
}
|
||||
|
||||
//stop server
|
||||
func StopServer(id int) error {
|
||||
//if v, ok := RunList[id]; ok {
|
||||
if v, ok := RunList.Load(id); ok {
|
||||
if v, ok := RunList[id]; ok {
|
||||
if svr, ok := v.(proxy.Service); ok {
|
||||
if err := svr.Close(); err != nil {
|
||||
return err
|
||||
@ -174,8 +169,7 @@ func StopServer(id int) error {
|
||||
t.Status = false
|
||||
file.GetDb().UpdateTask(t)
|
||||
}
|
||||
//delete(RunList, id)
|
||||
RunList.Delete(id)
|
||||
delete(RunList, id)
|
||||
return nil
|
||||
}
|
||||
return errors.New("task is not running")
|
||||
@ -185,8 +179,7 @@ func StopServer(id int) error {
|
||||
func AddTask(t *file.Tunnel) error {
|
||||
if t.Mode == "secret" || t.Mode == "p2p" {
|
||||
logs.Info("secret task %s start ", t.Remark)
|
||||
//RunList[t.Id] = nil
|
||||
RunList.Store(t.Id, nil)
|
||||
RunList[t.Id] = nil
|
||||
return nil
|
||||
}
|
||||
if b := tool.TestServerPort(t.Port, t.Mode); !b && t.Mode != "httpHostServer" {
|
||||
@ -198,13 +191,11 @@ func AddTask(t *file.Tunnel) error {
|
||||
}
|
||||
if svr := NewMode(Bridge, t); svr != nil {
|
||||
logs.Info("tunnel task %s start mode:%s port %d", t.Remark, t.Mode, t.Port)
|
||||
//RunList[t.Id] = svr
|
||||
RunList.Store(t.Id, svr)
|
||||
RunList[t.Id] = svr
|
||||
go func() {
|
||||
if err := svr.Start(); err != nil {
|
||||
logs.Error("clientId %d taskId %d start error %s", t.Client.Id, t.Id, err)
|
||||
//delete(RunList, t.Id)
|
||||
RunList.Delete(t.Id)
|
||||
delete(RunList, t.Id)
|
||||
return
|
||||
}
|
||||
}()
|
||||
@ -228,8 +219,7 @@ func StartTask(id int) error {
|
||||
|
||||
//delete task
|
||||
func DelTask(id int) error {
|
||||
//if _, ok := RunList[id]; ok {
|
||||
if _, ok := RunList.Load(id); ok {
|
||||
if _, ok := RunList[id]; ok {
|
||||
if err := StopServer(id); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -259,8 +249,7 @@ func GetTunnel(start, length int, typeVal string, clientId int, search string) (
|
||||
}
|
||||
if start--; start < 0 {
|
||||
if length--; length >= 0 {
|
||||
//if _, ok := RunList[v.Id]; ok {
|
||||
if _, ok := RunList.Load(v.Id); ok {
|
||||
if _, ok := RunList[v.Id]; ok {
|
||||
v.RunStatus = true
|
||||
} else {
|
||||
v.RunStatus = false
|
||||
|
@ -5,9 +5,9 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/file"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
)
|
||||
|
||||
func TestServerConfig() {
|
||||
@ -52,10 +52,10 @@ func TestServerConfig() {
|
||||
if port, err := strconv.Atoi(p); err != nil {
|
||||
log.Fatalln("get https port error", err)
|
||||
} else {
|
||||
if beego.AppConfig.String("pemPath") != "" && !common.FileExists(filepath.Join(common.GetRunPath(), beego.AppConfig.String("pemPath"))) {
|
||||
if !common.FileExists(filepath.Join(common.GetRunPath(), beego.AppConfig.String("pemPath"))) {
|
||||
log.Fatalf("ssl certFile %s is not exist", beego.AppConfig.String("pemPath"))
|
||||
}
|
||||
if beego.AppConfig.String("keyPath") != "" && !common.FileExists(filepath.Join(common.GetRunPath(), beego.AppConfig.String("keyPath"))) {
|
||||
if !common.FileExists(filepath.Join(common.GetRunPath(), beego.AppConfig.String("ketPath"))) {
|
||||
log.Fatalf("ssl keyFile %s is not exist", beego.AppConfig.String("pemPath"))
|
||||
}
|
||||
isInArr(&postTcpArr, port, "http port", "tcp")
|
||||
|
@ -5,12 +5,12 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/shirou/gopsutil/v3/cpu"
|
||||
"github.com/shirou/gopsutil/v3/load"
|
||||
"github.com/shirou/gopsutil/v3/mem"
|
||||
"github.com/shirou/gopsutil/v3/net"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/shirou/gopsutil/cpu"
|
||||
"github.com/shirou/gopsutil/load"
|
||||
"github.com/shirou/gopsutil/mem"
|
||||
"github.com/shirou/gopsutil/net"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -4,8 +4,8 @@ import (
|
||||
"encoding/hex"
|
||||
"time"
|
||||
|
||||
"ehang.io/nps/lib/crypt"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/cnlh/nps/lib/crypt"
|
||||
)
|
||||
|
||||
type AuthController struct {
|
||||
|
@ -7,11 +7,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/crypt"
|
||||
"ehang.io/nps/lib/file"
|
||||
"ehang.io/nps/server"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/crypt"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/server"
|
||||
)
|
||||
|
||||
type BaseController struct {
|
||||
@ -33,13 +33,10 @@ func (s *BaseController) Prepare() {
|
||||
timestamp := s.GetIntNoErr("timestamp")
|
||||
configKey := beego.AppConfig.String("auth_key")
|
||||
timeNowUnix := time.Now().Unix()
|
||||
if !(md5Key != "" && (math.Abs(float64(timeNowUnix-int64(timestamp))) <= 20) && (crypt.Md5(configKey+strconv.Itoa(timestamp)) == md5Key)) {
|
||||
if !((math.Abs(float64(timeNowUnix-int64(timestamp))) <= 20) && (crypt.Md5(configKey+strconv.Itoa(timestamp)) == md5Key)) {
|
||||
if s.GetSession("auth") != true {
|
||||
s.Redirect(beego.AppConfig.String("web_base_url")+"/login/index", 302)
|
||||
}
|
||||
} else {
|
||||
s.SetSession("isAdmin", true)
|
||||
s.Data["isAdmin"] = true
|
||||
}
|
||||
if s.GetSession("isAdmin") != nil && !s.GetSession("isAdmin").(bool) {
|
||||
s.Ctx.Input.SetData("client_id", s.GetSession("clientId").(int))
|
||||
@ -141,17 +138,10 @@ func ajax(str string, status int) map[string]interface{} {
|
||||
}
|
||||
|
||||
//ajax table返回
|
||||
func (s *BaseController) AjaxTable(list interface{}, cnt int, recordsTotal int, kwargs map[string]interface{}) {
|
||||
func (s *BaseController) AjaxTable(list interface{}, cnt int, recordsTotal int) {
|
||||
json := make(map[string]interface{})
|
||||
json["rows"] = list
|
||||
json["total"] = recordsTotal
|
||||
if kwargs != nil {
|
||||
for k, v := range kwargs {
|
||||
if v != nil {
|
||||
json[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
s.Data["json"] = json
|
||||
s.ServeJSON()
|
||||
s.StopRun()
|
||||
|
@ -1,11 +1,11 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/file"
|
||||
"ehang.io/nps/lib/rate"
|
||||
"ehang.io/nps/server"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/lib/rate"
|
||||
"github.com/cnlh/nps/server"
|
||||
)
|
||||
|
||||
type ClientController struct {
|
||||
@ -28,12 +28,7 @@ func (s *ClientController) List() {
|
||||
clientId = clientIdSession.(int)
|
||||
}
|
||||
list, cnt := server.GetClientList(start, length, s.getEscapeString("search"), s.getEscapeString("sort"), s.getEscapeString("order"), clientId)
|
||||
cmd := make(map[string]interface{})
|
||||
ip := s.Ctx.Request.Host
|
||||
cmd["ip"] = common.GetIpByAddr(ip)
|
||||
cmd["bridgeType"] = beego.AppConfig.String("bridge_type")
|
||||
cmd["bridgePort"] = server.Bridge.TunnelPort
|
||||
s.AjaxTable(list, cnt, cnt, cmd)
|
||||
s.AjaxTable(list, cnt, cnt)
|
||||
}
|
||||
|
||||
//添加客户端
|
||||
@ -66,6 +61,10 @@ func (s *ClientController) Add() {
|
||||
FlowLimit: int64(s.GetIntNoErr("flow_limit")),
|
||||
},
|
||||
}
|
||||
if t.RateLimit > 0 {
|
||||
t.Rate = rate.NewRate(int64(t.RateLimit * 1024))
|
||||
t.Rate.Start()
|
||||
}
|
||||
if err := file.GetDb().NewClient(t); err != nil {
|
||||
s.AjaxErr(err.Error())
|
||||
}
|
||||
@ -102,8 +101,6 @@ func (s *ClientController) Edit() {
|
||||
} else {
|
||||
if c, err := file.GetDb().GetClient(id); err != nil {
|
||||
s.error()
|
||||
s.AjaxErr("client ID not found")
|
||||
return
|
||||
} else {
|
||||
if s.getEscapeString("web_username") != "" {
|
||||
if s.getEscapeString("web_username") == beego.AppConfig.String("web_username") || !file.GetDb().VerifyUserName(s.getEscapeString("web_username"), c.Id) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"ehang.io/nps/lib/file"
|
||||
"ehang.io/nps/server"
|
||||
"ehang.io/nps/server/tool"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/server"
|
||||
"github.com/cnlh/nps/server/tool"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
@ -82,7 +82,7 @@ func (s *IndexController) GetTunnel() {
|
||||
taskType := s.getEscapeString("type")
|
||||
clientId := s.GetIntNoErr("client_id")
|
||||
list, cnt := server.GetTunnel(start, length, taskType, clientId, s.getEscapeString("search"))
|
||||
s.AjaxTable(list, cnt, cnt, nil)
|
||||
s.AjaxTable(list, cnt, cnt)
|
||||
}
|
||||
|
||||
func (s *IndexController) Add() {
|
||||
@ -215,7 +215,7 @@ func (s *IndexController) HostList() {
|
||||
start, length := s.GetAjaxParams()
|
||||
clientId := s.GetIntNoErr("client_id")
|
||||
list, cnt := file.GetDb().GetHost(start, length, clientId, s.getEscapeString("search"))
|
||||
s.AjaxTable(list, cnt, cnt, nil)
|
||||
s.AjaxTable(list, cnt, cnt)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,10 +6,10 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"ehang.io/nps/lib/common"
|
||||
"ehang.io/nps/lib/file"
|
||||
"ehang.io/nps/server"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/cnlh/nps/lib/common"
|
||||
"github.com/cnlh/nps/lib/file"
|
||||
"github.com/cnlh/nps/server"
|
||||
)
|
||||
|
||||
type LoginController struct {
|
||||
@ -24,28 +24,11 @@ type record struct {
|
||||
}
|
||||
|
||||
func (self *LoginController) Index() {
|
||||
// Try login implicitly, will succeed if it's configured as no-auth(empty username&password).
|
||||
webBaseUrl := beego.AppConfig.String("web_base_url")
|
||||
if self.doLogin("", "", false) {
|
||||
self.Redirect(webBaseUrl+"/index/index", 302)
|
||||
}
|
||||
self.Data["web_base_url"] = webBaseUrl
|
||||
self.Data["web_base_url"] = beego.AppConfig.String("web_base_url")
|
||||
self.Data["register_allow"], _ = beego.AppConfig.Bool("allow_user_register")
|
||||
self.TplName = "login/index.html"
|
||||
}
|
||||
|
||||
func (self *LoginController) Verify() {
|
||||
username := self.GetString("username")
|
||||
password := self.GetString("password")
|
||||
if self.doLogin(username, password, true) {
|
||||
self.Data["json"] = map[string]interface{}{"status": 1, "msg": "login success"}
|
||||
} else {
|
||||
self.Data["json"] = map[string]interface{}{"status": 0, "msg": "username or password incorrect"}
|
||||
}
|
||||
self.ServeJSON()
|
||||
}
|
||||
|
||||
func (self *LoginController) doLogin(username, password string, explicit bool) bool {
|
||||
clearIprecord()
|
||||
ip, _, _ := net.SplitHostPort(self.Ctx.Request.RemoteAddr)
|
||||
if v, ok := ipRecord.Load(ip); ok {
|
||||
@ -54,11 +37,13 @@ func (self *LoginController) doLogin(username, password string, explicit bool) b
|
||||
vv.hasLoginFailTimes = 0
|
||||
}
|
||||
if vv.hasLoginFailTimes >= 10 {
|
||||
return false
|
||||
self.Data["json"] = map[string]interface{}{"status": 0, "msg": "username or password incorrect"}
|
||||
self.ServeJSON()
|
||||
return
|
||||
}
|
||||
}
|
||||
var auth bool
|
||||
if password == beego.AppConfig.String("web_password") && username == beego.AppConfig.String("web_username") {
|
||||
if self.GetString("password") == beego.AppConfig.String("web_password") && self.GetString("username") == beego.AppConfig.String("web_username") {
|
||||
self.SetSession("isAdmin", true)
|
||||
self.DelSession("clientId")
|
||||
self.DelSession("username")
|
||||
@ -73,13 +58,13 @@ func (self *LoginController) doLogin(username, password string, explicit bool) b
|
||||
return true
|
||||
}
|
||||
if v.WebUserName == "" && v.WebPassword == "" {
|
||||
if username != "user" || v.VerifyKey != password {
|
||||
if self.GetString("username") != "user" || v.VerifyKey != self.GetString("password") {
|
||||
return true
|
||||
} else {
|
||||
auth = true
|
||||
}
|
||||
}
|
||||
if !auth && v.WebPassword == password && v.WebUserName == username {
|
||||
if !auth && v.WebPassword == self.GetString("password") && self.GetString("username") == v.WebUserName {
|
||||
auth = true
|
||||
}
|
||||
if auth {
|
||||
@ -93,17 +78,18 @@ func (self *LoginController) doLogin(username, password string, explicit bool) b
|
||||
}
|
||||
if auth {
|
||||
self.SetSession("auth", true)
|
||||
self.Data["json"] = map[string]interface{}{"status": 1, "msg": "login success"}
|
||||
ipRecord.Delete(ip)
|
||||
return true
|
||||
|
||||
} else {
|
||||
if v, load := ipRecord.LoadOrStore(ip, &record{hasLoginFailTimes: 1, lastLoginTime: time.Now()}); load {
|
||||
vv := v.(*record)
|
||||
vv.lastLoginTime = time.Now()
|
||||
vv.hasLoginFailTimes += 1
|
||||
ipRecord.Store(ip, vv)
|
||||
}
|
||||
self.Data["json"] = map[string]interface{}{"status": 0, "msg": "username or password incorrect"}
|
||||
}
|
||||
if v, load := ipRecord.LoadOrStore(ip, &record{hasLoginFailTimes: 1, lastLoginTime: time.Now()}); load && explicit {
|
||||
vv := v.(*record)
|
||||
vv.lastLoginTime = time.Now()
|
||||
vv.hasLoginFailTimes += 1
|
||||
ipRecord.Store(ip, vv)
|
||||
}
|
||||
return false
|
||||
self.ServeJSON()
|
||||
}
|
||||
func (self *LoginController) Register() {
|
||||
if self.Ctx.Request.Method == "GET" {
|
||||
|
@ -1,8 +1,8 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"ehang.io/nps/web/controllers"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/cnlh/nps/web/controllers"
|
||||
)
|
||||
|
||||
func Init() {
|
||||
|
6
web/static/css/bootstrap-table.min.css
vendored
6
web/static/css/bootstrap-table.min.css
vendored
File diff suppressed because one or more lines are too long
7
web/static/css/bootstrap.min.css
vendored
7
web/static/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
@ -1,462 +0,0 @@
|
||||
/*
|
||||
* This combined file was created by the DataTables downloader builder:
|
||||
* https://datatables.net/download
|
||||
*
|
||||
* To rebuild or modify this file with the latest versions of the included
|
||||
* software please visit:
|
||||
* https://datatables.net/download/#dt/dt-1.10.20
|
||||
*
|
||||
* Included libraries:
|
||||
* DataTables 1.10.20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Table styles
|
||||
*/
|
||||
table.dataTable {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
clear: both;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
/*
|
||||
* Header and footer styles
|
||||
*/
|
||||
/*
|
||||
* Body styles
|
||||
*/
|
||||
}
|
||||
table.dataTable thead th,
|
||||
table.dataTable tfoot th {
|
||||
font-weight: bold;
|
||||
}
|
||||
table.dataTable thead th,
|
||||
table.dataTable thead td {
|
||||
padding: 10px 18px;
|
||||
border-bottom: 1px solid #111;
|
||||
}
|
||||
table.dataTable thead th:active,
|
||||
table.dataTable thead td:active {
|
||||
outline: none;
|
||||
}
|
||||
table.dataTable tfoot th,
|
||||
table.dataTable tfoot td {
|
||||
padding: 10px 18px 6px 18px;
|
||||
border-top: 1px solid #111;
|
||||
}
|
||||
table.dataTable thead .sorting,
|
||||
table.dataTable thead .sorting_asc,
|
||||
table.dataTable thead .sorting_desc,
|
||||
table.dataTable thead .sorting_asc_disabled,
|
||||
table.dataTable thead .sorting_desc_disabled {
|
||||
cursor: pointer;
|
||||
*cursor: hand;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center right;
|
||||
}
|
||||
table.dataTable thead .sorting {
|
||||
background-image: url("DataTables-1.10.20/images/sort_both.png");
|
||||
}
|
||||
table.dataTable thead .sorting_asc {
|
||||
background-image: url("DataTables-1.10.20/images/sort_asc.png");
|
||||
}
|
||||
table.dataTable thead .sorting_desc {
|
||||
background-image: url("DataTables-1.10.20/images/sort_desc.png");
|
||||
}
|
||||
table.dataTable thead .sorting_asc_disabled {
|
||||
background-image: url("DataTables-1.10.20/images/sort_asc_disabled.png");
|
||||
}
|
||||
table.dataTable thead .sorting_desc_disabled {
|
||||
background-image: url("DataTables-1.10.20/images/sort_desc_disabled.png");
|
||||
}
|
||||
table.dataTable tbody tr {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
table.dataTable tbody tr.selected {
|
||||
background-color: #B0BED9;
|
||||
}
|
||||
table.dataTable tbody th,
|
||||
table.dataTable tbody td {
|
||||
padding: 8px 10px;
|
||||
}
|
||||
table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
table.dataTable.row-border tbody tr:first-child th,
|
||||
table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,
|
||||
table.dataTable.display tbody tr:first-child td {
|
||||
border-top: none;
|
||||
}
|
||||
table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {
|
||||
border-top: 1px solid #ddd;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
table.dataTable.cell-border tbody tr th:first-child,
|
||||
table.dataTable.cell-border tbody tr td:first-child {
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
table.dataTable.cell-border tbody tr:first-child th,
|
||||
table.dataTable.cell-border tbody tr:first-child td {
|
||||
border-top: none;
|
||||
}
|
||||
table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {
|
||||
background-color: #acbad4;
|
||||
}
|
||||
table.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
table.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {
|
||||
background-color: #aab7d1;
|
||||
}
|
||||
table.dataTable.order-column tbody tr > .sorting_1,
|
||||
table.dataTable.order-column tbody tr > .sorting_2,
|
||||
table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,
|
||||
table.dataTable.display tbody tr > .sorting_2,
|
||||
table.dataTable.display tbody tr > .sorting_3 {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
table.dataTable.order-column tbody tr.selected > .sorting_1,
|
||||
table.dataTable.order-column tbody tr.selected > .sorting_2,
|
||||
table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,
|
||||
table.dataTable.display tbody tr.selected > .sorting_2,
|
||||
table.dataTable.display tbody tr.selected > .sorting_3 {
|
||||
background-color: #acbad5;
|
||||
}
|
||||
table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {
|
||||
background-color: #a6b4cd;
|
||||
}
|
||||
table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {
|
||||
background-color: #a8b5cf;
|
||||
}
|
||||
table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {
|
||||
background-color: #a9b7d1;
|
||||
}
|
||||
table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {
|
||||
background-color: #fcfcfc;
|
||||
}
|
||||
table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {
|
||||
background-color: #fefefe;
|
||||
}
|
||||
table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {
|
||||
background-color: #acbad5;
|
||||
}
|
||||
table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {
|
||||
background-color: #aebcd6;
|
||||
}
|
||||
table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {
|
||||
background-color: #afbdd8;
|
||||
}
|
||||
table.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
table.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {
|
||||
background-color: #ececec;
|
||||
}
|
||||
table.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {
|
||||
background-color: #efefef;
|
||||
}
|
||||
table.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {
|
||||
background-color: #a2aec7;
|
||||
}
|
||||
table.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {
|
||||
background-color: #a3b0c9;
|
||||
}
|
||||
table.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {
|
||||
background-color: #a5b2cb;
|
||||
}
|
||||
table.dataTable.no-footer {
|
||||
border-bottom: 1px solid #111;
|
||||
}
|
||||
table.dataTable.nowrap th, table.dataTable.nowrap td {
|
||||
white-space: nowrap;
|
||||
}
|
||||
table.dataTable.compact thead th,
|
||||
table.dataTable.compact thead td {
|
||||
padding: 4px 17px 4px 4px;
|
||||
}
|
||||
table.dataTable.compact tfoot th,
|
||||
table.dataTable.compact tfoot td {
|
||||
padding: 4px;
|
||||
}
|
||||
table.dataTable.compact tbody th,
|
||||
table.dataTable.compact tbody td {
|
||||
padding: 4px;
|
||||
}
|
||||
table.dataTable th.dt-left,
|
||||
table.dataTable td.dt-left {
|
||||
text-align: left;
|
||||
}
|
||||
table.dataTable th.dt-center,
|
||||
table.dataTable td.dt-center,
|
||||
table.dataTable td.dataTables_empty {
|
||||
text-align: center;
|
||||
}
|
||||
table.dataTable th.dt-right,
|
||||
table.dataTable td.dt-right {
|
||||
text-align: right;
|
||||
}
|
||||
table.dataTable th.dt-justify,
|
||||
table.dataTable td.dt-justify {
|
||||
text-align: justify;
|
||||
}
|
||||
table.dataTable th.dt-nowrap,
|
||||
table.dataTable td.dt-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
table.dataTable thead th.dt-head-left,
|
||||
table.dataTable thead td.dt-head-left,
|
||||
table.dataTable tfoot th.dt-head-left,
|
||||
table.dataTable tfoot td.dt-head-left {
|
||||
text-align: left;
|
||||
}
|
||||
table.dataTable thead th.dt-head-center,
|
||||
table.dataTable thead td.dt-head-center,
|
||||
table.dataTable tfoot th.dt-head-center,
|
||||
table.dataTable tfoot td.dt-head-center {
|
||||
text-align: center;
|
||||
}
|
||||
table.dataTable thead th.dt-head-right,
|
||||
table.dataTable thead td.dt-head-right,
|
||||
table.dataTable tfoot th.dt-head-right,
|
||||
table.dataTable tfoot td.dt-head-right {
|
||||
text-align: right;
|
||||
}
|
||||
table.dataTable thead th.dt-head-justify,
|
||||
table.dataTable thead td.dt-head-justify,
|
||||
table.dataTable tfoot th.dt-head-justify,
|
||||
table.dataTable tfoot td.dt-head-justify {
|
||||
text-align: justify;
|
||||
}
|
||||
table.dataTable thead th.dt-head-nowrap,
|
||||
table.dataTable thead td.dt-head-nowrap,
|
||||
table.dataTable tfoot th.dt-head-nowrap,
|
||||
table.dataTable tfoot td.dt-head-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
table.dataTable tbody th.dt-body-left,
|
||||
table.dataTable tbody td.dt-body-left {
|
||||
text-align: left;
|
||||
}
|
||||
table.dataTable tbody th.dt-body-center,
|
||||
table.dataTable tbody td.dt-body-center {
|
||||
text-align: center;
|
||||
}
|
||||
table.dataTable tbody th.dt-body-right,
|
||||
table.dataTable tbody td.dt-body-right {
|
||||
text-align: right;
|
||||
}
|
||||
table.dataTable tbody th.dt-body-justify,
|
||||
table.dataTable tbody td.dt-body-justify {
|
||||
text-align: justify;
|
||||
}
|
||||
table.dataTable tbody th.dt-body-nowrap,
|
||||
table.dataTable tbody td.dt-body-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
table.dataTable,
|
||||
table.dataTable th,
|
||||
table.dataTable td {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
/*
|
||||
* Control feature layout
|
||||
*/
|
||||
.dataTables_wrapper {
|
||||
position: relative;
|
||||
clear: both;
|
||||
*zoom: 1;
|
||||
zoom: 1;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_length {
|
||||
float: left;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter input {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_info {
|
||||
clear: both;
|
||||
float: left;
|
||||
padding-top: 0.755em;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_paginate {
|
||||
float: right;
|
||||
text-align: right;
|
||||
padding-top: 0.25em;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_paginate .paginate_button {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
min-width: 1.5em;
|
||||
padding: 0.5em 1em;
|
||||
margin-left: 2px;
|
||||
text-align: center;
|
||||
text-decoration: none !important;
|
||||
cursor: pointer;
|
||||
*cursor: hand;
|
||||
color: #333 !important;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
|
||||
color: #333 !important;
|
||||
border: 1px solid #979797;
|
||||
background-color: white;
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));
|
||||
/* Chrome,Safari4+ */
|
||||
background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);
|
||||
/* Chrome10+,Safari5.1+ */
|
||||
background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);
|
||||
/* FF3.6+ */
|
||||
background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);
|
||||
/* IE10+ */
|
||||
background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);
|
||||
/* Opera 11.10+ */
|
||||
background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);
|
||||
/* W3C */
|
||||
}
|
||||
.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {
|
||||
cursor: default;
|
||||
color: #666 !important;
|
||||
border: 1px solid transparent;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_paginate .paginate_button:hover {
|
||||
color: white !important;
|
||||
border: 1px solid #111;
|
||||
background-color: #585858;
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));
|
||||
/* Chrome,Safari4+ */
|
||||
background: -webkit-linear-gradient(top, #585858 0%, #111 100%);
|
||||
/* Chrome10+,Safari5.1+ */
|
||||
background: -moz-linear-gradient(top, #585858 0%, #111 100%);
|
||||
/* FF3.6+ */
|
||||
background: -ms-linear-gradient(top, #585858 0%, #111 100%);
|
||||
/* IE10+ */
|
||||
background: -o-linear-gradient(top, #585858 0%, #111 100%);
|
||||
/* Opera 11.10+ */
|
||||
background: linear-gradient(to bottom, #585858 0%, #111 100%);
|
||||
/* W3C */
|
||||
}
|
||||
.dataTables_wrapper .dataTables_paginate .paginate_button:active {
|
||||
outline: none;
|
||||
background-color: #2b2b2b;
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));
|
||||
/* Chrome,Safari4+ */
|
||||
background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
|
||||
/* Chrome10+,Safari5.1+ */
|
||||
background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
|
||||
/* FF3.6+ */
|
||||
background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
|
||||
/* IE10+ */
|
||||
background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
|
||||
/* Opera 11.10+ */
|
||||
background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);
|
||||
/* W3C */
|
||||
box-shadow: inset 0 0 3px #111;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_paginate .ellipsis {
|
||||
padding: 0 1em;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_processing {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
margin-left: -50%;
|
||||
margin-top: -25px;
|
||||
padding-top: 20px;
|
||||
text-align: center;
|
||||
font-size: 1.2em;
|
||||
background-color: white;
|
||||
background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));
|
||||
background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
|
||||
background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
|
||||
background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
|
||||
background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
|
||||
background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
|
||||
}
|
||||
.dataTables_wrapper .dataTables_length,
|
||||
.dataTables_wrapper .dataTables_filter,
|
||||
.dataTables_wrapper .dataTables_info,
|
||||
.dataTables_wrapper .dataTables_processing,
|
||||
.dataTables_wrapper .dataTables_paginate {
|
||||
color: #333;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_scroll {
|
||||
clear: both;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {
|
||||
*margin-top: -1px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th > div.dataTables_sizing,
|
||||
.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td > div.dataTables_sizing, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th > div.dataTables_sizing,
|
||||
.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td > div.dataTables_sizing {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
.dataTables_wrapper.no-footer .dataTables_scrollBody {
|
||||
border-bottom: 1px solid #111;
|
||||
}
|
||||
.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,
|
||||
.dataTables_wrapper.no-footer div.dataTables_scrollBody > table {
|
||||
border-bottom: none;
|
||||
}
|
||||
.dataTables_wrapper:after {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
content: "";
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
.dataTables_wrapper .dataTables_info,
|
||||
.dataTables_wrapper .dataTables_paginate {
|
||||
float: none;
|
||||
text-align: center;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_paginate {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 640px) {
|
||||
.dataTables_wrapper .dataTables_length,
|
||||
.dataTables_wrapper .dataTables_filter {
|
||||
float: none;
|
||||
text-align: center;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
|
4
web/static/css/font-awesome.min.css
vendored
Executable file
4
web/static/css/font-awesome.min.css
vendored
Executable file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user