github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/proxies/proxy.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package proxies 19 20 import ( 21 "fmt" 22 "github.com/aacfactory/errors" 23 "github.com/aacfactory/fns/clusters" 24 "github.com/aacfactory/fns/context" 25 "github.com/aacfactory/fns/runtime" 26 "github.com/aacfactory/fns/services" 27 "github.com/aacfactory/fns/transports" 28 "github.com/aacfactory/logs" 29 ) 30 31 type ProxyOptions struct { 32 Log logs.Logger 33 Config Config 34 Runtime *runtime.Runtime 35 Manager clusters.ClusterEndpointsManager 36 Dialer transports.Dialer 37 } 38 39 type Proxy interface { 40 Construct(options ProxyOptions) (err error) 41 Port() int 42 Run(ctx context.Context) (err error) 43 Shutdown(ctx context.Context) 44 } 45 46 func New(options ...Option) (p Proxy, err error) { 47 opt := Options{ 48 transport: nil, 49 middlewares: make([]transports.Middleware, 0, 1), 50 handlers: make([]transports.MuxHandler, 0, 1), 51 } 52 for _, option := range options { 53 optErr := option(&opt) 54 if optErr != nil { 55 err = errors.Warning("fns: new proxy failed").WithCause(optErr) 56 return 57 } 58 } 59 if opt.transport == nil { 60 err = errors.Warning("fns: new proxy failed").WithCause(fmt.Errorf("transport is required")) 61 return 62 } 63 p = &proxy{ 64 log: nil, 65 transport: opt.transport, 66 middlewares: opt.middlewares, 67 handlers: opt.handlers, 68 } 69 return 70 } 71 72 type proxy struct { 73 log logs.Logger 74 transport transports.Transport 75 middlewares transports.Middlewares 76 handlers []transports.MuxHandler 77 } 78 79 func (p *proxy) Construct(options ProxyOptions) (err error) { 80 p.log = options.Log 81 // config 82 config := options.Config 83 // builtins 84 builtins := make([]services.Service, 0, 1) 85 // middlewares 86 middlewares := make([]transports.Middleware, 0, 1) 87 middlewares = append(middlewares, runtime.Middleware(options.Runtime)) 88 var corsMiddleware transports.Middleware 89 for _, middleware := range p.middlewares { 90 builtin, isBuiltin := middleware.(services.Middleware) 91 if isBuiltin { 92 builtins = append(builtins, builtin.Services()...) 93 } 94 if middleware.Name() == "cors" { 95 corsMiddleware = middleware 96 continue 97 } 98 middlewares = append(middlewares, middleware) 99 } 100 if corsMiddleware != nil { 101 middlewares = append([]transports.Middleware{corsMiddleware}, middlewares...) 102 } 103 middleware, middlewareErr := transports.WaveMiddlewares(p.log, config.Config, middlewares) 104 if middlewareErr != nil { 105 panic(fmt.Errorf("%+v", errors.Warning("fns: new application failed, new transport middleware failed").WithCause(middlewareErr))) 106 return 107 } 108 p.middlewares = middleware 109 // handlers 110 mux := transports.NewMux() 111 for _, handler := range p.handlers { 112 handlerConfig, handlerConfigErr := config.HandlerConfig(handler.Name()) 113 if handlerConfigErr != nil { 114 err = errors.Warning("fns: construct proxy failed, new transport handler failed").WithCause(handlerConfigErr).WithMeta("handler", handler.Name()) 115 return 116 } 117 handlerErr := handler.Construct(transports.MuxHandlerOptions{ 118 Log: p.log.With("handler", handler.Name()), 119 Config: handlerConfig, 120 }) 121 if handlerErr != nil { 122 err = errors.Warning("fns: construct proxy failed, new transport handler failed").WithCause(handlerErr).WithMeta("handler", handler.Name()) 123 return 124 } 125 mux.Add(handler) 126 builtin, isBuiltin := handler.(services.MuxHandler) 127 if isBuiltin { 128 builtins = append(builtins, builtin.Services()...) 129 } 130 } 131 mux.Add(NewProxyHandler(options.Manager, options.Dialer)) 132 // transport 133 transportErr := p.transport.Construct(transports.Options{ 134 Log: p.log.With("transport", p.transport.Name()), 135 Config: config.Config, 136 Handler: middleware.Handler(mux), 137 }) 138 if transportErr != nil { 139 err = errors.Warning("fns: construct proxy failed, new transport failed").WithCause(transportErr) 140 return 141 } 142 for _, builtin := range builtins { 143 err = options.Manager.Add(builtin) 144 if err != nil { 145 err = errors.Warning("fns: construct proxy failed, deploy service failed").WithCause(err) 146 return 147 } 148 } 149 return 150 } 151 152 func (p *proxy) Port() int { 153 return p.transport.Port() 154 } 155 156 func (p *proxy) Run(_ context.Context) (err error) { 157 err = p.transport.ListenAndServe() 158 if err != nil { 159 err = errors.Warning("fns: proxy run failed").WithCause(err) 160 return 161 } 162 return 163 } 164 165 func (p *proxy) Shutdown(ctx context.Context) { 166 p.middlewares.Close() 167 p.transport.Shutdown(ctx) 168 return 169 }