From 01fed8d1a97dce7d19d520877949f6e19054ee54 Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 19 Dec 2024 18:13:25 +0800 Subject: [PATCH 01/11] Update stale workflow (#4600) --- .github/workflows/stale.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index f5cc538f..784053e8 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -21,14 +21,14 @@ jobs: steps: - uses: actions/stale@v9 with: - stale-issue-message: 'Issues go stale after 21d of inactivity. Stale issues rot after an additional 7d of inactivity and eventually close.' - stale-pr-message: "PRs go stale after 21d of inactivity. Stale PRs rot after an additional 7d of inactivity and eventually close." + stale-issue-message: 'Issues go stale after 14d of inactivity. Stale issues rot after an additional 3d of inactivity and eventually close.' + stale-pr-message: "PRs go stale after 14d of inactivity. Stale PRs rot after an additional 3d of inactivity and eventually close." stale-issue-label: 'lifecycle/stale' exempt-issue-labels: 'bug,doc,enhancement,future,proposal,question,testing,todo,easy,help wanted,assigned' stale-pr-label: 'lifecycle/stale' exempt-pr-labels: 'bug,doc,enhancement,future,proposal,question,testing,todo,easy,help wanted,assigned' - days-before-stale: 21 - days-before-close: 7 + days-before-stale: 14 + days-before-close: 3 debug-only: ${{ github.event.inputs.debug-only }} exempt-all-pr-milestones: true exempt-all-pr-assignees: true From 092e5d3f94c76f744daed396195e6ca2f322ee96 Mon Sep 17 00:00:00 2001 From: Gabriel Marin Date: Thu, 2 Jan 2025 05:24:08 +0200 Subject: [PATCH 02/11] client, pkg, server, test: replaced 'interface{}' with 'any' (#4611) --- client/event/event.go | 2 +- client/proxy/proxy_manager.go | 2 +- pkg/config/legacy/client.go | 4 ++-- pkg/config/legacy/server.go | 2 +- pkg/config/load.go | 2 +- pkg/msg/ctl.go | 2 +- pkg/msg/msg.go | 2 +- pkg/plugin/server/http.go | 2 +- pkg/plugin/server/manager.go | 10 ++++----- pkg/plugin/server/plugin.go | 2 +- pkg/plugin/server/types.go | 14 ++++++------- pkg/util/log/log.go | 12 +++++------ pkg/util/vhost/router.go | 4 ++-- pkg/util/xlog/xlog.go | 10 ++++----- server/dashboard_api.go | 34 +++++++++++++++---------------- test/e2e/framework/expect.go | 32 ++++++++++++++--------------- test/e2e/framework/log.go | 6 +++--- test/e2e/framework/mockservers.go | 6 +++--- test/e2e/framework/request.go | 6 +++--- 19 files changed, 77 insertions(+), 77 deletions(-) diff --git a/client/event/event.go b/client/event/event.go index bf7090d9..acdc96ba 100644 --- a/client/event/event.go +++ b/client/event/event.go @@ -8,7 +8,7 @@ import ( var ErrPayloadType = errors.New("error payload type") -type Handler func(payload interface{}) error +type Handler func(payload any) error type StartProxyPayload struct { NewProxyMsg *msg.NewProxy diff --git a/client/proxy/proxy_manager.go b/client/proxy/proxy_manager.go index 95778ce0..d42aedc0 100644 --- a/client/proxy/proxy_manager.go +++ b/client/proxy/proxy_manager.go @@ -96,7 +96,7 @@ func (pm *Manager) HandleWorkConn(name string, workConn net.Conn, m *msg.StartWo } } -func (pm *Manager) HandleEvent(payload interface{}) error { +func (pm *Manager) HandleEvent(payload any) error { var m msg.Message switch e := payload.(type) { case *event.StartProxyPayload: diff --git a/pkg/config/legacy/client.go b/pkg/config/legacy/client.go index 7c16c73d..0d677d9c 100644 --- a/pkg/config/legacy/client.go +++ b/pkg/config/legacy/client.go @@ -170,7 +170,7 @@ type ClientCommonConf struct { } // Supported sources including: string(file path), []byte, Reader interface. -func UnmarshalClientConfFromIni(source interface{}) (ClientCommonConf, error) { +func UnmarshalClientConfFromIni(source any) (ClientCommonConf, error) { f, err := ini.LoadSources(ini.LoadOptions{ Insensitive: false, InsensitiveSections: false, @@ -203,7 +203,7 @@ func UnmarshalClientConfFromIni(source interface{}) (ClientCommonConf, error) { // otherwise just start proxies in startProxy map func LoadAllProxyConfsFromIni( prefix string, - source interface{}, + source any, start []string, ) (map[string]ProxyConf, map[string]VisitorConf, error) { f, err := ini.LoadSources(ini.LoadOptions{ diff --git a/pkg/config/legacy/server.go b/pkg/config/legacy/server.go index c58f76ad..1cfa1bdc 100644 --- a/pkg/config/legacy/server.go +++ b/pkg/config/legacy/server.go @@ -217,7 +217,7 @@ func GetDefaultServerConf() ServerCommonConf { } } -func UnmarshalServerConfFromIni(source interface{}) (ServerCommonConf, error) { +func UnmarshalServerConfFromIni(source any) (ServerCommonConf, error) { f, err := ini.LoadSources(ini.LoadOptions{ Insensitive: false, InsensitiveSections: false, diff --git a/pkg/config/load.go b/pkg/config/load.go index f9a705eb..fa814fd0 100644 --- a/pkg/config/load.go +++ b/pkg/config/load.go @@ -118,7 +118,7 @@ func LoadConfigure(b []byte, c any, strict bool) error { defer v1.DisallowUnknownFieldsMu.Unlock() v1.DisallowUnknownFields = strict - var tomlObj interface{} + var tomlObj any // Try to unmarshal as TOML first; swallow errors from that (assume it's not valid TOML). if err := toml.Unmarshal(b, &tomlObj); err == nil { b, err = json.Marshal(&tomlObj) diff --git a/pkg/msg/ctl.go b/pkg/msg/ctl.go index bf0c71a7..57681b12 100644 --- a/pkg/msg/ctl.go +++ b/pkg/msg/ctl.go @@ -39,6 +39,6 @@ func ReadMsgInto(c io.Reader, msg Message) (err error) { return msgCtl.ReadMsgInto(c, msg) } -func WriteMsg(c io.Writer, msg interface{}) (err error) { +func WriteMsg(c io.Writer, msg any) (err error) { return msgCtl.WriteMsg(c, msg) } diff --git a/pkg/msg/msg.go b/pkg/msg/msg.go index a6344d08..d466f231 100644 --- a/pkg/msg/msg.go +++ b/pkg/msg/msg.go @@ -40,7 +40,7 @@ const ( TypeNatHoleReport = '6' ) -var msgTypeMap = map[byte]interface{}{ +var msgTypeMap = map[byte]any{ TypeLogin: Login{}, TypeLoginResp: LoginResp{}, TypeNewProxy: NewProxy{}, diff --git a/pkg/plugin/server/http.go b/pkg/plugin/server/http.go index 7108b7fb..6046c38a 100644 --- a/pkg/plugin/server/http.go +++ b/pkg/plugin/server/http.go @@ -72,7 +72,7 @@ func (p *httpPlugin) IsSupport(op string) bool { return false } -func (p *httpPlugin) Handle(ctx context.Context, op string, content interface{}) (*Response, interface{}, error) { +func (p *httpPlugin) Handle(ctx context.Context, op string, content any) (*Response, any, error) { r := &Request{ Version: APIVersion, Op: op, diff --git a/pkg/plugin/server/manager.go b/pkg/plugin/server/manager.go index ed96444a..8f23b529 100644 --- a/pkg/plugin/server/manager.go +++ b/pkg/plugin/server/manager.go @@ -75,7 +75,7 @@ func (m *Manager) Login(content *LoginContent) (*LoginContent, error) { Reject: false, Unchange: true, } - retContent interface{} + retContent any err error ) reqid, _ := util.RandID() @@ -109,7 +109,7 @@ func (m *Manager) NewProxy(content *NewProxyContent) (*NewProxyContent, error) { Reject: false, Unchange: true, } - retContent interface{} + retContent any err error ) reqid, _ := util.RandID() @@ -168,7 +168,7 @@ func (m *Manager) Ping(content *PingContent) (*PingContent, error) { Reject: false, Unchange: true, } - retContent interface{} + retContent any err error ) reqid, _ := util.RandID() @@ -202,7 +202,7 @@ func (m *Manager) NewWorkConn(content *NewWorkConnContent) (*NewWorkConnContent, Reject: false, Unchange: true, } - retContent interface{} + retContent any err error ) reqid, _ := util.RandID() @@ -236,7 +236,7 @@ func (m *Manager) NewUserConn(content *NewUserConnContent) (*NewUserConnContent, Reject: false, Unchange: true, } - retContent interface{} + retContent any err error ) reqid, _ := util.RandID() diff --git a/pkg/plugin/server/plugin.go b/pkg/plugin/server/plugin.go index 0d34de54..9456ee9b 100644 --- a/pkg/plugin/server/plugin.go +++ b/pkg/plugin/server/plugin.go @@ -32,5 +32,5 @@ const ( type Plugin interface { Name() string IsSupport(op string) bool - Handle(ctx context.Context, op string, content interface{}) (res *Response, retContent interface{}, err error) + Handle(ctx context.Context, op string, content any) (res *Response, retContent any, err error) } diff --git a/pkg/plugin/server/types.go b/pkg/plugin/server/types.go index d7d98cb6..c9fc4a40 100644 --- a/pkg/plugin/server/types.go +++ b/pkg/plugin/server/types.go @@ -19,16 +19,16 @@ import ( ) type Request struct { - Version string `json:"version"` - Op string `json:"op"` - Content interface{} `json:"content"` + Version string `json:"version"` + Op string `json:"op"` + Content any `json:"content"` } type Response struct { - Reject bool `json:"reject"` - RejectReason string `json:"reject_reason"` - Unchange bool `json:"unchange"` - Content interface{} `json:"content"` + Reject bool `json:"reject"` + RejectReason string `json:"reject_reason"` + Unchange bool `json:"unchange"` + Content any `json:"content"` } type LoginContent struct { diff --git a/pkg/util/log/log.go b/pkg/util/log/log.go index e2125365..327d4ef6 100644 --- a/pkg/util/log/log.go +++ b/pkg/util/log/log.go @@ -67,27 +67,27 @@ func InitLogger(logPath string, levelStr string, maxDays int, disableLogColor bo Logger = Logger.WithOptions(options...) } -func Errorf(format string, v ...interface{}) { +func Errorf(format string, v ...any) { Logger.Errorf(format, v...) } -func Warnf(format string, v ...interface{}) { +func Warnf(format string, v ...any) { Logger.Warnf(format, v...) } -func Infof(format string, v ...interface{}) { +func Infof(format string, v ...any) { Logger.Infof(format, v...) } -func Debugf(format string, v ...interface{}) { +func Debugf(format string, v ...any) { Logger.Debugf(format, v...) } -func Tracef(format string, v ...interface{}) { +func Tracef(format string, v ...any) { Logger.Tracef(format, v...) } -func Logf(level log.Level, offset int, format string, v ...interface{}) { +func Logf(level log.Level, offset int, format string, v ...any) { Logger.Logf(level, offset, format, v...) } diff --git a/pkg/util/vhost/router.go b/pkg/util/vhost/router.go index 4df79aa7..315ff9e7 100644 --- a/pkg/util/vhost/router.go +++ b/pkg/util/vhost/router.go @@ -24,7 +24,7 @@ type Router struct { httpUser string // store any object here - payload interface{} + payload any } func NewRouters() *Routers { @@ -33,7 +33,7 @@ func NewRouters() *Routers { } } -func (r *Routers) Add(domain, location, httpUser string, payload interface{}) error { +func (r *Routers) Add(domain, location, httpUser string, payload any) error { domain = strings.ToLower(domain) r.mutex.Lock() diff --git a/pkg/util/xlog/xlog.go b/pkg/util/xlog/xlog.go index 184c0c1f..a1a58d42 100644 --- a/pkg/util/xlog/xlog.go +++ b/pkg/util/xlog/xlog.go @@ -94,22 +94,22 @@ func (l *Logger) Spawn() *Logger { return nl } -func (l *Logger) Errorf(format string, v ...interface{}) { +func (l *Logger) Errorf(format string, v ...any) { log.Logger.Errorf(l.prefixString+format, v...) } -func (l *Logger) Warnf(format string, v ...interface{}) { +func (l *Logger) Warnf(format string, v ...any) { log.Logger.Warnf(l.prefixString+format, v...) } -func (l *Logger) Infof(format string, v ...interface{}) { +func (l *Logger) Infof(format string, v ...any) { log.Logger.Infof(l.prefixString+format, v...) } -func (l *Logger) Debugf(format string, v ...interface{}) { +func (l *Logger) Debugf(format string, v ...any) { log.Logger.Debugf(l.prefixString+format, v...) } -func (l *Logger) Tracef(format string, v ...interface{}) { +func (l *Logger) Tracef(format string, v ...any) { log.Logger.Tracef(l.prefixString+format, v...) } diff --git a/server/dashboard_api.go b/server/dashboard_api.go index f34da4ef..a29433a6 100644 --- a/server/dashboard_api.go +++ b/server/dashboard_api.go @@ -196,15 +196,15 @@ func getConfByType(proxyType string) any { // Get proxy info. type ProxyStatsInfo struct { - Name string `json:"name"` - Conf interface{} `json:"conf"` - ClientVersion string `json:"clientVersion,omitempty"` - TodayTrafficIn int64 `json:"todayTrafficIn"` - TodayTrafficOut int64 `json:"todayTrafficOut"` - CurConns int64 `json:"curConns"` - LastStartTime string `json:"lastStartTime"` - LastCloseTime string `json:"lastCloseTime"` - Status string `json:"status"` + Name string `json:"name"` + Conf any `json:"conf"` + ClientVersion string `json:"clientVersion,omitempty"` + TodayTrafficIn int64 `json:"todayTrafficIn"` + TodayTrafficOut int64 `json:"todayTrafficOut"` + CurConns int64 `json:"curConns"` + LastStartTime string `json:"lastStartTime"` + LastCloseTime string `json:"lastCloseTime"` + Status string `json:"status"` } type GetProxyInfoResp struct { @@ -272,14 +272,14 @@ func (svr *Service) getProxyStatsByType(proxyType string) (proxyInfos []*ProxySt // Get proxy info by name. type GetProxyStatsResp struct { - Name string `json:"name"` - Conf interface{} `json:"conf"` - TodayTrafficIn int64 `json:"todayTrafficIn"` - TodayTrafficOut int64 `json:"todayTrafficOut"` - CurConns int64 `json:"curConns"` - LastStartTime string `json:"lastStartTime"` - LastCloseTime string `json:"lastCloseTime"` - Status string `json:"status"` + Name string `json:"name"` + Conf any `json:"conf"` + TodayTrafficIn int64 `json:"todayTrafficIn"` + TodayTrafficOut int64 `json:"todayTrafficOut"` + CurConns int64 `json:"curConns"` + LastStartTime string `json:"lastStartTime"` + LastCloseTime string `json:"lastCloseTime"` + Status string `json:"status"` } // /api/proxy/:type/:name diff --git a/test/e2e/framework/expect.go b/test/e2e/framework/expect.go index 3c357bb0..8e904489 100644 --- a/test/e2e/framework/expect.go +++ b/test/e2e/framework/expect.go @@ -5,75 +5,75 @@ import ( ) // ExpectEqual expects the specified two are the same, otherwise an exception raises -func ExpectEqual(actual interface{}, extra interface{}, explain ...interface{}) { +func ExpectEqual(actual any, extra any, explain ...any) { gomega.ExpectWithOffset(1, actual).To(gomega.Equal(extra), explain...) } // ExpectEqualValues expects the specified two are the same, it not strict about type -func ExpectEqualValues(actual interface{}, extra interface{}, explain ...interface{}) { +func ExpectEqualValues(actual any, extra any, explain ...any) { gomega.ExpectWithOffset(1, actual).To(gomega.BeEquivalentTo(extra), explain...) } -func ExpectEqualValuesWithOffset(offset int, actual interface{}, extra interface{}, explain ...interface{}) { +func ExpectEqualValuesWithOffset(offset int, actual any, extra any, explain ...any) { gomega.ExpectWithOffset(1+offset, actual).To(gomega.BeEquivalentTo(extra), explain...) } // ExpectNotEqual expects the specified two are not the same, otherwise an exception raises -func ExpectNotEqual(actual interface{}, extra interface{}, explain ...interface{}) { +func ExpectNotEqual(actual any, extra any, explain ...any) { gomega.ExpectWithOffset(1, actual).NotTo(gomega.Equal(extra), explain...) } // ExpectError expects an error happens, otherwise an exception raises -func ExpectError(err error, explain ...interface{}) { +func ExpectError(err error, explain ...any) { gomega.ExpectWithOffset(1, err).To(gomega.HaveOccurred(), explain...) } -func ExpectErrorWithOffset(offset int, err error, explain ...interface{}) { +func ExpectErrorWithOffset(offset int, err error, explain ...any) { gomega.ExpectWithOffset(1+offset, err).To(gomega.HaveOccurred(), explain...) } // ExpectNoError checks if "err" is set, and if so, fails assertion while logging the error. -func ExpectNoError(err error, explain ...interface{}) { +func ExpectNoError(err error, explain ...any) { ExpectNoErrorWithOffset(1, err, explain...) } // ExpectNoErrorWithOffset checks if "err" is set, and if so, fails assertion while logging the error at "offset" levels above its caller // (for example, for call chain f -> g -> ExpectNoErrorWithOffset(1, ...) error would be logged for "f"). -func ExpectNoErrorWithOffset(offset int, err error, explain ...interface{}) { +func ExpectNoErrorWithOffset(offset int, err error, explain ...any) { gomega.ExpectWithOffset(1+offset, err).NotTo(gomega.HaveOccurred(), explain...) } -func ExpectContainSubstring(actual, substr string, explain ...interface{}) { +func ExpectContainSubstring(actual, substr string, explain ...any) { gomega.ExpectWithOffset(1, actual).To(gomega.ContainSubstring(substr), explain...) } // ExpectConsistOf expects actual contains precisely the extra elements. The ordering of the elements does not matter. -func ExpectConsistOf(actual interface{}, extra interface{}, explain ...interface{}) { +func ExpectConsistOf(actual any, extra any, explain ...any) { gomega.ExpectWithOffset(1, actual).To(gomega.ConsistOf(extra), explain...) } -func ExpectContainElements(actual interface{}, extra interface{}, explain ...interface{}) { +func ExpectContainElements(actual any, extra any, explain ...any) { gomega.ExpectWithOffset(1, actual).To(gomega.ContainElements(extra), explain...) } -func ExpectNotContainElements(actual interface{}, extra interface{}, explain ...interface{}) { +func ExpectNotContainElements(actual any, extra any, explain ...any) { gomega.ExpectWithOffset(1, actual).NotTo(gomega.ContainElements(extra), explain...) } // ExpectHaveKey expects the actual map has the key in the keyset -func ExpectHaveKey(actual interface{}, key interface{}, explain ...interface{}) { +func ExpectHaveKey(actual any, key any, explain ...any) { gomega.ExpectWithOffset(1, actual).To(gomega.HaveKey(key), explain...) } // ExpectEmpty expects actual is empty -func ExpectEmpty(actual interface{}, explain ...interface{}) { +func ExpectEmpty(actual any, explain ...any) { gomega.ExpectWithOffset(1, actual).To(gomega.BeEmpty(), explain...) } -func ExpectTrue(actual interface{}, explain ...interface{}) { +func ExpectTrue(actual any, explain ...any) { gomega.ExpectWithOffset(1, actual).Should(gomega.BeTrue(), explain...) } -func ExpectTrueWithOffset(offset int, actual interface{}, explain ...interface{}) { +func ExpectTrueWithOffset(offset int, actual any, explain ...any) { gomega.ExpectWithOffset(1+offset, actual).Should(gomega.BeTrue(), explain...) } diff --git a/test/e2e/framework/log.go b/test/e2e/framework/log.go index 3cd99063..a466f68b 100644 --- a/test/e2e/framework/log.go +++ b/test/e2e/framework/log.go @@ -11,18 +11,18 @@ func nowStamp() string { return time.Now().Format(time.StampMilli) } -func log(level string, format string, args ...interface{}) { +func log(level string, format string, args ...any) { fmt.Fprintf(ginkgo.GinkgoWriter, nowStamp()+": "+level+": "+format+"\n", args...) } // Logf logs the info. -func Logf(format string, args ...interface{}) { +func Logf(format string, args ...any) { log("INFO", format, args...) } // Failf logs the fail info, including a stack trace starts with its direct caller // (for example, for call chain f -> g -> Failf("foo", ...) error would be logged for "g"). -func Failf(format string, args ...interface{}) { +func Failf(format string, args ...any) { msg := fmt.Sprintf(format, args...) skip := 1 ginkgo.Fail(msg, skip) diff --git a/test/e2e/framework/mockservers.go b/test/e2e/framework/mockservers.go index 2aea36da..6b6c2868 100644 --- a/test/e2e/framework/mockservers.go +++ b/test/e2e/framework/mockservers.go @@ -67,8 +67,8 @@ func (m *MockServers) Close() { os.Remove(m.udsEchoServer.BindAddr()) } -func (m *MockServers) GetTemplateParams() map[string]interface{} { - ret := make(map[string]interface{}) +func (m *MockServers) GetTemplateParams() map[string]any { + ret := make(map[string]any) ret[TCPEchoServerPort] = m.tcpEchoServer.BindPort() ret[UDPEchoServerPort] = m.udpEchoServer.BindPort() ret[UDSEchoServerAddr] = m.udsEchoServer.BindAddr() @@ -76,7 +76,7 @@ func (m *MockServers) GetTemplateParams() map[string]interface{} { return ret } -func (m *MockServers) GetParam(key string) interface{} { +func (m *MockServers) GetParam(key string) any { params := m.GetTemplateParams() if v, ok := params[key]; ok { return v diff --git a/test/e2e/framework/request.go b/test/e2e/framework/request.go index 1fc67fe8..f56fc973 100644 --- a/test/e2e/framework/request.go +++ b/test/e2e/framework/request.go @@ -42,7 +42,7 @@ type RequestExpect struct { f *Framework expectResp []byte expectError bool - explain []interface{} + explain []any } func NewRequestExpect(f *Framework) *RequestExpect { @@ -51,7 +51,7 @@ func NewRequestExpect(f *Framework) *RequestExpect { f: f, expectResp: []byte(consts.TestString), expectError: false, - explain: make([]interface{}, 0), + explain: make([]any, 0), } } @@ -94,7 +94,7 @@ func (e *RequestExpect) ExpectError(expectErr bool) *RequestExpect { return e } -func (e *RequestExpect) Explain(explain ...interface{}) *RequestExpect { +func (e *RequestExpect) Explain(explain ...any) *RequestExpect { e.explain = explain return e } From 6542dcd4ed6bf660a142db7634bcc296bd00f8c5 Mon Sep 17 00:00:00 2001 From: Andreas Deininger Date: Thu, 2 Jan 2025 04:33:56 +0100 Subject: [PATCH 03/11] Fix typos (#4615) --- README.md | 4 ++-- web/frpc/src/components/ClientConfigure.vue | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 16fd3c31..ab9ef37b 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ frp also offers a P2P connect mode. * [Client Plugins](#client-plugins) * [Server Manage Plugins](#server-manage-plugins) * [SSH Tunnel Gateway](#ssh-tunnel-gateway) -* [Releated Projects](#releated-projects) +* [Related Projects](#related-projects) * [Contributing](#contributing) * [Donation](#donation) * [GitHub Sponsors](#github-sponsors) @@ -1260,7 +1260,7 @@ frpc tcp --proxy_name "test-tcp" --local_ip 127.0.0.1 --local_port 8080 --remote Please refer to this [document](/doc/ssh_tunnel_gateway.md) for more information. -## Releated Projects +## Related Projects * [gofrp/plugin](https://github.com/gofrp/plugin) - A repository for frp plugins that contains a variety of plugins implemented based on the frp extension mechanism, meeting the customization needs of different scenarios. * [gofrp/tiny-frpc](https://github.com/gofrp/tiny-frpc) - A lightweight version of the frp client (around 3.5MB at minimum) implemented using the ssh protocol, supporting some of the most commonly used features, suitable for devices with limited resources. diff --git a/web/frpc/src/components/ClientConfigure.vue b/web/frpc/src/components/ClientConfigure.vue index d276437d..d22d0926 100644 --- a/web/frpc/src/components/ClientConfigure.vue +++ b/web/frpc/src/components/ClientConfigure.vue @@ -8,7 +8,7 @@ type="textarea" autosize v-model="textarea" - placeholder="frpc configrue file, can not be empty..." + placeholder="frpc configure file, can not be empty..." > From 27db6217ecda9236f5bc25c65824f1e723810751 Mon Sep 17 00:00:00 2001 From: fatedier Date: Mon, 6 Jan 2025 14:22:57 +0800 Subject: [PATCH 04/11] frpc: support metadatas and annotations in frpc proxy commands (#4623) --- Release.md | 4 +--- pkg/config/flags.go | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Release.md b/Release.md index d75b07cb..046e4d48 100644 --- a/Release.md +++ b/Release.md @@ -1,5 +1,3 @@ ### Features -* `tzdata` is installed by default in the container image, and the time zone can be set using the `TZ` environment variable. -* The `quic-bind-port` command line parameter is supported in frps, which specifies the port for accepting frpc connections using the QUIC protocol. -* The vhost HTTP proxy of frps supports the h2c protocol. +* Support metadatas and annotations in frpc proxy commands. diff --git a/pkg/config/flags.go b/pkg/config/flags.go index f9d9e3e4..6027b622 100644 --- a/pkg/config/flags.go +++ b/pkg/config/flags.go @@ -106,6 +106,8 @@ func registerProxyBaseConfigFlags(cmd *cobra.Command, c *v1.ProxyBaseConfig, opt } cmd.Flags().StringVarP(&c.Name, "proxy_name", "n", "", "proxy name") + cmd.Flags().StringToStringVarP(&c.Metadatas, "metadatas", "", nil, "metadata key-value pairs (e.g., key1=value1,key2=value2)") + cmd.Flags().StringToStringVarP(&c.Annotations, "annotations", "", nil, "annotation key-value pairs (e.g., key1=value1,key2=value2)") if !options.sshMode { cmd.Flags().StringVarP(&c.LocalIP, "local_ip", "i", "127.0.0.1", "local ip") From 450b8393bc5a06fd1182690b967e8deb0c20b606 Mon Sep 17 00:00:00 2001 From: "Jeb.Wang" Date: Thu, 16 Jan 2025 10:50:57 +0800 Subject: [PATCH 05/11] Fix goroutine leaks * Fix goroutine leaks --- server/proxy/xtcp.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/server/proxy/xtcp.go b/server/proxy/xtcp.go index f69d0790..1ccf331c 100644 --- a/server/proxy/xtcp.go +++ b/server/proxy/xtcp.go @@ -17,8 +17,7 @@ package proxy import ( "fmt" "reflect" - - "github.com/fatedier/golib/errors" + "sync" v1 "github.com/fatedier/frp/pkg/config/v1" "github.com/fatedier/frp/pkg/msg" @@ -32,7 +31,8 @@ type XTCPProxy struct { *BaseProxy cfg *v1.XTCPProxyConfig - closeCh chan struct{} + closeCh chan struct{} + closeOnce sync.Once } func NewXTCPProxy(baseProxy *BaseProxy) Proxy { @@ -43,6 +43,7 @@ func NewXTCPProxy(baseProxy *BaseProxy) Proxy { return &XTCPProxy{ BaseProxy: baseProxy, cfg: unwrapped, + closeCh: make(chan struct{}), } } @@ -87,9 +88,9 @@ func (pxy *XTCPProxy) Run() (remoteAddr string, err error) { } func (pxy *XTCPProxy) Close() { - pxy.BaseProxy.Close() - pxy.rc.NatHoleController.CloseClient(pxy.GetName()) - _ = errors.PanicToError(func() { + pxy.closeOnce.Do(func() { + pxy.BaseProxy.Close() + pxy.rc.NatHoleController.CloseClient(pxy.GetName()) close(pxy.closeCh) }) } From b8d3ace1139f5bcfee816d9844bba4780d052ba8 Mon Sep 17 00:00:00 2001 From: hansmi Date: Fri, 7 Feb 2025 04:33:11 +0100 Subject: [PATCH 06/11] Use text/template instead of html/template for config pre-processing (#4656) --- pkg/config/load.go | 2 +- pkg/config/load_test.go | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/pkg/config/load.go b/pkg/config/load.go index fa814fd0..fa394dda 100644 --- a/pkg/config/load.go +++ b/pkg/config/load.go @@ -18,10 +18,10 @@ import ( "bytes" "encoding/json" "fmt" - "html/template" "os" "path/filepath" "strings" + "text/template" toml "github.com/pelletier/go-toml/v2" "github.com/samber/lo" diff --git a/pkg/config/load_test.go b/pkg/config/load_test.go index b3f77800..980a332a 100644 --- a/pkg/config/load_test.go +++ b/pkg/config/load_test.go @@ -112,6 +112,29 @@ func TestLoadServerConfigStrictMode(t *testing.T) { } } +func TestRenderWithTemplate(t *testing.T) { + tests := []struct { + name string + content string + want string + }{ + {"toml", tomlServerContent, tomlServerContent}, + {"yaml", yamlServerContent, yamlServerContent}, + {"json", jsonServerContent, jsonServerContent}, + {"template numeric", `key = {{ 123 }}`, "key = 123"}, + {"template string", `key = {{ "xyz" }}`, "key = xyz"}, + {"template quote", `key = {{ printf "%q" "with space" }}`, `key = "with space"`}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + require := require.New(t) + got, err := RenderWithTemplate([]byte(test.content), nil) + require.NoError(err) + require.EqualValues(test.want, string(got)) + }) + } +} + func TestCustomStructStrictMode(t *testing.T) { require := require.New(t) From 8b86e1473ca8d180e03b57c2ca50daa6f2880a82 Mon Sep 17 00:00:00 2001 From: ubergeek77 Date: Tue, 11 Feb 2025 21:28:30 -0600 Subject: [PATCH 07/11] Fix ports not being released on Service.Close() (#4666) --- server/service.go | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/server/service.go b/server/service.go index 27c4110d..86d82a2a 100644 --- a/server/service.go +++ b/server/service.go @@ -77,7 +77,7 @@ type Service struct { muxer *mux.Mux // Accept connections from client - listener net.Listener + muxListener net.Listener // Accept connections using kcp kcpListener net.Listener @@ -125,6 +125,11 @@ type Service struct { ctx context.Context // call cancel to stop service cancel context.CancelFunc + + // Track listeners so they can be closed manually + vhostHTTPSListener net.Listener + tcpmuxHTTPConnectListener net.Listener + tcpListener net.Listener } func NewService(cfg *v1.ServerConfig) (*Service, error) { @@ -180,6 +185,8 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) { return nil, fmt.Errorf("create server listener error, %v", err) } + // Save listener so it can be closed in svr.Close() + svr.tcpmuxHTTPConnectListener = l svr.rc.TCPMuxHTTPConnectMuxer, err = tcpmux.NewHTTPConnectTCPMuxer(l, cfg.TCPMuxPassthrough, vhostReadWriteTimeout) if err != nil { return nil, fmt.Errorf("create vhost tcpMuxer error, %v", err) @@ -226,14 +233,16 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) { return nil, fmt.Errorf("create server listener error, %v", err) } + // Save listener so it can be closed in svr.Close() + svr.tcpListener = ln + svr.muxer = mux.NewMux(ln) svr.muxer.SetKeepAlive(time.Duration(cfg.Transport.TCPKeepAlive) * time.Second) go func() { _ = svr.muxer.Serve() }() ln = svr.muxer.DefaultListener() - - svr.listener = ln + svr.muxListener = ln log.Infof("frps tcp listen on %s", address) // Listen for accepting connections from client using kcp protocol. @@ -318,7 +327,8 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) { } log.Infof("https service listen on %s", address) } - + // Save listener so it can be closed in svr.Close() + svr.vhostHTTPSListener = l svr.rc.VhostHTTPSMuxer, err = vhost.NewHTTPSMuxer(l, vhostReadWriteTimeout) if err != nil { return nil, fmt.Errorf("create vhost httpsMuxer error, %v", err) @@ -374,11 +384,11 @@ func (svr *Service) Run(ctx context.Context) { go svr.sshTunnelGateway.Run() } - svr.HandleListener(svr.listener, false) + svr.HandleListener(svr.muxListener, false) <-svr.ctx.Done() // service context may not be canceled by svr.Close(), we should call it here to release resources - if svr.listener != nil { + if svr.muxListener != nil { svr.Close() } } @@ -400,9 +410,25 @@ func (svr *Service) Close() error { svr.tlsListener.Close() svr.tlsConfig = nil } - if svr.listener != nil { - svr.listener.Close() - svr.listener = nil + if svr.muxListener != nil { + svr.muxListener.Close() + svr.muxListener = nil + } + if svr.vhostHTTPSListener != nil { + svr.vhostHTTPSListener.Close() + svr.vhostHTTPSListener = nil + } + if svr.tcpmuxHTTPConnectListener != nil { + svr.tcpmuxHTTPConnectListener.Close() + svr.tcpmuxHTTPConnectListener = nil + } + if svr.webServer != nil { + svr.webServer.Close() + svr.webServer = nil + } + if svr.tcpListener != nil { + svr.tcpListener.Close() + svr.tcpListener = nil } svr.ctlManager.Close() if svr.cancel != nil { From e0dd947e6af0bc1116e1120ee422f5a8ab18869d Mon Sep 17 00:00:00 2001 From: fatedier Date: Wed, 12 Feb 2025 12:22:57 +0800 Subject: [PATCH 08/11] frps: release resources in service.Close() (#4667) --- go.mod | 2 +- go.sum | 4 +-- pkg/ssh/gateway.go | 4 +++ pkg/util/vhost/vhost.go | 4 +++ server/controller/resource.go | 10 ++++++++ server/service.go | 48 ++++++++++------------------------- 6 files changed, 35 insertions(+), 37 deletions(-) diff --git a/go.mod b/go.mod index 957fc7f4..5809def8 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22.0 require ( github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 github.com/coreos/go-oidc/v3 v3.10.0 - github.com/fatedier/golib v0.5.0 + github.com/fatedier/golib v0.5.1 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.0 diff --git a/go.sum b/go.sum index 4b771361..e1053561 100644 --- a/go.sum +++ b/go.sum @@ -21,8 +21,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs 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/fatedier/golib v0.5.0 h1:hNcH7hgfIFqVWbP+YojCCAj4eO94pPf4dEF8lmq2jWs= -github.com/fatedier/golib v0.5.0/go.mod h1:W6kIYkIFxHsTzbgqg5piCxIiDo4LzwgTY6R5W8l9NFQ= +github.com/fatedier/golib v0.5.1 h1:hcKAnaw5mdI/1KWRGejxR+i1Hn/NvbY5UsMKDr7o13M= +github.com/fatedier/golib v0.5.1/go.mod h1:W6kIYkIFxHsTzbgqg5piCxIiDo4LzwgTY6R5W8l9NFQ= github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d h1:ynk1ra0RUqDWQfvFi5KtMiSobkVQ3cNc0ODb8CfIETo= github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= diff --git a/pkg/ssh/gateway.go b/pkg/ssh/gateway.go index 5716f040..4d90f338 100644 --- a/pkg/ssh/gateway.go +++ b/pkg/ssh/gateway.go @@ -112,6 +112,10 @@ func (g *Gateway) Run() { } } +func (g *Gateway) Close() error { + return g.ln.Close() +} + func (g *Gateway) handleConn(conn net.Conn) { defer conn.Close() diff --git a/pkg/util/vhost/vhost.go b/pkg/util/vhost/vhost.go index e62a1caf..75b472b6 100644 --- a/pkg/util/vhost/vhost.go +++ b/pkg/util/vhost/vhost.go @@ -100,6 +100,10 @@ func (v *Muxer) SetRewriteHostFunc(f hostRewriteFunc) *Muxer { return v } +func (v *Muxer) Close() error { + return v.listener.Close() +} + type ChooseEndpointFunc func() (string, error) type CreateConnFunc func(remoteAddr string) (net.Conn, error) diff --git a/server/controller/resource.go b/server/controller/resource.go index 47236c9e..9d14b18d 100644 --- a/server/controller/resource.go +++ b/server/controller/resource.go @@ -59,3 +59,13 @@ type ResourceController struct { // All server manager plugin PluginManager *plugin.Manager } + +func (rc *ResourceController) Close() error { + if rc.VhostHTTPSMuxer != nil { + rc.VhostHTTPSMuxer.Close() + } + if rc.TCPMuxHTTPConnectMuxer != nil { + rc.TCPMuxHTTPConnectMuxer.Close() + } + return nil +} diff --git a/server/service.go b/server/service.go index 86d82a2a..d1dd68a1 100644 --- a/server/service.go +++ b/server/service.go @@ -77,7 +77,7 @@ type Service struct { muxer *mux.Mux // Accept connections from client - muxListener net.Listener + listener net.Listener // Accept connections using kcp kcpListener net.Listener @@ -125,11 +125,6 @@ type Service struct { ctx context.Context // call cancel to stop service cancel context.CancelFunc - - // Track listeners so they can be closed manually - vhostHTTPSListener net.Listener - tcpmuxHTTPConnectListener net.Listener - tcpListener net.Listener } func NewService(cfg *v1.ServerConfig) (*Service, error) { @@ -185,8 +180,6 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) { return nil, fmt.Errorf("create server listener error, %v", err) } - // Save listener so it can be closed in svr.Close() - svr.tcpmuxHTTPConnectListener = l svr.rc.TCPMuxHTTPConnectMuxer, err = tcpmux.NewHTTPConnectTCPMuxer(l, cfg.TCPMuxPassthrough, vhostReadWriteTimeout) if err != nil { return nil, fmt.Errorf("create vhost tcpMuxer error, %v", err) @@ -233,16 +226,14 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) { return nil, fmt.Errorf("create server listener error, %v", err) } - // Save listener so it can be closed in svr.Close() - svr.tcpListener = ln - svr.muxer = mux.NewMux(ln) svr.muxer.SetKeepAlive(time.Duration(cfg.Transport.TCPKeepAlive) * time.Second) go func() { _ = svr.muxer.Serve() }() ln = svr.muxer.DefaultListener() - svr.muxListener = ln + + svr.listener = ln log.Infof("frps tcp listen on %s", address) // Listen for accepting connections from client using kcp protocol. @@ -327,8 +318,7 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) { } log.Infof("https service listen on %s", address) } - // Save listener so it can be closed in svr.Close() - svr.vhostHTTPSListener = l + svr.rc.VhostHTTPSMuxer, err = vhost.NewHTTPSMuxer(l, vhostReadWriteTimeout) if err != nil { return nil, fmt.Errorf("create vhost httpsMuxer error, %v", err) @@ -384,11 +374,11 @@ func (svr *Service) Run(ctx context.Context) { go svr.sshTunnelGateway.Run() } - svr.HandleListener(svr.muxListener, false) + svr.HandleListener(svr.listener, false) <-svr.ctx.Done() // service context may not be canceled by svr.Close(), we should call it here to release resources - if svr.muxListener != nil { + if svr.listener != nil { svr.Close() } } @@ -396,40 +386,30 @@ func (svr *Service) Run(ctx context.Context) { func (svr *Service) Close() error { if svr.kcpListener != nil { svr.kcpListener.Close() - svr.kcpListener = nil } if svr.quicListener != nil { svr.quicListener.Close() - svr.quicListener = nil } if svr.websocketListener != nil { svr.websocketListener.Close() - svr.websocketListener = nil } if svr.tlsListener != nil { svr.tlsListener.Close() - svr.tlsConfig = nil } - if svr.muxListener != nil { - svr.muxListener.Close() - svr.muxListener = nil + if svr.sshTunnelListener != nil { + svr.sshTunnelListener.Close() } - if svr.vhostHTTPSListener != nil { - svr.vhostHTTPSListener.Close() - svr.vhostHTTPSListener = nil - } - if svr.tcpmuxHTTPConnectListener != nil { - svr.tcpmuxHTTPConnectListener.Close() - svr.tcpmuxHTTPConnectListener = nil + if svr.listener != nil { + svr.listener.Close() } if svr.webServer != nil { svr.webServer.Close() - svr.webServer = nil } - if svr.tcpListener != nil { - svr.tcpListener.Close() - svr.tcpListener = nil + if svr.sshTunnelGateway != nil { + svr.sshTunnelGateway.Close() } + svr.rc.Close() + svr.muxer.Close() svr.ctlManager.Close() if svr.cancel != nil { svr.cancel() From 1e8db667434f8f43cd60c16e9a6d694e9bd6e420 Mon Sep 17 00:00:00 2001 From: fatedier Date: Wed, 12 Feb 2025 12:30:37 +0800 Subject: [PATCH 09/11] update Release.md (#4668) --- Release.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Release.md b/Release.md index 046e4d48..11b788a6 100644 --- a/Release.md +++ b/Release.md @@ -1,3 +1,7 @@ ### Features * Support metadatas and annotations in frpc proxy commands. + +### Fixes + +* Properly release resources in service.Close() to prevent resource leaks when used as a library. From 9757a351c66c89c15812a20e2fbd4f152bdefe9f Mon Sep 17 00:00:00 2001 From: fatedier Date: Fri, 7 Mar 2025 16:56:08 +0800 Subject: [PATCH 10/11] fix golangci lint config (#4698) --- .circleci/config.yml | 2 +- .golangci.yml | 3 ++- go.mod | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3dff8a52..ede1f5fe 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,7 @@ version: 2 jobs: go-version-latest: docker: - - image: cimg/go:1.22-node + - image: cimg/go:1.23-node resource_class: large steps: - checkout diff --git a/.golangci.yml b/.golangci.yml index 5651ef5c..a45e4ba3 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -48,7 +48,8 @@ linters-settings: check-blank: false govet: # report about shadowed variables - check-shadowing: false + disable: + - shadow maligned: # print struct with more effective memory layout or not, false by default suggest-new: true diff --git a/go.mod b/go.mod index 5809def8..ecf20211 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/fatedier/frp -go 1.22.0 +go 1.23.0 require ( github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 From 773169e0c44070facd652c4b8b3fe6e6ff4d78f3 Mon Sep 17 00:00:00 2001 From: fatedier Date: Fri, 7 Mar 2025 17:22:51 +0800 Subject: [PATCH 11/11] update version (#4699) --- pkg/util/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/util/version/version.go b/pkg/util/version/version.go index 9b75f236..f56e1ec0 100644 --- a/pkg/util/version/version.go +++ b/pkg/util/version/version.go @@ -14,7 +14,7 @@ package version -var version = "0.61.1" +var version = "0.61.2" func Full() string { return version