Documentation
¶
Overview ¶
Package native implements the subscription package's v2 administrator routes in the package itself, on the kernel's v2_subscription_group, v2_subscription_template, v2_plan_subscription_group and v2_subscription_group_node_protocols tables adopted in place (kernel.storage.adopt). Legacy handlers and native routes share the tables, so a route can switch between them at any time. Responses are byte-compatible with the legacy handlers (internal/tests/subscriptioncompat); the bound and answered types mirror the kernel model (package model).
Subscription group membership (v2_user_subscription_group) is subscriber state, which only the kernel writes: granting a user a group, taking it away and deleting a group's members go through KernelSubscriber (kernel.subscriber.groups.v1), and without it those routes stay legacy. So does the user's subscription summary, which the kernel caches and answers through KernelSubscriber (kernel.subscriber.summary.v1).
Other domains are read through kernel views only:
- kapi_plan_catalog_v1 for whether a plan exists;
- kapi_subscriber_entitlement_v1 for whether a user exists and the traffic group members used;
- kapi_user_subscription_group_v1 for the subscription groups a user holds and until when;
- kapi_node_protocol_v1 and kapi_node_heartbeat_v1 for which node a protocol belongs to and when it last reported.
Four routes have no native handler and stay bridged; see bridgedRoutes in packages/subscription/control.
Index ¶
- Constants
- func DeleteGroupRequestID(groupID uint, token string) string
- func GrantRequestID(userID, groupID uint, expireAt, transferEnable, nextRenewPrice *int64, ...) string
- func RevokeRequestID(userID, groupID uint, token string) string
- type Entitlement
- type NodeHeartbeat
- type NodeProtocol
- type PlanCatalog
- type Service
- func (s *Service) AssignPlanGroup(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) CreateGroup(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) CreateTemplate(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) DeleteGroup(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) DeleteTemplate(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) Formats(context.Context, pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) GrantUserGroup(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) Group(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) GroupTemplates(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) Groups(ctx context.Context, _ pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) Handlers() map[string]pluginhostsdk.NativeHandler
- func (s *Service) LinkProtocols(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) PlanGroups(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) ProtocolTypes(context.Context, pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) RemovePlanGroup(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) RevokeUserGroup(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) Stats(ctx context.Context, _ pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) Summary(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) Template(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) UpdateGroup(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) UpdateTemplate(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- func (s *Service) UserGroups(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
- type Subscriber
- type Summary
- type UserGroup
Constants ¶
const ( DeleteGroupRouteID = "subscription.admin.subscription.groups.id.delete" GrantUserGroupRouteID = "subscription.admin.subscription.users.user_id.groups.post" RevokeUserGroupRouteID = "subscription.admin.subscription.users.user_id.groups.group_id.delete" )
The routes that change subscription group membership; they have a native handler only with a Subscriber.
const SummaryRouteID = "subscription.user.subscription.get"
SummaryRouteID is GET /api/v2/user/subscription; it has a native handler only with a Subscriber.
Variables ¶
This section is empty.
Functions ¶
func DeleteGroupRequestID ¶
DeleteGroupRequestID names the removal of a deleted group's members, as GrantRequestID names a grant (service.SubscriptionGroupDeleteRequestID).
func GrantRequestID ¶
func GrantRequestID(userID, groupID uint, expireAt, transferEnable, nextRenewPrice *int64, token string) string
GrantRequestID names an administrator's grant of a subscription group to a user in Control's subscriber request ledger, so a retried request is applied once. token identifies the HTTP request: its Idempotency-Key, else its X-Request-ID, else a fresh random value. The digest also covers the granted fields, so a key reused for other values is another grant. The kernel's legacy handler derives the same id (service.SubscriptionGroupGrantRequestID), so a retry is recognized whichever side serves it.
func RevokeRequestID ¶
RevokeRequestID names an administrator's removal of a user's group, as GrantRequestID names a grant (service.SubscriptionGroupRevokeRequestID).
Types ¶
type Entitlement ¶
Entitlement is the part of a kapi_subscriber_entitlement_v1 row the routes read: that the user exists, and the traffic they used.
type NodeHeartbeat ¶
NodeHeartbeat is a row of kapi_node_heartbeat_v1: when a node last reported.
func (NodeHeartbeat) TableName ¶
func (NodeHeartbeat) TableName() string
TableName is the kernel view.
type NodeProtocol ¶
NodeProtocol is a row of kapi_node_protocol_v1: a node protocol and its node, without its settings.
func (NodeProtocol) TableName ¶
func (NodeProtocol) TableName() string
TableName is the kernel view.
type PlanCatalog ¶
type PlanCatalog struct {
ID uint `gorm:"primaryKey"`
}
PlanCatalog is the part of a kapi_plan_catalog_v1 row the routes read.
type Service ¶
type Service struct {
// Open returns the package's storage connection, on which the adopted
// tables and the granted views are visible.
Open func(ctx context.Context) (*gorm.DB, error)
// Subscriber is the kernel's KernelSubscriber; without it the routes
// that change subscription group membership and the user's
// subscription summary have no native handler and stay legacy.
Subscriber Subscriber
// Now defaults to time.Now.
Now func() time.Time
// NewToken names a request that carries neither an Idempotency-Key nor
// an X-Request-ID; it defaults to a random UUID.
NewToken func() string
}
Service holds what the native routes need.
func (*Service) AssignPlanGroup ¶
func (s *Service) AssignPlanGroup(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
AssignPlanGroup is POST /api/v2/admin/subscription/plans/:plan_id/groups: the plan grants the group, once.
func (*Service) CreateGroup ¶
func (s *Service) CreateGroup(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
CreateGroup is POST /api/v2/admin/subscription/groups. As in the kernel, only the group's own columns are written: templates and protocols in the body are dropped.
func (*Service) CreateTemplate ¶
func (s *Service) CreateTemplate(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
CreateTemplate is POST /api/v2/admin/subscription/groups/:id/templates. As in the kernel, only the template's own columns are written, in the group the path names: a nested "group" is dropped.
func (*Service) DeleteGroup ¶
func (s *Service) DeleteGroup(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
DeleteGroup is DELETE /api/v2/admin/subscription/groups/:id. Control first takes the group from its members (KernelSubscriber.RemoveSubscriptionGroupMembers); then the group's templates, plan links and node protocol links go with the group, in one transaction. A retry after a failure in between finds no members and completes.
func (*Service) DeleteTemplate ¶
func (s *Service) DeleteTemplate(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
DeleteTemplate is DELETE /api/v2/admin/subscription/templates/:id.
func (*Service) Formats ¶
func (s *Service) Formats(context.Context, pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
Formats is GET /api/v2/admin/subscription/formats: the formats a subscription link can be rendered in.
func (*Service) GrantUserGroup ¶
func (s *Service) GrantUserGroup(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
GrantUserGroup is POST /api/v2/admin/subscription/users/:user_id/groups: the user holds the group, with its own expiry, traffic and renewal price when given. Control creates the membership, or sets the given fields of an existing one (KernelSubscriber.GrantSubscriptionGroup).
func (*Service) Group ¶
func (s *Service) Group(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
Group is GET /api/v2/admin/subscription/groups/:id, with its templates.
func (*Service) GroupTemplates ¶
func (s *Service) GroupTemplates(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
GroupTemplates is GET /api/v2/admin/subscription/groups/:id/templates.
func (*Service) Groups ¶
func (s *Service) Groups(ctx context.Context, _ pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
Groups is GET /api/v2/admin/subscription/groups.
func (*Service) Handlers ¶
func (s *Service) Handlers() map[string]pluginhostsdk.NativeHandler
Handlers returns the native handlers by route id.
func (*Service) LinkProtocols ¶
func (s *Service) LinkProtocols(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
LinkProtocols is POST /api/v2/admin/subscription/groups/:id/protocols: the group's node protocols become exactly the listed ones. A protocol is known by kapi_node_protocol_v1; the link rows are the adopted v2_subscription_group_node_protocols. The kernel's association replace also touches the group's updated_at, and so does this.
func (*Service) PlanGroups ¶
func (s *Service) PlanGroups(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
PlanGroups is GET /api/v2/admin/subscription/plans/:plan_id/groups.
func (*Service) ProtocolTypes ¶
func (s *Service) ProtocolTypes(context.Context, pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
ProtocolTypes is GET /api/v2/admin/subscription/protocols: the protocol types a template can have.
func (*Service) RemovePlanGroup ¶
func (s *Service) RemovePlanGroup(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
RemovePlanGroup is DELETE /api/v2/admin/subscription/plans/:plan_id/groups/:group_id.
func (*Service) RevokeUserGroup ¶
func (s *Service) RevokeUserGroup(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
RevokeUserGroup is DELETE /api/v2/admin/subscription/users/:user_id/groups/:group_id (KernelSubscriber.RevokeSubscriptionGroup).
func (*Service) Stats ¶
func (s *Service) Stats(ctx context.Context, _ pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
Stats is GET /api/v2/admin/subscription/stats. Members and their expiry come from kapi_user_subscription_group_v1, their traffic from kapi_subscriber_entitlement_v1, and a protocol's node and its last report from kapi_node_protocol_v1 and kapi_node_heartbeat_v1. As in the kernel, a count that fails stays zero.
func (*Service) Summary ¶
func (s *Service) Summary(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
Summary is GET /api/v2/user/subscription: the caller's summary the kernel caches for 30 seconds, read through KernelSubscriber.GetSubscriptionSummary (kernel.subscriber.summary.v1), with the subscription link settings the kernel adds on every call. The kernel keeps the one cache both modes read, so a native answer carries the summary and cached_at the legacy handler would, and refresh=true (only that exact value, as gin's c.Query) rebuilds it.
func (*Service) Template ¶
func (s *Service) Template(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
Template is GET /api/v2/admin/subscription/templates/:id.
func (*Service) UpdateGroup ¶
func (s *Service) UpdateGroup(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
UpdateGroup is PUT /api/v2/admin/subscription/groups/:id. The body replaces every column, as the kernel's Save does: a missing field is written as its zero value, and an unknown id creates the group.
func (*Service) UpdateTemplate ¶
func (s *Service) UpdateTemplate(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
UpdateTemplate is PUT /api/v2/admin/subscription/templates/:id: a partial update by column, as the kernel's UpdateTemplateFields does, answered with the stored template.
func (*Service) UserGroups ¶
func (s *Service) UserGroups(ctx context.Context, request pluginhostsdk.NativeRequest) (pluginhostsdk.NativeResponse, error)
UserGroups is GET /api/v2/admin/subscription/users/:user_id/groups: the groups a user holds and that have not expired, from kapi_user_subscription_group_v1.
type Subscriber ¶
type Subscriber interface {
GrantSubscriptionGroup(ctx context.Context, in *kernelsubscriberv1.GrantSubscriptionGroupRequest, opts ...grpc.CallOption) (*kernelsubscriberv1.GrantSubscriptionGroupResponse, error)
RevokeSubscriptionGroup(ctx context.Context, in *kernelsubscriberv1.RevokeSubscriptionGroupRequest, opts ...grpc.CallOption) (*kernelsubscriberv1.RevokeSubscriptionGroupResponse, error)
RemoveSubscriptionGroupMembers(ctx context.Context, in *kernelsubscriberv1.RemoveSubscriptionGroupMembersRequest, opts ...grpc.CallOption) (*kernelsubscriberv1.RemoveSubscriptionGroupMembersResponse, error)
GetSubscriptionSummary(ctx context.Context, in *kernelsubscriberv1.GetSubscriptionSummaryRequest, opts ...grpc.CallOption) (*kernelsubscriberv1.GetSubscriptionSummaryResponse, error)
}
Subscriber is the part of KernelSubscriber the native routes call: the membership family (kernel.subscriber.groups.v1), since v2_user_subscription_group is subscriber state the kernel alone writes, and the subscription summary (kernel.subscriber.summary.v1), which the kernel caches.
type Summary ¶
type Summary struct {
UserID uint64 `json:"user_id"`
Email string `json:"email"`
PlanID *uint64 `json:"plan_id"`
PlanName string `json:"plan_name"`
TransferEnable int64 `json:"transfer_enable"`
UsedTraffic int64 `json:"used_traffic"`
UploadTraffic int64 `json:"upload_traffic"`
DownloadTraffic int64 `json:"download_traffic"`
ExpiredAt int64 `json:"expired_at"`
IsExpired bool `json:"is_expired"`
DaysRemaining int64 `json:"days_remaining"`
UsagePercent float64 `json:"usage_percent"`
SubscribePath string `json:"subscribe_path,omitempty"`
SubscribeDomains []string `json:"subscribe_domains,omitempty"`
CachedAt time.Time `json:"cached_at"`
}
Summary is the user's subscription summary, with the fields and tags of the kernel's service.UserSubscription.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package model mirrors the kernel model types the subscription routes bind request bodies to and answer with: the same type names, fields and tags, in a package of the same name.
|
Package model mirrors the kernel model types the subscription routes bind request bodies to and answer with: the same type names, fields and tags, in a package of the same name. |