github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/app/subscription/subscriptionmanager/subdocupdater.go (about) 1 package subscriptionmanager 2 3 import ( 4 "fmt" 5 "strings" 6 "time" 7 "unicode" 8 9 "golang.org/x/crypto/sha3" 10 11 "github.com/v2fly/v2ray-core/v5/app/subscription/containers" 12 "github.com/v2fly/v2ray-core/v5/app/subscription/documentfetcher" 13 "github.com/v2fly/v2ray-core/v5/app/subscription/specs" 14 ) 15 16 func (s *SubscriptionManagerImpl) updateSubscription(subscriptionName string) error { 17 var trackedSub *trackedSubscription 18 if trackedSubFound, found := s.trackedSubscriptions[subscriptionName]; !found { 19 return newError("not found") 20 } else { 21 trackedSub = trackedSubFound 22 } 23 importSource := trackedSub.importSource 24 docFetcher, err := documentfetcher.GetFetcher("http") 25 if err != nil { 26 return newError("failed to get fetcher: ", err) 27 } 28 if strings.HasPrefix(importSource.Url, "data:") { 29 docFetcher, err = documentfetcher.GetFetcher("dataurl") 30 if err != nil { 31 return newError("failed to get fetcher: ", err) 32 } 33 } 34 35 downloadedDocument, err := docFetcher.DownloadDocument(s.ctx, importSource) 36 if err != nil { 37 return newError("failed to download document: ", err) 38 } 39 40 trackedSub.originalDocument = downloadedDocument 41 42 container, err := containers.TryAllParsers(trackedSub.originalDocument, "") 43 if err != nil { 44 return newError("failed to parse document: ", err) 45 } 46 47 trackedSub.originalContainer = container 48 49 parsedDocument := &specs.SubscriptionDocument{} 50 parsedDocument.Metadata = container.Metadata 51 52 trackedSub.originalServerConfig = make(map[string]*originalServerConfig) 53 54 for _, server := range trackedSub.originalContainer.ServerSpecs { 55 documentHash := sha3.Sum256(server.Content) 56 serverConfigHashName := fmt.Sprintf("%x", documentHash) 57 parsed, err := s.converter.TryAllConverters(server.Content, "outbound", server.KindHint) 58 if err != nil { 59 trackedSub.originalServerConfig["!!!"+serverConfigHashName] = &originalServerConfig{data: server.Content} 60 continue 61 } 62 s.polyfillServerConfig(parsed, serverConfigHashName) 63 parsedDocument.Server = append(parsedDocument.Server, parsed) 64 trackedSub.originalServerConfig[parsed.Id] = &originalServerConfig{data: server.Content} 65 } 66 newError("new subscription document fetched and parsed from ", subscriptionName).AtInfo().WriteToLog() 67 if err := s.applySubscriptionTo(subscriptionName, parsedDocument); err != nil { 68 return newError("failed to apply subscription: ", err) 69 } 70 trackedSub.currentDocument = parsedDocument 71 trackedSub.currentDocumentExpireTime = time.Now().Add(time.Second * time.Duration(importSource.DefaultExpireSeconds)) 72 return nil 73 } 74 75 func (s *SubscriptionManagerImpl) polyfillServerConfig(document *specs.SubscriptionServerConfig, hash string) { 76 document.Id = hash 77 78 if document.Metadata == nil { 79 document.Metadata = make(map[string]string) 80 } 81 82 if id, ok := document.Metadata[ServerMetadataID]; !ok || id == "" { 83 document.Metadata[ServerMetadataID] = document.Id 84 } else { 85 document.Id = document.Metadata[ServerMetadataID] 86 } 87 88 if fqn, ok := document.Metadata[ServerMetadataFullyQualifiedName]; !ok || fqn == "" { 89 document.Metadata[ServerMetadataFullyQualifiedName] = hash 90 } 91 92 if tagName, ok := document.Metadata[ServerMetadataTagName]; !ok || tagName == "" { 93 document.Metadata[ServerMetadataTagName] = document.Metadata[ServerMetadataID] 94 } 95 document.Metadata[ServerMetadataTagName] = s.restrictTagName(document.Metadata[ServerMetadataTagName]) 96 } 97 98 func (s *SubscriptionManagerImpl) restrictTagName(tagName string) string { 99 newTagName := &strings.Builder{} 100 somethingRemoved := false 101 for _, c := range tagName { 102 if (unicode.IsLetter(c) || unicode.IsNumber(c)) && c < 128 { 103 newTagName.WriteRune(c) 104 } else { 105 somethingRemoved = true 106 } 107 } 108 newTagNameString := newTagName.String() 109 if len(newTagNameString) > 24 { 110 newTagNameString = newTagNameString[:15] 111 somethingRemoved = true 112 } 113 if somethingRemoved { 114 hashedTagName := sha3.Sum256([]byte(tagName)) 115 hashedTagNameString := fmt.Sprintf("%x", hashedTagName) 116 newTagNameString = newTagNameString + "_" + hashedTagNameString[:8] 117 } 118 return newTagNameString 119 }