// Copyright 2019 fatedier, fatedier@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package plugin import ( "context" "errors" "fmt" "github.com/fatedier/frp/utils/util" "github.com/fatedier/frp/utils/xlog" ) type Manager struct { loginPlugins []Plugin newProxyPlugins []Plugin pingPlugins []Plugin newWorkConnPlugins []Plugin } func NewManager() *Manager { return &Manager{ loginPlugins: make([]Plugin, 0), newProxyPlugins: make([]Plugin, 0), pingPlugins: make([]Plugin, 0), newWorkConnPlugins: make([]Plugin, 0), } } func (m *Manager) Register(p Plugin) { if p.IsSupport(OpLogin) { m.loginPlugins = append(m.loginPlugins, p) } if p.IsSupport(OpNewProxy) { m.newProxyPlugins = append(m.newProxyPlugins, p) } if p.IsSupport(OpPing) { m.pingPlugins = append(m.pingPlugins, p) } if p.IsSupport(OpNewWorkConn) { m.pingPlugins = append(m.pingPlugins, p) } } func (m *Manager) Login(content *LoginContent) (*LoginContent, error) { var ( res = &Response{ Reject: false, Unchange: true, } retContent interface{} err error ) reqid, _ := util.RandId() xl := xlog.New().AppendPrefix("reqid: " + reqid) ctx := xlog.NewContext(context.Background(), xl) ctx = NewReqidContext(ctx, reqid) for _, p := range m.loginPlugins { res, retContent, err = p.Handle(ctx, OpLogin, *content) if err != nil { xl.Warn("send Login request to plugin [%s] error: %v", p.Name(), err) return nil, errors.New("send Login request to plugin error") } if res.Reject { return nil, fmt.Errorf("%s", res.RejectReason) } if !res.Unchange { content = retContent.(*LoginContent) } } return content, nil } func (m *Manager) NewProxy(content *NewProxyContent) (*NewProxyContent, error) { var ( res = &Response{ Reject: false, Unchange: true, } retContent interface{} err error ) reqid, _ := util.RandId() xl := xlog.New().AppendPrefix("reqid: " + reqid) ctx := xlog.NewContext(context.Background(), xl) ctx = NewReqidContext(ctx, reqid) for _, p := range m.newProxyPlugins { res, retContent, err = p.Handle(ctx, OpNewProxy, *content) if err != nil { xl.Warn("send NewProxy request to plugin [%s] error: %v", p.Name(), err) return nil, errors.New("send NewProxy request to plugin error") } if res.Reject { return nil, fmt.Errorf("%s", res.RejectReason) } if !res.Unchange { content = retContent.(*NewProxyContent) } } return content, nil } func (m *Manager) Ping(content *PingContent) (*PingContent, error) { var ( res = &Response{ Reject: false, Unchange: true, } retContent interface{} err error ) reqid, _ := util.RandId() xl := xlog.New().AppendPrefix("reqid: " + reqid) ctx := xlog.NewContext(context.Background(), xl) ctx = NewReqidContext(ctx, reqid) for _, p := range m.pingPlugins { res, retContent, err = p.Handle(ctx, OpPing, *content) if err != nil { xl.Warn("send Ping request to plugin [%s] error: %v", p.Name(), err) return nil, errors.New("send Ping request to plugin error") } if res.Reject { return nil, fmt.Errorf("%s", res.RejectReason) } if !res.Unchange { content = retContent.(*PingContent) } } return content, nil } func (m *Manager) NewWorkConn(content *NewWorkConnContent) (*NewWorkConnContent, error) { var ( res = &Response{ Reject: false, Unchange: true, } retContent interface{} err error ) reqid, _ := util.RandId() xl := xlog.New().AppendPrefix("reqid: " + reqid) ctx := xlog.NewContext(context.Background(), xl) ctx = NewReqidContext(ctx, reqid) for _, p := range m.pingPlugins { res, retContent, err = p.Handle(ctx, OpPing, *content) if err != nil { xl.Warn("send NewWorkConn request to plugin [%s] error: %v", p.Name(), err) return nil, errors.New("send NewWorkConn request to plugin error") } if res.Reject { return nil, fmt.Errorf("%s", res.RejectReason) } if !res.Unchange { content = retContent.(*NewWorkConnContent) } } return content, nil }