Merge pull request #3668 from fatedier/dev

bump version to v0.52.1
This commit is contained in:
fatedier 2023-10-11 17:16:07 +08:00 committed by GitHub
commit 31fa3f021a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 260 additions and 237 deletions

View File

@ -761,6 +761,8 @@ allowPorts = [
`vhostHTTPPort` and `vhostHTTPSPort` in frps can use same port with `bindPort`. frps will detect the connection's protocol and handle it correspondingly. `vhostHTTPPort` and `vhostHTTPSPort` in frps can use same port with `bindPort`. frps will detect the connection's protocol and handle it correspondingly.
What you need to pay attention to is that if you want to configure `vhostHTTPSPort` and `bindPort` to the same port, you need to first set `transport.tls.disableCustomTLSFirstByte` to false.
We would like to try to allow multiple proxies bind a same remote port with different protocols in the future. We would like to try to allow multiple proxies bind a same remote port with different protocols in the future.
### Bandwidth Limit ### Bandwidth Limit

View File

@ -1,9 +1,6 @@
### Features ### Fixes
* Configuration: We now support TOML, YAML, and JSON for configuration. Please note that INI is deprecated and will be removed in future releases. New features will only be available in TOML, YAML, or JSON. Users wanting these new features should switch their configuration format accordingly. #2521 * `transport.tls.disableCustomTLSFirstByte` doesn't have any effect.
* The Server API did not return the data correctly.
### Breaking Changes * The Dashboard is unable to display data.
* `natHoleStunServer` is missing a default value.
* Change the way to start the visitor through the command line from `frpc stcp --role=visitor xxx` to `frpc stcp visitor xxx`.
* Modified the semantics of the `server_addr` in the command line, no longer including the port. Added the `server_port` parameter to configure the port.
* No longer support range ports mapping in TOML/YAML/JSON.

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>frps dashboard</title> <title>frps dashboard</title>
<script type="module" crossorigin src="./index-ea3edf22.js"></script> <script type="module" crossorigin src="./index-9465253b.js"></script>
<link rel="stylesheet" href="./index-1e0c7400.css"> <link rel="stylesheet" href="./index-1e0c7400.css">
</head> </head>

View File

@ -476,6 +476,9 @@ func (cm *ConnectionManager) realConnect() (net.Conn, error) {
// Make sure that if it is wss, the websocket hook is executed after the tls hook. // Make sure that if it is wss, the websocket hook is executed after the tls hook.
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: utilnet.DialHookWebsocket(protocol, tlsConfig.ServerName), Priority: 110})) dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: utilnet.DialHookWebsocket(protocol, tlsConfig.ServerName), Priority: 110}))
default: default:
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{
Hook: utilnet.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(cm.cfg.Transport.TLS.DisableCustomTLSFirstByte)),
}))
dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig)) dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig))
} }

View File

@ -83,7 +83,7 @@ enablePrometheus = true
# console or real logFile path like ./frps.log # console or real logFile path like ./frps.log
log.to = "./frps.log" log.to = "./frps.log"
# trace, debug, info, warn, error # trace, debug, info, warn, error
log.level = info log.level = "info"
log.maxDays = 3 log.maxDays = 3
# disable log colors when log.to is console, default is false # disable log colors when log.to is console, default is false
log.disablePrintColor = false log.disablePrintColor = false

View File

@ -306,6 +306,7 @@ func Convert_ProxyConf_To_v1(conf ProxyConf) v1.ProxyConfigurer {
c := &v1.XTCPProxyConfig{ProxyBaseConfig: *outBase} c := &v1.XTCPProxyConfig{ProxyBaseConfig: *outBase}
c.Secretkey = v.Sk c.Secretkey = v.Sk
c.AllowUsers = v.AllowUsers c.AllowUsers = v.AllowUsers
out = c
} }
return out return out
} }

View File

@ -27,7 +27,7 @@ type HTTPPluginOptions struct {
Addr string `ini:"addr"` Addr string `ini:"addr"`
Path string `ini:"path"` Path string `ini:"path"`
Ops []string `ini:"ops"` Ops []string `ini:"ops"`
TLSVerify bool `ini:"tls_verify"` TLSVerify bool `ini:"tlsVerify"`
} }
// ServerCommonConf contains information for a server service. It is // ServerCommonConf contains information for a server service. It is

View File

@ -76,6 +76,7 @@ func (c *ClientCommonConfig) Complete() {
c.ServerAddr = util.EmptyOr(c.ServerAddr, "0.0.0.0") c.ServerAddr = util.EmptyOr(c.ServerAddr, "0.0.0.0")
c.ServerPort = util.EmptyOr(c.ServerPort, 7000) c.ServerPort = util.EmptyOr(c.ServerPort, 7000)
c.LoginFailExit = util.EmptyOr(c.LoginFailExit, lo.ToPtr(true)) c.LoginFailExit = util.EmptyOr(c.LoginFailExit, lo.ToPtr(true))
c.NatHoleSTUNServer = util.EmptyOr(c.NatHoleSTUNServer, "stun.easyvoip.com:3478")
c.Auth.Complete() c.Auth.Complete()
c.Log.Complete() c.Log.Complete()

View File

@ -31,4 +31,5 @@ func TestClientConfigComplete(t *testing.T) {
require.Equal(true, lo.FromPtr(c.LoginFailExit)) require.Equal(true, lo.FromPtr(c.LoginFailExit))
require.Equal(true, lo.FromPtr(c.Transport.TLS.Enable)) require.Equal(true, lo.FromPtr(c.Transport.TLS.Enable))
require.Equal(true, lo.FromPtr(c.Transport.TLS.DisableCustomTLSFirstByte)) require.Equal(true, lo.FromPtr(c.Transport.TLS.DisableCustomTLSFirstByte))
require.NotEmpty(c.NatHoleSTUNServer)
} }

View File

@ -109,7 +109,7 @@ type HTTPPluginOptions struct {
Addr string `json:"addr"` Addr string `json:"addr"`
Path string `json:"path"` Path string `json:"path"`
Ops []string `json:"ops"` Ops []string `json:"ops"`
TLSVerify bool `json:"tls_verify,omitempty"` TLSVerify bool `json:"tlsVerify,omitempty"`
} }
type HeaderOperations struct { type HeaderOperations struct {

View File

@ -16,7 +16,6 @@ package v1
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"reflect" "reflect"
) )
@ -30,7 +29,7 @@ type TypedClientPluginOptions struct {
func (c *TypedClientPluginOptions) UnmarshalJSON(b []byte) error { func (c *TypedClientPluginOptions) UnmarshalJSON(b []byte) error {
if len(b) == 4 && string(b) == "null" { if len(b) == 4 && string(b) == "null" {
return errors.New("type is required") return nil
} }
typeStruct := struct { typeStruct := struct {
@ -41,6 +40,9 @@ func (c *TypedClientPluginOptions) UnmarshalJSON(b []byte) error {
} }
c.Type = typeStruct.Type c.Type = typeStruct.Type
if c.Type == "" {
return nil
}
v, ok := clientPluginOptionsTypeMap[typeStruct.Type] v, ok := clientPluginOptionsTypeMap[typeStruct.Type]
if !ok { if !ok {

View File

@ -19,7 +19,7 @@ import (
"strings" "strings"
) )
var version = "0.52.0" var version = "0.52.1"
func Full() string { func Full() string {
return version return version

View File

@ -34,24 +34,24 @@ type GeneralResponse struct {
type serverInfoResp struct { type serverInfoResp struct {
Version string `json:"version"` Version string `json:"version"`
BindPort int `json:"bind_port"` BindPort int `json:"bindPort"`
VhostHTTPPort int `json:"vhost_http_port"` VhostHTTPPort int `json:"vhostHTTPPort"`
VhostHTTPSPort int `json:"vhost_https_port"` VhostHTTPSPort int `json:"vhostHTTPSPort"`
TCPMuxHTTPConnectPort int `json:"tcpmux_httpconnect_port"` TCPMuxHTTPConnectPort int `json:"tcpmuxHTTPConnectPort"`
KCPBindPort int `json:"kcp_bind_port"` KCPBindPort int `json:"kcpBindPort"`
QUICBindPort int `json:"quic_bind_port"` QUICBindPort int `json:"quicBindPort"`
SubdomainHost string `json:"subdomain_host"` SubdomainHost string `json:"subdomainHost"`
MaxPoolCount int64 `json:"max_pool_count"` MaxPoolCount int64 `json:"maxPoolCount"`
MaxPortsPerClient int64 `json:"max_ports_per_client"` MaxPortsPerClient int64 `json:"maxPortsPerClient"`
HeartBeatTimeout int64 `json:"heart_beat_timeout"` HeartBeatTimeout int64 `json:"heartbeatTimeout"`
AllowPortsStr string `json:"allow_ports_str,omitempty"` AllowPortsStr string `json:"allowPortsStr,omitempty"`
TLSOnly bool `json:"tls_only,omitempty"` TLSForce bool `json:"tlsForce,omitempty"`
TotalTrafficIn int64 `json:"total_traffic_in"` TotalTrafficIn int64 `json:"totalTrafficIn"`
TotalTrafficOut int64 `json:"total_traffic_out"` TotalTrafficOut int64 `json:"totalTrafficOut"`
CurConns int64 `json:"cur_conns"` CurConns int64 `json:"curConns"`
ClientCounts int64 `json:"client_counts"` ClientCounts int64 `json:"clientCounts"`
ProxyTypeCounts map[string]int64 `json:"proxy_type_count"` ProxyTypeCounts map[string]int64 `json:"proxyTypeCount"`
} }
// /healthz // /healthz
@ -85,7 +85,7 @@ func (svr *Service) APIServerInfo(w http.ResponseWriter, r *http.Request) {
MaxPortsPerClient: svr.cfg.MaxPortsPerClient, MaxPortsPerClient: svr.cfg.MaxPortsPerClient,
HeartBeatTimeout: svr.cfg.Transport.HeartbeatTimeout, HeartBeatTimeout: svr.cfg.Transport.HeartbeatTimeout,
AllowPortsStr: types.PortsRangeSlice(svr.cfg.AllowPorts).String(), AllowPortsStr: types.PortsRangeSlice(svr.cfg.AllowPorts).String(),
TLSOnly: svr.cfg.Transport.TLS.Force, TLSForce: svr.cfg.Transport.TLS.Force,
TotalTrafficIn: serverStats.TotalTrafficIn, TotalTrafficIn: serverStats.TotalTrafficIn,
TotalTrafficOut: serverStats.TotalTrafficOut, TotalTrafficOut: serverStats.TotalTrafficOut,
@ -104,7 +104,7 @@ type BaseOutConf struct {
type TCPOutConf struct { type TCPOutConf struct {
BaseOutConf BaseOutConf
RemotePort int `json:"remote_port"` RemotePort int `json:"remotePort"`
} }
type TCPMuxOutConf struct { type TCPMuxOutConf struct {
@ -115,14 +115,14 @@ type TCPMuxOutConf struct {
type UDPOutConf struct { type UDPOutConf struct {
BaseOutConf BaseOutConf
RemotePort int `json:"remote_port"` RemotePort int `json:"remotePort"`
} }
type HTTPOutConf struct { type HTTPOutConf struct {
BaseOutConf BaseOutConf
v1.DomainConfig v1.DomainConfig
Locations []string `json:"locations"` Locations []string `json:"locations"`
HostHeaderRewrite string `json:"host_header_rewrite"` HostHeaderRewrite string `json:"hostHeaderRewrite"`
} }
type HTTPSOutConf struct { type HTTPSOutConf struct {
@ -163,12 +163,12 @@ func getConfByType(proxyType string) any {
type ProxyStatsInfo struct { type ProxyStatsInfo struct {
Name string `json:"name"` Name string `json:"name"`
Conf interface{} `json:"conf"` Conf interface{} `json:"conf"`
ClientVersion string `json:"client_version,omitempty"` ClientVersion string `json:"clientVersion,omitempty"`
TodayTrafficIn int64 `json:"today_traffic_in"` TodayTrafficIn int64 `json:"todayTrafficIn"`
TodayTrafficOut int64 `json:"today_traffic_out"` TodayTrafficOut int64 `json:"todayTrafficOut"`
CurConns int64 `json:"cur_conns"` CurConns int64 `json:"curConns"`
LastStartTime string `json:"last_start_time"` LastStartTime string `json:"lastStartTime"`
LastCloseTime string `json:"last_close_time"` LastCloseTime string `json:"lastCloseTime"`
Status string `json:"status"` Status string `json:"status"`
} }
@ -236,11 +236,11 @@ func (svr *Service) getProxyStatsByType(proxyType string) (proxyInfos []*ProxySt
type GetProxyStatsResp struct { type GetProxyStatsResp struct {
Name string `json:"name"` Name string `json:"name"`
Conf interface{} `json:"conf"` Conf interface{} `json:"conf"`
TodayTrafficIn int64 `json:"today_traffic_in"` TodayTrafficIn int64 `json:"todayTrafficIn"`
TodayTrafficOut int64 `json:"today_traffic_out"` TodayTrafficOut int64 `json:"todayTrafficOut"`
CurConns int64 `json:"cur_conns"` CurConns int64 `json:"curConns"`
LastStartTime string `json:"last_start_time"` LastStartTime string `json:"lastStartTime"`
LastCloseTime string `json:"last_close_time"` LastCloseTime string `json:"lastCloseTime"`
Status string `json:"status"` Status string `json:"status"`
} }
@ -310,8 +310,8 @@ func (svr *Service) getProxyStatsByTypeAndName(proxyType string, proxyName strin
// /api/traffic/:name // /api/traffic/:name
type GetProxyTrafficResp struct { type GetProxyTrafficResp struct {
Name string `json:"name"` Name string `json:"name"`
TrafficIn []int64 `json:"traffic_in"` TrafficIn []int64 `json:"trafficIn"`
TrafficOut []int64 `json:"traffic_out"` TrafficOut []int64 `json:"trafficOut"`
} }
func (svr *Service) APIProxyTraffic(w http.ResponseWriter, r *http.Request) { func (svr *Service) APIProxyTraffic(w http.ResponseWriter, r *http.Request) {

View File

@ -25,6 +25,7 @@ log.level = "trace"
DefaultClientConfig = ` DefaultClientConfig = `
serverAddr = "127.0.0.1" serverAddr = "127.0.0.1"
serverPort = {{ .%s }} serverPort = {{ .%s }}
loginFailExit = false
log.level = "trace" log.level = "trace"
` `
@ -38,6 +39,7 @@ log.level = "trace"
[common] [common]
server_addr = 127.0.0.1 server_addr = 127.0.0.1
server_port = {{ .%s }} server_port = {{ .%s }}
login_fail_exit = false
log_level = trace log_level = trace
` `
) )

View File

@ -40,6 +40,7 @@ func (f *Framework) RunProcesses(serverTemplates []string, clientTemplates []str
currentServerProcesses = append(currentServerProcesses, p) currentServerProcesses = append(currentServerProcesses, p)
err = p.Start() err = p.Start()
ExpectNoError(err) ExpectNoError(err)
time.Sleep(500 * time.Millisecond)
} }
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)

View File

@ -291,7 +291,7 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
}) })
}) })
ginkgo.Describe("TLS with disable_custom_tls_first_byte set to false", func() { ginkgo.Describe("TLS with disableCustomTLSFirstByte set to false", func() {
supportProtocols := []string{"tcp", "kcp", "quic", "websocket"} supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
for _, protocol := range supportProtocols { for _, protocol := range supportProtocols {
tmp := protocol tmp := protocol
@ -322,4 +322,22 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
}) })
} }
}) })
ginkgo.Describe("Use same port for bindPort and vhostHTTPSPort", func() {
supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
for _, protocol := range supportProtocols {
tmp := protocol
defineClientServerTest("Use same port for bindPort and vhostHTTPSPort: "+strings.ToUpper(tmp), f, &generalTestConfigures{
server: fmt.Sprintf(`
vhostHTTPSPort = {{ .%s }}
%s
`, consts.PortServerName, renderBindPortConfig(protocol)),
// transport.tls.disableCustomTLSFirstByte should set to false when vhostHTTPSPort is same as bindPort
client: fmt.Sprintf(`
transport.protocol = "%s"
transport.tls.disableCustomTLSFirstByte = false
`, protocol),
})
}
})
}) })

View File

@ -1,3 +1,5 @@
// Generated by 'unplugin-auto-import' // Generated by 'unplugin-auto-import'
export {} export {}
declare global {} declare global {
}

View File

@ -10,16 +10,16 @@ import ProxyView from './ProxyView.vue'
let proxies = ref<HTTPProxy[]>([]) let proxies = ref<HTTPProxy[]>([])
const fetchData = () => { const fetchData = () => {
let vhost_http_port: number let vhostHTTPPort: number
let subdomain_host: string let subdomainHost: string
fetch('../api/serverinfo', { credentials: 'include' }) fetch('../api/serverinfo', { credentials: 'include' })
.then((res) => { .then((res) => {
return res.json() return res.json()
}) })
.then((json) => { .then((json) => {
vhost_http_port = json.vhost_http_port vhostHTTPPort = json.vhostHTTPPort
subdomain_host = json.subdomain_host subdomainHost = json.subdomainHost
if (vhost_http_port == null || vhost_http_port == 0) { if (vhostHTTPPort == null || vhostHTTPPort == 0) {
return return
} }
fetch('../api/proxy/http', { credentials: 'include' }) fetch('../api/proxy/http', { credentials: 'include' })
@ -29,7 +29,7 @@ const fetchData = () => {
.then((json) => { .then((json) => {
for (let proxyStats of json.proxies) { for (let proxyStats of json.proxies) {
proxies.value.push( proxies.value.push(
new HTTPProxy(proxyStats, vhost_http_port, subdomain_host) new HTTPProxy(proxyStats, vhostHTTPPort, subdomainHost)
) )
} }
}) })

View File

@ -10,16 +10,16 @@ import ProxyView from './ProxyView.vue'
let proxies = ref<HTTPSProxy[]>([]) let proxies = ref<HTTPSProxy[]>([])
const fetchData = () => { const fetchData = () => {
let vhost_https_port: number let vhostHTTPSPort: number
let subdomain_host: string let subdomainHost: string
fetch('../api/serverinfo', { credentials: 'include' }) fetch('../api/serverinfo', { credentials: 'include' })
.then((res) => { .then((res) => {
return res.json() return res.json()
}) })
.then((json) => { .then((json) => {
vhost_https_port = json.vhost_https_port vhostHTTPSPort = json.vhostHTTPSPort
subdomain_host = json.subdomain_host subdomainHost = json.subdomainHost
if (vhost_https_port == null || vhost_https_port == 0) { if (vhostHTTPSPort == null || vhostHTTPSPort == 0) {
return return
} }
fetch('../api/proxy/https', { credentials: 'include' }) fetch('../api/proxy/https', { credentials: 'include' })
@ -29,7 +29,7 @@ const fetchData = () => {
.then((json) => { .then((json) => {
for (let proxyStats of json.proxies) { for (let proxyStats of json.proxies) {
proxies.value.push( proxies.value.push(
new HTTPSProxy(proxyStats, vhost_https_port, subdomain_host) new HTTPSProxy(proxyStats, vhostHTTPSPort, subdomainHost)
) )
} }
}) })

View File

@ -14,7 +14,7 @@
trigger="click" trigger="click"
> >
<template #default> <template #default>
<Traffic :proxy_name="props.row.name" /> <Traffic :proxyName="props.row.name" />
</template> </template>
<template #reference> <template #reference>
@ -37,19 +37,19 @@
</el-table-column> </el-table-column>
<el-table-column <el-table-column
label="Traffic In" label="Traffic In"
prop="traffic_in" prop="trafficIn"
:formatter="formatTrafficIn" :formatter="formatTrafficIn"
sortable sortable
> >
</el-table-column> </el-table-column>
<el-table-column <el-table-column
label="Traffic Out" label="Traffic Out"
prop="traffic_out" prop="trafficOut"
:formatter="formatTrafficOut" :formatter="formatTrafficOut"
sortable sortable
> >
</el-table-column> </el-table-column>
<el-table-column label="ClientVersion" prop="client_version" sortable> <el-table-column label="ClientVersion" prop="clientVersion" sortable>
</el-table-column> </el-table-column>
<el-table-column label="Status" prop="status" sortable> <el-table-column label="Status" prop="status" sortable>
<template #default="scope"> <template #default="scope">
@ -75,10 +75,10 @@ defineProps<{
}>() }>()
const formatTrafficIn = (row: BaseProxy, _: TableColumnCtx<BaseProxy>) => { const formatTrafficIn = (row: BaseProxy, _: TableColumnCtx<BaseProxy>) => {
return Humanize.fileSize(row.traffic_in) return Humanize.fileSize(row.trafficIn)
} }
const formatTrafficOut = (row: BaseProxy, _: TableColumnCtx<BaseProxy>) => { const formatTrafficOut = (row: BaseProxy, _: TableColumnCtx<BaseProxy>) => {
return Humanize.fileSize(row.traffic_out) return Humanize.fileSize(row.trafficOut)
} }
</script> </script>

View File

@ -12,7 +12,7 @@
<span>{{ row.type }}</span> <span>{{ row.type }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Domains"> <el-form-item label="Domains">
<span>{{ row.custom_domains }}</span> <span>{{ row.customDomains }}</span>
</el-form-item> </el-form-item>
<el-form-item label="SubDomain"> <el-form-item label="SubDomain">
<span>{{ row.subdomain }}</span> <span>{{ row.subdomain }}</span>
@ -21,7 +21,7 @@
<span>{{ row.locations }}</span> <span>{{ row.locations }}</span>
</el-form-item> </el-form-item>
<el-form-item label="HostRewrite"> <el-form-item label="HostRewrite">
<span>{{ row.host_header_rewrite }}</span> <span>{{ row.hostHeaderRewrite }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Encryption"> <el-form-item label="Encryption">
<span>{{ row.encryption }}</span> <span>{{ row.encryption }}</span>
@ -30,10 +30,10 @@
<span>{{ row.compression }}</span> <span>{{ row.compression }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Last Start"> <el-form-item label="Last Start">
<span>{{ row.last_start_time }}</span> <span>{{ row.lastStartTime }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Last Close"> <el-form-item label="Last Close">
<span>{{ row.last_close_time }}</span> <span>{{ row.lastCloseTime }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -54,10 +54,10 @@
<span>{{ row.compression }}</span> <span>{{ row.compression }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Last Start"> <el-form-item label="Last Start">
<span>{{ row.last_start_time }}</span> <span>{{ row.lastStartTime }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Last Close"> <el-form-item label="Last Close">
<span>{{ row.last_close_time }}</span> <span>{{ row.lastCloseTime }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>

View File

@ -12,58 +12,58 @@
<span>{{ data.version }}</span> <span>{{ data.version }}</span>
</el-form-item> </el-form-item>
<el-form-item label="BindPort"> <el-form-item label="BindPort">
<span>{{ data.bind_port }}</span> <span>{{ data.bindPort }}</span>
</el-form-item> </el-form-item>
<el-form-item label="KCP Bind Port" v-if="data.kcp_bind_port != 0"> <el-form-item label="KCP Bind Port" v-if="data.kcpBindPort != 0">
<span>{{ data.kcp_bind_port }}</span> <span>{{ data.kcpBindPort }}</span>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
label="QUIC Bind Port" label="QUIC Bind Port"
v-if="data.quic_bind_port != 0" v-if="data.quicBindPort != 0"
> >
<span>{{ data.quic_bind_port }}</span> <span>{{ data.quicBindPort }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Http Port" v-if="data.vhost_http_port != 0"> <el-form-item label="Http Port" v-if="data.vhostHTTPPort != 0">
<span>{{ data.vhost_http_port }}</span> <span>{{ data.vhostHTTPPort }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Https Port" v-if="data.vhost_https_port != 0"> <el-form-item label="Https Port" v-if="data.vhostHTTPSPort != 0">
<span>{{ data.vhost_https_port }}</span> <span>{{ data.vhostHTTPSPort }}</span>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
label="TCPMux HTTPConnect Port" label="TCPMux HTTPConnect Port"
v-if="data.tcpmux_httpconnect_port != 0" v-if="data.tcpmuxHTTPConnectPort != 0"
> >
<span>{{ data.tcpmux_httpconnect_port }}</span> <span>{{ data.tcpmuxHTTPConnectPort }}</span>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
label="Subdomain Host" label="Subdomain Host"
v-if="data.subdomain_host != ''" v-if="data.subdomainHost != ''"
> >
<LongSpan :content="data.subdomain_host" :length="30"></LongSpan> <LongSpan :content="data.subdomainHost" :length="30"></LongSpan>
</el-form-item> </el-form-item>
<el-form-item label="Max PoolCount"> <el-form-item label="Max PoolCount">
<span>{{ data.max_pool_count }}</span> <span>{{ data.maxPoolCount }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Max Ports Per Client"> <el-form-item label="Max Ports Per Client">
<span>{{ data.max_ports_per_client }}</span> <span>{{ data.maxPortsPerClient }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Allow Ports" v-if="data.allow_ports_str != ''"> <el-form-item label="Allow Ports" v-if="data.allowPortsStr != ''">
<LongSpan :content="data.allow_ports_str" :length="30"></LongSpan> <LongSpan :content="data.allowPortsStr" :length="30"></LongSpan>
</el-form-item> </el-form-item>
<el-form-item label="TLS Only" v-if="data.tls_only === true"> <el-form-item label="TLS Force" v-if="data.tlsForce === true">
<span>{{ data.tls_only }}</span> <span>{{ data.tlsForce }}</span>
</el-form-item> </el-form-item>
<el-form-item label="HeartBeat Timeout"> <el-form-item label="HeartBeat Timeout">
<span>{{ data.heart_beat_timeout }}</span> <span>{{ data.heartbeatTimeout }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Client Counts"> <el-form-item label="Client Counts">
<span>{{ data.client_counts }}</span> <span>{{ data.clientCounts }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Current Connections"> <el-form-item label="Current Connections">
<span>{{ data.cur_conns }}</span> <span>{{ data.curConns }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Proxy Counts"> <el-form-item label="Proxy Counts">
<span>{{ data.proxy_counts }}</span> <span>{{ data.proxyCounts }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
@ -87,21 +87,21 @@ import LongSpan from './LongSpan.vue'
let data = ref({ let data = ref({
version: '', version: '',
bind_port: 0, bindPort: 0,
kcp_bind_port: 0, kcpBindPort: 0,
quic_bind_port: 0, quicBindPort: 0,
vhost_http_port: 0, vhostHTTPPort: 0,
vhost_https_port: 0, vhostHTTPSPort: 0,
tcpmux_httpconnect_port: 0, tcpmuxHTTPConnectPort: 0,
subdomain_host: '', subdomainHost: '',
max_pool_count: 0, maxPoolCount: 0,
max_ports_per_client: '', maxPortsPerClient: '',
allow_ports_str: '', allowPortsStr: '',
tls_only: false, tlsForce: false,
heart_beat_timeout: 0, heartbeatTimeout: 0,
client_counts: 0, clientCounts: 0,
cur_conns: 0, curConns: 0,
proxy_counts: 0, proxyCounts: 0,
}) })
const fetchData = () => { const fetchData = () => {
@ -109,50 +109,50 @@ const fetchData = () => {
.then((res) => res.json()) .then((res) => res.json())
.then((json) => { .then((json) => {
data.value.version = json.version data.value.version = json.version
data.value.bind_port = json.bind_port data.value.bindPort = json.bindPort
data.value.kcp_bind_port = json.kcp_bind_port data.value.kcpBindPort = json.kcpBindPort
data.value.quic_bind_port = json.quic_bind_port data.value.quicBindPort = json.quicBindPort
data.value.vhost_http_port = json.vhost_http_port data.value.vhostHTTPPort = json.vhostHTTPPort
data.value.vhost_https_port = json.vhost_https_port data.value.vhostHTTPSPort = json.vhostHTTPSPort
data.value.tcpmux_httpconnect_port = json.tcpmux_httpconnect_port data.value.tcpmuxHTTPConnectPort = json.tcpmuxHTTPConnectPort
data.value.subdomain_host = json.subdomain_host data.value.subdomainHost = json.subdomainHost
data.value.max_pool_count = json.max_pool_count data.value.maxPoolCount = json.maxPoolCount
data.value.max_ports_per_client = json.max_ports_per_client data.value.maxPortsPerClient = json.maxPortsPerClient
if (data.value.max_ports_per_client == '0') { if (data.value.maxPortsPerClient == '0') {
data.value.max_ports_per_client = 'no limit' data.value.maxPortsPerClient = 'no limit'
} }
data.value.allow_ports_str = json.allow_ports_str data.value.allowPortsStr = json.allowPortsStr
data.value.tls_only = json.tls_only data.value.tlsForce = json.tlsForce
data.value.heart_beat_timeout = json.heart_beat_timeout data.value.heartbeatTimeout = json.heartbeatTimeout
data.value.client_counts = json.client_counts data.value.clientCounts = json.clientCounts
data.value.cur_conns = json.cur_conns data.value.curConns = json.curConns
data.value.proxy_counts = 0 data.value.proxyCounts = 0
if (json.proxy_type_count != null) { if (json.proxyTypeCount != null) {
if (json.proxy_type_count.tcp != null) { if (json.proxyTypeCount.tcp != null) {
data.value.proxy_counts += json.proxy_type_count.tcp data.value.proxyCounts += json.proxyTypeCount.tcp
} }
if (json.proxy_type_count.udp != null) { if (json.proxyTypeCount.udp != null) {
data.value.proxy_counts += json.proxy_type_count.udp data.value.proxyCounts += json.proxyTypeCount.udp
} }
if (json.proxy_type_count.http != null) { if (json.proxyTypeCount.http != null) {
data.value.proxy_counts += json.proxy_type_count.http data.value.proxyCounts += json.proxyTypeCount.http
} }
if (json.proxy_type_count.https != null) { if (json.proxyTypeCount.https != null) {
data.value.proxy_counts += json.proxy_type_count.https data.value.proxyCounts += json.proxyTypeCount.https
} }
if (json.proxy_type_count.stcp != null) { if (json.proxyTypeCount.stcp != null) {
data.value.proxy_counts += json.proxy_type_count.stcp data.value.proxyCounts += json.proxyTypeCount.stcp
} }
if (json.proxy_type_count.sudp != null) { if (json.proxyTypeCount.sudp != null) {
data.value.proxy_counts += json.proxy_type_count.sudp data.value.proxyCounts += json.proxyTypeCount.sudp
} }
if (json.proxy_type_count.xtcp != null) { if (json.proxyTypeCount.xtcp != null) {
data.value.proxy_counts += json.proxy_type_count.xtcp data.value.proxyCounts += json.proxyTypeCount.xtcp
} }
} }
// draw chart // draw chart
DrawTrafficChart('traffic', json.total_traffic_in, json.total_traffic_out) DrawTrafficChart('traffic', json.totalTrafficIn, json.totalTrafficOut)
DrawProxyChart('proxies', json) DrawProxyChart('proxies', json)
}) })
.catch(() => { .catch(() => {

View File

@ -1,5 +1,5 @@
<template> <template>
<div :id="proxy_name" style="width: 600px; height: 400px"></div> <div :id="proxyName" style="width: 600px; height: 400px"></div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -7,17 +7,17 @@ import { ElMessage } from 'element-plus'
import { DrawProxyTrafficChart } from '../utils/chart.js' import { DrawProxyTrafficChart } from '../utils/chart.js'
const props = defineProps<{ const props = defineProps<{
proxy_name: string proxyName: string
}>() }>()
const fetchData = () => { const fetchData = () => {
let url = '../api/traffic/' + props.proxy_name let url = '../api/traffic/' + props.proxyName
fetch(url, { credentials: 'include' }) fetch(url, { credentials: 'include' })
.then((res) => { .then((res) => {
return res.json() return res.json()
}) })
.then((json) => { .then((json) => {
DrawProxyTrafficChart(props.proxy_name, json.traffic_in, json.traffic_out) DrawProxyTrafficChart(props.proxyName, json.trafficIn, json.trafficOut)
}) })
.catch((err) => { .catch((err) => {
ElMessage({ ElMessage({

View File

@ -121,71 +121,71 @@ function DrawProxyChart(elementId: string, serverInfo: any) {
} }
if ( if (
serverInfo.proxy_type_count.tcp != null && serverInfo.proxyTypeCount.tcp != null &&
serverInfo.proxy_type_count.tcp != 0 serverInfo.proxyTypeCount.tcp != 0
) { ) {
option.series[0].data.push({ option.series[0].data.push({
value: serverInfo.proxy_type_count.tcp, value: serverInfo.proxyTypeCount.tcp,
name: 'TCP', name: 'TCP',
}) })
option.legend.data.push('TCP') option.legend.data.push('TCP')
} }
if ( if (
serverInfo.proxy_type_count.udp != null && serverInfo.proxyTypeCount.udp != null &&
serverInfo.proxy_type_count.udp != 0 serverInfo.proxyTypeCount.udp != 0
) { ) {
option.series[0].data.push({ option.series[0].data.push({
value: serverInfo.proxy_type_count.udp, value: serverInfo.proxyTypeCount.udp,
name: 'UDP', name: 'UDP',
}) })
option.legend.data.push('UDP') option.legend.data.push('UDP')
} }
if ( if (
serverInfo.proxy_type_count.http != null && serverInfo.proxyTypeCount.http != null &&
serverInfo.proxy_type_count.http != 0 serverInfo.proxyTypeCount.http != 0
) { ) {
option.series[0].data.push({ option.series[0].data.push({
value: serverInfo.proxy_type_count.http, value: serverInfo.proxyTypeCount.http,
name: 'HTTP', name: 'HTTP',
}) })
option.legend.data.push('HTTP') option.legend.data.push('HTTP')
} }
if ( if (
serverInfo.proxy_type_count.https != null && serverInfo.proxyTypeCount.https != null &&
serverInfo.proxy_type_count.https != 0 serverInfo.proxyTypeCount.https != 0
) { ) {
option.series[0].data.push({ option.series[0].data.push({
value: serverInfo.proxy_type_count.https, value: serverInfo.proxyTypeCount.https,
name: 'HTTPS', name: 'HTTPS',
}) })
option.legend.data.push('HTTPS') option.legend.data.push('HTTPS')
} }
if ( if (
serverInfo.proxy_type_count.stcp != null && serverInfo.proxyTypeCount.stcp != null &&
serverInfo.proxy_type_count.stcp != 0 serverInfo.proxyTypeCount.stcp != 0
) { ) {
option.series[0].data.push({ option.series[0].data.push({
value: serverInfo.proxy_type_count.stcp, value: serverInfo.proxyTypeCount.stcp,
name: 'STCP', name: 'STCP',
}) })
option.legend.data.push('STCP') option.legend.data.push('STCP')
} }
if ( if (
serverInfo.proxy_type_count.sudp != null && serverInfo.proxyTypeCount.sudp != null &&
serverInfo.proxy_type_count.sudp != 0 serverInfo.proxyTypeCount.sudp != 0
) { ) {
option.series[0].data.push({ option.series[0].data.push({
value: serverInfo.proxy_type_count.sudp, value: serverInfo.proxyTypeCount.sudp,
name: 'SUDP', name: 'SUDP',
}) })
option.legend.data.push('SUDP') option.legend.data.push('SUDP')
} }
if ( if (
serverInfo.proxy_type_count.xtcp != null && serverInfo.proxyTypeCount.xtcp != null &&
serverInfo.proxy_type_count.xtcp != 0 serverInfo.proxyTypeCount.xtcp != 0
) { ) {
option.series[0].data.push({ option.series[0].data.push({
value: serverInfo.proxy_type_count.xtcp, value: serverInfo.proxyTypeCount.xtcp,
name: 'XTCP', name: 'XTCP',
}) })
option.legend.data.push('XTCP') option.legend.data.push('XTCP')

View File

@ -4,42 +4,43 @@ class BaseProxy {
encryption: boolean encryption: boolean
compression: boolean compression: boolean
conns: number conns: number
traffic_in: number trafficIn: number
traffic_out: number trafficOut: number
last_start_time: string lastStartTime: string
last_close_time: string lastCloseTime: string
status: string status: string
client_version: string clientVersion: string
addr: string addr: string
port: number port: number
custom_domains: string customDomains: string
host_header_rewrite: string hostHeaderRewrite: string
locations: string locations: string
subdomain: string subdomain: string
constructor(proxyStats: any) { constructor(proxyStats: any) {
this.name = proxyStats.name this.name = proxyStats.name
this.type = '' this.type = ''
if (proxyStats.conf != null) { this.encryption = false
this.encryption = proxyStats.conf.use_encryption this.compression = false
this.compression = proxyStats.conf.use_compression if (proxyStats.conf != null && proxyStats.conf.useEncryption != null) {
} else { this.encryption = proxyStats.conf.useEncryption
this.encryption = false
this.compression = false
} }
this.conns = proxyStats.cur_conns if (proxyStats.conf != null && proxyStats.conf.useCompression != null) {
this.traffic_in = proxyStats.today_traffic_in this.compression = proxyStats.conf.useCompression
this.traffic_out = proxyStats.today_traffic_out }
this.last_start_time = proxyStats.last_start_time this.conns = proxyStats.curConns
this.last_close_time = proxyStats.last_close_time this.trafficIn = proxyStats.todayTrafficIn
this.trafficOut = proxyStats.todayTrafficOut
this.lastStartTime = proxyStats.lastStartTime
this.lastCloseTime = proxyStats.lastCloseTime
this.status = proxyStats.status this.status = proxyStats.status
this.client_version = proxyStats.client_version this.clientVersion = proxyStats.clientVersion
this.addr = '' this.addr = ''
this.port = 0 this.port = 0
this.custom_domains = '' this.customDomains = ''
this.host_header_rewrite = '' this.hostHeaderRewrite = ''
this.locations = '' this.locations = ''
this.subdomain = '' this.subdomain = ''
} }
@ -50,8 +51,8 @@ class TCPProxy extends BaseProxy {
super(proxyStats) super(proxyStats)
this.type = 'tcp' this.type = 'tcp'
if (proxyStats.conf != null) { if (proxyStats.conf != null) {
this.addr = ':' + proxyStats.conf.remote_port this.addr = ':' + proxyStats.conf.remotePort
this.port = proxyStats.conf.remote_port this.port = proxyStats.conf.remotePort
} else { } else {
this.addr = '' this.addr = ''
this.port = 0 this.port = 0
@ -64,8 +65,8 @@ class UDPProxy extends BaseProxy {
super(proxyStats) super(proxyStats)
this.type = 'udp' this.type = 'udp'
if (proxyStats.conf != null) { if (proxyStats.conf != null) {
this.addr = ':' + proxyStats.conf.remote_port this.addr = ':' + proxyStats.conf.remotePort
this.port = proxyStats.conf.remote_port this.port = proxyStats.conf.remotePort
} else { } else {
this.addr = '' this.addr = ''
this.port = 0 this.port = 0
@ -74,43 +75,35 @@ class UDPProxy extends BaseProxy {
} }
class HTTPProxy extends BaseProxy { class HTTPProxy extends BaseProxy {
constructor(proxyStats: any, port: number, subdomain_host: string) { constructor(proxyStats: any, port: number, subdomainHost: string) {
super(proxyStats) super(proxyStats)
this.type = 'http' this.type = 'http'
this.port = port this.port = port
if (proxyStats.conf != null) { if (proxyStats.conf != null) {
this.custom_domains = proxyStats.conf.custom_domains if (proxyStats.conf.customDomains != null) {
this.host_header_rewrite = proxyStats.conf.host_header_rewrite this.customDomains = proxyStats.conf.customDomains
this.locations = proxyStats.conf.locations }
if (proxyStats.conf.subdomain != '') { this.hostHeaderRewrite = proxyStats.conf.hostHeaderRewrite
this.subdomain = proxyStats.conf.subdomain + '.' + subdomain_host this.locations = proxyStats.conf.locations
} else { if (proxyStats.conf.subdomain != null && proxyStats.conf.subdomain != '') {
this.subdomain = '' this.subdomain = proxyStats.conf.subdomain + '.' + subdomainHost
} }
} else {
this.custom_domains = ''
this.host_header_rewrite = ''
this.subdomain = ''
this.locations = ''
} }
} }
} }
class HTTPSProxy extends BaseProxy { class HTTPSProxy extends BaseProxy {
constructor(proxyStats: any, port: number, subdomain_host: string) { constructor(proxyStats: any, port: number, subdomainHost: string) {
super(proxyStats) super(proxyStats)
this.type = 'https' this.type = 'https'
this.port = port this.port = port
if (proxyStats.conf != null) { if (proxyStats.conf != null) {
this.custom_domains = proxyStats.conf.custom_domains if (proxyStats.conf.customDomains != null) {
if (proxyStats.conf.subdomain != '') { this.customDomains = proxyStats.conf.customDomains
this.subdomain = proxyStats.conf.subdomain + '.' + subdomain_host }
} else { if (proxyStats.conf.subdomain != null && proxyStats.conf.subdomain != '') {
this.subdomain = '' this.subdomain = proxyStats.conf.subdomain + '.' + subdomainHost
} }
} else {
this.custom_domains = ''
this.subdomain = ''
} }
} }
} }