| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- package libbox
- import (
- "slices"
- "strings"
- "time"
- "github.com/sagernet/sing-box/daemon"
- M "github.com/sagernet/sing/common/metadata"
- )
- type StatusMessage struct {
- Memory int64
- Goroutines int32
- ConnectionsIn int32
- ConnectionsOut int32
- TrafficAvailable bool
- Uplink int64
- Downlink int64
- UplinkTotal int64
- DownlinkTotal int64
- }
- type SystemProxyStatus struct {
- Available bool
- Enabled bool
- }
- type OutboundGroup struct {
- Tag string
- Type string
- Selectable bool
- Selected string
- IsExpand bool
- itemList []*OutboundGroupItem
- }
- func (g *OutboundGroup) GetItems() OutboundGroupItemIterator {
- return newIterator(g.itemList)
- }
- type OutboundGroupIterator interface {
- Next() *OutboundGroup
- HasNext() bool
- }
- type OutboundGroupItem struct {
- Tag string
- Type string
- URLTestTime int64
- URLTestDelay int32
- }
- type OutboundGroupItemIterator interface {
- Next() *OutboundGroupItem
- HasNext() bool
- }
- const (
- ConnectionStateAll = iota
- ConnectionStateActive
- ConnectionStateClosed
- )
- const (
- ConnectionEventNew = iota
- ConnectionEventUpdate
- ConnectionEventClosed
- )
- const (
- closedConnectionMaxAge = int64((5 * time.Minute) / time.Millisecond)
- )
- type ConnectionEvent struct {
- Type int32
- ID string
- Connection *Connection
- UplinkDelta int64
- DownlinkDelta int64
- ClosedAt int64
- }
- type ConnectionEvents struct {
- Reset bool
- events []*ConnectionEvent
- }
- func (c *ConnectionEvents) Iterator() ConnectionEventIterator {
- return newIterator(c.events)
- }
- type ConnectionEventIterator interface {
- Next() *ConnectionEvent
- HasNext() bool
- }
- type Connections struct {
- connectionMap map[string]*Connection
- input []Connection
- filtered []Connection
- filterState int32
- filterApplied bool
- }
- func NewConnections() *Connections {
- return &Connections{
- connectionMap: make(map[string]*Connection),
- }
- }
- func (c *Connections) ApplyEvents(events *ConnectionEvents) {
- if events == nil {
- return
- }
- if events.Reset {
- c.connectionMap = make(map[string]*Connection)
- }
- for _, event := range events.events {
- switch event.Type {
- case ConnectionEventNew:
- if event.Connection != nil {
- conn := *event.Connection
- c.connectionMap[event.ID] = &conn
- }
- case ConnectionEventUpdate:
- if conn, ok := c.connectionMap[event.ID]; ok {
- conn.Uplink = event.UplinkDelta
- conn.Downlink = event.DownlinkDelta
- conn.UplinkTotal += event.UplinkDelta
- conn.DownlinkTotal += event.DownlinkDelta
- }
- case ConnectionEventClosed:
- if event.Connection != nil {
- conn := *event.Connection
- conn.ClosedAt = event.ClosedAt
- conn.Uplink = 0
- conn.Downlink = 0
- c.connectionMap[event.ID] = &conn
- continue
- }
- if conn, ok := c.connectionMap[event.ID]; ok {
- conn.ClosedAt = event.ClosedAt
- conn.Uplink = 0
- conn.Downlink = 0
- }
- }
- }
- c.evictClosedConnections(time.Now().UnixMilli())
- c.input = c.input[:0]
- for _, conn := range c.connectionMap {
- c.input = append(c.input, *conn)
- }
- if c.filterApplied {
- c.FilterState(c.filterState)
- } else {
- c.filtered = c.filtered[:0]
- c.filtered = append(c.filtered, c.input...)
- }
- }
- func (c *Connections) evictClosedConnections(nowMilliseconds int64) {
- for id, conn := range c.connectionMap {
- if conn.ClosedAt == 0 {
- continue
- }
- if nowMilliseconds-conn.ClosedAt > closedConnectionMaxAge {
- delete(c.connectionMap, id)
- }
- }
- }
- func (c *Connections) FilterState(state int32) {
- c.filterApplied = true
- c.filterState = state
- c.filtered = c.filtered[:0]
- switch state {
- case ConnectionStateAll:
- c.filtered = append(c.filtered, c.input...)
- case ConnectionStateActive:
- for _, connection := range c.input {
- if connection.ClosedAt == 0 {
- c.filtered = append(c.filtered, connection)
- }
- }
- case ConnectionStateClosed:
- for _, connection := range c.input {
- if connection.ClosedAt != 0 {
- c.filtered = append(c.filtered, connection)
- }
- }
- }
- }
- func (c *Connections) SortByDate() {
- slices.SortStableFunc(c.filtered, func(x, y Connection) int {
- if x.CreatedAt < y.CreatedAt {
- return 1
- } else if x.CreatedAt > y.CreatedAt {
- return -1
- } else {
- return strings.Compare(y.ID, x.ID)
- }
- })
- }
- func (c *Connections) SortByTraffic() {
- slices.SortStableFunc(c.filtered, func(x, y Connection) int {
- xTraffic := x.Uplink + x.Downlink
- yTraffic := y.Uplink + y.Downlink
- if xTraffic < yTraffic {
- return 1
- } else if xTraffic > yTraffic {
- return -1
- } else {
- return strings.Compare(y.ID, x.ID)
- }
- })
- }
- func (c *Connections) SortByTrafficTotal() {
- slices.SortStableFunc(c.filtered, func(x, y Connection) int {
- xTraffic := x.UplinkTotal + x.DownlinkTotal
- yTraffic := y.UplinkTotal + y.DownlinkTotal
- if xTraffic < yTraffic {
- return 1
- } else if xTraffic > yTraffic {
- return -1
- } else {
- return strings.Compare(y.ID, x.ID)
- }
- })
- }
- func (c *Connections) Iterator() ConnectionIterator {
- return newPtrIterator(c.filtered)
- }
- type ProcessInfo struct {
- ProcessID int64
- UserID int32
- UserName string
- ProcessPath string
- packageNames []string
- }
- func (p *ProcessInfo) PackageNames() StringIterator {
- return newIterator(p.packageNames)
- }
- type Connection struct {
- ID string
- Inbound string
- InboundType string
- IPVersion int32
- Network string
- Source string
- Destination string
- Domain string
- Protocol string
- User string
- FromOutbound string
- CreatedAt int64
- ClosedAt int64
- Uplink int64
- Downlink int64
- UplinkTotal int64
- DownlinkTotal int64
- Rule string
- Outbound string
- OutboundType string
- chainList []string
- ProcessInfo *ProcessInfo
- }
- func (c *Connection) Chain() StringIterator {
- return newIterator(c.chainList)
- }
- func (c *Connection) DisplayDestination() string {
- destination := M.ParseSocksaddr(c.Destination)
- if destination.IsIP() && c.Domain != "" {
- destination = M.Socksaddr{
- Fqdn: c.Domain,
- Port: destination.Port,
- }
- return destination.String()
- }
- return c.Destination
- }
- type ConnectionIterator interface {
- Next() *Connection
- HasNext() bool
- }
- func statusMessageFromGRPC(status *daemon.Status) *StatusMessage {
- if status == nil {
- return nil
- }
- return &StatusMessage{
- Memory: int64(status.Memory),
- Goroutines: status.Goroutines,
- ConnectionsIn: status.ConnectionsIn,
- ConnectionsOut: status.ConnectionsOut,
- TrafficAvailable: status.TrafficAvailable,
- Uplink: status.Uplink,
- Downlink: status.Downlink,
- UplinkTotal: status.UplinkTotal,
- DownlinkTotal: status.DownlinkTotal,
- }
- }
- func outboundGroupIteratorFromGRPC(groups *daemon.Groups) OutboundGroupIterator {
- if groups == nil || len(groups.Group) == 0 {
- return newIterator([]*OutboundGroup{})
- }
- var libboxGroups []*OutboundGroup
- for _, g := range groups.Group {
- libboxGroup := &OutboundGroup{
- Tag: g.Tag,
- Type: g.Type,
- Selectable: g.Selectable,
- Selected: g.Selected,
- IsExpand: g.IsExpand,
- }
- for _, item := range g.Items {
- libboxGroup.itemList = append(libboxGroup.itemList, &OutboundGroupItem{
- Tag: item.Tag,
- Type: item.Type,
- URLTestTime: item.UrlTestTime,
- URLTestDelay: item.UrlTestDelay,
- })
- }
- libboxGroups = append(libboxGroups, libboxGroup)
- }
- return newIterator(libboxGroups)
- }
- func outboundGroupItemListFromGRPC(list *daemon.OutboundList) OutboundGroupItemIterator {
- if list == nil || len(list.Outbounds) == 0 {
- return newIterator([]*OutboundGroupItem{})
- }
- var items []*OutboundGroupItem
- for _, ob := range list.Outbounds {
- items = append(items, &OutboundGroupItem{
- Tag: ob.Tag,
- Type: ob.Type,
- URLTestTime: ob.UrlTestTime,
- URLTestDelay: ob.UrlTestDelay,
- })
- }
- return newIterator(items)
- }
- func connectionFromGRPC(conn *daemon.Connection) Connection {
- var processInfo *ProcessInfo
- if conn.ProcessInfo != nil {
- processInfo = &ProcessInfo{
- ProcessID: int64(conn.ProcessInfo.ProcessId),
- UserID: conn.ProcessInfo.UserId,
- UserName: conn.ProcessInfo.UserName,
- ProcessPath: conn.ProcessInfo.ProcessPath,
- packageNames: conn.ProcessInfo.PackageNames,
- }
- }
- return Connection{
- ID: conn.Id,
- Inbound: conn.Inbound,
- InboundType: conn.InboundType,
- IPVersion: conn.IpVersion,
- Network: conn.Network,
- Source: conn.Source,
- Destination: conn.Destination,
- Domain: conn.Domain,
- Protocol: conn.Protocol,
- User: conn.User,
- FromOutbound: conn.FromOutbound,
- CreatedAt: conn.CreatedAt,
- ClosedAt: conn.ClosedAt,
- Uplink: conn.Uplink,
- Downlink: conn.Downlink,
- UplinkTotal: conn.UplinkTotal,
- DownlinkTotal: conn.DownlinkTotal,
- Rule: conn.Rule,
- Outbound: conn.Outbound,
- OutboundType: conn.OutboundType,
- chainList: conn.ChainList,
- ProcessInfo: processInfo,
- }
- }
- func connectionEventFromGRPC(event *daemon.ConnectionEvent) *ConnectionEvent {
- if event == nil {
- return nil
- }
- libboxEvent := &ConnectionEvent{
- Type: int32(event.Type),
- ID: event.Id,
- UplinkDelta: event.UplinkDelta,
- DownlinkDelta: event.DownlinkDelta,
- ClosedAt: event.ClosedAt,
- }
- if event.Connection != nil {
- conn := connectionFromGRPC(event.Connection)
- libboxEvent.Connection = &conn
- }
- return libboxEvent
- }
- func connectionEventsFromGRPC(events *daemon.ConnectionEvents) *ConnectionEvents {
- if events == nil {
- return nil
- }
- libboxEvents := &ConnectionEvents{
- Reset: events.Reset_,
- }
- for _, event := range events.Events {
- if libboxEvent := connectionEventFromGRPC(event); libboxEvent != nil {
- libboxEvents.events = append(libboxEvents.events, libboxEvent)
- }
- }
- return libboxEvents
- }
- func systemProxyStatusFromGRPC(status *daemon.SystemProxyStatus) *SystemProxyStatus {
- if status == nil {
- return nil
- }
- return &SystemProxyStatus{
- Available: status.Available,
- Enabled: status.Enabled,
- }
- }
- func systemProxyStatusToGRPC(status *SystemProxyStatus) *daemon.SystemProxyStatus {
- if status == nil {
- return nil
- }
- return &daemon.SystemProxyStatus{
- Available: status.Available,
- Enabled: status.Enabled,
- }
- }
|