stats.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package stats
  2. //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
  3. import (
  4. "context"
  5. "github.com/xtls/xray-core/common"
  6. "github.com/xtls/xray-core/common/errors"
  7. "github.com/xtls/xray-core/features"
  8. )
  9. // Counter is the interface for stats counters.
  10. //
  11. // xray:api:stable
  12. type Counter interface {
  13. // Value is the current value of the counter.
  14. Value() int64
  15. // Set sets a new value to the counter, and returns the previous one.
  16. Set(int64) int64
  17. // Add adds a value to the current counter value, and returns the previous value.
  18. Add(int64) int64
  19. }
  20. // Channel is the interface for stats channel.
  21. //
  22. // xray:api:stable
  23. type Channel interface {
  24. // Runnable implies that Channel is a runnable unit.
  25. common.Runnable
  26. // Publish broadcasts a message through the channel with a controlling context.
  27. Publish(context.Context, interface{})
  28. // Subscribers returns all subscribers.
  29. Subscribers() []chan interface{}
  30. // Subscribe registers for listening to channel stream and returns a new listener channel.
  31. Subscribe() (chan interface{}, error)
  32. // Unsubscribe unregisters a listener channel from current Channel object.
  33. Unsubscribe(chan interface{}) error
  34. }
  35. // SubscribeRunnableChannel subscribes the channel and starts it if there is first subscriber coming.
  36. func SubscribeRunnableChannel(c Channel) (chan interface{}, error) {
  37. if len(c.Subscribers()) == 0 {
  38. if err := c.Start(); err != nil {
  39. return nil, err
  40. }
  41. }
  42. return c.Subscribe()
  43. }
  44. // UnsubscribeClosableChannel unsubscribes the channel and close it if there is no more subscriber.
  45. func UnsubscribeClosableChannel(c Channel, sub chan interface{}) error {
  46. if err := c.Unsubscribe(sub); err != nil {
  47. return err
  48. }
  49. if len(c.Subscribers()) == 0 {
  50. return c.Close()
  51. }
  52. return nil
  53. }
  54. // Manager is the interface for stats manager.
  55. //
  56. // xray:api:stable
  57. type Manager interface {
  58. features.Feature
  59. // RegisterCounter registers a new counter to the manager. The identifier string must not be empty, and unique among other counters.
  60. RegisterCounter(string) (Counter, error)
  61. // UnregisterCounter unregisters a counter from the manager by its identifier.
  62. UnregisterCounter(string) error
  63. // GetCounter returns a counter by its identifier.
  64. GetCounter(string) Counter
  65. // RegisterChannel registers a new channel to the manager. The identifier string must not be empty, and unique among other channels.
  66. RegisterChannel(string) (Channel, error)
  67. // UnregisterChannel unregisters a channel from the manager by its identifier.
  68. UnregisterChannel(string) error
  69. // GetChannel returns a channel by its identifier.
  70. GetChannel(string) Channel
  71. }
  72. // GetOrRegisterCounter tries to get the StatCounter first. If not exist, it then tries to create a new counter.
  73. func GetOrRegisterCounter(m Manager, name string) (Counter, error) {
  74. counter := m.GetCounter(name)
  75. if counter != nil {
  76. return counter, nil
  77. }
  78. return m.RegisterCounter(name)
  79. }
  80. // GetOrRegisterChannel tries to get the StatChannel first. If not exist, it then tries to create a new channel.
  81. func GetOrRegisterChannel(m Manager, name string) (Channel, error) {
  82. channel := m.GetChannel(name)
  83. if channel != nil {
  84. return channel, nil
  85. }
  86. return m.RegisterChannel(name)
  87. }
  88. // ManagerType returns the type of Manager interface. Can be used to implement common.HasType.
  89. //
  90. // xray:api:stable
  91. func ManagerType() interface{} {
  92. return (*Manager)(nil)
  93. }
  94. // NoopManager is an implementation of Manager, which doesn't has actual functionalities.
  95. type NoopManager struct{}
  96. // Type implements common.HasType.
  97. func (NoopManager) Type() interface{} {
  98. return ManagerType()
  99. }
  100. // RegisterCounter implements Manager.
  101. func (NoopManager) RegisterCounter(string) (Counter, error) {
  102. return nil, errors.New("not implemented")
  103. }
  104. // UnregisterCounter implements Manager.
  105. func (NoopManager) UnregisterCounter(string) error {
  106. return nil
  107. }
  108. // GetCounter implements Manager.
  109. func (NoopManager) GetCounter(string) Counter {
  110. return nil
  111. }
  112. // RegisterChannel implements Manager.
  113. func (NoopManager) RegisterChannel(string) (Channel, error) {
  114. return nil, errors.New("not implemented")
  115. }
  116. // UnregisterChannel implements Manager.
  117. func (NoopManager) UnregisterChannel(string) error {
  118. return nil
  119. }
  120. // GetChannel implements Manager.
  121. func (NoopManager) GetChannel(string) Channel {
  122. return nil
  123. }
  124. // Start implements common.Runnable.
  125. func (NoopManager) Start() error { return nil }
  126. // Close implements common.Closable.
  127. func (NoopManager) Close() error { return nil }