github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/router/subscriber.go (about)

     1  package router
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"hash/crc32"
     7  	"reflect"
     8  	"strings"
     9  
    10  	"github.com/volts-dev/utils"
    11  	"github.com/volts-dev/volts/registry"
    12  )
    13  
    14  type (
    15  	SubscriberOption func(*SubscriberConfig)
    16  
    17  	SubscriberConfig struct {
    18  		Context context.Context
    19  		Queue   string
    20  		// AutoAck defaults to true. When a handler returns
    21  		// with a nil error the message is acked.
    22  		AutoAck  bool
    23  		Internal bool
    24  	}
    25  	/*
    26  		handler struct {
    27  			method  reflect.Value
    28  			reqType reflect.Type
    29  			ctxType reflect.Type
    30  		}
    31  	*/
    32  	subscriber struct {
    33  		topic      string
    34  		rcvr       reflect.Value
    35  		typ        reflect.Type
    36  		subscriber interface{} // 原型 subscriber
    37  		handlers   []*handler
    38  		endpoints  []*registry.Endpoint
    39  		config     SubscriberConfig
    40  	}
    41  
    42  	TSubscriberContext struct {
    43  	}
    44  	// Subscriber interface represents a subscription to a given topic using
    45  	// a specific subscriber function or object with endpoints. It mirrors
    46  	// the handler in its behavior.
    47  	ISubscriber interface {
    48  		Topic() string
    49  		Subscriber() interface{} // 原型
    50  		Endpoints() []*registry.Endpoint
    51  		Handlers() []*handler
    52  		Config() SubscriberConfig
    53  	}
    54  )
    55  
    56  func validateSubscriber(sub ISubscriber) error {
    57  	return nil
    58  }
    59  
    60  func extractValue(v reflect.Type, d int) *registry.Value {
    61  	if d == 3 {
    62  		return nil
    63  	}
    64  	if v == nil {
    65  		return nil
    66  	}
    67  
    68  	if v.Kind() == reflect.Ptr {
    69  		v = v.Elem()
    70  	}
    71  
    72  	arg := &registry.Value{
    73  		Name: v.Name(),
    74  		Type: v.Name(),
    75  	}
    76  
    77  	switch v.Kind() {
    78  	case reflect.Struct:
    79  		for i := 0; i < v.NumField(); i++ {
    80  			f := v.Field(i)
    81  			val := extractValue(f.Type, d+1)
    82  			if val == nil {
    83  				continue
    84  			}
    85  
    86  			// if we can find a json tag use it
    87  			if tags := f.Tag.Get("json"); len(tags) > 0 {
    88  				parts := strings.Split(tags, ",")
    89  				val.Name = parts[0]
    90  			}
    91  
    92  			// if there's no name default it
    93  			if len(val.Name) == 0 {
    94  				val.Name = v.Field(i).Name
    95  			}
    96  
    97  			arg.Values = append(arg.Values, val)
    98  		}
    99  	case reflect.Slice:
   100  		p := v.Elem()
   101  		if p.Kind() == reflect.Ptr {
   102  			p = p.Elem()
   103  		}
   104  		arg.Type = "[]" + p.Name()
   105  		val := extractValue(v.Elem(), d+1)
   106  		if val != nil {
   107  			arg.Values = append(arg.Values, val)
   108  		}
   109  	}
   110  
   111  	return arg
   112  }
   113  
   114  func extractSubValue(typ reflect.Type) *registry.Value {
   115  	var reqType reflect.Type
   116  	switch typ.NumIn() {
   117  	case 1:
   118  		reqType = typ.In(0)
   119  	case 2:
   120  		reqType = typ.In(1)
   121  	case 3:
   122  		reqType = typ.In(2)
   123  	default:
   124  		return nil
   125  	}
   126  	return extractValue(reqType, 0)
   127  }
   128  
   129  func newSubscriber(topic string, sub any, opts ...SubscriberOption) ISubscriber {
   130  	cfg := SubscriberConfig{
   131  		AutoAck: true,
   132  	}
   133  
   134  	for _, o := range opts {
   135  		o(&cfg)
   136  	}
   137  
   138  	handlers, endpoints := parseSubscriber(topic, sub, opts...)
   139  	return &subscriber{
   140  		rcvr:       reflect.ValueOf(sub),
   141  		typ:        reflect.TypeOf(sub),
   142  		topic:      topic,
   143  		subscriber: sub,
   144  		handlers:   handlers,
   145  		endpoints:  endpoints,
   146  		config:     cfg,
   147  	}
   148  }
   149  
   150  func parseSubscriber(topic string, sub any, opts ...SubscriberOption) (handlers []*handler, endpoints []*registry.Endpoint) {
   151  	var hd *handler
   152  	switch v := sub.(type) {
   153  	case func(*TSubscriberContext):
   154  		hd = &handler{
   155  			Id:      int(crc32.ChecksumIEEE([]byte(topic))),
   156  			Manager: deflautHandlerManager,
   157  			Config:  &ControllerConfig{},
   158  			Type:    SubscriberHandler,
   159  			pos:     -1,
   160  
   161  			ctrlType:  reflect.TypeOf(v),
   162  			ctrlValue: reflect.ValueOf(v),
   163  		}
   164  
   165  		hd.TransportType = SubscribeHandler
   166  		hd.funcs = append(hd.funcs, &handle{IsFunc: true, SubFunc: v})
   167  
   168  		handlers = append(handlers, hd)
   169  		endpoints = append(endpoints, &registry.Endpoint{
   170  			Name:    "Func",
   171  			Request: extractSubValue(hd.ctrlType),
   172  			Metadata: map[string]string{
   173  				"topic":      topic,
   174  				"subscriber": "true",
   175  			},
   176  		})
   177  
   178  		return
   179  	default:
   180  		// init Value and Type
   181  		ctrlValue, ok := sub.(reflect.Value)
   182  		if !ok {
   183  			ctrlValue = reflect.ValueOf(sub)
   184  		}
   185  		ctrlType := ctrlValue.Type()
   186  		kind := ctrlType.Kind()
   187  		switch kind {
   188  		case reflect.Struct, reflect.Ptr:
   189  			// transfer prt to struct
   190  			if kind == reflect.Ptr {
   191  				ctrlValue = ctrlValue.Elem()
   192  				ctrlType = ctrlType.Elem()
   193  			}
   194  			// 获取控制器名称
   195  			var objName string
   196  			if v, ok := sub.(IString); ok {
   197  				objName = v.String()
   198  			} else {
   199  				objName = utils.DotCasedName(utils.Obj2Name(v))
   200  			}
   201  
   202  			var name string
   203  			var method reflect.Value
   204  			for i := 0; i < ctrlType.NumMethod(); i++ {
   205  				// get the method information from the ctrl Type
   206  				name = ctrlType.Method(i).Name
   207  				method = ctrlType.Method(i).Func
   208  
   209  				// 忽略非handler方法
   210  				if method.Type().NumIn() <= 1 {
   211  					continue
   212  				}
   213  
   214  				if method.CanInterface() {
   215  					hds, eps := parseSubscriber(objName+"."+name, method, opts...)
   216  
   217  					handlers = append(handlers, hds...)
   218  					endpoints = append(endpoints, eps...)
   219  				}
   220  
   221  			}
   222  			// the end of the struct mapping
   223  			return
   224  		case reflect.Func:
   225  			// Method must be exported.
   226  			if ctrlType.PkgPath() != "" {
   227  				log.Fatalf("Method %s must be exported", v)
   228  				return
   229  			}
   230  
   231  			hd = &handler{
   232  				Id:      int(crc32.ChecksumIEEE([]byte(topic))),
   233  				Manager: deflautHandlerManager,
   234  				Config:  &ControllerConfig{},
   235  				Type:    SubscriberHandler,
   236  				pos:     -1,
   237  
   238  				ctrlType:  ctrlValue.Type(),
   239  				ctrlValue: ctrlValue,
   240  			}
   241  			hd.Name = fmt.Sprintf("%s-%d", topic, hd.Id)
   242  
   243  			handlers = append(handlers, hd)
   244  			endpoints = append(endpoints, &registry.Endpoint{
   245  				Name:    hd.Name,
   246  				Request: extractSubValue(hd.ctrlType),
   247  				Metadata: map[string]string{
   248  					"topic":      topic,
   249  					"subscriber": "true",
   250  				},
   251  			})
   252  		default:
   253  			log.Fatal("controller must be func or bound method")
   254  		}
   255  	}
   256  
   257  	return handlers, endpoints
   258  }
   259  
   260  func (s *subscriber) Topic() string {
   261  	return s.topic
   262  }
   263  
   264  func (s *subscriber) Subscriber() interface{} {
   265  	return s.subscriber
   266  }
   267  
   268  func (s *subscriber) Endpoints() []*registry.Endpoint {
   269  	return s.endpoints
   270  }
   271  func (s *subscriber) Handlers() []*handler {
   272  	return s.handlers
   273  }
   274  
   275  func (s *subscriber) Config() SubscriberConfig {
   276  	return s.config
   277  }