| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 | package appimport (	"context"	"reflect"	"v2ray.com/core/common")type Application interface {	Interface() interface{}	Start() error	Close()}type InitializationCallback func() errorfunc CreateAppFromConfig(ctx context.Context, config interface{}) (Application, error) {	application, err := common.CreateObject(ctx, config)	if err != nil {		return nil, err	}	switch a := application.(type) {	case Application:		return a, nil	default:		return nil, newError("not an application")	}}// A Space contains all apps that may be available in a V2Ray runtime.// Caller must check the availability of an app by calling HasXXX before getting its instance.type Space interface {	GetApplication(appInterface interface{}) Application	AddApplication(application Application) error	Initialize() error	OnInitialize(InitializationCallback)	Start() error	Close()}type spaceImpl struct {	initialized bool	cache       map[reflect.Type]Application	appInit     []InitializationCallback}func NewSpace() Space {	return &spaceImpl{		cache:   make(map[reflect.Type]Application),		appInit: make([]InitializationCallback, 0, 32),	}}func (s *spaceImpl) OnInitialize(f InitializationCallback) {	if s.initialized {		f()	} else {		s.appInit = append(s.appInit, f)	}}func (s *spaceImpl) Initialize() error {	for _, f := range s.appInit {		if err := f(); err != nil {			return err		}	}	s.appInit = nil	s.initialized = true	return nil}func (s *spaceImpl) GetApplication(appInterface interface{}) Application {	if s == nil {		return nil	}	appType := reflect.TypeOf(appInterface)	return s.cache[appType]}func (s *spaceImpl) AddApplication(app Application) error {	if s == nil {		return newError("nil space").AtError()	}	appType := reflect.TypeOf(app.Interface())	s.cache[appType] = app	return nil}func (s *spaceImpl) Start() error {	for _, app := range s.cache {		if err := app.Start(); err != nil {			return err		}	}	return nil}func (s *spaceImpl) Close() {	for _, app := range s.cache {		app.Close()	}}type contextKey intconst (	spaceKey = contextKey(0))func AddApplicationToSpace(ctx context.Context, appConfig interface{}) error {	space := SpaceFromContext(ctx)	if space == nil {		return newError("no space in context").AtError()	}	application, err := CreateAppFromConfig(ctx, appConfig)	if err != nil {		return err	}	return space.AddApplication(application)}func SpaceFromContext(ctx context.Context) Space {	return ctx.Value(spaceKey).(Space)}func ContextWithSpace(ctx context.Context, space Space) context.Context {	return context.WithValue(ctx, spaceKey, space)}
 |