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  }