subscription

package
v0.13.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package subscription turns a user's hosts into client-ready connection links.

Index

Constants

View Source
const (
	PlaceholderProxies   = "{{PROXIES}}"   // Clash: the `proxies:` entries
	PlaceholderNames     = "{{NAMES}}"     // Clash: proxy names, quoted and comma-separated
	PlaceholderOutbounds = "{{OUTBOUNDS}}" // sing-box: outbound objects, JSON
	PlaceholderTags      = "{{TAGS}}"      // sing-box: outbound tags, JSON strings
	PlaceholderTitle     = "{{TITLE}}"
)

Placeholders a custom document can use. The panel supplies the parts it alone knows — the servers a subscriber is entitled to — and leaves everything else, rules, DNS, proxy groups, to the operator.

Variables

This section is empty.

Functions

func Base64

func Base64(b Bundle) string

Base64 renders the classic base64 subscription payload understood by nearly every client.

func Clash

func Clash(b Bundle) string

Clash renders a Mihomo/Clash.Meta profile. It is emitted as YAML by hand because the document is small, fixed in shape, and hand-writing it avoids a YAML dependency in the panel.

func Headers

func Headers(b Bundle) map[string]string

Headers are the subscription-userinfo style metadata clients read to display quota and expiry without opening the panel.

func Links(b Bundle) []string

Links renders one connection URI per enabled host.

func Render

func Render(b Bundle, f Format) string

Render produces the payload for a format.

func RenderWith added in v0.6.0

func RenderWith(b Bundle, f Format, t Templates) string

RenderWith is Render with operator templates applied where they exist.

A template that names no placeholder is served as written. That is a deliberate escape hatch — an operator pinning one fixed configuration is a legitimate thing to want — but it does mean the panel cannot warn that a subscriber's own servers went missing, so the UI says so.

func SingBox

func SingBox(b Bundle) string

SingBox renders a sing-box client configuration with a selector and a urltest group over every host.

func WireGuardConf added in v0.10.0

func WireGuardConf(b Bundle) string

WireGuardConf renders the subscriber's tunnel as the .conf file every WireGuard client reads — there is no URI scheme for WireGuard the way there is for VLESS, so a file is the only thing to hand over.

One file is one tunnel. When several WireGuard hosts are published the first enabled one wins rather than emitting several [Peer] blocks: two peers both claiming 0.0.0.0/0 is a configuration whose behaviour depends on the client, and a config that works differently on iOS and on Windows is worse than one that names a single server.

func XrayJSON added in v0.1.1

func XrayJSON(b Bundle) string

XrayJSON renders the "JSON subscription" that v2rayN, v2rayNG, Happ and Streisand accept: an array of complete Xray client configurations, one per host, each ready to run as-is. It is the most faithful of the formats — a vless:// link has to squeeze every stream setting through a query string, while this carries the same structure xray-core actually parses.

Every entry is self-contained on purpose. Clients present them as a server list and switch between them, so an entry that leaned on a shared block would stop working the moment the user picked a different one.

Types

type Bundle

type Bundle struct {
	User  *domain.User
	Hosts []domain.Host
	// Title is shown as the profile name in client apps.
	Title      string
	SupportURL string
	// UpdateInterval is how often clients should refresh, in hours.
	UpdateInterval int
}

Bundle is everything a subscription response is built from.

type Format

type Format string

Format is a subscription encoding a client understands.

const (
	FormatBase64  Format = "base64"
	FormatPlain   Format = "plain"
	FormatClash   Format = "clash"
	FormatSingBox Format = "singbox"
	FormatJSON    Format = "json"
	// WireGuard has no URI scheme, so its "format" is the .conf file itself.
	FormatWireGuard Format = "wireguard"
)

func DetectClientFormat added in v0.1.1

func DetectClientFormat(userAgent string) (Format, bool)

DetectClientFormat reports the format a client needs when it names itself. The second return distinguishes "this client requires Clash" from "no idea what this is" — the caller has a configured default for the second case, and collapsing the two would apply that default to clients that cannot read it.

func DetectFormat

func DetectFormat(userAgent string) Format

DetectFormat picks an encoding from the client's User-Agent, falling back to the base64 list that every client understands.

func (Format) ContentType

func (f Format) ContentType() string

ContentType is what the response should be served as.

func (Format) Valid

func (f Format) Valid() bool

type Info

type Info struct {
	Username        string     `json:"username"`
	Status          string     `json:"status"`
	UsedBytes       int64      `json:"usedTrafficBytes"`
	LimitBytes      int64      `json:"trafficLimitBytes"`
	LifetimeBytes   int64      `json:"lifetimeUsedTrafficBytes"`
	ExpireAt        *time.Time `json:"expireAt"`
	SubscriptionURL string     `json:"subscriptionUrl"`
	Links           []string   `json:"links"`
	Title           string     `json:"title"`
	SupportURL      string     `json:"supportUrl,omitempty"`
	DaysLeft        *int       `json:"daysLeft,omitempty"`
	// Notices an operator has published. Empty on a deployment that has never
	// used them, so the page simply renders nothing.
	Announcements []domain.Announcement `json:"announcements,omitempty"`
	// Page options, so the subscriber page renders what the operator chose
	// without a second request.
	ShowLinks   bool `json:"showLinks"`
	ShowFormats bool `json:"showFormats"`
}

Info is the JSON payload the subscription page renders.

func BuildInfo

func BuildInfo(b Bundle, subURL string) Info

type Templates added in v0.6.0

type Templates struct {
	Clash   string
	SingBox string
}

Templates lets an operator replace the two formats that are whole configuration documents rather than a list of links. Empty fields keep the built-in rendering.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL