github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/debug/debug_config.go (about)

     1  package debug
     2  
     3  import (
     4  	"context"
     5  	"github.com/isyscore/isc-gobase/config"
     6  	"github.com/isyscore/isc-gobase/logger"
     7  	baseNet "github.com/isyscore/isc-gobase/system/net"
     8  	etcdClientV3 "go.etcd.io/etcd/client/v3"
     9  	"os"
    10  	"strings"
    11  	"sync"
    12  )
    13  
    14  const (
    15  	DEBUG_ETCD_ENDPOINTS  = "debug.etcd.endpoints"
    16  	DEBUG_ETCD_USER       = "debug.etcd.user"
    17  	DEBUG_ETCD_PASSWORD   = "debug.etcd.password"
    18  	DEFAULT_ETCD_ENDPOINT = "etcd-service:22379"
    19  )
    20  
    21  var etcdClient *etcdClientV3.Client
    22  var keyListenerMap map[string][]KeyListener
    23  
    24  var loadLock sync.Mutex
    25  type KeyListener func(key string, value string)
    26  
    27  func Init() {
    28  	if !config.GetValueBoolDefault("debug.enable", true) {
    29  		return
    30  	}
    31  	InitWithParameter(GetEtcdConfig())
    32  }
    33  
    34  func InitWithParameter(endpoints []string, user, password string) {
    35  	loadLock.Lock()
    36  	defer loadLock.Unlock()
    37  	if etcdClient != nil {
    38  		return
    39  	}
    40  
    41  	for _, endpoint := range endpoints {
    42  		if !baseNet.IpPortAvailable(endpoint) {
    43  			// 如果想使用调试模式,请在环境变量里面或者配置文件里面配置如下
    44  			// debug.etcd.endpoints:多个{ip}:{port}格式,中间以逗号(英文逗号)分隔
    45  			// debug.etcd.user
    46  			// debug.etcd.password
    47  			logger.Warn("调试模式【%v】不可用,调试功能暂时不支持", endpoint)
    48  			return
    49  		}
    50  	}
    51  
    52  	_etcdClient := getEtcdClient(endpoints, user, password)
    53  	if _etcdClient == nil {
    54  		return
    55  	}
    56  
    57  	etcdClient = _etcdClient
    58  }
    59  
    60  func getEtcdClient(etcdPoints []string, user, password string) *etcdClientV3.Client {
    61  	// 客户端配置
    62  	etcdCfg := etcdClientV3.Config{
    63  		Endpoints: etcdPoints,
    64  		Username:  user,
    65  		Password:  password,
    66  	}
    67  
    68  	etcdClient, err := etcdClientV3.New(etcdCfg)
    69  	if err != nil {
    70  		logger.Error("生成etcd-client失败:%v", err.Error())
    71  		return nil
    72  	}
    73  
    74  	return etcdClient
    75  }
    76  
    77  // 优先级:vm配置 > 环境变量
    78  func GetEtcdConfig() ([]string, string, string) {
    79  	etcdEndpointStr := os.Getenv(DEBUG_ETCD_ENDPOINTS)
    80  	etcdEndpointStrOfConfig := config.GetValueString(DEBUG_ETCD_ENDPOINTS)
    81  	if etcdEndpointStrOfConfig != "" {
    82  		etcdEndpointStr = etcdEndpointStrOfConfig
    83  	}
    84  
    85  	if etcdEndpointStr == "" {
    86  		etcdEndpointStr = DEFAULT_ETCD_ENDPOINT
    87  	}
    88  
    89  	etcdEndpointsOriginal := strings.Split(etcdEndpointStr, ",")
    90  	var etcdEndpoints []string
    91  	for _, etcdEndpoint := range etcdEndpointsOriginal {
    92  		etcdEndpoint = strings.TrimSpace(etcdEndpoint)
    93  		if strings.HasPrefix(etcdEndpoint, "http://") {
    94  			etcdEndpoint = etcdEndpoint[len("http://"):]
    95  		}
    96  
    97  		etcdEndpoints = append(etcdEndpoints, etcdEndpoint)
    98  	}
    99  
   100  	etcdUser := os.Getenv(DEBUG_ETCD_USER)
   101  	etcdUserOfConfig := config.GetValueString(DEBUG_ETCD_USER)
   102  	if etcdUserOfConfig != "" {
   103  		etcdUser = etcdUserOfConfig
   104  	}
   105  
   106  	etcdPassword := os.Getenv(DEBUG_ETCD_PASSWORD)
   107  	etcdPasswordOfConfig := config.GetValueString(DEBUG_ETCD_PASSWORD)
   108  	if etcdPasswordOfConfig != "" {
   109  		etcdPassword = etcdPasswordOfConfig
   110  	}
   111  
   112  	return etcdEndpoints, etcdUser, etcdPassword
   113  }
   114  
   115  func AddWatcher(key string, keyListener KeyListener) {
   116  	if etcdClient == nil {
   117  		return
   118  	}
   119  
   120  	if keyListenerMap == nil {
   121  		keyListenerMap = map[string][]KeyListener{}
   122  	}
   123  	if eventWatchers, exist := keyListenerMap[key]; exist {
   124  		eventWatchers = append(eventWatchers, keyListener)
   125  		keyListenerMap[key] = eventWatchers
   126  	} else {
   127  		eventWatchers = []KeyListener{}
   128  		eventWatchers = append(eventWatchers, keyListener)
   129  		keyListenerMap[key] = eventWatchers
   130  	}
   131  }
   132  
   133  func Update(key, value string) {
   134  	ctx := context.Background()
   135  	_, err := etcdClient.Put(ctx, key, value)
   136  	if err != nil {
   137  		logger.Error("更新调试配置报错")
   138  		return
   139  	}
   140  }
   141  
   142  func StartWatch() {
   143  	for key, listeners := range keyListenerMap {
   144  		watchKey := key
   145  		keyListeners := listeners
   146  		go func() {
   147  			var currentVersion int64 = 0
   148  			ctx := context.Background()
   149  
   150  			// 首次启动获取最新的
   151  			rsp, err := etcdClient.Get(ctx, watchKey)
   152  			if err != nil {
   153  				logger.Error("获取etcd的key异常, %v", err.Error())
   154  				return
   155  			} else {
   156  				for _, kv := range rsp.Kvs {
   157  					if watchKey == string(kv.Key) {
   158  						currentVersion = kv.ModRevision
   159  						go notifyWatcher(watchKey, string(kv.Value), keyListeners)
   160  					}
   161  				}
   162  			}
   163  
   164  			// 根据本地保存的最新版本进行watch
   165  			watchRsp := etcdClient.Watch(ctx, watchKey, etcdClientV3.WithRev(currentVersion))
   166  			for res := range watchRsp {
   167  				for _, event := range res.Events {
   168  					if watchKey != string(event.Kv.Key) {
   169  						continue
   170  					}
   171  					latestModVersion := event.Kv.ModRevision
   172  
   173  					if currentVersion == event.Kv.ModRevision {
   174  						continue
   175  					} else if currentVersion < latestModVersion {
   176  						currentVersion = latestModVersion
   177  						go notifyWatcher(watchKey, string(event.Kv.Value), keyListeners)
   178  					}
   179  				}
   180  			}
   181  		}()
   182  	}
   183  }
   184  
   185  func notifyWatcher(key, value string, listeners []KeyListener) {
   186  	for _, listener := range listeners {
   187  		listener(key, value)
   188  	}
   189  }