package server import ( "encoding/json" "errors" "os" "sort" "sync" "time" "github.com/openp2p-cn/inp2p/pkg/protocol" ) type sdwanStore struct { mu sync.RWMutex path string cfg protocol.SDWANConfig multi map[int64]protocol.SDWANConfig } func newSDWANStore(path string) *sdwanStore { s := &sdwanStore{path: path, multi: make(map[int64]protocol.SDWANConfig)} _ = s.load() return s } func (s *sdwanStore) load() error { s.mu.Lock() defer s.mu.Unlock() b, err := os.ReadFile(s.path) if err != nil { if errors.Is(err, os.ErrNotExist) { return nil } return err } // try multi-tenant first var m map[int64]protocol.SDWANConfig if err := json.Unmarshal(b, &m); err == nil && len(m) > 0 { for k, v := range m { m[k] = normalizeSDWAN(v) } s.multi = m return nil } var c protocol.SDWANConfig if err := json.Unmarshal(b, &c); err != nil { return err } s.cfg = normalizeSDWAN(c) return nil } func (s *sdwanStore) save(cfg protocol.SDWANConfig) error { s.mu.Lock() defer s.mu.Unlock() cfg = normalizeSDWAN(cfg) cfg.UpdatedAt = time.Now().Unix() b, err := json.MarshalIndent(cfg, "", " ") if err != nil { return err } if err := os.WriteFile(s.path, b, 0644); err != nil { return err } s.cfg = cfg return nil } func (s *sdwanStore) saveTenant(tenantID int64, cfg protocol.SDWANConfig) error { s.mu.Lock() defer s.mu.Unlock() cfg = normalizeSDWAN(cfg) cfg.UpdatedAt = time.Now().Unix() if s.multi == nil { s.multi = make(map[int64]protocol.SDWANConfig) } s.multi[tenantID] = cfg b, err := json.MarshalIndent(s.multi, "", " ") if err != nil { return err } if err := os.WriteFile(s.path, b, 0644); err != nil { return err } return nil } func (s *sdwanStore) get() protocol.SDWANConfig { s.mu.RLock() defer s.mu.RUnlock() return s.cfg } func (s *sdwanStore) getTenant(tenantID int64) protocol.SDWANConfig { s.mu.RLock() defer s.mu.RUnlock() if s.multi == nil { return protocol.SDWANConfig{} } return s.multi[tenantID] } func normalizeSDWAN(c protocol.SDWANConfig) protocol.SDWANConfig { if c.Mode == "" { c.Mode = "hub" } if !c.Enabled { c.Enabled = true } // de-dup nodes by node name, keep last and sort for stable output m := make(map[string]string) for _, n := range c.Nodes { if n.Node == "" { continue } m[n.Node] = n.IP } c.Nodes = c.Nodes[:0] for node, ip := range m { c.Nodes = append(c.Nodes, protocol.SDWANNode{Node: node, IP: ip}) } sort.Slice(c.Nodes, func(i, j int) bool { return c.Nodes[i].Node < c.Nodes[j].Node }) return c }