دورة حياة Box
Box هو الحاوي الأعلى مستوى الذي يملك جميع المديرين والخدمات. تتبع دورة حياته نمط بدء متعدد المراحل لمعالجة ترتيب التبعيات المعقد.
المصدر: box.go، adapter/lifecycle.go
هيكل Box
go
type Box struct {
createdAt time.Time
logFactory log.Factory
logger log.ContextLogger
network *route.NetworkManager
endpoint *endpoint.Manager
inbound *inbound.Manager
outbound *outbound.Manager
service *boxService.Manager
dnsTransport *dns.TransportManager
dnsRouter *dns.Router
connection *route.ConnectionManager
router *route.Router
internalService []adapter.LifecycleService // cache-file, clash-api, v2ray-api, ntp
done chan struct{}
}الإنشاء (New)
تبني الدالة New() الرسم البياني الكامل للكائنات:
go
func New(options Options) (*Box, error) {
ctx := options.Context
ctx = service.ContextWithDefaultRegistry(ctx)
// 1. استرجاع السجلات من السياق
endpointRegistry := service.FromContext[adapter.EndpointRegistry](ctx)
inboundRegistry := service.FromContext[adapter.InboundRegistry](ctx)
outboundRegistry := service.FromContext[adapter.OutboundRegistry](ctx)
dnsTransportRegistry := service.FromContext[adapter.DNSTransportRegistry](ctx)
serviceRegistry := service.FromContext[adapter.ServiceRegistry](ctx)
// 2. إنشاء المديرين
endpointManager := endpoint.NewManager(...)
inboundManager := inbound.NewManager(...)
outboundManager := outbound.NewManager(...)
dnsTransportManager := dns.NewTransportManager(...)
serviceManager := boxService.NewManager(...)
// 3. تسجيل المديرين في السياق
service.MustRegister[adapter.EndpointManager](ctx, endpointManager)
service.MustRegister[adapter.InboundManager](ctx, inboundManager)
// ... إلخ.
// 4. إنشاء الموجّه وموجّه DNS
dnsRouter := dns.NewRouter(ctx, logFactory, dnsOptions)
networkManager := route.NewNetworkManager(ctx, ...)
connectionManager := route.NewConnectionManager(...)
router := route.NewRouter(ctx, ...)
// 5. تهيئة قواعد الموجّه
router.Initialize(routeOptions.Rules, routeOptions.RuleSet)
dnsRouter.Initialize(dnsOptions.Rules)
// 6. إنشاء جميع المكونات المُعدّة عبر السجلات
for _, transportOptions := range dnsOptions.Servers {
dnsTransportManager.Create(ctx, ..., transportOptions.Type, transportOptions.Options)
}
for _, endpointOptions := range options.Endpoints {
endpointManager.Create(ctx, ..., endpointOptions.Type, endpointOptions.Options)
}
for _, inboundOptions := range options.Inbounds {
inboundManager.Create(ctx, ..., inboundOptions.Type, inboundOptions.Options)
}
for _, outboundOptions := range options.Outbounds {
outboundManager.Create(ctx, ..., outboundOptions.Type, outboundOptions.Options)
}
// 7. تعيين الصادر الافتراضي ونقل DNS الافتراضي
outboundManager.Initialize(func() { return direct.NewOutbound(...) })
dnsTransportManager.Initialize(func() { return local.NewTransport(...) })
// 8. إنشاء الخدمات الداخلية (cache-file, clash-api, v2ray-api, ntp)
// ...
}مراحل البدء
تستخدم واجهة دورة الحياة تعداد StartStage:
go
type StartStage uint8
const (
StartStateInitialize StartStage = iota // المرحلة 0: الإعداد الداخلي
StartStateStart // المرحلة 1: بدء الخدمة
StartStatePostStart // المرحلة 2: خطافات ما بعد البدء
StartStateStarted // المرحلة 3: التنظيف
)
type Lifecycle interface {
Start(stage StartStage) error
Close() error
}ترتيب تنفيذ المراحل
PreStart():
المرحلة 0 (تهيئة): الخدمات الداخلية ← الشبكة ← نقل DNS ← موجّه DNS ←
الاتصال ← الموجّه ← الصادر ← الوارد ← نقطة النهاية ← الخدمة
المرحلة 1 (بدء): الصادر ← نقل DNS ← موجّه DNS ← الشبكة ←
الاتصال ← الموجّه
Start() (استكمال من PreStart):
المرحلة 1 (بدء): الخدمات الداخلية ← الوارد ← نقطة النهاية ← الخدمة
المرحلة 2 (ما بعد البدء): الصادر ← الشبكة ← نقل DNS ← موجّه DNS ←
الاتصال ← الموجّه ← الوارد ← نقطة النهاية ← الخدمة ←
الخدمات الداخلية
المرحلة 3 (مُبتدأ): الشبكة ← نقل DNS ← موجّه DNS ← الاتصال ←
الموجّه ← الصادر ← الوارد ← نقطة النهاية ← الخدمة ←
الخدمات الداخليةلماذا مراحل متعددة؟
- تهيئة: إنشاء الحالة الداخلية، حل التبعيات بين المديرين
- بدء: بدء الاستماع/الاتصال. تبدأ الصادرات أولاً (مطلوبة لنقل DNS والواردات)
- ما بعد البدء: المهام التي تتطلب تشغيل خدمات أخرى (مثل القواعد التي تشير إلى مجموعات قواعد)
- مُبتدأ: تنظيف البيانات المؤقتة، تشغيل جامع القمامة
الإيقاف
go
func (s *Box) Close() error {
close(s.done) // إشارة الإيقاف
// الإغلاق بترتيب عكسي للتبعيات:
// الخدمة ← نقطة النهاية ← الوارد ← الصادر ← الموجّه ←
// الاتصال ← موجّه DNS ← نقل DNS ← الشبكة
// ثم الخدمات الداخلية (cache-file, clash-api, إلخ.)
// ثم المسجّل
}PreStart مقابل Start
يدعم sing-box وضعين للبدء:
Box.Start()— بدء كامل، يستدعيpreStart()ثمstart()داخلياًBox.PreStart()— بدء جزئي لمنصات الأجهزة المحمولة حيث يجب أن تبدأ الواردات لاحقاً
يهيّئ PreStart كل شيء ويبدأ الصادرات/DNS/الموجّه، لكنه لا يبدأ الواردات/نقاط النهاية/الخدمات. هذا يسمح لطبقة المنصة بإعداد TUN قبل تدفق حركة المرور.
مراقب المهام
تستخدم كل مرحلة taskmonitor.New() لتسجيل العمليات البطيئة:
go
monitor := taskmonitor.New(s.logger, C.StartTimeout)
monitor.Start("start logger")
err := s.logFactory.Start()
monitor.Finish()إذا تجاوزت مهمة ما C.StartTimeout (60 ثانية)، يتم تسجيل تحذير باسم المهمة.