Highly-opinionated (ex-bullshit-free) MTPROTO proxy for Telegram. If you use v1.0 or upgrade broke you proxy, please read the chapter Version 2
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

stats.go 3.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package stats
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "strconv"
  6. "time"
  7. humanize "github.com/dustin/go-humanize"
  8. "github.com/9seconds/mtg/config"
  9. "github.com/9seconds/mtg/mtproto"
  10. )
  11. type uptime time.Time
  12. func (u uptime) MarshalJSON() ([]byte, error) {
  13. duration := time.Since(time.Time(u))
  14. value := map[string]string{
  15. "seconds": strconv.Itoa(int(duration.Seconds())),
  16. "human": humanize.Time(time.Time(u)),
  17. }
  18. return json.Marshal(value)
  19. }
  20. type connectionType struct {
  21. IPv6 uint32 `json:"ipv6"`
  22. IPv4 uint32 `json:"ipv4"`
  23. }
  24. type baseConnections struct {
  25. All connectionType `json:"all"`
  26. Abridged connectionType `json:"abridged"`
  27. Intermediate connectionType `json:"intermediate"`
  28. Secure connectionType `json:"secure"`
  29. }
  30. type connections struct {
  31. baseConnections
  32. }
  33. func (c connections) MarshalJSON() ([]byte, error) {
  34. c.All.IPv4 = c.Abridged.IPv4 + c.Intermediate.IPv4 + c.Secure.IPv4
  35. c.All.IPv6 = c.Abridged.IPv6 + c.Intermediate.IPv6 + c.Secure.IPv6
  36. return json.Marshal(c.baseConnections)
  37. }
  38. type traffic struct {
  39. ingress uint64
  40. egress uint64
  41. }
  42. func (t *traffic) dumpValue(value uint64) map[string]interface{} {
  43. return map[string]interface{}{
  44. "bytes": value,
  45. "human": humanize.Bytes(value),
  46. }
  47. }
  48. func (t traffic) MarshalJSON() ([]byte, error) {
  49. value := map[string]map[string]interface{}{
  50. "ingress": t.dumpValue(t.ingress),
  51. "egress": t.dumpValue(t.egress),
  52. }
  53. return json.Marshal(value)
  54. }
  55. type speed struct {
  56. ingress uint64
  57. egress uint64
  58. }
  59. func (s *speed) dumpValue(value uint64) map[string]interface{} {
  60. return map[string]interface{}{
  61. "bytes/s": value,
  62. "human": fmt.Sprintf("%s/s", humanize.Bytes(value)),
  63. }
  64. }
  65. func (s speed) MarshalJSON() ([]byte, error) {
  66. value := map[string]map[string]interface{}{
  67. "ingress": s.dumpValue(s.ingress),
  68. "egress": s.dumpValue(s.egress),
  69. }
  70. return json.Marshal(value)
  71. }
  72. // Stats represents a statistics of the proxy.
  73. type Stats struct {
  74. URLs config.IPURLs `json:"urls"`
  75. Connections connections `json:"connections"`
  76. Traffic traffic `json:"traffic"`
  77. Speed speed `json:"speed"`
  78. Uptime uptime `json:"uptime"`
  79. Crashes uint32 `json:"crashes"`
  80. previousTraffic traffic
  81. }
  82. func (s *Stats) start() {
  83. speedChan := time.Tick(time.Second)
  84. for {
  85. select {
  86. case <-speedChan:
  87. s.handleSpeed()
  88. case event := <-trafficChan:
  89. s.handleTraffic(event)
  90. case event := <-connectionsChan:
  91. s.handleConnection(event)
  92. case getStatsChan := <-statsChan:
  93. s.handleGetStats(getStatsChan)
  94. case <-crashesChan:
  95. s.handleCrash()
  96. }
  97. }
  98. }
  99. func (s *Stats) handleTraffic(evt trafficData) {
  100. if evt.ingress {
  101. s.Traffic.ingress += uint64(evt.traffic)
  102. } else {
  103. s.Traffic.egress += uint64(evt.traffic)
  104. }
  105. }
  106. func (s *Stats) handleSpeed() {
  107. s.Speed.ingress = s.Traffic.ingress - s.previousTraffic.ingress
  108. s.Speed.egress = s.Traffic.egress - s.previousTraffic.egress
  109. s.previousTraffic.ingress = s.Traffic.ingress
  110. s.previousTraffic.egress = s.Traffic.egress
  111. }
  112. func (s *Stats) handleConnection(evt connectionData) {
  113. var inc uint32 = 1
  114. if !evt.connected {
  115. inc = ^uint32(0)
  116. }
  117. var conn *connectionType
  118. switch evt.connectionType {
  119. case mtproto.ConnectionTypeAbridged:
  120. conn = &s.Connections.Abridged
  121. case mtproto.ConnectionTypeSecure:
  122. conn = &s.Connections.Secure
  123. default:
  124. conn = &s.Connections.Intermediate
  125. }
  126. if evt.addr.IP.To4() != nil {
  127. conn.IPv4 += inc
  128. } else {
  129. conn.IPv6 += inc
  130. }
  131. }
  132. func (s *Stats) handleGetStats(getStatsChan chan<- Stats) {
  133. getStatsChan <- *s
  134. }
  135. func (s *Stats) handleCrash() {
  136. s.Crashes++
  137. }
  138. // NewStats creates a new instance of Stats structure.
  139. func NewStats(conf *config.Config) *Stats {
  140. return &Stats{
  141. URLs: conf.GetURLs(),
  142. Uptime: uptime(time.Now()),
  143. }
  144. }