Skip to content

Commit

Permalink
refactor: set V2Ray API in configuration (#138)
Browse files Browse the repository at this point in the history
Stats and servers, a dance so grand,
With every change, more in command.
Modular ways, the future bright,
For network paths, a guiding light. 🌟
  • Loading branch information
xchacha20-poly1305 authored Jul 13, 2024
1 parent 846ec04 commit 3dcc6e5
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ class TrafficLooper(
trafficUpdater = TrafficUpdater(
box = proxy.box, items = idMap.values.toList()
)
proxy.box.setV2rayStats(tags.joinToString("\n"))
}

trafficUpdater.updateAll()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ import moe.matsuri.nb4a.SingBoxOptions.Rule_DefaultOptions
import moe.matsuri.nb4a.SingBoxOptions.User
import moe.matsuri.nb4a.SingBoxOptionsUtil
import moe.matsuri.nb4a.PREFIX_IP_DNS
import moe.matsuri.nb4a.SingBoxOptions.V2RayAPIOptions
import moe.matsuri.nb4a.SingBoxOptions.V2RayStatsServiceOptions
import moe.matsuri.nb4a.checkEmpty
import moe.matsuri.nb4a.makeSingBoxRule
import moe.matsuri.nb4a.makeSingBoxRuleSet
Expand Down Expand Up @@ -212,6 +214,13 @@ fun buildConfig(

return MyOptions().apply {
if (!forTest) experimental = ExperimentalOptions().apply {
if (!forExport) v2ray_api = V2RayAPIOptions().apply {
listen = "$LOCALHOST4:0" // Never really listen
stats = V2RayStatsServiceOptions().also {
it.enabled = true
it.outbounds = tagMap.values.toList() + TAG_PROXY + TAG_DIRECT
}
}
clash_api = ClashAPIOptions().apply {
external_controller = DataStore.clashAPIListen.ifBlank {
"$LOCALHOST4:${mkPort()}"
Expand Down
17 changes: 3 additions & 14 deletions libcore/box.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ import (
"context"
"fmt"
"io"
"strings"
"time"

box "github.com/sagernet/sing-box"
"github.com/sagernet/sing-box/common/conntrack"
C "github.com/sagernet/sing-box/constant"
_ "github.com/sagernet/sing-box/include"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/outbound"
"github.com/sagernet/sing/common/atomic"
E "github.com/sagernet/sing/common/exceptions"
Expand Down Expand Up @@ -45,8 +43,6 @@ type BoxInstance struct {
state atomic.TypedValue[boxState]
isMainInstance bool

v2api *v2rayapilite.V2RayServerLite

selector *outbound.Selector

pauseManager pause.Manager
Expand Down Expand Up @@ -162,19 +158,12 @@ func (b *BoxInstance) SetAsMain() {
goServeProtect(true)
}

func (b *BoxInstance) SetV2rayStats(outbounds string) {
b.v2api = v2rayapilite.NewSbV2rayServer(option.V2RayStatsServiceOptions{
Enabled: true,
Outbounds: strings.Split(outbounds, "\n"),
})
b.Box.Router().SetV2RayServer(b.v2api)
}

func (b *BoxInstance) QueryStats(tag, direct string) int64 {
if b.v2api == nil {
statsGetter := b.Router().V2RayServer().(v2rayapilite.StatsGetter)
if statsGetter == nil {
return 0
}
return b.v2api.QueryStats(fmt.Sprintf("outbound>>>%s>>>traffic>>>%s", tag, direct))
return statsGetter.QueryStats("outbound>>>" + tag + ">>>traffic>>>" + direct)
}

func (b *BoxInstance) SelectOutbound(tag string) (ok bool) {
Expand Down
48 changes: 48 additions & 0 deletions libcore/v2rayapilite/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package v2rayapilite

import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/experimental"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
)

func init() {
experimental.RegisterV2RayServerConstructor(NewServer)
}

var (
_ adapter.V2RayServer = (*V2rayServer)(nil)
_ StatsGetter = (*V2rayServer)(nil)
)

type StatsGetter interface {
QueryStats(name string) int64
}

type V2rayServer struct {
statsService *StatsService
}

func (v *V2rayServer) QueryStats(name string) int64 {
return v.statsService.QueryStats(name)
}

func NewServer(_ log.Logger, options option.V2RayAPIOptions) (adapter.V2RayServer, error) {
return &V2rayServer{
statsService: NewStatsService(common.PtrValueOrDefault(options.Stats)),
}, nil
}

func (v *V2rayServer) Start() error {
return nil
}

func (v *V2rayServer) Close() error {
return nil
}

func (v *V2rayServer) StatsService() adapter.V2RayStatsService {
return v.statsService
}
90 changes: 90 additions & 0 deletions libcore/v2rayapilite/state.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package v2rayapilite

import (
"net"
"sync"
"time"

"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/bufio"
N "github.com/sagernet/sing/common/network"
)

var (
_ adapter.V2RayStatsService = (*StatsService)(nil)
_ StatsGetter = (*StatsService)(nil)
)

type StatsService struct {
createdAt time.Time
outbounds map[string]bool
access sync.Mutex
counters map[string]*atomic.Int64
}

func NewStatsService(options option.V2RayStatsServiceOptions) *StatsService {
if !options.Enabled {
return nil
}
outbounds := make(map[string]bool)
for _, outbound := range options.Outbounds {
outbounds[outbound] = true
}
return &StatsService{
createdAt: time.Now(),
outbounds: outbounds,
counters: make(map[string]*atomic.Int64),
}
}

func (s *StatsService) QueryStats(name string) int64 {
s.access.Lock()
counter, loaded := s.counters[name]
s.access.Unlock()
if !loaded {
return 0
}

return counter.Swap(0)
}

func (s *StatsService) RoutedConnection(inbound string, outbound string, user string, conn net.Conn) net.Conn {
var readCounter []*atomic.Int64
var writeCounter []*atomic.Int64
countOutbound := outbound != "" && s.outbounds[outbound]
if !countOutbound {
return conn
}
s.access.Lock()
readCounter = append(readCounter, s.loadOrCreateCounter("outbound>>>"+outbound+">>>traffic>>>uplink"))
writeCounter = append(writeCounter, s.loadOrCreateCounter("outbound>>>"+outbound+">>>traffic>>>downlink"))
s.access.Unlock()
return bufio.NewInt64CounterConn(conn, readCounter, writeCounter)
}

func (s *StatsService) RoutedPacketConnection(inbound string, outbound string, user string, conn N.PacketConn) N.PacketConn {
var readCounter []*atomic.Int64
var writeCounter []*atomic.Int64
countOutbound := outbound != "" && s.outbounds[outbound]
if !countOutbound {
return conn
}
s.access.Lock()
readCounter = append(readCounter, s.loadOrCreateCounter("outbound>>>"+outbound+">>>traffic>>>uplink"))
writeCounter = append(writeCounter, s.loadOrCreateCounter("outbound>>>"+outbound+">>>traffic>>>downlink"))
s.access.Unlock()
return bufio.NewInt64CounterPacketConn(conn, readCounter, writeCounter)
}

//nolint:staticcheck
func (s *StatsService) loadOrCreateCounter(name string) *atomic.Int64 {
counter, loaded := s.counters[name]
if loaded {
return counter
}
counter = &atomic.Int64{}
s.counters[name] = counter
return counter
}
98 changes: 0 additions & 98 deletions libcore/v2rayapilite/v2ray_server.go

This file was deleted.

0 comments on commit 3dcc6e5

Please sign in to comment.