mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-22 00:21:30 +00:00
platform: Add openURL event
This commit is contained in:
parent
9585c53e9f
commit
718cffea9a
|
@ -20,6 +20,7 @@ type CommandClient struct {
|
||||||
type CommandClientOptions struct {
|
type CommandClientOptions struct {
|
||||||
Command int32
|
Command int32
|
||||||
StatusInterval int64
|
StatusInterval int64
|
||||||
|
IsMainClient bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommandClientHandler interface {
|
type CommandClientHandler interface {
|
||||||
|
@ -28,6 +29,7 @@ type CommandClientHandler interface {
|
||||||
ClearLogs()
|
ClearLogs()
|
||||||
WriteLogs(messageList StringIterator)
|
WriteLogs(messageList StringIterator)
|
||||||
WriteStatus(message *StatusMessage)
|
WriteStatus(message *StatusMessage)
|
||||||
|
OpenURL(url string)
|
||||||
WriteGroups(message OutboundGroupIterator)
|
WriteGroups(message OutboundGroupIterator)
|
||||||
InitializeClashMode(modeList StringIterator, currentMode string)
|
InitializeClashMode(modeList StringIterator, currentMode string)
|
||||||
UpdateClashMode(newMode string)
|
UpdateClashMode(newMode string)
|
||||||
|
@ -91,9 +93,13 @@ func (c *CommandClient) Connect() error {
|
||||||
c.handler.Connected()
|
c.handler.Connected()
|
||||||
go c.handleLogConn(conn)
|
go c.handleLogConn(conn)
|
||||||
case CommandStatus:
|
case CommandStatus:
|
||||||
|
err = binary.Write(conn, binary.BigEndian, c.options.IsMainClient)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "write is main client")
|
||||||
|
}
|
||||||
err = binary.Write(conn, binary.BigEndian, c.options.StatusInterval)
|
err = binary.Write(conn, binary.BigEndian, c.options.StatusInterval)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "write interval")
|
return E.Cause(err, "write header")
|
||||||
}
|
}
|
||||||
c.handler.Connected()
|
c.handler.Connected()
|
||||||
go c.handleStatusConn(conn)
|
go c.handleStatusConn(conn)
|
||||||
|
|
40
experimental/libbox/command_event.go
Normal file
40
experimental/libbox/command_event.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package libbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/varbin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type myEvent interface {
|
||||||
|
writeTo(writer varbin.Writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readEvent(reader varbin.Reader) (myEvent, error) {
|
||||||
|
eventType, err := reader.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch eventType {
|
||||||
|
case eventTypeEmpty:
|
||||||
|
return nil, nil
|
||||||
|
case eventTypeOpenURL:
|
||||||
|
url, err := varbin.ReadValue[string](reader, binary.BigEndian)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &eventOpenURL{URL: url}, nil
|
||||||
|
default:
|
||||||
|
return nil, E.New("unknown event type: ", eventType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type eventOpenURL struct {
|
||||||
|
URL string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *eventOpenURL) writeTo(writer varbin.Writer) {
|
||||||
|
writer.WriteByte(eventTypeOpenURL)
|
||||||
|
varbin.Write(writer, binary.BigEndian, e.URL)
|
||||||
|
}
|
|
@ -33,6 +33,7 @@ type CommandServer struct {
|
||||||
urlTestUpdate chan struct{}
|
urlTestUpdate chan struct{}
|
||||||
modeUpdate chan struct{}
|
modeUpdate chan struct{}
|
||||||
logReset chan struct{}
|
logReset chan struct{}
|
||||||
|
events chan myEvent
|
||||||
|
|
||||||
closedConnections []Connection
|
closedConnections []Connection
|
||||||
}
|
}
|
||||||
|
@ -52,6 +53,7 @@ func NewCommandServer(handler CommandServerHandler, maxLines int32) *CommandServ
|
||||||
urlTestUpdate: make(chan struct{}, 1),
|
urlTestUpdate: make(chan struct{}, 1),
|
||||||
modeUpdate: make(chan struct{}, 1),
|
modeUpdate: make(chan struct{}, 1),
|
||||||
logReset: make(chan struct{}, 1),
|
logReset: make(chan struct{}, 1),
|
||||||
|
events: make(chan myEvent, 8),
|
||||||
}
|
}
|
||||||
server.observer = observable.NewObserver[string](server.subscriber, 64)
|
server.observer = observable.NewObserver[string](server.subscriber, 64)
|
||||||
return server
|
return server
|
||||||
|
@ -61,6 +63,12 @@ func (s *CommandServer) SetService(newService *BoxService) {
|
||||||
if newService != nil {
|
if newService != nil {
|
||||||
service.PtrFromContext[urltest.HistoryStorage](newService.ctx).SetHook(s.urlTestUpdate)
|
service.PtrFromContext[urltest.HistoryStorage](newService.ctx).SetHook(s.urlTestUpdate)
|
||||||
newService.instance.Router().ClashServer().(*clashapi.Server).SetModeUpdateHook(s.modeUpdate)
|
newService.instance.Router().ClashServer().(*clashapi.Server).SetModeUpdateHook(s.modeUpdate)
|
||||||
|
newService.platformInterface.openURLFunc = func(url string) {
|
||||||
|
select {
|
||||||
|
case s.events <- &eventOpenURL{URL: url}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s.service = newService
|
s.service = newService
|
||||||
s.notifyURLTestUpdate()
|
s.notifyURLTestUpdate()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
std_bufio "bufio"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"net"
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -9,9 +10,15 @@ import (
|
||||||
"github.com/sagernet/sing-box/common/conntrack"
|
"github.com/sagernet/sing-box/common/conntrack"
|
||||||
"github.com/sagernet/sing-box/experimental/clashapi"
|
"github.com/sagernet/sing-box/experimental/clashapi"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
F "github.com/sagernet/sing/common/format"
|
||||||
"github.com/sagernet/sing/common/memory"
|
"github.com/sagernet/sing/common/memory"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
eventTypeEmpty byte = iota
|
||||||
|
eventTypeOpenURL
|
||||||
|
)
|
||||||
|
|
||||||
type StatusMessage struct {
|
type StatusMessage struct {
|
||||||
Memory int64
|
Memory int64
|
||||||
Goroutines int32
|
Goroutines int32
|
||||||
|
@ -44,31 +51,73 @@ func (s *CommandServer) readStatus() StatusMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommandServer) handleStatusConn(conn net.Conn) error {
|
func (s *CommandServer) handleStatusConn(conn net.Conn) error {
|
||||||
|
var isMainClient bool
|
||||||
|
err := binary.Read(conn, binary.BigEndian, &isMainClient)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "read is main client")
|
||||||
|
}
|
||||||
var interval int64
|
var interval int64
|
||||||
err := binary.Read(conn, binary.BigEndian, &interval)
|
err = binary.Read(conn, binary.BigEndian, &interval)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "read interval")
|
return E.Cause(err, "read interval")
|
||||||
}
|
}
|
||||||
ticker := time.NewTicker(time.Duration(interval))
|
ticker := time.NewTicker(time.Duration(interval))
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
ctx := connKeepAlive(conn)
|
ctx := connKeepAlive(conn)
|
||||||
for {
|
writer := std_bufio.NewWriter(conn)
|
||||||
err = binary.Write(conn, binary.BigEndian, s.readStatus())
|
if isMainClient {
|
||||||
if err != nil {
|
for {
|
||||||
return err
|
writer.WriteByte(eventTypeEmpty)
|
||||||
|
err = binary.Write(writer, binary.BigEndian, s.readStatus())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
writer.Flush()
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case <-ticker.C:
|
||||||
|
case event := <-s.events:
|
||||||
|
event.writeTo(writer)
|
||||||
|
writer.Flush()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
select {
|
} else {
|
||||||
case <-ctx.Done():
|
for {
|
||||||
return ctx.Err()
|
err = binary.Write(writer, binary.BigEndian, s.readStatus())
|
||||||
case <-ticker.C:
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
writer.Flush()
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case <-ticker.C:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommandClient) handleStatusConn(conn net.Conn) {
|
func (c *CommandClient) handleStatusConn(conn net.Conn) {
|
||||||
|
reader := std_bufio.NewReader(conn)
|
||||||
for {
|
for {
|
||||||
|
if c.options.IsMainClient {
|
||||||
|
rawEvent, err := readEvent(reader)
|
||||||
|
if err != nil {
|
||||||
|
c.handler.Disconnected(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch event := rawEvent.(type) {
|
||||||
|
case *eventOpenURL:
|
||||||
|
c.handler.OpenURL(event.URL)
|
||||||
|
continue
|
||||||
|
case nil:
|
||||||
|
default:
|
||||||
|
panic(F.ToString("unexpected event type: ", event))
|
||||||
|
}
|
||||||
|
}
|
||||||
var message StatusMessage
|
var message StatusMessage
|
||||||
err := binary.Read(conn, binary.BigEndian, &message)
|
err := binary.Read(reader, binary.BigEndian, &message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.handler.Disconnected(err.Error())
|
c.handler.Disconnected(err.Error())
|
||||||
return
|
return
|
||||||
|
|
|
@ -134,6 +134,9 @@ func (s *interfaceMonitorStub) RegisterCallback(callback tun.DefaultInterfaceUpd
|
||||||
func (s *interfaceMonitorStub) UnregisterCallback(element *list.Element[tun.DefaultInterfaceUpdateCallback]) {
|
func (s *interfaceMonitorStub) UnregisterCallback(element *list.Element[tun.DefaultInterfaceUpdateCallback]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *platformInterfaceStub) OpenURL(url string) {
|
||||||
|
}
|
||||||
|
|
||||||
func FormatConfig(configContent string) (string, error) {
|
func FormatConfig(configContent string) (string, error) {
|
||||||
options, err := parseConfig(configContent)
|
options, err := parseConfig(configContent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -25,4 +25,5 @@ type Interface interface {
|
||||||
ClearDNSCache()
|
ClearDNSCache()
|
||||||
ReadWIFIState() adapter.WIFIState
|
ReadWIFIState() adapter.WIFIState
|
||||||
process.Searcher
|
process.Searcher
|
||||||
|
OpenURL(url string)
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,9 @@ type BoxService struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
instance *box.Box
|
instance *box.Box
|
||||||
|
platformInterface *platformInterfaceWrapper
|
||||||
pauseManager pause.Manager
|
pauseManager pause.Manager
|
||||||
urlTestHistoryStorage *urltest.HistoryStorage
|
urlTestHistoryStorage *urltest.HistoryStorage
|
||||||
|
|
||||||
servicePauseFields
|
servicePauseFields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
instance: instance,
|
instance: instance,
|
||||||
|
platformInterface: platformWrapper,
|
||||||
urlTestHistoryStorage: urlTestHistoryStorage,
|
urlTestHistoryStorage: urlTestHistoryStorage,
|
||||||
pauseManager: service.FromContext[pause.Manager](ctx),
|
pauseManager: service.FromContext[pause.Manager](ctx),
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -102,9 +103,10 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type platformInterfaceWrapper struct {
|
type platformInterfaceWrapper struct {
|
||||||
iif PlatformInterface
|
iif PlatformInterface
|
||||||
useProcFS bool
|
useProcFS bool
|
||||||
router adapter.Router
|
router adapter.Router
|
||||||
|
openURLFunc func(url string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *platformInterfaceWrapper) Initialize(ctx context.Context, router adapter.Router) error {
|
func (w *platformInterfaceWrapper) Initialize(ctx context.Context, router adapter.Router) error {
|
||||||
|
@ -238,3 +240,9 @@ func (w *platformInterfaceWrapper) DisableColors() bool {
|
||||||
func (w *platformInterfaceWrapper) WriteMessage(level log.Level, message string) {
|
func (w *platformInterfaceWrapper) WriteMessage(level log.Level, message string) {
|
||||||
w.iif.WriteLog(message)
|
w.iif.WriteLog(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *platformInterfaceWrapper) OpenURL(url string) {
|
||||||
|
if w.openURLFunc != nil {
|
||||||
|
w.openURLFunc(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue