Repository navigation
Expand file tree
/
Copy pathnextserver.go
More file actions
123 lines (114 loc) · 3.25 KB
/
Copy pathnextserver.go
File metadata and controls
123 lines (114 loc) · 3.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package nextserver
import (
"context"
"io"
"os"
"strings"
"time"
"github.com/The-NeXT-Project/NeXT-Server/common/profiler"
"github.com/The-NeXT-Project/NeXT-Server/common/reporter"
"github.com/The-NeXT-Project/NeXT-Server/constant"
"github.com/The-NeXT-Project/NeXT-Server/option"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
)
type Instance struct {
options option.Options
logFactory log.Factory
logger log.ContextLogger
reporter reporter.Reporter
profiler io.Closer
servers []*Server
}
func New(ctx context.Context, options option.Options) (*Instance, error) {
if len(options.Servers) == 0 {
return nil, E.New("no servers configured")
}
// First, so that every later failure is reported.
errorReporter, err := reporter.New(options.Sentry)
if err != nil {
return nil, err
}
instance, err := newInstance(ctx, options, errorReporter)
if err != nil {
errorReporter.CaptureError(err)
errorReporter.Close()
return nil, err
}
return instance, nil
}
func newInstance(ctx context.Context, options option.Options, errorReporter reporter.Reporter) (*Instance, error) {
logFactory, err := log.New(log.Options{
Context: ctx,
Options: common.PtrValueOrDefault(options.Log),
DefaultWriter: os.Stderr,
BaseTime: time.Now(),
})
if err != nil {
return nil, E.Cause(err, "create logger")
}
instance := &Instance{
options: options,
logFactory: logFactory,
logger: reporter.WrapLogger(logFactory.Logger(), errorReporter),
reporter: errorReporter,
}
for index, serverOptions := range options.Servers {
logger := instance.logger
if len(options.Servers) > 1 {
logger = reporter.WrapLogger(logFactory.NewLogger(F.ToString("server[", index, "]")), errorReporter)
}
server, err := NewServer(ctx, logger, errorReporter, serverOptions)
if err != nil {
return nil, E.Cause(err, "server[", index, "]")
}
instance.servers = append(instance.servers, server)
}
return instance, nil
}
func (i *Instance) Start() error {
err := i.start()
if err != nil {
i.reporter.CaptureError(err)
}
return err
}
func (i *Instance) start() error {
err := i.logFactory.Start()
if err != nil {
return E.Cause(err, "start logger")
}
if missing := constant.MissingDefaultBuildTags(); len(missing) > 0 {
i.logger.Warn("built without -tags ", strings.Join(missing, ","), ", the features they enable are unavailable")
}
i.profiler, err = profiler.Start(i.options.Pprof, i.logger)
if err != nil {
return err
}
for index, server := range i.servers {
err = server.Start()
if err != nil {
return E.Cause(err, "server[", index, "]")
}
}
i.logger.Info("next-server ", constant.Version, " started")
return nil
}
// Close stops every server, then the profiler, so that its CPU profile
// covers the shutdown, and sends pending error reports last.
func (i *Instance) Close() error {
var errs []error
for index, server := range i.servers {
err := server.Close()
if err != nil {
errs = append(errs, E.Cause(err, "server[", index, "]"))
}
}
if i.profiler != nil {
errs = append(errs, i.profiler.Close())
}
errs = append(errs, i.logFactory.Close(), i.reporter.Close())
return E.Errors(errs...)
}