|  | @@ -1,5 +1,16 @@
 | 
	
		
			
				|  |  |  package app
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +import (
 | 
	
		
			
				|  |  | +	"errors"
 | 
	
		
			
				|  |  | +	"sync/atomic"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	"github.com/v2ray/v2ray-core/common"
 | 
	
		
			
				|  |  | +)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +var (
 | 
	
		
			
				|  |  | +	ErrorMissingApplication = errors.New("App: Failed to found one or more applications.")
 | 
	
		
			
				|  |  | +)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  type ID int
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // Context of a function call from proxy to app.
 | 
	
	
		
			
				|  | @@ -11,22 +22,60 @@ type Caller interface {
 | 
	
		
			
				|  |  |  	Tag() string
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +type Application interface {
 | 
	
		
			
				|  |  | +	common.Releasable
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +type ApplicationInitializer func() error
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  // 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 {
 | 
	
		
			
				|  |  | +	Initialize() error
 | 
	
		
			
				|  |  | +	InitializeApplication(ApplicationInitializer)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	HasApp(ID) bool
 | 
	
		
			
				|  |  | -	GetApp(ID) interface{}
 | 
	
		
			
				|  |  | -	BindApp(ID, interface{})
 | 
	
		
			
				|  |  | +	GetApp(ID) Application
 | 
	
		
			
				|  |  | +	BindApp(ID, Application)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  type spaceImpl struct {
 | 
	
		
			
				|  |  | -	cache map[ID]interface{}
 | 
	
		
			
				|  |  | +	cache      map[ID]Application
 | 
	
		
			
				|  |  | +	initSignal chan struct{}
 | 
	
		
			
				|  |  | +	initErrors chan error
 | 
	
		
			
				|  |  | +	appsToInit int32
 | 
	
		
			
				|  |  | +	appsDone   int32
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func NewSpace() Space {
 | 
	
		
			
				|  |  |  	return &spaceImpl{
 | 
	
		
			
				|  |  | -		cache: make(map[ID]interface{}),
 | 
	
		
			
				|  |  | +		cache:      make(map[ID]Application),
 | 
	
		
			
				|  |  | +		initSignal: make(chan struct{}),
 | 
	
		
			
				|  |  | +		initErrors: make(chan error, 1),
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func (this *spaceImpl) InitializeApplication(f ApplicationInitializer) {
 | 
	
		
			
				|  |  | +	atomic.AddInt32(&(this.appsToInit), 1)
 | 
	
		
			
				|  |  | +	go func() {
 | 
	
		
			
				|  |  | +		<-this.initSignal
 | 
	
		
			
				|  |  | +		err := f()
 | 
	
		
			
				|  |  | +		if err != nil {
 | 
	
		
			
				|  |  | +			this.initErrors <- err
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		count := atomic.AddInt32(&(this.appsDone), 1)
 | 
	
		
			
				|  |  | +		if count == this.appsToInit {
 | 
	
		
			
				|  |  | +			close(this.initErrors)
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}()
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +func (this *spaceImpl) Initialize() error {
 | 
	
		
			
				|  |  | +	close(this.initSignal)
 | 
	
		
			
				|  |  | +	if err, open := <-this.initErrors; open {
 | 
	
		
			
				|  |  | +		return err
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | +	return nil
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func (this *spaceImpl) HasApp(id ID) bool {
 | 
	
	
		
			
				|  | @@ -34,7 +83,7 @@ func (this *spaceImpl) HasApp(id ID) bool {
 | 
	
		
			
				|  |  |  	return found
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (this *spaceImpl) GetApp(id ID) interface{} {
 | 
	
		
			
				|  |  | +func (this *spaceImpl) GetApp(id ID) Application {
 | 
	
		
			
				|  |  |  	obj, found := this.cache[id]
 | 
	
		
			
				|  |  |  	if !found {
 | 
	
		
			
				|  |  |  		return nil
 | 
	
	
		
			
				|  | @@ -42,6 +91,6 @@ func (this *spaceImpl) GetApp(id ID) interface{} {
 | 
	
		
			
				|  |  |  	return obj
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (this *spaceImpl) BindApp(id ID, object interface{}) {
 | 
	
		
			
				|  |  | -	this.cache[id] = object
 | 
	
		
			
				|  |  | +func (this *spaceImpl) BindApp(id ID, application Application) {
 | 
	
		
			
				|  |  | +	this.cache[id] = application
 | 
	
		
			
				|  |  |  }
 |