Browse Source

ssm-api: Fix save cache

世界 1 month ago
parent
commit
5841d410a1
2 changed files with 57 additions and 10 deletions
  1. 19 2
      service/ssmapi/cache.go
  2. 38 8
      service/ssmapi/server.go

+ 19 - 2
service/ssmapi/cache.go

@@ -49,6 +49,9 @@ func (s *Service) loadCache() error {
 		os.RemoveAll(basePath)
 		return err
 	}
+	s.cacheMutex.Lock()
+	s.lastSavedCache = cacheBinary
+	s.cacheMutex.Unlock()
 	return nil
 }
 
@@ -56,16 +59,30 @@ func (s *Service) saveCache() error {
 	if s.cachePath == "" {
 		return nil
 	}
+	cacheBinary, err := s.encodeCache()
+	if err != nil {
+		return err
+	}
+	s.cacheMutex.Lock()
+	defer s.cacheMutex.Unlock()
+	if bytes.Equal(s.lastSavedCache, cacheBinary) {
+		return nil
+	}
+	return s.writeCache(cacheBinary)
+}
+
+func (s *Service) writeCache(cacheBinary []byte) error {
 	basePath := filemanager.BasePath(s.ctx, s.cachePath)
 	err := os.MkdirAll(filepath.Dir(basePath), 0o777)
 	if err != nil {
 		return err
 	}
-	cacheBinary, err := s.encodeCache()
+	err = os.WriteFile(basePath, cacheBinary, 0o644)
 	if err != nil {
 		return err
 	}
-	return os.WriteFile(s.cachePath, cacheBinary, 0o644)
+	s.lastSavedCache = cacheBinary
+	return nil
 }
 
 func (s *Service) decodeCache(cacheBinary []byte) error {

+ 38 - 8
service/ssmapi/server.go

@@ -4,6 +4,8 @@ import (
 	"context"
 	"errors"
 	"net/http"
+	"sync"
+	"time"
 
 	"github.com/sagernet/sing-box/adapter"
 	boxService "github.com/sagernet/sing-box/adapter/service"
@@ -28,21 +30,27 @@ func RegisterService(registry *boxService.Registry) {
 
 type Service struct {
 	boxService.Adapter
-	ctx        context.Context
-	logger     log.ContextLogger
-	listener   *listener.Listener
-	tlsConfig  tls.ServerConfig
-	httpServer *http.Server
-	traffics   map[string]*TrafficManager
-	users      map[string]*UserManager
-	cachePath  string
+	ctx            context.Context
+	cancel         context.CancelFunc
+	logger         log.ContextLogger
+	listener       *listener.Listener
+	tlsConfig      tls.ServerConfig
+	httpServer     *http.Server
+	traffics       map[string]*TrafficManager
+	users          map[string]*UserManager
+	cachePath      string
+	saveTicker     *time.Ticker
+	lastSavedCache []byte
+	cacheMutex     sync.Mutex
 }
 
 func NewService(ctx context.Context, logger log.ContextLogger, tag string, options option.SSMAPIServiceOptions) (adapter.Service, error) {
+	ctx, cancel := context.WithCancel(ctx)
 	chiRouter := chi.NewRouter()
 	s := &Service{
 		Adapter: boxService.NewAdapter(C.TypeSSMAPI, tag),
 		ctx:     ctx,
+		cancel:  cancel,
 		logger:  logger,
 		listener: listener.New(listener.Options{
 			Context: ctx,
@@ -95,6 +103,8 @@ func (s *Service) Start(stage adapter.StartStage) error {
 	if err != nil {
 		s.logger.Error(E.Cause(err, "load cache"))
 	}
+	s.saveTicker = time.NewTicker(1 * time.Minute)
+	go s.loopSaveCache()
 	if s.tlsConfig != nil {
 		err = s.tlsConfig.Start()
 		if err != nil {
@@ -120,7 +130,27 @@ func (s *Service) Start(stage adapter.StartStage) error {
 	return nil
 }
 
+func (s *Service) loopSaveCache() {
+	for {
+		select {
+		case <-s.ctx.Done():
+			return
+		case <-s.saveTicker.C:
+			err := s.saveCache()
+			if err != nil {
+				s.logger.Error(E.Cause(err, "save cache"))
+			}
+		}
+	}
+}
+
 func (s *Service) Close() error {
+	if s.cancel != nil {
+		s.cancel()
+	}
+	if s.saveTicker != nil {
+		s.saveTicker.Stop()
+	}
 	err := s.saveCache()
 	if err != nil {
 		s.logger.Error(E.Cause(err, "save cache"))