github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/components/config/setting.go (about) 1 package config 2 3 import ( 4 "context" 5 "fmt" 6 "runtime" 7 "runtime/debug" 8 "sync" 9 10 "github.com/Asutorufa/yuhaiin/internal/version" 11 "github.com/Asutorufa/yuhaiin/pkg/protos/config" 12 gc "github.com/Asutorufa/yuhaiin/pkg/protos/config/grpc" 13 "github.com/Asutorufa/yuhaiin/pkg/protos/config/listener" 14 "github.com/Asutorufa/yuhaiin/pkg/utils/jsondb" 15 "google.golang.org/protobuf/proto" 16 "google.golang.org/protobuf/types/known/emptypb" 17 ) 18 19 type Setting interface { 20 gc.ConfigServiceServer 21 AddObserver(Observer) 22 } 23 24 type Observer interface { 25 Update(*config.Setting) 26 } 27 28 type ObserverFunc func(*config.Setting) 29 30 func (o ObserverFunc) Update(s *config.Setting) { o(s) } 31 32 type setting struct { 33 gc.UnimplementedConfigServiceServer 34 35 db *jsondb.DB[*config.Setting] 36 37 os []Observer 38 39 mu sync.RWMutex 40 } 41 42 func NewConfig(path string) Setting { 43 return &setting{db: jsondb.Open(path, defaultSetting(path))} 44 } 45 46 func (c *setting) Info(context.Context, *emptypb.Empty) (*config.Info, error) { return Info(), nil } 47 48 func Info() *config.Info { 49 var build []string 50 info, ok := debug.ReadBuildInfo() 51 if ok { 52 for _, v := range info.Settings { 53 build = append(build, fmt.Sprintf("%s=%s", v.Key, v.Value)) 54 } 55 } 56 57 return &config.Info{ 58 Version: version.Version, 59 Commit: version.GitCommit, 60 BuildTime: version.BuildTime, 61 GoVersion: runtime.Version(), 62 Platform: runtime.GOOS + "/" + runtime.GOARCH, 63 Compiler: runtime.Compiler, 64 Arch: runtime.GOARCH, 65 Os: runtime.GOOS, 66 Build: build, 67 } 68 } 69 70 func (c *setting) Load(context.Context, *emptypb.Empty) (*config.Setting, error) { 71 c.mu.RLock() 72 defer c.mu.RUnlock() 73 return c.db.Data, nil 74 } 75 76 func (c *setting) Save(_ context.Context, s *config.Setting) (*emptypb.Empty, error) { 77 c.mu.Lock() 78 defer c.mu.Unlock() 79 80 c.db.Data = proto.Clone(s).(*config.Setting) 81 for k, v := range c.db.Data.Server.Servers { 82 key := "server-" + k 83 _, ok := c.db.Data.Server.Inbounds[key] 84 if ok { 85 continue 86 } 87 88 if c.db.Data.Server.Inbounds == nil { 89 c.db.Data.Server.Inbounds = make(map[string]*listener.Inbound) 90 } 91 92 c.db.Data.Server.Inbounds[key] = v.ToInbound() 93 delete(c.db.Data.Server.Servers, k) 94 } 95 96 if err := c.db.Save(); err != nil { 97 return &emptypb.Empty{}, fmt.Errorf("save settings failed: %w", err) 98 } 99 100 wg := sync.WaitGroup{} 101 for i := range c.os { 102 wg.Add(1) 103 go func(o Observer) { 104 defer wg.Done() 105 o.Update(proto.Clone(c.db.Data).(*config.Setting)) 106 }(c.os[i]) 107 } 108 wg.Wait() 109 110 return &emptypb.Empty{}, nil 111 } 112 113 func (c *setting) AddObserver(o Observer) { 114 if o == nil { 115 return 116 } 117 c.mu.Lock() 118 defer c.mu.Unlock() 119 120 c.os = append(c.os, o) 121 o.Update(c.db.Data) 122 }