settings trim: remove dead settings, upstream remnants, JSON/Clash subscriptions
Per SETTINGS-AUDIT (all three tiers approved 2026-10-23): Dead settings: - panelOutbound, ipLimitAllowlist (+ orphan parser job), outboundDownThreshold - tg fake events outbound.down/outbound.up/xray.crash (no publisher in lite) - phantom routing sub-tabs (Happ/Clash/Incy) and subJsonRules direct-rules tab (no backend keys); subHideSettings moved to the subscription info tab first Upstream remnants: - ldap* / smtp* model+schema keys, EmailNotifications orphan component - twoFactorEnable/twoFactorToken + login-page probe (no backend handler) - externalTrafficInform* Newly approved removals: - JSON subscription family (producer, routes, UA auto-detect, mux/finalmask/ observatory) and Clash subscription family (producer, routes, UA detect) - SubBalancer (table, service, controller, settings tab) - subThemeDir (subscription page falls back to the built-in template) - datepicker jalalian option (gregorian only; Persian picker removed) JSON/Clash endpoints now 404; link-format output pinned by regression tests. Guarded keys untouched: webListen/webPort/webBasePath/certs, tg* chain, expireDiff/trafficDiff/tgBotProxy, subHideSettings, pageSize/tgLang.
This commit is contained in:
@@ -137,23 +137,20 @@ func (t *Tgbot) SubmitAddClient() (bool, error) {
|
||||
})
|
||||
}
|
||||
|
||||
// buildSubscriptionURLs builds the HTML sub page URL and JSON subscription URL for a client email
|
||||
func (t *Tgbot) buildSubscriptionURLs(email string) (string, string, error) {
|
||||
// buildSubscriptionURLs builds the subscription page URL for a client email
|
||||
func (t *Tgbot) buildSubscriptionURLs(email string) (string, error) {
|
||||
// Resolve subId from client email
|
||||
traffic, client, err := t.inboundService.GetClientByEmail(email)
|
||||
_ = traffic
|
||||
if err != nil || client == nil {
|
||||
return "", "", errors.New("client not found")
|
||||
return "", errors.New("client not found")
|
||||
}
|
||||
|
||||
// Gather settings to construct absolute URLs
|
||||
subURI, _ := t.settingService.GetSubURI()
|
||||
subJsonURI, _ := t.settingService.GetSubJsonURI()
|
||||
subDomain, _ := t.settingService.GetSubDomain()
|
||||
subPort, _ := t.settingService.GetSubPort()
|
||||
subPath, _ := t.settingService.GetSubPath()
|
||||
subJsonPath, _ := t.settingService.GetSubJsonPath()
|
||||
subJsonEnable, _ := t.settingService.GetSubJsonEnable()
|
||||
subKeyFile, _ := t.settingService.GetSubKeyFile()
|
||||
subCertFile, _ := t.settingService.GetSubCertFile()
|
||||
|
||||
@@ -189,17 +186,10 @@ func (t *Tgbot) buildSubscriptionURLs(email string) (string, string, error) {
|
||||
if !strings.HasSuffix(subPath, "/") {
|
||||
subPath = subPath + "/"
|
||||
}
|
||||
if !strings.HasPrefix(subJsonPath, "/") {
|
||||
subJsonPath = "/" + subJsonPath
|
||||
}
|
||||
if !strings.HasSuffix(subJsonPath, "/") {
|
||||
subJsonPath = subJsonPath + "/"
|
||||
}
|
||||
|
||||
var subURL string
|
||||
var subJsonURL string
|
||||
|
||||
// If pre-configured URIs are available, use them directly
|
||||
// If a pre-configured URI is available, use it directly
|
||||
if subURI != "" {
|
||||
if !strings.HasSuffix(subURI, "/") {
|
||||
subURI = subURI + "/"
|
||||
@@ -209,32 +199,17 @@ func (t *Tgbot) buildSubscriptionURLs(email string) (string, string, error) {
|
||||
subURL = fmt.Sprintf("%s://%s%s%s", scheme, host, subPath, client.SubID)
|
||||
}
|
||||
|
||||
if subJsonURI != "" {
|
||||
if !strings.HasSuffix(subJsonURI, "/") {
|
||||
subJsonURI = subJsonURI + "/"
|
||||
}
|
||||
subJsonURL = fmt.Sprintf("%s%s", subJsonURI, client.SubID)
|
||||
} else {
|
||||
subJsonURL = fmt.Sprintf("%s://%s%s%s", scheme, host, subJsonPath, client.SubID)
|
||||
}
|
||||
|
||||
if !subJsonEnable {
|
||||
subJsonURL = ""
|
||||
}
|
||||
return subURL, subJsonURL, nil
|
||||
return subURL, nil
|
||||
}
|
||||
|
||||
// sendClientSubLinks sends the subscription links for the client to the chat.
|
||||
func (t *Tgbot) sendClientSubLinks(chatId int64, email string) {
|
||||
subURL, subJsonURL, err := t.buildSubscriptionURLs(email)
|
||||
subURL, err := t.buildSubscriptionURLs(email)
|
||||
if err != nil {
|
||||
t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation")+"\r\n"+err.Error())
|
||||
return
|
||||
}
|
||||
msg := "Subscription URL:\r\n<code>" + subURL + "</code>"
|
||||
if subJsonURL != "" {
|
||||
msg += "\r\n\r\nJSON URL:\r\n<code>" + subJsonURL + "</code>"
|
||||
}
|
||||
inlineKeyboard := tu.InlineKeyboard(
|
||||
tu.InlineKeyboardRow(
|
||||
tu.InlineKeyboardButton(t.I18nBot("subscription.individualLinks")).WithCallbackData(t.encodeQuery("client_individual_links "+email)),
|
||||
@@ -249,7 +224,7 @@ func (t *Tgbot) sendClientSubLinks(chatId int64, email string) {
|
||||
// sendClientIndividualLinks fetches the subscription content (individual links) and sends it to the user
|
||||
func (t *Tgbot) sendClientIndividualLinks(chatId int64, email string) {
|
||||
// Build the HTML sub page URL; we'll call it with header Accept to get raw content
|
||||
subURL, _, err := t.buildSubscriptionURLs(email)
|
||||
subURL, err := t.buildSubscriptionURLs(email)
|
||||
if err != nil {
|
||||
t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation")+"\r\n"+err.Error())
|
||||
return
|
||||
@@ -329,9 +304,9 @@ func (t *Tgbot) sendClientIndividualLinks(chatId int64, email string) {
|
||||
}
|
||||
}
|
||||
|
||||
// sendClientQRLinks generates QR images for subscription URL, JSON URL, and a few individual links, then sends them
|
||||
// sendClientQRLinks generates QR images for the subscription URL and a few individual links, then sends them
|
||||
func (t *Tgbot) sendClientQRLinks(chatId int64, email string) {
|
||||
subURL, subJsonURL, err := t.buildSubscriptionURLs(email)
|
||||
subURL, err := t.buildSubscriptionURLs(email)
|
||||
if err != nil {
|
||||
t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation")+"\r\n"+err.Error())
|
||||
return
|
||||
@@ -359,19 +334,6 @@ func (t *Tgbot) sendClientQRLinks(chatId int64, email string) {
|
||||
t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation")+"\r\n"+err.Error())
|
||||
}
|
||||
|
||||
// Send JSON URL QR (filename: subjson.png) when available
|
||||
if subJsonURL != "" {
|
||||
if png, err := createQR(subJsonURL, 320); err == nil {
|
||||
document := tu.Document(
|
||||
tu.ID(chatId),
|
||||
tu.FileFromBytes(png, "subjson.png"),
|
||||
)
|
||||
_, _ = bot.SendDocument(context.Background(), document)
|
||||
} else {
|
||||
t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.errorOperation")+"\r\n"+err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Also generate a few individual links' QRs (first up to 5)
|
||||
subPageURL := subURL
|
||||
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, subPageURL, nil)
|
||||
|
||||
@@ -62,41 +62,6 @@ func (t *Tgbot) formatEventMessage(e eventbus.Event) string {
|
||||
header := fmt.Sprintf("<b>📡 %s</b>\n", host)
|
||||
|
||||
switch e.Type {
|
||||
case eventbus.EventOutboundDown:
|
||||
msg := header + t.I18nBot("tgbot.messages.eventOutboundDown",
|
||||
"Tag=="+e.Source)
|
||||
if data, ok := e.Data.(*eventbus.OutboundHealthData); ok {
|
||||
if data.Error != "" {
|
||||
msg += "\n" + t.I18nBot("tgbot.messages.eventErrorDetail",
|
||||
"Error=="+data.Error)
|
||||
}
|
||||
if data.Delay > 0 {
|
||||
msg += "\n" + t.I18nBot("tgbot.messages.eventDelayDetail",
|
||||
"Delay=="+fmt.Sprintf("%d", data.Delay))
|
||||
}
|
||||
}
|
||||
return msg
|
||||
|
||||
case eventbus.EventOutboundUp:
|
||||
msg := header + t.I18nBot("tgbot.messages.eventOutboundUp",
|
||||
"Tag=="+e.Source)
|
||||
if data, ok := e.Data.(*eventbus.OutboundHealthData); ok && data.Delay > 0 {
|
||||
msg += "\n" + t.I18nBot("tgbot.messages.eventDelayDetail",
|
||||
"Delay=="+fmt.Sprintf("%d", data.Delay))
|
||||
}
|
||||
return msg
|
||||
|
||||
case eventbus.EventXrayCrash:
|
||||
errStr := ""
|
||||
if e.Data != nil {
|
||||
errStr = fmt.Sprint(e.Data)
|
||||
}
|
||||
msg := header + "🔥 " + t.I18nBot("tgbot.messages.eventXrayCrash")
|
||||
if errStr != "" {
|
||||
msg += "\n" + t.I18nBot("tgbot.messages.eventXrayCrashError", "Error=="+errStr)
|
||||
}
|
||||
return msg
|
||||
|
||||
case eventbus.EventNodeDown:
|
||||
msg := header + "🔴 " + t.I18nBot("tgbot.messages.eventNodeDown", "Name=="+e.Source)
|
||||
if data, ok := e.Data.(*eventbus.NodeHealthData); ok && data.XrayError != "" {
|
||||
|
||||
Reference in New Issue
Block a user