2020-11-25 14:01:53 +03:00
|
|
|
package stats
|
|
|
|
|
2020-12-04 04:36:16 +03:00
|
|
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
2020-11-25 14:01:53 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
2020-12-04 04:36:16 +03:00
|
|
|
"github.com/xtls/xray-core/common"
|
2024-06-29 21:32:57 +03:00
|
|
|
"github.com/xtls/xray-core/common/errors"
|
2020-12-04 04:36:16 +03:00
|
|
|
"github.com/xtls/xray-core/features"
|
2020-11-25 14:01:53 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
// Counter is the interface for stats counters.
|
|
|
|
//
|
|
|
|
// xray:api:stable
|
|
|
|
type Counter interface {
|
|
|
|
// Value is the current value of the counter.
|
|
|
|
Value() int64
|
|
|
|
// Set sets a new value to the counter, and returns the previous one.
|
|
|
|
Set(int64) int64
|
|
|
|
// Add adds a value to the current counter value, and returns the previous value.
|
|
|
|
Add(int64) int64
|
|
|
|
}
|
|
|
|
|
|
|
|
// Channel is the interface for stats channel.
|
|
|
|
//
|
|
|
|
// xray:api:stable
|
|
|
|
type Channel interface {
|
2022-04-01 11:38:27 +03:00
|
|
|
// Runnable implies that Channel is a runnable unit.
|
2020-11-25 14:01:53 +03:00
|
|
|
common.Runnable
|
|
|
|
// Publish broadcasts a message through the channel with a controlling context.
|
|
|
|
Publish(context.Context, interface{})
|
2022-04-01 11:38:27 +03:00
|
|
|
// Subscribers returns all subscribers.
|
2020-11-25 14:01:53 +03:00
|
|
|
Subscribers() []chan interface{}
|
|
|
|
// Subscribe registers for listening to channel stream and returns a new listener channel.
|
|
|
|
Subscribe() (chan interface{}, error)
|
|
|
|
// Unsubscribe unregisters a listener channel from current Channel object.
|
|
|
|
Unsubscribe(chan interface{}) error
|
|
|
|
}
|
|
|
|
|
|
|
|
// SubscribeRunnableChannel subscribes the channel and starts it if there is first subscriber coming.
|
|
|
|
func SubscribeRunnableChannel(c Channel) (chan interface{}, error) {
|
|
|
|
if len(c.Subscribers()) == 0 {
|
|
|
|
if err := c.Start(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return c.Subscribe()
|
|
|
|
}
|
|
|
|
|
2022-04-01 11:38:27 +03:00
|
|
|
// UnsubscribeClosableChannel unsubscribes the channel and close it if there is no more subscriber.
|
2020-11-25 14:01:53 +03:00
|
|
|
func UnsubscribeClosableChannel(c Channel, sub chan interface{}) error {
|
|
|
|
if err := c.Unsubscribe(sub); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if len(c.Subscribers()) == 0 {
|
|
|
|
return c.Close()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Manager is the interface for stats manager.
|
|
|
|
//
|
|
|
|
// xray:api:stable
|
|
|
|
type Manager interface {
|
|
|
|
features.Feature
|
|
|
|
|
|
|
|
// RegisterCounter registers a new counter to the manager. The identifier string must not be empty, and unique among other counters.
|
|
|
|
RegisterCounter(string) (Counter, error)
|
|
|
|
// UnregisterCounter unregisters a counter from the manager by its identifier.
|
|
|
|
UnregisterCounter(string) error
|
|
|
|
// GetCounter returns a counter by its identifier.
|
|
|
|
GetCounter(string) Counter
|
|
|
|
|
|
|
|
// RegisterChannel registers a new channel to the manager. The identifier string must not be empty, and unique among other channels.
|
|
|
|
RegisterChannel(string) (Channel, error)
|
2022-04-01 11:38:27 +03:00
|
|
|
// UnregisterChannel unregisters a channel from the manager by its identifier.
|
2020-11-25 14:01:53 +03:00
|
|
|
UnregisterChannel(string) error
|
|
|
|
// GetChannel returns a channel by its identifier.
|
|
|
|
GetChannel(string) Channel
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetOrRegisterCounter tries to get the StatCounter first. If not exist, it then tries to create a new counter.
|
|
|
|
func GetOrRegisterCounter(m Manager, name string) (Counter, error) {
|
|
|
|
counter := m.GetCounter(name)
|
|
|
|
if counter != nil {
|
|
|
|
return counter, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return m.RegisterCounter(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetOrRegisterChannel tries to get the StatChannel first. If not exist, it then tries to create a new channel.
|
|
|
|
func GetOrRegisterChannel(m Manager, name string) (Channel, error) {
|
|
|
|
channel := m.GetChannel(name)
|
|
|
|
if channel != nil {
|
|
|
|
return channel, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return m.RegisterChannel(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ManagerType returns the type of Manager interface. Can be used to implement common.HasType.
|
|
|
|
//
|
|
|
|
// xray:api:stable
|
|
|
|
func ManagerType() interface{} {
|
|
|
|
return (*Manager)(nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NoopManager is an implementation of Manager, which doesn't has actual functionalities.
|
|
|
|
type NoopManager struct{}
|
|
|
|
|
|
|
|
// Type implements common.HasType.
|
|
|
|
func (NoopManager) Type() interface{} {
|
|
|
|
return ManagerType()
|
|
|
|
}
|
|
|
|
|
|
|
|
// RegisterCounter implements Manager.
|
|
|
|
func (NoopManager) RegisterCounter(string) (Counter, error) {
|
2024-06-29 21:32:57 +03:00
|
|
|
return nil, errors.New("not implemented")
|
2020-11-25 14:01:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// UnregisterCounter implements Manager.
|
|
|
|
func (NoopManager) UnregisterCounter(string) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetCounter implements Manager.
|
|
|
|
func (NoopManager) GetCounter(string) Counter {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// RegisterChannel implements Manager.
|
|
|
|
func (NoopManager) RegisterChannel(string) (Channel, error) {
|
2024-06-29 21:32:57 +03:00
|
|
|
return nil, errors.New("not implemented")
|
2020-11-25 14:01:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// UnregisterChannel implements Manager.
|
|
|
|
func (NoopManager) UnregisterChannel(string) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetChannel implements Manager.
|
|
|
|
func (NoopManager) GetChannel(string) Channel {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start implements common.Runnable.
|
|
|
|
func (NoopManager) Start() error { return nil }
|
|
|
|
|
|
|
|
// Close implements common.Closable.
|
|
|
|
func (NoopManager) Close() error { return nil }
|