|
@@ -1077,20 +1077,73 @@ func (s *SubService) ResolveRequest(c *gin.Context) (scheme string, host string,
|
|
|
return
|
|
|
}
|
|
|
|
|
|
-// BuildURLs constructs absolute subscription and json URLs.
|
|
|
-// BuildURLs constructs subscription and JSON subscription URLs for a given subscription ID.
|
|
|
+// BuildURLs constructs absolute subscription and JSON subscription URLs for a given subscription ID.
|
|
|
+// It prioritizes configured URIs, then individual settings, and finally falls back to request-derived components.
|
|
|
func (s *SubService) BuildURLs(scheme, hostWithPort, subPath, subJsonPath, subId string) (subURL, subJsonURL string) {
|
|
|
- if strings.HasSuffix(subPath, "/") {
|
|
|
- subURL = scheme + "://" + hostWithPort + subPath + subId
|
|
|
- } else {
|
|
|
- subURL = scheme + "://" + hostWithPort + strings.TrimRight(subPath, "/") + "/" + subId
|
|
|
+ // Input validation
|
|
|
+ if subId == "" {
|
|
|
+ return "", ""
|
|
|
}
|
|
|
- if strings.HasSuffix(subJsonPath, "/") {
|
|
|
- subJsonURL = scheme + "://" + hostWithPort + subJsonPath + subId
|
|
|
- } else {
|
|
|
- subJsonURL = scheme + "://" + hostWithPort + strings.TrimRight(subJsonPath, "/") + "/" + subId
|
|
|
+
|
|
|
+ // Get configured URIs first (highest priority)
|
|
|
+ configuredSubURI, _ := s.settingService.GetSubURI()
|
|
|
+ configuredSubJsonURI, _ := s.settingService.GetSubJsonURI()
|
|
|
+
|
|
|
+ // Determine base scheme and host (cached to avoid duplicate calls)
|
|
|
+ var baseScheme, baseHostWithPort string
|
|
|
+ if configuredSubURI == "" || configuredSubJsonURI == "" {
|
|
|
+ baseScheme, baseHostWithPort = s.getBaseSchemeAndHost(scheme, hostWithPort)
|
|
|
}
|
|
|
- return
|
|
|
+
|
|
|
+ // Build subscription URL
|
|
|
+ subURL = s.buildSingleURL(configuredSubURI, baseScheme, baseHostWithPort, subPath, subId)
|
|
|
+
|
|
|
+ // Build JSON subscription URL
|
|
|
+ subJsonURL = s.buildSingleURL(configuredSubJsonURI, baseScheme, baseHostWithPort, subJsonPath, subId)
|
|
|
+
|
|
|
+ return subURL, subJsonURL
|
|
|
+}
|
|
|
+
|
|
|
+// getBaseSchemeAndHost determines the base scheme and host from settings or falls back to request values
|
|
|
+func (s *SubService) getBaseSchemeAndHost(requestScheme, requestHostWithPort string) (string, string) {
|
|
|
+ subDomain, err := s.settingService.GetSubDomain()
|
|
|
+ if err != nil || subDomain == "" {
|
|
|
+ return requestScheme, requestHostWithPort
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get port and TLS settings
|
|
|
+ subPort, _ := s.settingService.GetSubPort()
|
|
|
+ subKeyFile, _ := s.settingService.GetSubKeyFile()
|
|
|
+ subCertFile, _ := s.settingService.GetSubCertFile()
|
|
|
+
|
|
|
+ // Determine scheme from TLS configuration
|
|
|
+ scheme := "http"
|
|
|
+ if subKeyFile != "" && subCertFile != "" {
|
|
|
+ scheme = "https"
|
|
|
+ }
|
|
|
+
|
|
|
+ // Build host:port, always include port for clarity
|
|
|
+ hostWithPort := fmt.Sprintf("%s:%d", subDomain, subPort)
|
|
|
+
|
|
|
+ return scheme, hostWithPort
|
|
|
+}
|
|
|
+
|
|
|
+// buildSingleURL constructs a single URL using configured URI or base components
|
|
|
+func (s *SubService) buildSingleURL(configuredURI, baseScheme, baseHostWithPort, basePath, subId string) string {
|
|
|
+ if configuredURI != "" {
|
|
|
+ return s.joinPathWithID(configuredURI, subId)
|
|
|
+ }
|
|
|
+
|
|
|
+ baseURL := fmt.Sprintf("%s://%s", baseScheme, baseHostWithPort)
|
|
|
+ return s.joinPathWithID(baseURL+basePath, subId)
|
|
|
+}
|
|
|
+
|
|
|
+// joinPathWithID safely joins a base path with a subscription ID
|
|
|
+func (s *SubService) joinPathWithID(basePath, subId string) string {
|
|
|
+ if strings.HasSuffix(basePath, "/") {
|
|
|
+ return basePath + subId
|
|
|
+ }
|
|
|
+ return basePath + "/" + subId
|
|
|
}
|
|
|
|
|
|
// BuildPageData parses header and prepares the template view model.
|
|
@@ -1103,10 +1156,7 @@ func (s *SubService) BuildPageData(subId string, hostHeader string, traffic xray
|
|
|
remained := ""
|
|
|
if traffic.Total > 0 {
|
|
|
total = common.FormatTraffic(traffic.Total)
|
|
|
- left := traffic.Total - (traffic.Up + traffic.Down)
|
|
|
- if left < 0 {
|
|
|
- left = 0
|
|
|
- }
|
|
|
+ left := max(traffic.Total-(traffic.Up+traffic.Down), 0)
|
|
|
remained = common.FormatTraffic(left)
|
|
|
}
|
|
|
|