github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/app/subscription/subscriptionmanager/manager.go (about)

     1  package subscriptionmanager
     2  
     3  import (
     4  	"archive/zip"
     5  	"bytes"
     6  	"context"
     7  	"time"
     8  
     9  	core "github.com/v2fly/v2ray-core/v5"
    10  	"github.com/v2fly/v2ray-core/v5/app/subscription"
    11  	"github.com/v2fly/v2ray-core/v5/app/subscription/entries"
    12  	"github.com/v2fly/v2ray-core/v5/app/subscription/entries/nonnative/nonnativeifce"
    13  	"github.com/v2fly/v2ray-core/v5/common"
    14  	"github.com/v2fly/v2ray-core/v5/common/task"
    15  	"github.com/v2fly/v2ray-core/v5/features/extension"
    16  )
    17  
    18  //go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
    19  
    20  type SubscriptionManagerImpl struct {
    21  	config *subscription.Config
    22  	ctx    context.Context
    23  
    24  	s         *core.Instance
    25  	converter *entries.ConverterRegistry
    26  
    27  	trackedSubscriptions map[string]*trackedSubscription
    28  
    29  	refreshTask *task.Periodic
    30  }
    31  
    32  func (s *SubscriptionManagerImpl) Type() interface{} {
    33  	return extension.SubscriptionManagerType()
    34  }
    35  
    36  func (s *SubscriptionManagerImpl) housekeeping() error {
    37  	for subscriptionName := range s.trackedSubscriptions {
    38  		if err := s.checkupSubscription(subscriptionName); err != nil {
    39  			newError("failed to checkup subscription: ", err).AtWarning().WriteToLog()
    40  		}
    41  	}
    42  	return nil
    43  }
    44  
    45  func (s *SubscriptionManagerImpl) Start() error {
    46  	if err := s.refreshTask.Start(); err != nil {
    47  		return err
    48  	}
    49  	return nil
    50  }
    51  
    52  func (s *SubscriptionManagerImpl) Close() error {
    53  	if err := s.refreshTask.Close(); err != nil {
    54  		return err
    55  	}
    56  	return nil
    57  }
    58  
    59  func (s *SubscriptionManagerImpl) init() error {
    60  	s.refreshTask = &task.Periodic{
    61  		Interval: time.Duration(60) * time.Second,
    62  		Execute:  s.housekeeping,
    63  	}
    64  	s.trackedSubscriptions = make(map[string]*trackedSubscription)
    65  	s.converter = entries.GetOverlayConverterRegistry()
    66  	if s.config.NonnativeConverterOverlay != nil {
    67  		zipReader, err := zip.NewReader(bytes.NewReader(s.config.NonnativeConverterOverlay), int64(len(s.config.NonnativeConverterOverlay)))
    68  		if err != nil {
    69  			return newError("failed to read nonnative converter overlay: ", err)
    70  		}
    71  		converter, err := nonnativeifce.NewNonNativeConverterConstructor(zipReader)
    72  		if err != nil {
    73  			return newError("failed to construct nonnative converter: ", err)
    74  		}
    75  		if err := s.converter.RegisterConverter("user_nonnative", converter); err != nil {
    76  			return newError("failed to register user nonnative converter: ", err)
    77  		}
    78  	}
    79  
    80  	for _, v := range s.config.Imports {
    81  		tracked, err := newTrackedSubscription(v)
    82  		if err != nil {
    83  			return newError("failed to init subscription ", v.Name, ": ", err)
    84  		}
    85  		s.trackedSubscriptions[v.Name] = tracked
    86  	}
    87  	return nil
    88  }
    89  
    90  func NewSubscriptionManager(ctx context.Context, config *subscription.Config) (*SubscriptionManagerImpl, error) {
    91  	instance := core.MustFromContext(ctx)
    92  	impl := &SubscriptionManagerImpl{ctx: ctx, s: instance, config: config}
    93  	if err := impl.init(); err != nil {
    94  		return nil, newError("failed to init subscription manager: ", err)
    95  	}
    96  	return impl, nil
    97  }
    98  
    99  func init() {
   100  	common.Must(common.RegisterConfig((*subscription.Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
   101  		return NewSubscriptionManager(ctx, config.(*subscription.Config))
   102  	}))
   103  }