Add shadowsocks-multiuser control api

This commit is contained in:
世界
2022-07-27 21:57:21 +08:00
parent aa074a2063
commit c240f1b359
7 changed files with 363 additions and 22 deletions

View File

@@ -2,19 +2,18 @@ package badjson
import (
"bytes"
"reflect"
"github.com/sagernet/sing-box/common/json"
E "github.com/sagernet/sing/common/exceptions"
)
type JSONArray[T any] []T
type JSONArray []any
func (a JSONArray[T]) MarshalJSON() ([]byte, error) {
return json.Marshal([]T(a))
func (a JSONArray) MarshalJSON() ([]byte, error) {
return json.Marshal([]any(a))
}
func (a *JSONArray[T]) UnmarshalJSON(content []byte) error {
func (a *JSONArray) UnmarshalJSON(content []byte) error {
decoder := json.NewDecoder(bytes.NewReader(content))
arrayStart, err := decoder.Token()
if err != nil {
@@ -35,17 +34,12 @@ func (a *JSONArray[T]) UnmarshalJSON(content []byte) error {
return nil
}
func (a *JSONArray[T]) decodeJSON(decoder *json.Decoder) error {
func (a *JSONArray) decodeJSON(decoder *json.Decoder) error {
for decoder.More() {
value, err := decodeJSON(decoder)
item, err := decodeJSON(decoder)
if err != nil {
return err
}
item, ok := value.(T)
if !ok {
var defValue T
return E.New("can't cast ", value, " to ", reflect.TypeOf(defValue))
}
*a = append(*a, item)
}
return nil

View File

@@ -1,10 +1,17 @@
package badjson
import (
"bytes"
"github.com/sagernet/sing-box/common/json"
E "github.com/sagernet/sing/common/exceptions"
)
func Decode(content []byte) (any, error) {
decoder := json.NewDecoder(bytes.NewReader(content))
return decodeJSON(decoder)
}
func decodeJSON(decoder *json.Decoder) (any, error) {
rawToken, err := decoder.Token()
if err != nil {
@@ -27,7 +34,7 @@ func decodeJSON(decoder *json.Decoder) (any, error) {
}
return &object, nil
case '[':
var array JSONArray[any]
var array JSONArray
err = array.decodeJSON(decoder)
if err != nil {
return nil, err

View File

@@ -0,0 +1,57 @@
package pipelistener
import (
"io"
"net"
)
var _ net.Listener = (*Listener)(nil)
type Listener struct {
pipe chan net.Conn
done chan struct{}
}
func New(channelSize int) *Listener {
return &Listener{
pipe: make(chan net.Conn, channelSize),
done: make(chan struct{}),
}
}
func (l *Listener) Serve(conn net.Conn) {
l.pipe <- conn
}
func (l *Listener) Accept() (net.Conn, error) {
select {
case conn := <-l.pipe:
return conn, nil
case <-l.done:
return nil, io.ErrClosedPipe
}
}
func (l *Listener) Close() error {
select {
case <-l.done:
return io.ErrClosedPipe
default:
}
close(l.done)
return nil
}
func (l *Listener) Addr() net.Addr {
return addr{}
}
type addr struct{}
func (a addr) Network() string {
return "pipe"
}
func (a addr) String() string {
return "pipe"
}

View File

@@ -0,0 +1,145 @@
package trafficcontrol
import (
"io"
"net"
"sync"
"sync/atomic"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)
type Manager[U comparable] struct {
access sync.Mutex
users map[U]*Traffic
}
type Traffic struct {
Upload uint64
Download uint64
}
func NewManager[U comparable]() *Manager[U] {
return &Manager[U]{
users: make(map[U]*Traffic),
}
}
func (m *Manager[U]) Reset() {
m.users = make(map[U]*Traffic)
}
func (m *Manager[U]) TrackConnection(user U, conn net.Conn) net.Conn {
m.access.Lock()
defer m.access.Unlock()
var traffic *Traffic
if t, loaded := m.users[user]; loaded {
traffic = t
} else {
traffic = new(Traffic)
m.users[user] = traffic
}
return &TrackConn{conn, traffic}
}
func (m *Manager[U]) TrackPacketConnection(user U, conn N.PacketConn) N.PacketConn {
m.access.Lock()
defer m.access.Unlock()
var traffic *Traffic
if t, loaded := m.users[user]; loaded {
traffic = t
} else {
traffic = new(Traffic)
m.users[user] = traffic
}
return &TrackPacketConn{conn, traffic}
}
func (m *Manager[U]) ReadTraffics() map[U]Traffic {
m.access.Lock()
defer m.access.Unlock()
trafficMap := make(map[U]Traffic)
for user, traffic := range m.users {
upload := atomic.SwapUint64(&traffic.Upload, 0)
download := atomic.SwapUint64(&traffic.Download, 0)
if upload == 0 && download == 0 {
continue
}
trafficMap[user] = Traffic{
Upload: upload,
Download: download,
}
}
return trafficMap
}
type TrackConn struct {
net.Conn
*Traffic
}
func (c *TrackConn) Read(p []byte) (n int, err error) {
n, err = c.Conn.Read(p)
if n > 0 {
atomic.AddUint64(&c.Upload, uint64(n))
}
return
}
func (c *TrackConn) Write(p []byte) (n int, err error) {
n, err = c.Conn.Write(p)
if n > 0 {
atomic.AddUint64(&c.Download, uint64(n))
}
return
}
func (c *TrackConn) WriteTo(w io.Writer) (n int64, err error) {
n, err = bufio.Copy(w, c.Conn)
if n > 0 {
atomic.AddUint64(&c.Upload, uint64(n))
}
return
}
func (c *TrackConn) ReadFrom(r io.Reader) (n int64, err error) {
n, err = bufio.Copy(c.Conn, r)
if n > 0 {
atomic.AddUint64(&c.Download, uint64(n))
}
return
}
func (c *TrackConn) Upstream() any {
return c.Conn
}
type TrackPacketConn struct {
N.PacketConn
*Traffic
}
func (c *TrackPacketConn) ReadPacket(buffer *buf.Buffer) (M.Socksaddr, error) {
destination, err := c.PacketConn.ReadPacket(buffer)
if err == nil {
atomic.AddUint64(&c.Upload, uint64(buffer.Len()))
}
return destination, err
}
func (c *TrackPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
n := buffer.Len()
err := c.PacketConn.WritePacket(buffer, destination)
if err == nil {
atomic.AddUint64(&c.Download, uint64(n))
}
return err
}
func (c *TrackPacketConn) Upstream() any {
return c.PacketConn
}