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 }