github.com/imannamdari/v2ray-core/v5@v5.0.5/v2ray.go (about) 1 package core 2 3 import ( 4 "context" 5 "reflect" 6 "sync" 7 8 "github.com/imannamdari/v2ray-core/v5/common" 9 "github.com/imannamdari/v2ray-core/v5/common/environment" 10 "github.com/imannamdari/v2ray-core/v5/common/environment/transientstorageimpl" 11 "github.com/imannamdari/v2ray-core/v5/common/serial" 12 "github.com/imannamdari/v2ray-core/v5/features" 13 "github.com/imannamdari/v2ray-core/v5/features/dns" 14 "github.com/imannamdari/v2ray-core/v5/features/dns/localdns" 15 "github.com/imannamdari/v2ray-core/v5/features/inbound" 16 "github.com/imannamdari/v2ray-core/v5/features/outbound" 17 "github.com/imannamdari/v2ray-core/v5/features/policy" 18 "github.com/imannamdari/v2ray-core/v5/features/routing" 19 "github.com/imannamdari/v2ray-core/v5/features/stats" 20 ) 21 22 // Server is an instance of V2Ray. At any time, there must be at most one Server instance running. 23 type Server interface { 24 common.Runnable 25 } 26 27 // ServerType returns the type of the server. 28 func ServerType() interface{} { 29 return (*Instance)(nil) 30 } 31 32 type resolution struct { 33 deps []reflect.Type 34 callback interface{} 35 } 36 37 func getFeature(allFeatures []features.Feature, t reflect.Type) features.Feature { 38 for _, f := range allFeatures { 39 if reflect.TypeOf(f.Type()) == t { 40 return f 41 } 42 } 43 return nil 44 } 45 46 func (r *resolution) resolve(allFeatures []features.Feature) (bool, error) { 47 var fs []features.Feature 48 for _, d := range r.deps { 49 f := getFeature(allFeatures, d) 50 if f == nil { 51 return false, nil 52 } 53 fs = append(fs, f) 54 } 55 56 callback := reflect.ValueOf(r.callback) 57 var input []reflect.Value 58 callbackType := callback.Type() 59 for i := 0; i < callbackType.NumIn(); i++ { 60 pt := callbackType.In(i) 61 for _, f := range fs { 62 if reflect.TypeOf(f).AssignableTo(pt) { 63 input = append(input, reflect.ValueOf(f)) 64 break 65 } 66 } 67 } 68 69 if len(input) != callbackType.NumIn() { 70 panic("Can't get all input parameters") 71 } 72 73 var err error 74 ret := callback.Call(input) 75 errInterface := reflect.TypeOf((*error)(nil)).Elem() 76 for i := len(ret) - 1; i >= 0; i-- { 77 if ret[i].Type() == errInterface { 78 v := ret[i].Interface() 79 if v != nil { 80 err = v.(error) 81 } 82 break 83 } 84 } 85 86 return true, err 87 } 88 89 // Instance combines all functionalities in V2Ray. 90 type Instance struct { 91 access sync.Mutex 92 features []features.Feature 93 featureResolutions []resolution 94 running bool 95 env environment.RootEnvironment 96 97 ctx context.Context 98 } 99 100 func AddInboundHandler(server *Instance, config *InboundHandlerConfig) error { 101 inboundManager := server.GetFeature(inbound.ManagerType()).(inbound.Manager) 102 proxyEnv := server.env.ProxyEnvironment("i" + config.Tag) 103 rawHandler, err := CreateObjectWithEnvironment(server, config, proxyEnv) 104 if err != nil { 105 return err 106 } 107 handler, ok := rawHandler.(inbound.Handler) 108 if !ok { 109 return newError("not an InboundHandler") 110 } 111 if err := inboundManager.AddHandler(server.ctx, handler); err != nil { 112 return err 113 } 114 return nil 115 } 116 117 func addInboundHandlers(server *Instance, configs []*InboundHandlerConfig) error { 118 for _, inboundConfig := range configs { 119 if err := AddInboundHandler(server, inboundConfig); err != nil { 120 return err 121 } 122 } 123 124 return nil 125 } 126 127 func AddOutboundHandler(server *Instance, config *OutboundHandlerConfig) error { 128 outboundManager := server.GetFeature(outbound.ManagerType()).(outbound.Manager) 129 proxyEnv := server.env.ProxyEnvironment("o" + config.Tag) 130 rawHandler, err := CreateObjectWithEnvironment(server, config, proxyEnv) 131 if err != nil { 132 return err 133 } 134 handler, ok := rawHandler.(outbound.Handler) 135 if !ok { 136 return newError("not an OutboundHandler") 137 } 138 if err := outboundManager.AddHandler(server.ctx, handler); err != nil { 139 return err 140 } 141 return nil 142 } 143 144 func addOutboundHandlers(server *Instance, configs []*OutboundHandlerConfig) error { 145 for _, outboundConfig := range configs { 146 if err := AddOutboundHandler(server, outboundConfig); err != nil { 147 return err 148 } 149 } 150 151 return nil 152 } 153 154 // RequireFeatures is a helper function to require features from Instance in context. 155 // See Instance.RequireFeatures for more information. 156 func RequireFeatures(ctx context.Context, callback interface{}) error { 157 v := MustFromContext(ctx) 158 return v.RequireFeatures(callback) 159 } 160 161 // New returns a new V2Ray instance based on given configuration. 162 // The instance is not started at this point. 163 // To ensure V2Ray instance works properly, the config must contain one Dispatcher, one InboundHandlerManager and one OutboundHandlerManager. Other features are optional. 164 func New(config *Config) (*Instance, error) { 165 server := &Instance{ctx: context.Background()} 166 167 done, err := initInstanceWithConfig(config, server) 168 if done { 169 return nil, err 170 } 171 172 return server, nil 173 } 174 175 func NewWithContext(ctx context.Context, config *Config) (*Instance, error) { 176 server := &Instance{ctx: ctx} 177 178 done, err := initInstanceWithConfig(config, server) 179 if done { 180 return nil, err 181 } 182 183 return server, nil 184 } 185 186 func initInstanceWithConfig(config *Config, server *Instance) (bool, error) { 187 if config.Transport != nil { 188 features.PrintDeprecatedFeatureWarning("global transport settings") 189 } 190 if err := config.Transport.Apply(); err != nil { 191 return true, err 192 } 193 194 server.env = environment.NewRootEnvImpl(server.ctx, transientstorageimpl.NewScopedTransientStorageImpl()) 195 196 for _, appSettings := range config.App { 197 settings, err := serial.GetInstanceOf(appSettings) 198 if err != nil { 199 return true, err 200 } 201 key := appSettings.TypeUrl 202 appEnv := server.env.AppEnvironment(key) 203 obj, err := CreateObjectWithEnvironment(server, settings, appEnv) 204 if err != nil { 205 return true, err 206 } 207 if feature, ok := obj.(features.Feature); ok { 208 if err := server.AddFeature(feature); err != nil { 209 return true, err 210 } 211 } 212 } 213 214 essentialFeatures := []struct { 215 Type interface{} 216 Instance features.Feature 217 }{ 218 {dns.ClientType(), localdns.New()}, 219 {policy.ManagerType(), policy.DefaultManager{}}, 220 {routing.RouterType(), routing.DefaultRouter{}}, 221 {stats.ManagerType(), stats.NoopManager{}}, 222 } 223 224 for _, f := range essentialFeatures { 225 if server.GetFeature(f.Type) == nil { 226 if err := server.AddFeature(f.Instance); err != nil { 227 return true, err 228 } 229 } 230 } 231 232 if server.featureResolutions != nil { 233 return true, newError("not all dependency are resolved.") 234 } 235 236 if err := addInboundHandlers(server, config.Inbound); err != nil { 237 return true, err 238 } 239 240 if err := addOutboundHandlers(server, config.Outbound); err != nil { 241 return true, err 242 } 243 return false, nil 244 } 245 246 // Type implements common.HasType. 247 func (s *Instance) Type() interface{} { 248 return ServerType() 249 } 250 251 // Close shutdown the V2Ray instance. 252 func (s *Instance) Close() error { 253 s.access.Lock() 254 defer s.access.Unlock() 255 256 s.running = false 257 258 var errors []interface{} 259 for _, f := range s.features { 260 if err := f.Close(); err != nil { 261 errors = append(errors, err) 262 } 263 } 264 if len(errors) > 0 { 265 return newError("failed to close all features").Base(newError(serial.Concat(errors...))) 266 } 267 268 return nil 269 } 270 271 // RequireFeatures registers a callback, which will be called when all dependent features are registered. 272 // The callback must be a func(). All its parameters must be features.Feature. 273 func (s *Instance) RequireFeatures(callback interface{}) error { 274 callbackType := reflect.TypeOf(callback) 275 if callbackType.Kind() != reflect.Func { 276 panic("not a function") 277 } 278 279 var featureTypes []reflect.Type 280 for i := 0; i < callbackType.NumIn(); i++ { 281 featureTypes = append(featureTypes, reflect.PtrTo(callbackType.In(i))) 282 } 283 284 r := resolution{ 285 deps: featureTypes, 286 callback: callback, 287 } 288 if finished, err := r.resolve(s.features); finished { 289 return err 290 } 291 s.featureResolutions = append(s.featureResolutions, r) 292 return nil 293 } 294 295 // AddFeature registers a feature into current Instance. 296 func (s *Instance) AddFeature(feature features.Feature) error { 297 s.features = append(s.features, feature) 298 299 if s.running { 300 if err := feature.Start(); err != nil { 301 newError("failed to start feature").Base(err).WriteToLog() 302 } 303 return nil 304 } 305 306 if s.featureResolutions == nil { 307 return nil 308 } 309 310 var pendingResolutions []resolution 311 for _, r := range s.featureResolutions { 312 finished, err := r.resolve(s.features) 313 if finished && err != nil { 314 return err 315 } 316 if !finished { 317 pendingResolutions = append(pendingResolutions, r) 318 } 319 } 320 if len(pendingResolutions) == 0 { 321 s.featureResolutions = nil 322 } else if len(pendingResolutions) < len(s.featureResolutions) { 323 s.featureResolutions = pendingResolutions 324 } 325 326 return nil 327 } 328 329 // GetFeature returns a feature of the given type, or nil if such feature is not registered. 330 func (s *Instance) GetFeature(featureType interface{}) features.Feature { 331 return getFeature(s.features, reflect.TypeOf(featureType)) 332 } 333 334 // Start starts the V2Ray instance, including all registered features. When Start returns error, the state of the instance is unknown. 335 // A V2Ray instance can be started only once. Upon closing, the instance is not guaranteed to start again. 336 // 337 // v2ray:api:stable 338 func (s *Instance) Start() error { 339 s.access.Lock() 340 defer s.access.Unlock() 341 342 s.running = true 343 for _, f := range s.features { 344 if err := f.Start(); err != nil { 345 return err 346 } 347 } 348 349 newError("V2Ray ", Version(), " started").AtWarning().WriteToLog() 350 351 return nil 352 }