mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-25 05:46:18 +00:00
feat(sub): expose live online status and add ?format=info endpoint
Custom subscription templates only received the lastOnline timestamp, so template authors had to fake an online indicator by comparing it against the current time, and the page was a one-shot server render with no way to refresh usage without reloading the whole HTML. The template context (and window.__SUB_PAGE_DATA__) now carries isOnline, computed from the panel's own online-client tracking (local xray plus remote nodes) at render time. The subscription URL also answers ?format=info with the page view-model as JSON — minus the links, with emails deduplicated — so templates can poll live status cheaply. The shared view-model construction moved into buildSubPageData/subPageContext so the HTML page, the SPA payload and the info JSON cannot drift apart. Also documents the previously injected but undocumented announce template variable.
This commit is contained in:
@@ -35,3 +35,35 @@ func TestBuildPageData_SplitsMultiHostLinks(t *testing.T) {
|
||||
t.Fatalf("Emails = %v, want %v", page.Emails, wantEmails)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubIsOnline(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
sub []string
|
||||
online []string
|
||||
want bool
|
||||
}{
|
||||
{name: "nobody online", sub: []string{"a@x"}, online: nil, want: false},
|
||||
{name: "no sub emails", sub: nil, online: []string{"a@x"}, want: false},
|
||||
{name: "sub client online", sub: []string{"a@x"}, online: []string{"z@x", "a@x"}, want: true},
|
||||
{name: "only other clients online", sub: []string{"a@x"}, online: []string{"z@x"}, want: false},
|
||||
{name: "any of several sub entries online", sub: []string{"a@x", "b@x"}, online: []string{"b@x"}, want: true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := subIsOnline(tt.sub, tt.online); got != tt.want {
|
||||
t.Fatalf("subIsOnline(%v, %v) = %v, want %v", tt.sub, tt.online, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildPageData_IsOnlineFalseWithoutLiveConnections(t *testing.T) {
|
||||
s := &SubService{}
|
||||
|
||||
page := s.BuildPageData("s1", "", xray.ClientTraffic{}, 0, []string{"vless://a@h1:443?type=tcp#DE-john@x"}, []string{"john@x"}, "", "", "", "/", "", "")
|
||||
|
||||
if page.IsOnline {
|
||||
t.Fatal("IsOnline must be false when the subscription's client has no live connection")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user