نظام Instance والميزات
core.Instance هو الكائن المركزي الذي يحتفظ بجميع الميزات (DNS، التوجيه، مدراء الوكلاء، إلخ.) ويدير دورة حياتها.
هيكل Instance
// core/xray.go
type Instance struct {
statusLock sync.Mutex
features []features.Feature
pendingResolutions []resolution
pendingOptionalResolutions []resolution
running bool
resolveLock sync.Mutex
ctx context.Context
}النسخة هي في جوهرها حاوية حقن اعتماديات. تُسجِّل الميزات نفسها، ويمكن لميزات أخرى أن تُعلن عن اعتماديات يتم حلها عندما تصبح جميع الميزات المطلوبة متوفرة.
واجهة Feature
كل مكون رئيسي ينفذ واجهة features.Feature:
// features/feature.go
type Feature interface {
common.HasType // Type() interface{}
common.Runnable // Start() error, Close() error
}يتم تحديد أنواع الميزات بقيم مؤشرات حارسة:
func ManagerType() interface{} { return (*Manager)(nil) }
func ClientType() interface{} { return (*Client)(nil) }تسلسل التهيئة
sequenceDiagram
participant Config
participant Instance
participant Feature
participant InboundMgr
participant OutboundMgr
Config->>Instance: New(config)
loop لكل إعداد تطبيق
Instance->>Instance: CreateObject(settings)
Instance->>Feature: AddFeature(feature)
Feature-->>Instance: حل الاعتماديات المعلقة
end
Note over Instance: تسجيل القيم الافتراضية تلقائياً<br/>(DNS، Policy، Router، Stats)
Instance->>Instance: InitSystemDialer(dns, obm)
Instance->>Instance: التحقق: هل جميع الاعتماديات محلولة؟
loop لكل إعداد وارد
Instance->>InboundMgr: AddHandler(handler)
end
loop لكل إعداد صادر
Instance->>OutboundMgr: AddHandler(handler)
end
Note over Instance: النسخة جاهزة (لم تبدأ بعد)
Instance->>Instance: Start()
loop لكل ميزة
Instance->>Feature: Start()
endالخطوات الرئيسية في initInstanceWithConfig()
ميزات التطبيق: التكرار على
config.App(المُوزِّع، المُوجِّه، DNS، السياسات، الإحصائيات، إلخ.)، إنشاء الكائنات عبرCreateObject()، وتسجيلها كميزات.القيم الافتراضية الأساسية: إذا لم يتم تهيئة DNS أو Policy أو Router أو Stats، يتم تسجيل تنفيذات افتراضية (بدون عمليات):
goessentialFeatures := []struct{ Type, Instance }{ {dns.ClientType(), localdns.New()}, {policy.ManagerType(), policy.DefaultManager{}}, {routing.RouterType(), routing.DefaultRouter{}}, {stats.ManagerType(), stats.NoopManager{}}, }تهيئة مُتصل النظام: تهيئة مُتصل النظام العام بعميل DNS ومدير الصادر (لحل DNS في الصادر
freedom).فحص الاعتماديات: إذا بقيت أي
pendingResolutionsدون حل، يفشل التهيئة مع خطأ.المعالجات: إضافة جميع معالجات الوارد والصادر.
حل الاعتماديات
آلية RequireFeatures() تُمكِّن حقن الاعتماديات المُؤجَّل:
// مكون يُعلن عما يحتاجه:
core.RequireFeatures(ctx, func(om outbound.Manager, router routing.Router,
pm policy.Manager, sm stats.Manager, dc dns.Client) error {
return d.Init(config, om, router, pm, sm)
})عند استدعاء RequireFeatures():
- التحقق مما إذا كانت جميع أنواع المعاملات مسجلة مسبقاً
- إذا نعم، يتم استدعاء رد النداء فوراً
- إذا لا، يتم تخزينها كـ
resolutionفيpendingResolutions - في كل مرة يتم فيها استدعاء
AddFeature()، تتم إعادة فحص جميع الحلول المعلقة
يستخدم الحل الانعكاس (reflection) لمطابقة أنواع المعاملات:
type resolution struct {
deps []reflect.Type // أنواع الميزات المطلوبة
callback interface{} // func(features...) error
}إنشاء الكائنات
CreateObject() هي دالة المصنع التي تحول إعدادات protobuf إلى كائنات وقت التشغيل:
// يُستدعى من core/config.go
func CreateObject(server *Instance, config interface{}) (interface{}, error) {
ctx := context.WithValue(server.ctx, xrayKey, server)
return common.CreateObject(ctx, config)
}يستدعي هذا سجل الإعدادات حيث يرتبط كل نوع protobuf بدالة مُنشئ مسجلة عبر common.RegisterConfig().
نمط سجل الإعدادات
كل مكون يتبع هذا النمط:
func init() {
common.Must(common.RegisterConfig((*Config)(nil),
func(ctx context.Context, config interface{}) (interface{}, error) {
c := config.(*Config)
// بناء كائن وقت التشغيل من الإعدادات
return NewHandler(ctx, c)
}))
}نوع Config في protobuf هو المفتاح، ودالة المصنع تنشئ كائن وقت التشغيل. المُغلِّف TypedMessage (protobuf Any) يوفر إلغاء تسلسل آمن النوع.
ملاحظات التنفيذ
لإعادة تنفيذ نظام Instance:
- تحتاج إلى سجل ميزات يربط أنواع الميزات بالنسخ
- مُحلل اعتماديات يُطلق ردود النداء عندما تتوفر جميع الاعتماديات
- مُفكك تسلسل للإعدادات يربط أنواع الإعدادات بالمُنشئات
- دورة حياة الميزة: التسجيل ← حل الاعتماديات ← البدء ← الإغلاق
يمكن استبدال النهج المبني على الانعكاس بتسجيل صريح في اللغات ذات الأنواع الثابتة:
instance.addFeature(dispatcherFeature)
instance.addFeature(routerFeature)
// المُوجِّه يرى أن المُوزِّع متوفر، فيحل اعتماديته