| skipped 24 lines |
25 | 25 | | var _ adapter.Service = (*Box)(nil) |
26 | 26 | | |
27 | 27 | | type Box struct { |
28 | | - | createdAt time.Time |
29 | | - | router adapter.Router |
30 | | - | inbounds []adapter.Inbound |
31 | | - | outbounds []adapter.Outbound |
32 | | - | logFactory log.Factory |
33 | | - | logger log.ContextLogger |
34 | | - | logFile *os.File |
35 | | - | clashServer adapter.ClashServer |
36 | | - | v2rayServer adapter.V2RayServer |
37 | | - | done chan struct{} |
| 28 | + | createdAt time.Time |
| 29 | + | router adapter.Router |
| 30 | + | inbounds []adapter.Inbound |
| 31 | + | outbounds []adapter.Outbound |
| 32 | + | logFactory log.Factory |
| 33 | + | logger log.ContextLogger |
| 34 | + | logFile *os.File |
| 35 | + | preServices map[string]adapter.Service |
| 36 | + | postServices map[string]adapter.Service |
| 37 | + | done chan struct{} |
38 | 38 | | } |
39 | 39 | | |
40 | 40 | | func New(ctx context.Context, options option.Options, platformInterface platform.Interface) (*Box, error) { |
| skipped 125 lines |
166 | 166 | | if err != nil { |
167 | 167 | | return nil, err |
168 | 168 | | } |
169 | | - | |
170 | | - | var clashServer adapter.ClashServer |
171 | | - | var v2rayServer adapter.V2RayServer |
| 169 | + | preServices := make(map[string]adapter.Service) |
| 170 | + | postServices := make(map[string]adapter.Service) |
172 | 171 | | if needClashAPI { |
173 | | - | clashServer, err = experimental.NewClashServer(router, observableLogFactory, common.PtrValueOrDefault(options.Experimental.ClashAPI)) |
| 172 | + | clashServer, err := experimental.NewClashServer(router, observableLogFactory, common.PtrValueOrDefault(options.Experimental.ClashAPI)) |
174 | 173 | | if err != nil { |
175 | 174 | | return nil, E.Cause(err, "create clash api server") |
176 | 175 | | } |
177 | 176 | | router.SetClashServer(clashServer) |
| 177 | + | preServices["clash api"] = clashServer |
178 | 178 | | } |
179 | 179 | | if needV2RayAPI { |
180 | | - | v2rayServer, err = experimental.NewV2RayServer(logFactory.NewLogger("v2ray-api"), common.PtrValueOrDefault(options.Experimental.V2RayAPI)) |
| 180 | + | v2rayServer, err := experimental.NewV2RayServer(logFactory.NewLogger("v2ray-api"), common.PtrValueOrDefault(options.Experimental.V2RayAPI)) |
181 | 181 | | if err != nil { |
182 | 182 | | return nil, E.Cause(err, "create v2ray api server") |
183 | 183 | | } |
184 | 184 | | router.SetV2RayServer(v2rayServer) |
| 185 | + | preServices["v2ray api"] = v2rayServer |
185 | 186 | | } |
186 | 187 | | return &Box{ |
187 | | - | router: router, |
188 | | - | inbounds: inbounds, |
189 | | - | outbounds: outbounds, |
190 | | - | createdAt: createdAt, |
191 | | - | logFactory: logFactory, |
192 | | - | logger: logFactory.Logger(), |
193 | | - | logFile: logFile, |
194 | | - | clashServer: clashServer, |
195 | | - | v2rayServer: v2rayServer, |
196 | | - | done: make(chan struct{}), |
| 188 | + | router: router, |
| 189 | + | inbounds: inbounds, |
| 190 | + | outbounds: outbounds, |
| 191 | + | createdAt: createdAt, |
| 192 | + | logFactory: logFactory, |
| 193 | + | logger: logFactory.Logger(), |
| 194 | + | logFile: logFile, |
| 195 | + | preServices: preServices, |
| 196 | + | postServices: postServices, |
| 197 | + | done: make(chan struct{}), |
197 | 198 | | }, nil |
198 | 199 | | } |
199 | 200 | | |
| 201 | + | func (s *Box) PreStart() error { |
| 202 | + | err := s.preStart() |
| 203 | + | if err != nil { |
| 204 | + | // TODO: remove catch error |
| 205 | + | defer func() { |
| 206 | + | v := recover() |
| 207 | + | if v != nil { |
| 208 | + | log.Error(E.Cause(err, "origin error")) |
| 209 | + | debug.PrintStack() |
| 210 | + | panic("panic on early close: " + fmt.Sprint(v)) |
| 211 | + | } |
| 212 | + | }() |
| 213 | + | s.Close() |
| 214 | + | return err |
| 215 | + | } |
| 216 | + | s.logger.Info("sing-box pre-started (", F.Seconds(time.Since(s.createdAt).Seconds()), "s)") |
| 217 | + | return nil |
| 218 | + | } |
| 219 | + | |
200 | 220 | | func (s *Box) Start() error { |
201 | 221 | | err := s.start() |
202 | 222 | | if err != nil { |
| skipped 7 lines |
210 | 230 | | } |
211 | 231 | | }() |
212 | 232 | | s.Close() |
| 233 | + | return err |
213 | 234 | | } |
214 | | - | return err |
| 235 | + | s.logger.Info("sing-box started (", F.Seconds(time.Since(s.createdAt).Seconds()), "s)") |
| 236 | + | return nil |
215 | 237 | | } |
216 | 238 | | |
217 | | - | func (s *Box) start() error { |
218 | | - | if s.clashServer != nil { |
219 | | - | err := s.clashServer.Start() |
220 | | - | if err != nil { |
221 | | - | return E.Cause(err, "start clash api server") |
222 | | - | } |
223 | | - | } |
224 | | - | if s.v2rayServer != nil { |
225 | | - | err := s.v2rayServer.Start() |
| 239 | + | func (s *Box) preStart() error { |
| 240 | + | for serviceName, service := range s.preServices { |
| 241 | + | err := adapter.PreStart(service) |
226 | 242 | | if err != nil { |
227 | | - | return E.Cause(err, "start v2ray api server") |
| 243 | + | return E.Cause(err, "pre-start ", serviceName) |
228 | 244 | | } |
229 | 245 | | } |
230 | 246 | | for i, out := range s.outbounds { |
| skipped 10 lines |
241 | 257 | | } |
242 | 258 | | } |
243 | 259 | | } |
244 | | - | err := s.router.Start() |
| 260 | + | return s.router.Start() |
| 261 | + | } |
| 262 | + | |
| 263 | + | func (s *Box) start() error { |
| 264 | + | err := s.preStart() |
245 | 265 | | if err != nil { |
246 | 266 | | return err |
247 | 267 | | } |
| 268 | + | for serviceName, service := range s.preServices { |
| 269 | + | err = service.Start() |
| 270 | + | if err != nil { |
| 271 | + | return E.Cause(err, "start ", serviceName) |
| 272 | + | } |
| 273 | + | } |
248 | 274 | | for i, in := range s.inbounds { |
249 | 275 | | err = in.Start() |
250 | 276 | | if err != nil { |
| skipped 6 lines |
257 | 283 | | return E.Cause(err, "initialize inbound/", in.Type(), "[", tag, "]") |
258 | 284 | | } |
259 | 285 | | } |
260 | | - | |
261 | | - | s.logger.Info("sing-box started (", F.Seconds(time.Since(s.createdAt).Seconds()), "s)") |
| 286 | + | for serviceName, service := range s.postServices { |
| 287 | + | err = service.Start() |
| 288 | + | if err != nil { |
| 289 | + | return E.Cause(err, "start ", serviceName) |
| 290 | + | } |
| 291 | + | } |
262 | 292 | | return nil |
263 | 293 | | } |
264 | 294 | | |
| skipped 5 lines |
270 | 300 | | close(s.done) |
271 | 301 | | } |
272 | 302 | | var errors error |
| 303 | + | for serviceName, service := range s.postServices { |
| 304 | + | errors = E.Append(errors, service.Close(), func(err error) error { |
| 305 | + | return E.Cause(err, "close ", serviceName) |
| 306 | + | }) |
| 307 | + | } |
273 | 308 | | for i, in := range s.inbounds { |
274 | 309 | | errors = E.Append(errors, in.Close(), func(err error) error { |
275 | 310 | | return E.Cause(err, "close inbound/", in.Type(), "[", i, "]") |
| skipped 9 lines |
285 | 320 | | return E.Cause(err, "close router") |
286 | 321 | | }) |
287 | 322 | | } |
| 323 | + | for serviceName, service := range s.preServices { |
| 324 | + | errors = E.Append(errors, service.Close(), func(err error) error { |
| 325 | + | return E.Cause(err, "close ", serviceName) |
| 326 | + | }) |
| 327 | + | } |
288 | 328 | | if err := common.Close(s.logFactory); err != nil { |
289 | 329 | | errors = E.Append(errors, err, func(err error) error { |
290 | 330 | | return E.Cause(err, "close log factory") |
291 | | - | }) |
292 | | - | } |
293 | | - | if err := common.Close(s.clashServer); err != nil { |
294 | | - | errors = E.Append(errors, err, func(err error) error { |
295 | | - | return E.Cause(err, "close clash api server") |
296 | | - | }) |
297 | | - | } |
298 | | - | if err := common.Close(s.v2rayServer); err != nil { |
299 | | - | errors = E.Append(errors, err, func(err error) error { |
300 | | - | return E.Cause(err, "close v2ray api server") |
301 | 331 | | }) |
302 | 332 | | } |
303 | 333 | | if s.logFile != nil { |
| skipped 11 lines |