command_types.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. package libbox
  2. import (
  3. "slices"
  4. "strings"
  5. "time"
  6. "github.com/sagernet/sing-box/daemon"
  7. M "github.com/sagernet/sing/common/metadata"
  8. )
  9. type StatusMessage struct {
  10. Memory int64
  11. Goroutines int32
  12. ConnectionsIn int32
  13. ConnectionsOut int32
  14. TrafficAvailable bool
  15. Uplink int64
  16. Downlink int64
  17. UplinkTotal int64
  18. DownlinkTotal int64
  19. }
  20. type SystemProxyStatus struct {
  21. Available bool
  22. Enabled bool
  23. }
  24. type OutboundGroup struct {
  25. Tag string
  26. Type string
  27. Selectable bool
  28. Selected string
  29. IsExpand bool
  30. itemList []*OutboundGroupItem
  31. }
  32. func (g *OutboundGroup) GetItems() OutboundGroupItemIterator {
  33. return newIterator(g.itemList)
  34. }
  35. type OutboundGroupIterator interface {
  36. Next() *OutboundGroup
  37. HasNext() bool
  38. }
  39. type OutboundGroupItem struct {
  40. Tag string
  41. Type string
  42. URLTestTime int64
  43. URLTestDelay int32
  44. }
  45. type OutboundGroupItemIterator interface {
  46. Next() *OutboundGroupItem
  47. HasNext() bool
  48. }
  49. const (
  50. ConnectionStateAll = iota
  51. ConnectionStateActive
  52. ConnectionStateClosed
  53. )
  54. const (
  55. ConnectionEventNew = iota
  56. ConnectionEventUpdate
  57. ConnectionEventClosed
  58. )
  59. const (
  60. closedConnectionMaxAge = int64((5 * time.Minute) / time.Millisecond)
  61. )
  62. type ConnectionEvent struct {
  63. Type int32
  64. ID string
  65. Connection *Connection
  66. UplinkDelta int64
  67. DownlinkDelta int64
  68. ClosedAt int64
  69. }
  70. type ConnectionEvents struct {
  71. Reset bool
  72. events []*ConnectionEvent
  73. }
  74. func (c *ConnectionEvents) Iterator() ConnectionEventIterator {
  75. return newIterator(c.events)
  76. }
  77. type ConnectionEventIterator interface {
  78. Next() *ConnectionEvent
  79. HasNext() bool
  80. }
  81. type Connections struct {
  82. connectionMap map[string]*Connection
  83. input []Connection
  84. filtered []Connection
  85. filterState int32
  86. filterApplied bool
  87. }
  88. func NewConnections() *Connections {
  89. return &Connections{
  90. connectionMap: make(map[string]*Connection),
  91. }
  92. }
  93. func (c *Connections) ApplyEvents(events *ConnectionEvents) {
  94. if events == nil {
  95. return
  96. }
  97. if events.Reset {
  98. c.connectionMap = make(map[string]*Connection)
  99. }
  100. for _, event := range events.events {
  101. switch event.Type {
  102. case ConnectionEventNew:
  103. if event.Connection != nil {
  104. conn := *event.Connection
  105. c.connectionMap[event.ID] = &conn
  106. }
  107. case ConnectionEventUpdate:
  108. if conn, ok := c.connectionMap[event.ID]; ok {
  109. conn.Uplink = event.UplinkDelta
  110. conn.Downlink = event.DownlinkDelta
  111. conn.UplinkTotal += event.UplinkDelta
  112. conn.DownlinkTotal += event.DownlinkDelta
  113. }
  114. case ConnectionEventClosed:
  115. if event.Connection != nil {
  116. conn := *event.Connection
  117. conn.ClosedAt = event.ClosedAt
  118. conn.Uplink = 0
  119. conn.Downlink = 0
  120. c.connectionMap[event.ID] = &conn
  121. continue
  122. }
  123. if conn, ok := c.connectionMap[event.ID]; ok {
  124. conn.ClosedAt = event.ClosedAt
  125. conn.Uplink = 0
  126. conn.Downlink = 0
  127. }
  128. }
  129. }
  130. c.evictClosedConnections(time.Now().UnixMilli())
  131. c.input = c.input[:0]
  132. for _, conn := range c.connectionMap {
  133. c.input = append(c.input, *conn)
  134. }
  135. if c.filterApplied {
  136. c.FilterState(c.filterState)
  137. } else {
  138. c.filtered = c.filtered[:0]
  139. c.filtered = append(c.filtered, c.input...)
  140. }
  141. }
  142. func (c *Connections) evictClosedConnections(nowMilliseconds int64) {
  143. for id, conn := range c.connectionMap {
  144. if conn.ClosedAt == 0 {
  145. continue
  146. }
  147. if nowMilliseconds-conn.ClosedAt > closedConnectionMaxAge {
  148. delete(c.connectionMap, id)
  149. }
  150. }
  151. }
  152. func (c *Connections) FilterState(state int32) {
  153. c.filterApplied = true
  154. c.filterState = state
  155. c.filtered = c.filtered[:0]
  156. switch state {
  157. case ConnectionStateAll:
  158. c.filtered = append(c.filtered, c.input...)
  159. case ConnectionStateActive:
  160. for _, connection := range c.input {
  161. if connection.ClosedAt == 0 {
  162. c.filtered = append(c.filtered, connection)
  163. }
  164. }
  165. case ConnectionStateClosed:
  166. for _, connection := range c.input {
  167. if connection.ClosedAt != 0 {
  168. c.filtered = append(c.filtered, connection)
  169. }
  170. }
  171. }
  172. }
  173. func (c *Connections) SortByDate() {
  174. slices.SortStableFunc(c.filtered, func(x, y Connection) int {
  175. if x.CreatedAt < y.CreatedAt {
  176. return 1
  177. } else if x.CreatedAt > y.CreatedAt {
  178. return -1
  179. } else {
  180. return strings.Compare(y.ID, x.ID)
  181. }
  182. })
  183. }
  184. func (c *Connections) SortByTraffic() {
  185. slices.SortStableFunc(c.filtered, func(x, y Connection) int {
  186. xTraffic := x.Uplink + x.Downlink
  187. yTraffic := y.Uplink + y.Downlink
  188. if xTraffic < yTraffic {
  189. return 1
  190. } else if xTraffic > yTraffic {
  191. return -1
  192. } else {
  193. return strings.Compare(y.ID, x.ID)
  194. }
  195. })
  196. }
  197. func (c *Connections) SortByTrafficTotal() {
  198. slices.SortStableFunc(c.filtered, func(x, y Connection) int {
  199. xTraffic := x.UplinkTotal + x.DownlinkTotal
  200. yTraffic := y.UplinkTotal + y.DownlinkTotal
  201. if xTraffic < yTraffic {
  202. return 1
  203. } else if xTraffic > yTraffic {
  204. return -1
  205. } else {
  206. return strings.Compare(y.ID, x.ID)
  207. }
  208. })
  209. }
  210. func (c *Connections) Iterator() ConnectionIterator {
  211. return newPtrIterator(c.filtered)
  212. }
  213. type ProcessInfo struct {
  214. ProcessID int64
  215. UserID int32
  216. UserName string
  217. ProcessPath string
  218. PackageName string
  219. }
  220. type Connection struct {
  221. ID string
  222. Inbound string
  223. InboundType string
  224. IPVersion int32
  225. Network string
  226. Source string
  227. Destination string
  228. Domain string
  229. Protocol string
  230. User string
  231. FromOutbound string
  232. CreatedAt int64
  233. ClosedAt int64
  234. Uplink int64
  235. Downlink int64
  236. UplinkTotal int64
  237. DownlinkTotal int64
  238. Rule string
  239. Outbound string
  240. OutboundType string
  241. chainList []string
  242. ProcessInfo *ProcessInfo
  243. }
  244. func (c *Connection) Chain() StringIterator {
  245. return newIterator(c.chainList)
  246. }
  247. func (c *Connection) DisplayDestination() string {
  248. destination := M.ParseSocksaddr(c.Destination)
  249. if destination.IsIP() && c.Domain != "" {
  250. destination = M.Socksaddr{
  251. Fqdn: c.Domain,
  252. Port: destination.Port,
  253. }
  254. return destination.String()
  255. }
  256. return c.Destination
  257. }
  258. type ConnectionIterator interface {
  259. Next() *Connection
  260. HasNext() bool
  261. }
  262. func statusMessageFromGRPC(status *daemon.Status) *StatusMessage {
  263. if status == nil {
  264. return nil
  265. }
  266. return &StatusMessage{
  267. Memory: int64(status.Memory),
  268. Goroutines: status.Goroutines,
  269. ConnectionsIn: status.ConnectionsIn,
  270. ConnectionsOut: status.ConnectionsOut,
  271. TrafficAvailable: status.TrafficAvailable,
  272. Uplink: status.Uplink,
  273. Downlink: status.Downlink,
  274. UplinkTotal: status.UplinkTotal,
  275. DownlinkTotal: status.DownlinkTotal,
  276. }
  277. }
  278. func outboundGroupIteratorFromGRPC(groups *daemon.Groups) OutboundGroupIterator {
  279. if groups == nil || len(groups.Group) == 0 {
  280. return newIterator([]*OutboundGroup{})
  281. }
  282. var libboxGroups []*OutboundGroup
  283. for _, g := range groups.Group {
  284. libboxGroup := &OutboundGroup{
  285. Tag: g.Tag,
  286. Type: g.Type,
  287. Selectable: g.Selectable,
  288. Selected: g.Selected,
  289. IsExpand: g.IsExpand,
  290. }
  291. for _, item := range g.Items {
  292. libboxGroup.itemList = append(libboxGroup.itemList, &OutboundGroupItem{
  293. Tag: item.Tag,
  294. Type: item.Type,
  295. URLTestTime: item.UrlTestTime,
  296. URLTestDelay: item.UrlTestDelay,
  297. })
  298. }
  299. libboxGroups = append(libboxGroups, libboxGroup)
  300. }
  301. return newIterator(libboxGroups)
  302. }
  303. func connectionFromGRPC(conn *daemon.Connection) Connection {
  304. var processInfo *ProcessInfo
  305. if conn.ProcessInfo != nil {
  306. processInfo = &ProcessInfo{
  307. ProcessID: int64(conn.ProcessInfo.ProcessId),
  308. UserID: conn.ProcessInfo.UserId,
  309. UserName: conn.ProcessInfo.UserName,
  310. ProcessPath: conn.ProcessInfo.ProcessPath,
  311. PackageName: conn.ProcessInfo.PackageName,
  312. }
  313. }
  314. return Connection{
  315. ID: conn.Id,
  316. Inbound: conn.Inbound,
  317. InboundType: conn.InboundType,
  318. IPVersion: conn.IpVersion,
  319. Network: conn.Network,
  320. Source: conn.Source,
  321. Destination: conn.Destination,
  322. Domain: conn.Domain,
  323. Protocol: conn.Protocol,
  324. User: conn.User,
  325. FromOutbound: conn.FromOutbound,
  326. CreatedAt: conn.CreatedAt,
  327. ClosedAt: conn.ClosedAt,
  328. Uplink: conn.Uplink,
  329. Downlink: conn.Downlink,
  330. UplinkTotal: conn.UplinkTotal,
  331. DownlinkTotal: conn.DownlinkTotal,
  332. Rule: conn.Rule,
  333. Outbound: conn.Outbound,
  334. OutboundType: conn.OutboundType,
  335. chainList: conn.ChainList,
  336. ProcessInfo: processInfo,
  337. }
  338. }
  339. func connectionEventFromGRPC(event *daemon.ConnectionEvent) *ConnectionEvent {
  340. if event == nil {
  341. return nil
  342. }
  343. libboxEvent := &ConnectionEvent{
  344. Type: int32(event.Type),
  345. ID: event.Id,
  346. UplinkDelta: event.UplinkDelta,
  347. DownlinkDelta: event.DownlinkDelta,
  348. ClosedAt: event.ClosedAt,
  349. }
  350. if event.Connection != nil {
  351. conn := connectionFromGRPC(event.Connection)
  352. libboxEvent.Connection = &conn
  353. }
  354. return libboxEvent
  355. }
  356. func connectionEventsFromGRPC(events *daemon.ConnectionEvents) *ConnectionEvents {
  357. if events == nil {
  358. return nil
  359. }
  360. libboxEvents := &ConnectionEvents{
  361. Reset: events.Reset_,
  362. }
  363. for _, event := range events.Events {
  364. if libboxEvent := connectionEventFromGRPC(event); libboxEvent != nil {
  365. libboxEvents.events = append(libboxEvents.events, libboxEvent)
  366. }
  367. }
  368. return libboxEvents
  369. }
  370. func systemProxyStatusFromGRPC(status *daemon.SystemProxyStatus) *SystemProxyStatus {
  371. if status == nil {
  372. return nil
  373. }
  374. return &SystemProxyStatus{
  375. Available: status.Available,
  376. Enabled: status.Enabled,
  377. }
  378. }
  379. func systemProxyStatusToGRPC(status *SystemProxyStatus) *daemon.SystemProxyStatus {
  380. if status == nil {
  381. return nil
  382. }
  383. return &daemon.SystemProxyStatus{
  384. Available: status.Available,
  385. Enabled: status.Enabled,
  386. }
  387. }