forked from v2ray/v2ray-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
space.go
130 lines (111 loc) · 2.6 KB
/
space.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package app
import (
"context"
"reflect"
"v2ray.com/core/common"
)
type Application interface {
Interface() interface{}
Start() error
Close()
}
type InitializationCallback func() error
func 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 int
const (
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)
}