Skip to content

Commit b387211

Browse files
committed
new: add srun to run directly singbox without calling hiddify core
1 parent 6da8a29 commit b387211

File tree

5 files changed

+259
-38
lines changed

5 files changed

+259
-38
lines changed

.github/workflows/build.yml

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ jobs:
8484
needs:
8585
- calculate_version
8686
permissions: write-all
87-
if: false
87+
# if: false
8888
strategy:
8989
fail-fast: false
9090
matrix:
@@ -207,15 +207,15 @@ jobs:
207207
build-binary:
208208
name: Build binary
209209
# if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Binary'
210-
# if: ${{ inputs.channel=='prod' }}
210+
if: ${{ inputs.channel=='prod' }}
211211
runs-on: ubuntu-latest
212212
needs:
213213
- calculate_version
214214
env:
215215
CODE_VERSION: "-X github.com/hiddify/hiddify-core/v2/hcommon/constants.Version=${{ needs.calculate_version.outputs.hiddify_version }} -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.singbox_version }}"
216216

217217
strategy:
218-
fail-fast: false
218+
fail-fast: true
219219
matrix:
220220
include:
221221
- { os: linux, arch: amd64, variant: purego, naive: true }
@@ -357,7 +357,7 @@ jobs:
357357
mkdir -p dist
358358
go build -v -trimpath -o dist/hiddify-core -tags "${BUILD_TAGS}" \
359359
-ldflags '-s -buildid= ${CODE_VERSION} -X internal/godebug.defaultGODEBUG=multipathtcp=0 -checklinkname=0' \
360-
./cmd/
360+
./cmd/main/
361361
env:
362362
CGO_ENABLED: "0"
363363
GOOS: ${{ matrix.os }}
@@ -379,7 +379,7 @@ jobs:
379379
mkdir -p dist
380380
go build -v -trimpath -o dist/hiddify-core -tags "${BUILD_TAGS}" \
381381
-ldflags '-s -buildid= ${CODE_VERSION} -X internal/godebug.defaultGODEBUG=multipathtcp=0 -checklinkname=0' \
382-
./cmd/
382+
./cmd/main/
383383
env:
384384
CGO_ENABLED: "1"
385385
GOOS: linux
@@ -394,7 +394,7 @@ jobs:
394394
mkdir -p dist
395395
go build -v -trimpath -o dist/hiddify-core -tags "${BUILD_TAGS}" \
396396
-ldflags '-s -buildid= ${CODE_VERSION} -X internal/godebug.defaultGODEBUG=multipathtcp=0 -checklinkname=0' \
397-
./cmd/
397+
./cmd/main/
398398
env:
399399
CGO_ENABLED: "1"
400400
GOOS: linux
@@ -409,7 +409,7 @@ jobs:
409409
mkdir -p dist
410410
go build -v -trimpath -o dist/hiddify-core -tags "${BUILD_TAGS}" \
411411
-ldflags '-s -buildid= ${CODE_VERSION} -X internal/godebug.defaultGODEBUG=multipathtcp=0 -checklinkname=0' \
412-
./cmd/
412+
./cmd/main/
413413
env:
414414
CGO_ENABLED: "0"
415415
GOOS: ${{ matrix.os }}
@@ -429,7 +429,7 @@ jobs:
429429
mkdir -p dist
430430
GOOS=$BUILD_GOOS GOARCH=$BUILD_GOARCH build go build -v -trimpath -o dist/hiddify-core -tags "${BUILD_TAGS}" \
431431
-ldflags '-s -buildid= ${CODE_VERSION} -X internal/godebug.defaultGODEBUG=multipathtcp=0 -checklinkname=0' \
432-
./cmd/
432+
./cmd/main/
433433
env:
434434
CGO_ENABLED: "1"
435435
BUILD_GOOS: ${{ matrix.os }}
@@ -538,12 +538,12 @@ jobs:
538538
rm -r "${DIR_NAME}"
539539
- name: Cleanup
540540
run: rm -f dist/hiddify-core dist/libcronet.so
541-
# - name: Upload artifact
542-
# uses: actions/upload-artifact@v4
543-
# with:
544-
# name: hiddify-core-${{ matrix.os }}_${{ matrix.arch }}${{ matrix.goarm && format('v{0}', matrix.goarm) }}${{ matrix.go386 && format('_{0}', matrix.go386) }}${{ matrix.gomips && format('_{0}', matrix.gomips) }}${{ matrix.legacy_name && format('-legacy-{0}', matrix.legacy_name) }}${{ matrix.variant && format('-{0}', matrix.variant) }}
545-
# path: "dist"
546-
# retention-days: 1
541+
- name: Upload artifact
542+
uses: actions/upload-artifact@v4
543+
with:
544+
name: hiddify-core-${{ matrix.os }}_${{ matrix.arch }}${{ matrix.goarm && format('v{0}', matrix.goarm) }}${{ matrix.go386 && format('_{0}', matrix.go386) }}${{ matrix.gomips && format('_{0}', matrix.gomips) }}${{ matrix.legacy_name && format('-legacy-{0}', matrix.legacy_name) }}${{ matrix.variant && format('-{0}', matrix.variant) }}
545+
path: "dist"
546+
retention-days: 1
547547

548548

549549

cmd/cmd_run.go renamed to cmd/cmd_hiddify_run.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,20 @@ import (
77
"github.com/spf13/cobra"
88
)
99

10-
var commandRun = &cobra.Command{
10+
var hcommandRun = &cobra.Command{
1111
Use: "run",
1212
Short: "run",
1313
Args: cobra.OnlyValidArgs,
1414
Run: runCommand,
1515
}
1616

1717
func init() {
18-
// commandRun.PersistentFlags().BoolP("help", "", false, "help for this command")
19-
// commandRun.Flags().StringVarP(&hiddifySettingPath, "hiddify", "d", "", "Hiddify Setting JSON Path")
18+
// hcommandRun.PersistentFlags().BoolP("help", "", false, "help for this command")
19+
// hcommandRun.Flags().StringVarP(&hiddifySettingPath, "hiddify", "d", "", "Hiddify Setting JSON Path")
2020

21-
addHConfigFlags(commandRun)
21+
addHConfigFlags(hcommandRun)
2222

23-
mainCommand.AddCommand(commandRun)
23+
mainCommand.AddCommand(hcommandRun)
2424
}
2525

2626
func runCommand(cmd *cobra.Command, args []string) {

cmd/cmd_sing_run.go

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"io"
6+
"os"
7+
"os/signal"
8+
"path/filepath"
9+
runtimeDebug "runtime/debug"
10+
"sort"
11+
"strings"
12+
"syscall"
13+
"time"
14+
15+
box "github.com/sagernet/sing-box"
16+
C "github.com/sagernet/sing-box/constant"
17+
"github.com/sagernet/sing-box/log"
18+
"github.com/sagernet/sing-box/option"
19+
E "github.com/sagernet/sing/common/exceptions"
20+
"github.com/sagernet/sing/common/json"
21+
"github.com/sagernet/sing/common/json/badjson"
22+
23+
"github.com/spf13/cobra"
24+
)
25+
26+
var (
27+
globalCtx context.Context
28+
configPaths []string
29+
configDirectories []string
30+
)
31+
var commandRun = &cobra.Command{
32+
Use: "srun",
33+
Short: "Run singbox service",
34+
Run: func(cmd *cobra.Command, args []string) {
35+
err := run()
36+
if err != nil {
37+
log.Fatal(err)
38+
}
39+
},
40+
}
41+
42+
func init() {
43+
mainCommand.AddCommand(commandRun)
44+
commandRun.Flags().StringArrayVarP(&configPaths, "config", "c", nil, "set configuration file path")
45+
commandRun.Flags().StringArrayVarP(&configDirectories, "config-directory", "C", nil, "set configuration directory path")
46+
}
47+
48+
type OptionsEntry struct {
49+
content []byte
50+
path string
51+
options option.Options
52+
}
53+
54+
func sreadConfigAt(path string) (*OptionsEntry, error) {
55+
var (
56+
configContent []byte
57+
err error
58+
)
59+
if path == "stdin" {
60+
configContent, err = io.ReadAll(os.Stdin)
61+
} else {
62+
configContent, err = os.ReadFile(path)
63+
}
64+
if err != nil {
65+
return nil, E.Cause(err, "read config at ", path)
66+
}
67+
options, err := json.UnmarshalExtendedContext[option.Options](globalCtx, configContent)
68+
if err != nil {
69+
return nil, E.Cause(err, "decode config at ", path)
70+
}
71+
return &OptionsEntry{
72+
content: configContent,
73+
path: path,
74+
options: options,
75+
}, nil
76+
}
77+
78+
func readConfig() ([]*OptionsEntry, error) {
79+
var optionsList []*OptionsEntry
80+
for _, path := range configPaths {
81+
optionsEntry, err := sreadConfigAt(path)
82+
if err != nil {
83+
return nil, err
84+
}
85+
optionsList = append(optionsList, optionsEntry)
86+
}
87+
for _, directory := range configDirectories {
88+
entries, err := os.ReadDir(directory)
89+
if err != nil {
90+
return nil, E.Cause(err, "read config directory at ", directory)
91+
}
92+
for _, entry := range entries {
93+
if !strings.HasSuffix(entry.Name(), ".json") || entry.IsDir() {
94+
continue
95+
}
96+
optionsEntry, err := sreadConfigAt(filepath.Join(directory, entry.Name()))
97+
if err != nil {
98+
return nil, err
99+
}
100+
optionsList = append(optionsList, optionsEntry)
101+
}
102+
}
103+
sort.Slice(optionsList, func(i, j int) bool {
104+
return optionsList[i].path < optionsList[j].path
105+
})
106+
return optionsList, nil
107+
}
108+
109+
func readConfigAndMerge() (option.Options, error) {
110+
optionsList, err := readConfig()
111+
if err != nil {
112+
return option.Options{}, err
113+
}
114+
if len(optionsList) == 1 {
115+
return optionsList[0].options, nil
116+
}
117+
var mergedMessage json.RawMessage
118+
for _, options := range optionsList {
119+
mergedMessage, err = badjson.MergeJSON(globalCtx, options.options.RawMessage, mergedMessage, false)
120+
if err != nil {
121+
return option.Options{}, E.Cause(err, "merge config at ", options.path)
122+
}
123+
}
124+
var mergedOptions option.Options
125+
err = mergedOptions.UnmarshalJSONContext(globalCtx, mergedMessage)
126+
if err != nil {
127+
return option.Options{}, E.Cause(err, "unmarshal merged config")
128+
}
129+
return mergedOptions, nil
130+
}
131+
132+
func create() (*box.Box, context.CancelFunc, error) {
133+
options, err := readConfigAndMerge()
134+
if err != nil {
135+
return nil, nil, err
136+
}
137+
if disableColor {
138+
if options.Log == nil {
139+
options.Log = &option.LogOptions{}
140+
}
141+
options.Log.DisableColor = true
142+
}
143+
ctx, cancel := context.WithCancel(globalCtx)
144+
instance, err := box.New(box.Options{
145+
Context: ctx,
146+
Options: options,
147+
})
148+
if err != nil {
149+
cancel()
150+
return nil, nil, E.Cause(err, "create service")
151+
}
152+
153+
osSignals := make(chan os.Signal, 1)
154+
signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
155+
defer func() {
156+
signal.Stop(osSignals)
157+
close(osSignals)
158+
}()
159+
startCtx, finishStart := context.WithCancel(context.Background())
160+
go func() {
161+
_, loaded := <-osSignals
162+
if loaded {
163+
cancel()
164+
closeMonitor(startCtx)
165+
}
166+
}()
167+
err = instance.Start()
168+
finishStart()
169+
if err != nil {
170+
cancel()
171+
return nil, nil, E.Cause(err, "start service")
172+
}
173+
return instance, cancel, nil
174+
}
175+
176+
func run() error {
177+
osSignals := make(chan os.Signal, 1)
178+
signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
179+
defer signal.Stop(osSignals)
180+
for {
181+
instance, cancel, err := create()
182+
if err != nil {
183+
return err
184+
}
185+
runtimeDebug.FreeOSMemory()
186+
for {
187+
osSignal := <-osSignals
188+
if osSignal == syscall.SIGHUP {
189+
err = check()
190+
if err != nil {
191+
log.Error(E.Cause(err, "reload service"))
192+
continue
193+
}
194+
}
195+
cancel()
196+
closeCtx, closed := context.WithCancel(context.Background())
197+
go closeMonitor(closeCtx)
198+
err = instance.Close()
199+
closed()
200+
if osSignal != syscall.SIGHUP {
201+
if err != nil {
202+
log.Error(E.Cause(err, "sing-box did not closed properly"))
203+
}
204+
return nil
205+
}
206+
break
207+
}
208+
}
209+
}
210+
211+
func closeMonitor(ctx context.Context) {
212+
time.Sleep(C.FatalStopTimeout)
213+
select {
214+
case <-ctx.Done():
215+
return
216+
default:
217+
}
218+
log.Fatal("sing-box did not close!")
219+
}

v2/hcore/warp.go

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,33 @@ package hcore
22

33
import (
44
"context"
5-
6-
"github.com/hiddify/hiddify-core/v2/config"
75
)
86

97
func (s *CoreService) GenerateWarpConfig(ctx context.Context, in *GenerateWarpConfigRequest) (*WarpGenerationResponse, error) {
108
return GenerateWarpConfig(in)
119
}
1210

1311
func GenerateWarpConfig(in *GenerateWarpConfigRequest) (*WarpGenerationResponse, error) {
14-
identity, log, wg, err := config.GenerateWarpInfo(in.LicenseKey, in.AccountId, in.AccessToken)
15-
if err != nil {
16-
return nil, err
17-
}
1812
return &WarpGenerationResponse{
19-
Account: &WarpAccount{
20-
AccountId: identity.ID,
21-
AccessToken: identity.Token,
22-
},
23-
Config: &WarpWireguardConfig{
24-
PrivateKey: wg.PrivateKey,
25-
LocalAddressIpv4: wg.LocalAddressIPv4,
26-
LocalAddressIpv6: wg.LocalAddressIPv6,
27-
PeerPublicKey: wg.PeerPublicKey,
28-
ClientId: wg.ClientID,
29-
},
30-
Log: log,
13+
Config: &WarpWireguardConfig{},
14+
Account: &WarpAccount{},
3115
}, nil
16+
// identity, log, wg, err := config.GenerateWarpInfo(in.LicenseKey, in.AccountId, in.AccessToken)
17+
// if err != nil {
18+
// return nil, err
19+
// }
20+
// return &WarpGenerationResponse{
21+
// Account: &WarpAccount{
22+
// AccountId: identity.ID,
23+
// AccessToken: identity.Token,
24+
// },
25+
// Config: &WarpWireguardConfig{
26+
// PrivateKey: wg.PrivateKey,
27+
// LocalAddressIpv4: wg.LocalAddressIPv4,
28+
// LocalAddressIpv6: wg.LocalAddressIPv6,
29+
// PeerPublicKey: wg.PeerPublicKey,
30+
// ClientId: wg.ClientID,
31+
// },
32+
// Log: log,
33+
// }, nil
3234
}

0 commit comments

Comments
 (0)