mirror of
https://github.com/koho/frpmgr.git
synced 2025-10-20 16:03:47 +08:00
126 lines
3.2 KiB
Go
126 lines
3.2 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
_ "github.com/fatedier/frp/assets/frpc"
|
|
"github.com/fatedier/frp/client"
|
|
"github.com/fatedier/frp/client/proxy"
|
|
"github.com/fatedier/frp/pkg/config"
|
|
"github.com/fatedier/frp/pkg/config/v1"
|
|
"github.com/fatedier/frp/pkg/util/log"
|
|
glog "github.com/fatedier/golib/log"
|
|
|
|
"github.com/koho/frpmgr/pkg/consts"
|
|
)
|
|
|
|
type FrpClientService struct {
|
|
svr *client.Service
|
|
file string
|
|
cfg *v1.ClientCommonConfig
|
|
done chan struct{}
|
|
statusExporter client.StatusExporter
|
|
logger *glog.RotateFileWriter
|
|
}
|
|
|
|
func NewFrpClientService(cfgFile string) (*FrpClientService, error) {
|
|
cfg, pxyCfgs, visitorCfgs, _, err := config.LoadClientConfig(cfgFile, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
svr, err := client.NewService(client.ServiceOptions{
|
|
Common: cfg,
|
|
ProxyCfgs: pxyCfgs,
|
|
VisitorCfgs: visitorCfgs,
|
|
ConfigFilePath: cfgFile,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
logger := initLogger(cfg.Log.To, cfg.Log.Level, int(cfg.Log.MaxDays))
|
|
return &FrpClientService{
|
|
svr: svr,
|
|
file: cfgFile,
|
|
cfg: cfg,
|
|
done: make(chan struct{}),
|
|
statusExporter: svr.StatusExporter(),
|
|
logger: logger,
|
|
}, nil
|
|
}
|
|
|
|
// Run starts frp client service in blocking mode.
|
|
func (s *FrpClientService) Run() {
|
|
defer close(s.done)
|
|
if s.file != "" {
|
|
log.Infof("start frpc service for config file [%s]", s.file)
|
|
defer log.Infof("frpc service for config file [%s] stopped", s.file)
|
|
}
|
|
|
|
// There's no guarantee that this function will return after a close call.
|
|
// So we can't wait for the Run function to finish.
|
|
if err := s.svr.Run(context.Background()); err != nil {
|
|
log.Errorf("run service error: %v", err)
|
|
}
|
|
}
|
|
|
|
// Stop closes all frp connections.
|
|
func (s *FrpClientService) Stop(wait bool) {
|
|
// Close client service.
|
|
if wait {
|
|
s.svr.GracefulClose(500 * time.Millisecond)
|
|
} else {
|
|
s.svr.Close()
|
|
}
|
|
}
|
|
|
|
// Reload creates or updates or removes proxies of frpc.
|
|
func (s *FrpClientService) Reload() error {
|
|
_, pxyCfgs, visitorCfgs, _, err := config.LoadClientConfig(s.file, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return s.svr.UpdateAllConfigurer(pxyCfgs, visitorCfgs)
|
|
}
|
|
|
|
func (s *FrpClientService) Done() <-chan struct{} {
|
|
return s.done
|
|
}
|
|
|
|
func (s *FrpClientService) GetProxyStatus(name string) (status *proxy.WorkingStatus, ok bool) {
|
|
proxyName := name
|
|
if s.cfg.User != "" {
|
|
proxyName = s.cfg.User + "." + name
|
|
}
|
|
status, ok = s.statusExporter.GetProxyStatus(proxyName)
|
|
if ok {
|
|
status.Name = name
|
|
if status.Err == "" {
|
|
if status.Type == consts.ProxyTypeTCP || status.Type == consts.ProxyTypeUDP {
|
|
status.RemoteAddr = s.cfg.ServerAddr + status.RemoteAddr
|
|
}
|
|
} else {
|
|
status.RemoteAddr = ""
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func initLogger(logPath string, levelStr string, maxDays int) *glog.RotateFileWriter {
|
|
var options []glog.Option
|
|
writer := glog.NewRotateFileWriter(glog.RotateFileConfig{
|
|
FileName: logPath,
|
|
Mode: glog.RotateFileModeDaily,
|
|
MaxDays: maxDays,
|
|
})
|
|
writer.Init()
|
|
options = append(options, glog.WithOutput(writer))
|
|
level, err := glog.ParseLevel(levelStr)
|
|
if err != nil {
|
|
level = glog.InfoLevel
|
|
}
|
|
options = append(options, glog.WithLevel(level))
|
|
log.Logger = log.Logger.WithOptions(options...)
|
|
return writer
|
|
}
|