postgres

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: 13 Imported by: 0

Documentation

Overview

Package postgres implements the panel's persistence layer on top of pgx.

Index

Constants

This section is empty.

Variables

View Source
var ErrConflict = errors.New("already exists")

ErrConflict is returned when a unique constraint rejects a write.

View Source
var ErrNotFound = errors.New("not found")

ErrNotFound is returned when a lookup by identity yields no row.

Functions

This section is empty.

Types

type Attention added in v0.9.0

type Attention struct {
	NodesOffline    int              `json:"nodesOffline"`
	NodesDegraded   int              `json:"nodesDegraded"`
	NodesOverQuota  int              `json:"nodesOverQuota"`
	UsersExpiring   int              `json:"usersExpiring"`
	UsersNearQuota  int              `json:"usersNearQuota"`
	UsersLimited    int              `json:"usersLimited"`
	PaymentsDueSoon int              `json:"paymentsDueSoon"`
	Expiring        []PendingWarning `json:"expiring"`
	NearQuota       []PendingWarning `json:"nearQuota"`
}

Attention is the short answer to "what needs me right now". Every figure is a count the dashboard can show without the operator opening four pages.

type HostInput

type HostInput struct {
	InboundID     string
	Remark        string
	Address       string
	Port          int
	Path          string
	SNI           string
	HostHeader    string
	ALPN          string
	Fingerprint   string
	PublicKey     string
	ShortID       string
	SpiderX       string
	Flow          string
	Security      string
	AllowInsecure bool
	Tags          []string
	IsDisabled    bool
	ViewPosition  int
}

type NodeConnectedInfo

type NodeConnectedInfo struct {
	AgentVersion  string
	XrayVersion   string
	Hostname      string
	OS            string
	Arch          string
	Kernel        string
	CPUCount      int
	CPUModel      string
	TotalRAMBytes int64
	ConfigHash    string
}

NodeConnectedInfo is written when an agent completes its handshake.

type NodeHeartbeat

type NodeHeartbeat struct {
	Health        domain.NodeHealth
	XrayRunning   bool
	XrayStartedAt *time.Time
	XrayVersion   string
	ConfigHash    string
	CPUUsage      float64
	UsedRAMBytes  int64
	TotalRAMBytes int64
	LoadAvg1      float64
	OnlineUsers   int
	Message       string
}

type NodeInput

type NodeInput struct {
	Name              string
	Address           string
	CountryCode       string
	Description       string
	IsDisabled        bool
	ConfigProfileID   *string
	ActiveInboundTags []string
	Consumption       float64
	TrafficLimitBytes int64
	TrafficReset      domain.TrafficResetStrategy
	NotifyPercent     int
	ViewPosition      int

	Provider      string
	ProviderURL   string
	CostAmount    float64
	CostCurrency  string
	BillingCycle  domain.BillingCycle
	NextPaymentAt *time.Time
	BillingNotes  string
	Tags          []string
}

type NodeSeries

type NodeSeries struct {
	NodeID   string         `json:"nodeUuid"`
	NodeName string         `json:"nodeName"`
	Points   []TrafficPoint `json:"points"`
	Total    int64          `json:"totalBytes"`
}

NodeSeries is per-node traffic over a window, grouped for stacked charts.

type Overview

type Overview struct {
	UsersTotal    int   `json:"usersTotal"`
	UsersActive   int   `json:"usersActive"`
	UsersDisabled int   `json:"usersDisabled"`
	UsersLimited  int   `json:"usersLimited"`
	UsersExpired  int   `json:"usersExpired"`
	UsersOnline   int   `json:"usersOnline"`
	NodesTotal    int   `json:"nodesTotal"`
	NodesOnline   int   `json:"nodesOnline"`
	NodesDisabled int   `json:"nodesDisabled"`
	HostsTotal    int   `json:"hostsTotal"`
	SquadsTotal   int   `json:"squadsTotal"`
	ProfilesTotal int   `json:"profilesTotal"`
	TrafficDay    int64 `json:"trafficLast24hBytes"`
	TrafficWeek   int64 `json:"trafficLast7dBytes"`
	TrafficMonth  int64 `json:"trafficLast30dBytes"`
	TrafficTotal  int64 `json:"trafficTotalBytes"`
}

Overview is the aggregate shown on the dashboard landing page.

type PendingWarning added in v0.9.0

type PendingWarning struct {
	UserID   string `json:"userUuid"`
	Username string `json:"username"`
	// Days until expiry, for an expiry warning.
	DaysLeft int `json:"daysLeft,omitempty"`
	// Percent of quota used, for a quota warning.
	Percent int `json:"percent,omitempty"`
	// The figures behind the percent, so a message can name them.
	UsedBytes  int64 `json:"usedBytes,omitempty"`
	LimitBytes int64 `json:"limitBytes,omitempty"`
}

PendingWarning is one subscriber the operator should hear about before the thing happens, rather than after.

type ProviderSpend

type ProviderSpend struct {
	Provider string  `json:"provider"`
	Nodes    int     `json:"nodes"`
	Monthly  float64 `json:"monthly"`
}

type ProvisionedUser

type ProvisionedUser struct {
	UUID           string
	Username       string
	VlessUUID      string
	TrojanPassword string
	SSPassword     string
	InboundTag     string
	WGPublicKey    string
	WGIndex        int64
}

ProvisionedUser is the minimal projection the orchestrator needs to inject a client into an xray inbound.

type ResponseRule added in v0.5.0

type ResponseRule struct {
	UUID      string    `json:"uuid"`
	Name      string    `json:"name"`
	MatchUA   string    `json:"matchUserAgent"`
	Format    string    `json:"format"`
	IsEnabled bool      `json:"isEnabled"`
	Priority  int       `json:"priority"`
	Hits      int64     `json:"hits"`
	CreatedAt time.Time `json:"createdAt"`
	UpdatedAt time.Time `json:"updatedAt"`
}

ResponseRule maps a client to the format it should be served.

type Session added in v0.6.0

type Session struct {
	UserID   string     `json:"userUuid"`
	Username string     `json:"username"`
	Status   string     `json:"status"`
	NodeID   string     `json:"nodeUuid"`
	NodeName string     `json:"nodeName"`
	Country  string     `json:"countryCode"`
	Bytes    int64      `json:"bytes"`
	LastSeen time.Time  `json:"lastSeen"`
	OnlineAt *time.Time `json:"onlineAt"`
}

Session is a subscriber currently carrying traffic, and where.

This is assembled from what the panel already collects rather than from a per-connection feed: xray reports usage per user per node, and a user that moved bytes in the last few minutes is, for an operator's purposes, online there. It cannot show individual connections or their addresses — that would need the agent to report them — and the UI says so rather than implying a precision it does not have.

type Snapshot added in v0.3.0

type Snapshot struct {
	// Schema is the last applied migration. A snapshot taken on a newer schema
	// cannot be trusted to load into an older one: a column that did not exist
	// yet would be dropped in silence, and the operator would find out when the
	// feature that used it stopped working.
	Schema  string `json:"schema"`
	TakenAt string `json:"takenAt"`
	// Tables maps a table name to its rows, each row a column→value object.
	// Column-keyed rather than positional so a snapshot stays readable, and so
	// a reordered column list cannot silently shift values into wrong fields.
	Tables map[string][]map[string]any `json:"tables"`
	Counts map[string]int              `json:"counts"`
	// Types records each column's Postgres type, because JSON cannot tell a
	// text[] from a jsonb array once both are a list of strings — and binding
	// one as the other is rejected. Without this, restore guesses and fails on
	// the first node row.
	Types map[string]map[string]string `json:"types"`
}

Snapshot is a portable copy of a panel's configuration.

type SpendSummary

type SpendSummary struct {
	Currency       string          `json:"currency"`
	MonthlyTotal   float64         `json:"monthlyTotal"`
	YearlyTotal    float64         `json:"yearlyTotal"`
	BilledNodes    int             `json:"billedNodes"`
	CostPerTB      float64         `json:"costPerTb"`
	TrafficMonthTB float64         `json:"trafficThisMonthTb"`
	ByProvider     []ProviderSpend `json:"byProvider"`
	Upcoming       []UpcomingBill  `json:"upcoming"`
	Overdue        int             `json:"overdue"`
}

SpendSummary is the infrastructure cost picture shown on the dashboard.

type Store

type Store struct {
	// contains filtered or unexported fields
}

func Connect

func Connect(ctx context.Context, dsn string) (*Store, error)

func (*Store) APITokenByHash

func (s *Store) APITokenByHash(ctx context.Context, hash string) (*domain.APIToken, error)

APITokenByHash resolves a presented token and rejects expired ones.

func (*Store) AddAllUsersToSquad

func (s *Store) AddAllUsersToSquad(ctx context.Context, squadID string) (int64, error)

AddAllUsersToSquad and RemoveAllUsersFromSquad back the bulk membership actions offered on the squad page.

func (*Store) AddNodeTraffic

func (s *Store) AddNodeTraffic(ctx context.Context, id string, bytes int64) error

func (*Store) AddUserTraffic

func (s *Store) AddUserTraffic(ctx context.Context, userID string, bytes int64) (used, limit int64, status domain.UserStatus, err error)

AddUserTraffic charges usage to a user and returns the user's post-update state so the caller can enforce limits.

func (*Store) AdminByUUID

func (s *Store) AdminByUUID(ctx context.Context, id string) (*domain.Admin, error)

func (*Store) AdminByUsername

func (s *Store) AdminByUsername(ctx context.Context, username string) (*domain.Admin, error)

func (*Store) AllDevices added in v0.4.0

func (s *Store) AllDevices(ctx context.Context, search string, limit int) ([]domain.Device, error)

AllDevices powers the hardware-id inspector: every known device across every subscriber, rather than one user at a time.

func (*Store) ApplyNodeHeartbeat

func (s *Store) ApplyNodeHeartbeat(ctx context.Context, id string, hb NodeHeartbeat) error

func (*Store) Attention added in v0.9.0

func (s *Store) Attention(ctx context.Context, expiryDays, quotaPercent int) (*Attention, error)

Attention counts without claiming anything — it is a read, and reading the dashboard must never consume a warning that has not been sent yet.

func (*Store) Channel added in v0.2.0

func (s *Store) Channel(ctx context.Context, id string) (*domain.NotificationChannel, error)

func (*Store) ChannelDeliveries added in v0.2.0

func (s *Store) ChannelDeliveries(ctx context.Context, id string, limit int) ([]domain.NotificationDelivery, error)

func (*Store) ClaimExpiryWarnings added in v0.9.0

func (s *Store) ClaimExpiryWarnings(ctx context.Context, within time.Duration) ([]PendingWarning, error)

ClaimExpiryWarnings returns the active users expiring within the window and marks them, so the caller can send one warning each.

The claim and the read are one statement: the maintenance loop runs every minute, and a select-then-update would send the same warning again on the next tick if anything failed in between. Marking by the expiry timestamp rather than a boolean means a rescheduled expiry earns a fresh warning, which is what an operator extending a subscription expects.

func (*Store) ClaimQuotaWarnings added in v0.9.0

func (s *Store) ClaimQuotaWarnings(ctx context.Context, percent int) ([]PendingWarning, error)

ClaimQuotaWarnings returns the active users past the threshold and marks them at their current usage.

Marking with the usage figure rather than a flag is what makes a reset clear the warning: after a monthly rollover used_traffic drops below the mark, the condition `used > quota_warned_at` is true again on the next crossing, and the subscriber is warned once per cycle rather than once ever.

func (*Store) ClaimTOTPStep added in v0.7.0

func (s *Store) ClaimTOTPStep(ctx context.Context, id string, step int64) (bool, error)

ClaimTOTPStep records a time step as used, and reports whether it was still unused. The comparison and the write are one statement so two requests racing with the same code cannot both win.

func (*Store) Close

func (s *Store) Close()

func (*Store) ConfirmTOTP added in v0.7.0

func (s *Store) ConfirmTOTP(ctx context.Context, id string, step int64, recoveryHashes []string) error

ConfirmTOTP turns a staged secret on, once a code proved the app has it.

func (*Store) ConsumeRecoveryCode added in v0.7.0

func (s *Store) ConsumeRecoveryCode(ctx context.Context, id, digest string) (bool, error)

ConsumeRecoveryCode removes one digest, and reports whether it was there. Removal is what makes a recovery code single-use.

func (*Store) CountAdmins

func (s *Store) CountAdmins(ctx context.Context) (int, error)

func (*Store) CreateAPIToken

func (s *Store) CreateAPIToken(ctx context.Context, name, hash, preview, createdBy string, expiresAt *time.Time) (*domain.APIToken, error)

func (*Store) CreateAdmin

func (s *Store) CreateAdmin(ctx context.Context, username, passwordHash string, role domain.AdminRole) (*domain.Admin, error)

func (*Store) CreateAnnouncement added in v0.2.0

func (s *Store) CreateAnnouncement(ctx context.Context, a domain.Announcement) (*domain.Announcement, error)

func (*Store) CreateChannel added in v0.2.0

func (*Store) CreateHost

func (s *Store) CreateHost(ctx context.Context, in HostInput) (*domain.Host, error)

func (*Store) CreateNode

func (s *Store) CreateNode(ctx context.Context, in NodeInput, tokenHash, tokenPreview string) (*domain.Node, error)

func (*Store) CreateProfile

func (s *Store) CreateProfile(ctx context.Context, name string, kind domain.ProfileKind, config json.RawMessage, inbounds []domain.ConfigProfileInbound) (*domain.ConfigProfile, error)

func (*Store) CreateRule added in v0.5.0

func (s *Store) CreateRule(ctx context.Context, r ResponseRule) (*ResponseRule, error)

func (*Store) CreateSquad

func (s *Store) CreateSquad(ctx context.Context, name, info string, inboundIDs []string) (*domain.Squad, error)

func (*Store) CreateUser

func (s *Store) CreateUser(ctx context.Context, in UserInput, sec UserSecrets) (*domain.User, error)

func (*Store) DeleteAPIToken

func (s *Store) DeleteAPIToken(ctx context.Context, id string) error

func (*Store) DeleteAdmin

func (s *Store) DeleteAdmin(ctx context.Context, id string) error

func (*Store) DeleteAnnouncement added in v0.2.0

func (s *Store) DeleteAnnouncement(ctx context.Context, id string) error

func (*Store) DeleteChannel added in v0.2.0

func (s *Store) DeleteChannel(ctx context.Context, id string) error

func (*Store) DeleteDevice

func (s *Store) DeleteDevice(ctx context.Context, userID, hwid string) error

func (*Store) DeleteHost

func (s *Store) DeleteHost(ctx context.Context, id string) error

func (*Store) DeleteNode

func (s *Store) DeleteNode(ctx context.Context, id string) error

func (*Store) DeleteProfile

func (s *Store) DeleteProfile(ctx context.Context, id string) error

func (*Store) DeleteRule added in v0.5.0

func (s *Store) DeleteRule(ctx context.Context, id string) error

func (*Store) DeleteSquad

func (s *Store) DeleteSquad(ctx context.Context, id string) error

func (*Store) DeleteUser

func (s *Store) DeleteUser(ctx context.Context, id string) error

func (*Store) DisableTOTP added in v0.7.0

func (s *Store) DisableTOTP(ctx context.Context, id string) error

DisableTOTP clears the second factor and every recovery code with it, so a re-enrolment cannot be unlocked by a code from the previous one.

func (*Store) EnabledChannels added in v0.2.0

func (s *Store) EnabledChannels(ctx context.Context) ([]domain.NotificationChannel, error)

EnabledChannels is the dispatcher's read path, kept separate so a disabled channel costs nothing at delivery time.

func (*Store) ExpireUsers

func (s *Store) ExpireUsers(ctx context.Context) (int64, error)

ExpireUsers flips past-due active users to EXPIRED and returns how many changed.

func (*Store) ExportSnapshot added in v0.3.0

func (s *Store) ExportSnapshot(ctx context.Context) (*Snapshot, error)

ExportSnapshot reads every configuration table in one transaction, so the snapshot is a single consistent moment rather than a smear across the time it took to read.

func (*Store) Host

func (s *Store) Host(ctx context.Context, id string) (*domain.Host, error)

func (*Store) HostsForInbounds

func (s *Store) HostsForInbounds(ctx context.Context, inboundIDs []string) ([]domain.Host, error)

HostsForInbounds returns the enabled hosts published by any of the inbounds, which is how a user's subscription is assembled from their squads.

func (*Store) ImportSnapshot added in v0.3.0

func (s *Store) ImportSnapshot(ctx context.Context, snap *Snapshot, currentSchema string) error

ImportSnapshot replaces the current configuration with the snapshot's.

This is destructive by design — a restore that merged would leave a panel in a state that is neither the backup nor what was there before, which is the worst outcome of the three. It runs in one transaction: either the whole snapshot lands or the database is untouched.

func (*Store) Inbound

func (s *Store) Inbound(ctx context.Context, id string) (*domain.ConfigProfileInbound, error)

func (*Store) ListAPITokens

func (s *Store) ListAPITokens(ctx context.Context) ([]domain.APIToken, error)

func (*Store) ListAdmins

func (s *Store) ListAdmins(ctx context.Context) ([]domain.Admin, error)

func (*Store) ListAnnouncements added in v0.2.0

func (s *Store) ListAnnouncements(ctx context.Context) ([]domain.Announcement, error)

func (*Store) ListChannels added in v0.2.0

func (s *Store) ListChannels(ctx context.Context) ([]domain.NotificationChannel, error)

func (*Store) ListEvents

func (s *Store) ListEvents(ctx context.Context, limit int, kind string) ([]domain.Event, error)

func (*Store) ListHosts

func (s *Store) ListHosts(ctx context.Context) ([]domain.Host, error)

func (*Store) ListNodes

func (s *Store) ListNodes(ctx context.Context) ([]domain.Node, error)

func (*Store) ListProfiles

func (s *Store) ListProfiles(ctx context.Context) ([]domain.ConfigProfile, error)

func (*Store) ListRules added in v0.5.0

func (s *Store) ListRules(ctx context.Context) ([]ResponseRule, error)

func (*Store) ListSquads

func (s *Store) ListSquads(ctx context.Context) ([]domain.Squad, error)

func (*Store) ListUsers

func (s *Store) ListUsers(ctx context.Context, f UserFilter) ([]domain.User, int, error)

func (*Store) LiveAnnouncements added in v0.2.0

func (s *Store) LiveAnnouncements(ctx context.Context) ([]domain.Announcement, error)

LiveAnnouncements is what a subscriber sees. The window is filtered in SQL so the subscription path stays one query regardless of how many notices have accumulated over the life of the deployment.

func (*Store) LogEvent

func (s *Store) LogEvent(ctx context.Context, kind domain.EventKind, actor, subject, message string, meta any)

func (*Store) MarkAllNodesDisconnected

func (s *Store) MarkAllNodesDisconnected(ctx context.Context) error

MarkAllNodesDisconnected resets liveness state on panel start, since no agent stream survives a restart.

func (*Store) MarkNodeConnected

func (s *Store) MarkNodeConnected(ctx context.Context, id string, info NodeConnectedInfo) error

func (*Store) MarkNodeDisconnected

func (s *Store) MarkNodeDisconnected(ctx context.Context, id, reason string) error

func (*Store) MarkUserOnline

func (s *Store) MarkUserOnline(ctx context.Context, userID string)

func (*Store) MatchRule added in v0.5.0

func (s *Store) MatchRule(ctx context.Context, userAgent string) (string, bool)

MatchRule finds the first enabled rule whose pattern appears in the user agent, and counts the hit. Matching happens in SQL so the subscription path stays one round trip no matter how many rules exist.

func (*Store) Migrate

func (s *Store) Migrate(ctx context.Context) error

Migrate applies every embedded migration that has not run yet.

func (*Store) Node

func (s *Store) Node(ctx context.Context, id string) (*domain.Node, error)

func (*Store) NodeMetrics added in v0.2.0

func (s *Store) NodeMetrics(ctx context.Context, nodeID string, since time.Duration) ([]domain.NodeMetric, error)

func (*Store) NodeTrafficSeries

func (s *Store) NodeTrafficSeries(ctx context.Context, since time.Time, interval string) ([]NodeSeries, error)

func (*Store) NodesUsingProfile

func (s *Store) NodesUsingProfile(ctx context.Context, profileID string) ([]domain.Node, error)

NodesUsingProfile lists the nodes bound to a profile, used to fan out config changes after the profile document is edited.

func (*Store) OnEvent added in v0.2.0

func (s *Store) OnEvent(fn func(domain.Event))

OnEvent registers the hook LogEvent calls. Passing nil detaches it.

func (*Store) Overview

func (s *Store) Overview(ctx context.Context) (*Overview, error)

func (*Store) Pool

func (s *Store) Pool() *pgxpool.Pool

func (*Store) PreviewRule added in v0.5.0

func (s *Store) PreviewRule(ctx context.Context, userAgent string) (string, bool)

PreviewRule answers the same question as MatchRule without recording a hit, for the log line and for the operator's "what would this client get" probe.

func (*Store) Profile

func (s *Store) Profile(ctx context.Context, id string) (*domain.ConfigProfile, error)

func (*Store) ProfileInbounds

func (s *Store) ProfileInbounds(ctx context.Context, profileID string) ([]domain.ConfigProfileInbound, error)

ProfileInbounds returns the inbounds of one profile, or of every profile when profileID is empty.

func (*Store) PruneDeliveries added in v0.2.0

func (s *Store) PruneDeliveries(ctx context.Context, keepFor time.Duration) error

PruneDeliveries keeps the log from growing without bound. A panel that notifies on every user update produces a lot of rows, and none of them are interesting a week later.

func (*Store) PruneNodeMetrics added in v0.2.0

func (s *Store) PruneNodeMetrics(ctx context.Context, keepFor time.Duration) error

func (*Store) PruneSubscriptionRequests added in v0.4.0

func (s *Store) PruneSubscriptionRequests(ctx context.Context, keepFor time.Duration) error

func (*Store) PruneUsage

func (s *Store) PruneUsage(ctx context.Context, retention time.Duration) error

PruneUsage drops history older than the retention window.

func (*Store) RecordDelivery added in v0.2.0

func (s *Store) RecordDelivery(ctx context.Context, d domain.NotificationDelivery) error

RecordDelivery appends to the delivery log and rolls the denormalised health fields on the channel in the same statement pair, so the list view and the log can never disagree about the last outcome.

func (*Store) RecordNodeMetric added in v0.2.0

func (s *Store) RecordNodeMetric(ctx context.Context, nodeID string, m domain.NodeMetric) error

RecordNodeMetric stores one heartbeat sample. Samples are keyed by minute so a chatty agent cannot flood the table — a node heartbeating every few seconds would otherwise write tens of thousands of rows a day for a chart that is read at minute resolution anyway.

func (*Store) RecordNodeUsage

func (s *Store) RecordNodeUsage(ctx context.Context, nodeID string, at time.Time, bytes int64) error

func (*Store) RecordSubscriptionRequest added in v0.4.0

func (s *Store) RecordSubscriptionRequest(ctx context.Context, r SubscriptionRequest)

RecordSubscriptionRequest is fire-and-forget: a subscriber fetching their configuration must never fail because the audit write did.

func (*Store) RecordUserUsage

func (s *Store) RecordUserUsage(ctx context.Context, userID, nodeID string, at time.Time, bytes int64) error

func (*Store) RemoveAllUsersFromSquad

func (s *Store) RemoveAllUsersFromSquad(ctx context.Context, squadID string) (int64, error)

func (*Store) ReorderHosts

func (s *Store) ReorderHosts(ctx context.Context, order []string) error

func (*Store) ReplaceRecoveryCodes added in v0.7.0

func (s *Store) ReplaceRecoveryCodes(ctx context.Context, id string, hashes []string) error

ReplaceRecoveryCodes swaps the whole set, for regenerating them.

func (*Store) ResetDevices

func (s *Store) ResetDevices(ctx context.Context, userID string) error

func (*Store) ResetDueUserTraffic

func (s *Store) ResetDueUserTraffic(ctx context.Context) (int64, error)

ResetDueUserTraffic applies the per-user reset strategy and returns how many counters were rolled over.

func (*Store) ResetNodeTraffic

func (s *Store) ResetNodeTraffic(ctx context.Context, id string) error

func (*Store) ResetUserTraffic

func (s *Store) ResetUserTraffic(ctx context.Context, id string) error

func (*Store) RevokeUserSubscription

func (s *Store) RevokeUserSubscription(ctx context.Context, id, newSubUUID, newShort, newVless, newTrojan, newSS string) (*domain.User, error)

func (*Store) RollDuePayments

func (s *Store) RollDuePayments(ctx context.Context) ([]domain.Node, error)

RollDuePayments moves past-due nodes onto their next billing date and reports which ones rolled over, so the operator gets one notice per cycle.

func (*Store) RotateNodeToken

func (s *Store) RotateNodeToken(ctx context.Context, id, tokenHash, tokenPreview string) error

func (*Store) SchemaVersion added in v0.3.0

func (s *Store) SchemaVersion(ctx context.Context) (string, error)

SchemaVersion is the last applied migration, used to stamp and to check snapshots.

func (*Store) Sessions added in v0.6.0

func (s *Store) Sessions(ctx context.Context, within time.Duration, limit int) ([]Session, error)

Sessions lists who has moved traffic within the window, newest first.

func (*Store) SetNodeConfigHash

func (s *Store) SetNodeConfigHash(ctx context.Context, id, hash string) error

func (*Store) SetNodeDisabled

func (s *Store) SetNodeDisabled(ctx context.Context, id string, disabled bool) error

func (*Store) SetNodeHealth

func (s *Store) SetNodeHealth(ctx context.Context, id string, health domain.NodeHealth, message string) error

func (*Store) SetUserStatus

func (s *Store) SetUserStatus(ctx context.Context, id string, status domain.UserStatus) error

func (*Store) SetWireGuardKeys added in v0.10.0

func (s *Store) SetWireGuardKeys(ctx context.Context, id, private, public string) error

SetWireGuardKeys fills in a key pair, but only where one is not already set — so two panels racing on the same database cannot hand the same subscriber two different keys, one of which would silently never connect.

func (*Store) Settings

func (s *Store) Settings(ctx context.Context) (*domain.Settings, error)

Settings returns the singleton settings row, creating it if a very old installation somehow lacks one.

func (*Store) Spend

func (s *Store) Spend(ctx context.Context, defaultCurrency string) (*SpendSummary, error)

Spend aggregates node costs. Amounts are normalised to a monthly figure so nodes on different billing cycles can be compared and summed.

func (*Store) Squad

func (s *Store) Squad(ctx context.Context, id string) (*domain.Squad, error)

func (*Store) StageTOTPSecret added in v0.7.0

func (s *Store) StageTOTPSecret(ctx context.Context, id, secret string) error

StageTOTPSecret stores a secret that is not in force yet. Enrolment is two steps on purpose: a secret written straight to the account would lock an operator out if they scanned the QR into an app that never actually worked.

func (*Store) SubscriptionRequests added in v0.4.0

func (s *Store) SubscriptionRequests(ctx context.Context, userID string, failedOnly bool, limit int) ([]SubscriptionRequest, error)

SubscriptionRequests lists recent fetches, newest first. userID narrows it to one subscriber; failed lists only the ones that did not resolve, which is where a revoked link still being polled shows up.

func (*Store) TopUsers

func (s *Store) TopUsers(ctx context.Context, since time.Time, limit int) ([]TopUser, error)

func (*Store) TotalTrafficSeries

func (s *Store) TotalTrafficSeries(ctx context.Context, since time.Time, interval string) ([]TrafficPoint, error)

func (*Store) TouchAdminLogin

func (s *Store) TouchAdminLogin(ctx context.Context, id string)

func (*Store) TouchDevice

func (s *Store) TouchDevice(ctx context.Context, userID, hwid, userAgent, platform string, limit int) (allowed bool, count int, err error)

TouchDevice records a device against a subscription and reports whether the user is over their limit. A device already known never counts as new, so a returning client is not locked out by its own history.

func (*Store) TouchSubscriptionOpen

func (s *Store) TouchSubscriptionOpen(ctx context.Context, id, userAgent string)

func (*Store) UpdateAdmin

func (s *Store) UpdateAdmin(ctx context.Context, id string, role domain.AdminRole, disabled bool) (*domain.Admin, error)

func (*Store) UpdateAdminPassword

func (s *Store) UpdateAdminPassword(ctx context.Context, id, passwordHash string) error

func (*Store) UpdateAnnouncement added in v0.2.0

func (s *Store) UpdateAnnouncement(ctx context.Context, id string, a domain.Announcement) (*domain.Announcement, error)

func (*Store) UpdateChannel added in v0.2.0

func (*Store) UpdateHost

func (s *Store) UpdateHost(ctx context.Context, id string, in HostInput) (*domain.Host, error)

func (*Store) UpdateNode

func (s *Store) UpdateNode(ctx context.Context, id string, in NodeInput) (*domain.Node, error)

func (*Store) UpdateProfile

func (s *Store) UpdateProfile(ctx context.Context, id, name string, kind domain.ProfileKind, config json.RawMessage, inbounds []domain.ConfigProfileInbound) (*domain.ConfigProfile, error)

UpdateProfile rewrites the document and reconciles the extracted inbound rows. Inbounds are matched by tag so hosts and squads keep pointing at the same inbound identity across edits.

func (*Store) UpdateRule added in v0.5.0

func (s *Store) UpdateRule(ctx context.Context, id string, r ResponseRule) (*ResponseRule, error)

func (*Store) UpdateSettings

func (s *Store) UpdateSettings(ctx context.Context, in domain.Settings) (*domain.Settings, error)

func (*Store) UpdateSquad

func (s *Store) UpdateSquad(ctx context.Context, id, name, info string, inboundIDs []string) (*domain.Squad, error)

func (*Store) UpdateUser

func (s *Store) UpdateUser(ctx context.Context, id string, in UserInput) (*domain.User, error)

func (*Store) User

func (s *Store) User(ctx context.Context, id string) (*domain.User, error)

func (*Store) UserByShortUUID

func (s *Store) UserByShortUUID(ctx context.Context, short string) (*domain.User, error)

func (*Store) UserBySubscription

func (s *Store) UserBySubscription(ctx context.Context, subUUID string) (*domain.User, error)

func (*Store) UserDevices

func (s *Store) UserDevices(ctx context.Context, userID string) ([]domain.Device, error)

func (*Store) UserInboundIDs

func (s *Store) UserInboundIDs(ctx context.Context, userID string) ([]string, error)

UserInboundIDs lists the inbound identities a user can reach through their squads.

func (*Store) UserTags

func (s *Store) UserTags(ctx context.Context) ([]string, error)

func (*Store) UserTrafficSeries

func (s *Store) UserTrafficSeries(ctx context.Context, userID string, since time.Time) ([]TrafficPoint, error)

func (*Store) UsersForNode

func (s *Store) UsersForNode(ctx context.Context, profileID string, inboundTags []string) ([]ProvisionedUser, error)

UsersForNode returns every (user, inbound tag) pair that should be present in the config of the given node: active users, in a squad, whose squad grants an inbound of the node's profile that the node actually serves.

func (*Store) UsersForProfile added in v0.11.0

func (s *Store) UsersForProfile(ctx context.Context, profileID string) ([]domain.User, error)

func (*Store) UsersMissingWireGuardKeys added in v0.10.0

func (s *Store) UsersMissingWireGuardKeys(ctx context.Context, limit int) ([]string, error)

UsersMissingWireGuardKeys returns the users created before WireGuard existed, so the panel can give them a key pair without an operator touching anything.

type SubscriptionRequest added in v0.4.0

type SubscriptionRequest struct {
	ID        int64     `json:"id"`
	UserID    *string   `json:"userUuid"`
	Username  string    `json:"username"`
	Token     string    `json:"token"`
	IP        string    `json:"ip"`
	UserAgent string    `json:"userAgent"`
	Format    string    `json:"format"`
	Status    int       `json:"status"`
	HWID      string    `json:"hwid"`
	At        time.Time `json:"at"`
}

SubscriptionRequest is one fetch of a subscription link.

type TopUser

type TopUser struct {
	UserID   string `json:"uuid"`
	Username string `json:"username"`
	Bytes    int64  `json:"bytes"`
}

TopUser is an entry of the "biggest consumers" dashboard widget.

type TrafficPoint

type TrafficPoint struct {
	At    time.Time `json:"at"`
	Bytes int64     `json:"bytes"`
}

TrafficPoint is one row of a time series returned to the dashboard.

type UpcomingBill

type UpcomingBill struct {
	NodeID   string    `json:"nodeUuid"`
	NodeName string    `json:"nodeName"`
	Provider string    `json:"provider"`
	Amount   float64   `json:"amount"`
	Currency string    `json:"currency"`
	DueAt    time.Time `json:"dueAt"`
	DaysLeft int       `json:"daysLeft"`
}

type UserFilter

type UserFilter struct {
	Search  string
	Status  string
	SquadID string
	Tag     string
	Limit   int
	Offset  int
	SortBy  string
	Desc    bool
}

type UserInput

type UserInput struct {
	Username          string
	Status            domain.UserStatus
	TrafficLimitBytes int64
	TrafficReset      domain.TrafficResetStrategy
	ExpireAt          *time.Time
	Description       string
	Tag               string
	Email             string
	TelegramID        *int64
	HWIDDeviceLimit   int
	SquadIDs          []string
}

type UserSecrets

type UserSecrets struct {
	ShortUUID        string
	SubscriptionUUID string
	VlessUUID        string
	TrojanPassword   string
	SSPassword       string
	WGPrivateKey     string
	WGPublicKey      string
}

Jump to

Keyboard shortcuts

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