package mihomoapi import ( "encoding/json" "fmt" "time" ) type ConnectionSnapshot struct { Connections []Connection `json:"connections"` } type Connection struct { ID string `json:"id"` Metadata ConnectionMeta `json:"metadata"` Upload int64 `json:"upload"` Download int64 `json:"download"` Start time.Time `json:"start"` Chains []string `json:"chains"` Rule string `json:"rule"` RulePayload string `json:"rulePayload"` } type ConnectionMeta struct { Network string `json:"network"` Host string `json:"host"` RemoteDestination string `json:"remoteDestination"` DestinationIP string `json:"destinationIP"` DestinationPort string `json:"destinationPort"` SniffHost string `json:"sniffHost"` } func (c *Client) ConnectionSnapshot() (*ConnectionSnapshot, error) { var snap ConnectionSnapshot if err := c.getJSON("/connections", &snap); err != nil { return nil, err } return &snap, nil } // ParseConnectionSnapshot decodes Mihomo /connections JSON. func ParseConnectionSnapshot(data []byte) (*ConnectionSnapshot, error) { var snap ConnectionSnapshot if err := json.Unmarshal(data, &snap); err != nil { return nil, err } return &snap, nil } func (conn *Connection) RequestHost() string { if conn.Metadata.Host != "" { return conn.Metadata.Host } if conn.Metadata.SniffHost != "" { return conn.Metadata.SniffHost } if conn.Metadata.RemoteDestination != "" { return conn.Metadata.RemoteDestination } if conn.Metadata.DestinationIP != "" { return fmt.Sprintf("%s:%s", conn.Metadata.DestinationIP, conn.Metadata.DestinationPort) } return "" } func (conn *Connection) RuleLine() string { if conn.Rule == "" { return "" } if conn.RulePayload == "" { return conn.Rule } return conn.Rule + "," + conn.RulePayload } func (conn *Connection) OutboundNode() string { return ResolveLeafOutbound(conn.Chains, nil) } func (conn *Connection) LeafOutbound(policyGroups map[string]bool) string { return ResolveLeafOutbound(conn.Chains, policyGroups) } func (conn *Connection) ChainString() string { if len(conn.Chains) == 0 { return "" } b, _ := json.Marshal(conn.Chains) return string(b) } func (conn *Connection) IsSuccess() bool { for _, ch := range conn.Chains { if ch == "REJECT" || ch == "REJECT-DROP" { return false } } return conn.Upload+conn.Download > 0 }