mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-24 21:46:07 +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:
@@ -24,6 +24,7 @@ When rendering the template, the following variables are injected into the templ
|
||||
|
||||
* `{{ .sId }}`: Subscription ID (UUID).
|
||||
* `{{ .enabled }}`: Whether the subscription/client is enabled (boolean).
|
||||
* `{{ .isOnline }}`: Whether the subscription's client has a live connection right now (boolean). Computed from the panel's online-client tracking (local Xray plus any remote nodes) at render time.
|
||||
* `{{ .download }}`: Formatted download traffic (e.g. "2.5 GB").
|
||||
* `{{ .upload }}`: Formatted upload traffic.
|
||||
* `{{ .total }}`: Formatted total traffic limit.
|
||||
@@ -40,5 +41,41 @@ When rendering the template, the following variables are injected into the templ
|
||||
* `{{ .subTitle }}`: The subscription title configured in the panel (Subscription → Information). Useful for page branding/headings. May be empty.
|
||||
* `{{ .subSupportUrl }}`: The support URL configured in the panel. Useful for a "Contact support" link. May be empty.
|
||||
* `{{ .links }}`: A list (slice) of string configurations (VMess, VLESS, etc. URLs). You can loop through them using `{{ range .links }} ... {{ end }}`.
|
||||
* `{{ .emails }}`: A list (slice) of emails related to the subscription.
|
||||
* `{{ .emails }}`: A list (slice) of client emails, parallel to `links` — the email at index *i* owns the link at index *i*. May contain duplicates when one client has several links.
|
||||
* `{{ .announce }}`: The announcement text configured in the panel (Settings → Subscription → Announce). May be empty.
|
||||
* `{{ .datepicker }}`: Current calendar format used by the panel (e.g. "gregorian" or "jalali").
|
||||
|
||||
## Live Status JSON (`?format=info`)
|
||||
|
||||
Every subscription URL also answers `GET <sub URL>?format=info` with the same view-model as JSON —
|
||||
minus `links`, and with `emails` deduplicated — so a template can poll it and update usage or
|
||||
online status live without reloading the page:
|
||||
|
||||
```json
|
||||
{
|
||||
"sId": "…",
|
||||
"enabled": true,
|
||||
"isOnline": true,
|
||||
"used": "1.2 GB",
|
||||
"remained": "8.8 GB",
|
||||
"expire": 0,
|
||||
"lastOnline": 1735680000000,
|
||||
"…": "…"
|
||||
}
|
||||
```
|
||||
|
||||
Example polling snippet for a template:
|
||||
|
||||
```html
|
||||
<span id="status"></span>
|
||||
<script>
|
||||
async function refreshStatus() {
|
||||
const res = await fetch(window.location.pathname + '?format=info');
|
||||
if (!res.ok) return;
|
||||
const info = await res.json();
|
||||
document.getElementById('status').textContent = info.isOnline ? 'Online' : 'Offline';
|
||||
}
|
||||
refreshStatus();
|
||||
setInterval(refreshStatus, 10000);
|
||||
</script>
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user