github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/clusters/cluster.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 clusters
    19  
    20  import (
    21  	"fmt"
    22  	"github.com/aacfactory/configures"
    23  	"github.com/aacfactory/errors"
    24  	"github.com/aacfactory/fns/barriers"
    25  	"github.com/aacfactory/fns/clusters/proxy"
    26  	"github.com/aacfactory/fns/commons/versions"
    27  	"github.com/aacfactory/fns/context"
    28  	"github.com/aacfactory/fns/services"
    29  	"github.com/aacfactory/fns/shareds"
    30  	"github.com/aacfactory/fns/transports"
    31  	"github.com/aacfactory/logs"
    32  	"github.com/aacfactory/workers"
    33  	"strings"
    34  )
    35  
    36  type ClusterOptions struct {
    37  	Log     logs.Logger
    38  	Config  configures.Config
    39  	Id      string
    40  	Version versions.Version
    41  	Address string
    42  }
    43  
    44  type Cluster interface {
    45  	Construct(options ClusterOptions) (err error)
    46  	AddService(service Service)
    47  	Join(ctx context.Context) (err error)
    48  	Leave(ctx context.Context) (err error)
    49  	NodeEvents() (events <-chan NodeEvent)
    50  	Shared() (shared shareds.Shared)
    51  	Barrier() (barrier barriers.Barrier)
    52  }
    53  
    54  type ClusterBuilderOptions struct {
    55  	Config configures.Config
    56  	Log    logs.Logger
    57  }
    58  
    59  var (
    60  	clusterMap = make(map[string]Cluster)
    61  )
    62  
    63  func RegisterCluster(name string, cluster Cluster) {
    64  	clusterMap[name] = cluster
    65  }
    66  
    67  func loadCluster(name string) (cluster Cluster, has bool) {
    68  	cluster, has = clusterMap[name]
    69  	return
    70  }
    71  
    72  type Options struct {
    73  	Id      string
    74  	Version versions.Version
    75  	Port    int
    76  	Log     logs.Logger
    77  	Worker  workers.Workers
    78  	Local   services.EndpointsManager
    79  	Dialer  transports.Dialer
    80  	Config  Config
    81  }
    82  
    83  func New(options Options) (manager services.EndpointsManager, shared shareds.Shared, barrier barriers.Barrier, handlers []transports.MuxHandler, err error) {
    84  	// signature
    85  	signature := NewSignature(options.Config.Secret)
    86  	// host
    87  	hostRetrieverName := strings.TrimSpace(options.Config.HostRetriever)
    88  	if hostRetrieverName == "" {
    89  		hostRetrieverName = "default"
    90  	}
    91  	hostRetriever, hasHostRetriever := getHostRetriever(hostRetrieverName)
    92  	if !hasHostRetriever {
    93  		err = errors.Warning("fns: new cluster failed").WithCause(fmt.Errorf("host retriever was not found")).WithMeta("name", hostRetrieverName)
    94  		return
    95  	}
    96  	host, hostErr := hostRetriever()
    97  	if hostErr != nil {
    98  		err = errors.Warning("fns: new cluster failed").WithCause(hostErr)
    99  		return
   100  	}
   101  	address := fmt.Sprintf("%s:%d", host, options.Port)
   102  	// cluster
   103  	var cluster Cluster
   104  	if options.Config.Name == developmentName {
   105  		cluster = NewDevelopment(options.Dialer, signature)
   106  	} else {
   107  		has := false
   108  		cluster, has = loadCluster(options.Config.Name)
   109  		if !has {
   110  			err = errors.Warning("fns: new cluster failed").WithCause(fmt.Errorf("cluster was not found")).WithMeta("name", options.Config.Name)
   111  			return
   112  		}
   113  	}
   114  	if options.Config.Option == nil && len(options.Config.Option) < 2 {
   115  		options.Config.Option = []byte{'{', '}'}
   116  	}
   117  	clusterConfig, clusterConfigErr := configures.NewJsonConfig(options.Config.Option)
   118  	if clusterConfigErr != nil {
   119  		err = errors.Warning("fns: new cluster failed").WithCause(clusterConfigErr).WithMeta("name", options.Config.Name)
   120  		return
   121  	}
   122  	clusterErr := cluster.Construct(ClusterOptions{
   123  		Log:     options.Log.With("cluster", options.Config.Name),
   124  		Config:  clusterConfig,
   125  		Id:      options.Id,
   126  		Version: options.Version,
   127  		Address: address,
   128  	})
   129  	if clusterErr != nil {
   130  		err = errors.Warning("fns: new cluster failed").WithCause(clusterErr).WithMeta("name", options.Config.Name)
   131  		return
   132  	}
   133  	// shared
   134  	shared = cluster.Shared()
   135  	// barrier
   136  	barrier = cluster.Barrier()
   137  	// manager
   138  	manager = NewManager(options.Id, options.Version, address, cluster, options.Local, options.Worker, options.Log, options.Dialer, signature)
   139  	// handlers
   140  	handlers = make([]transports.MuxHandler, 0, 1)
   141  	handlers = append(handlers, NewInternalHandler(options.Local, signature))
   142  	if options.Config.Proxy {
   143  		// append proxy handler
   144  		handlers = append(handlers, proxy.NewHandler(signature, manager, cluster.Shared()))
   145  	}
   146  	return
   147  }