2016-06-30 22:21:57 +03:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
2018-12-19 10:33:23 +03:00
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"reflect"
|
|
|
|
"strings"
|
2020-10-10 00:38:35 +03:00
|
|
|
|
2021-10-26 22:36:04 +03:00
|
|
|
"go.unistack.org/micro/v3/broker"
|
|
|
|
"go.unistack.org/micro/v3/codec"
|
|
|
|
"go.unistack.org/micro/v3/metadata"
|
2024-04-23 22:21:27 +03:00
|
|
|
"go.unistack.org/micro/v3/options"
|
2021-10-26 22:36:04 +03:00
|
|
|
"go.unistack.org/micro/v3/register"
|
|
|
|
"go.unistack.org/micro/v3/server"
|
2016-06-30 22:21:57 +03:00
|
|
|
)
|
|
|
|
|
2018-12-19 10:33:23 +03:00
|
|
|
var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
|
|
|
|
|
|
|
|
type handler struct {
|
|
|
|
reqType reflect.Type
|
|
|
|
ctxType reflect.Type
|
2021-04-25 12:02:18 +03:00
|
|
|
method reflect.Value
|
2018-12-19 10:33:23 +03:00
|
|
|
}
|
|
|
|
|
2018-12-19 12:47:03 +03:00
|
|
|
type httpSubscriber struct {
|
2018-12-19 10:33:23 +03:00
|
|
|
topic string
|
|
|
|
rcvr reflect.Value
|
|
|
|
typ reflect.Type
|
|
|
|
subscriber interface{}
|
|
|
|
handlers []*handler
|
2021-01-29 14:32:32 +03:00
|
|
|
endpoints []*register.Endpoint
|
2018-12-19 10:33:23 +03:00
|
|
|
opts server.SubscriberOptions
|
|
|
|
}
|
|
|
|
|
|
|
|
func newSubscriber(topic string, sub interface{}, opts ...server.SubscriberOption) server.Subscriber {
|
2020-10-10 00:38:35 +03:00
|
|
|
options := server.NewSubscriberOptions(opts...)
|
2018-12-19 10:33:23 +03:00
|
|
|
|
2021-01-29 14:32:32 +03:00
|
|
|
var endpoints []*register.Endpoint
|
2018-12-19 10:33:23 +03:00
|
|
|
var handlers []*handler
|
|
|
|
|
|
|
|
if typ := reflect.TypeOf(sub); typ.Kind() == reflect.Func {
|
|
|
|
h := &handler{
|
|
|
|
method: reflect.ValueOf(sub),
|
|
|
|
}
|
|
|
|
|
|
|
|
switch typ.NumIn() {
|
|
|
|
case 1:
|
|
|
|
h.reqType = typ.In(0)
|
|
|
|
case 2:
|
|
|
|
h.ctxType = typ.In(0)
|
|
|
|
h.reqType = typ.In(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
handlers = append(handlers, h)
|
2021-01-29 14:32:32 +03:00
|
|
|
ep := ®ister.Endpoint{
|
2020-11-18 13:08:50 +03:00
|
|
|
Name: "Func",
|
2021-01-29 14:32:32 +03:00
|
|
|
Request: register.ExtractSubValue(typ),
|
2020-11-18 13:08:50 +03:00
|
|
|
Metadata: metadata.New(2),
|
|
|
|
}
|
|
|
|
ep.Metadata.Set("topic", topic)
|
|
|
|
ep.Metadata.Set("subscriber", "true")
|
|
|
|
endpoints = append(endpoints, ep)
|
2018-12-19 10:33:23 +03:00
|
|
|
} else {
|
|
|
|
hdlr := reflect.ValueOf(sub)
|
|
|
|
name := reflect.Indirect(hdlr).Type().Name()
|
|
|
|
|
|
|
|
for m := 0; m < typ.NumMethod(); m++ {
|
|
|
|
method := typ.Method(m)
|
|
|
|
h := &handler{
|
|
|
|
method: method.Func,
|
|
|
|
}
|
|
|
|
|
|
|
|
switch method.Type.NumIn() {
|
|
|
|
case 2:
|
|
|
|
h.reqType = method.Type.In(1)
|
|
|
|
case 3:
|
|
|
|
h.ctxType = method.Type.In(1)
|
|
|
|
h.reqType = method.Type.In(2)
|
|
|
|
}
|
|
|
|
|
|
|
|
handlers = append(handlers, h)
|
2021-01-29 14:32:32 +03:00
|
|
|
ep := ®ister.Endpoint{
|
2020-11-18 13:08:50 +03:00
|
|
|
Name: name + "." + method.Name,
|
2021-01-29 14:32:32 +03:00
|
|
|
Request: register.ExtractSubValue(method.Type),
|
2020-11-18 13:08:50 +03:00
|
|
|
Metadata: metadata.New(2),
|
|
|
|
}
|
|
|
|
ep.Metadata.Set("topic", topic)
|
|
|
|
ep.Metadata.Set("subscriber", "true")
|
|
|
|
endpoints = append(endpoints, ep)
|
2018-12-19 10:33:23 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-19 12:47:03 +03:00
|
|
|
return &httpSubscriber{
|
2018-12-19 10:33:23 +03:00
|
|
|
rcvr: reflect.ValueOf(sub),
|
|
|
|
typ: reflect.TypeOf(sub),
|
|
|
|
topic: topic,
|
|
|
|
subscriber: sub,
|
|
|
|
handlers: handlers,
|
|
|
|
endpoints: endpoints,
|
|
|
|
opts: options,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-09 21:14:55 +03:00
|
|
|
func (s *Server) createSubHandler(sb *httpSubscriber, opts server.Options) broker.Handler {
|
2019-07-07 14:46:31 +03:00
|
|
|
return func(p broker.Event) error {
|
2018-12-19 10:33:23 +03:00
|
|
|
msg := p.Message()
|
|
|
|
ct := msg.Header["Content-Type"]
|
|
|
|
cf, err := s.newCodec(ct)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-11-18 13:08:50 +03:00
|
|
|
hdr := metadata.Copy(msg.Header)
|
2021-04-26 00:43:06 +03:00
|
|
|
ctx := metadata.NewIncomingContext(context.Background(), hdr)
|
2018-12-19 10:33:23 +03:00
|
|
|
|
|
|
|
results := make(chan error, len(sb.handlers))
|
|
|
|
|
|
|
|
for i := 0; i < len(sb.handlers); i++ {
|
|
|
|
handler := sb.handlers[i]
|
|
|
|
|
|
|
|
var isVal bool
|
|
|
|
var req reflect.Value
|
|
|
|
|
|
|
|
if handler.reqType.Kind() == reflect.Ptr {
|
|
|
|
req = reflect.New(handler.reqType.Elem())
|
|
|
|
} else {
|
|
|
|
req = reflect.New(handler.reqType)
|
|
|
|
isVal = true
|
|
|
|
}
|
|
|
|
if isVal {
|
|
|
|
req = req.Elem()
|
|
|
|
}
|
|
|
|
|
2020-11-25 23:44:32 +03:00
|
|
|
buf := bytes.NewBuffer(msg.Body)
|
2018-12-19 10:33:23 +03:00
|
|
|
|
2020-11-25 23:44:32 +03:00
|
|
|
if err := cf.ReadHeader(buf, &codec.Message{}, codec.Event); err != nil {
|
2018-12-19 10:33:23 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-11-25 23:44:32 +03:00
|
|
|
if err := cf.ReadBody(buf, req.Interface()); err != nil {
|
2018-12-19 10:33:23 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
fn := func(ctx context.Context, msg server.Message) error {
|
|
|
|
var vals []reflect.Value
|
|
|
|
if sb.typ.Kind() != reflect.Func {
|
|
|
|
vals = append(vals, sb.rcvr)
|
|
|
|
}
|
|
|
|
if handler.ctxType != nil {
|
|
|
|
vals = append(vals, reflect.ValueOf(ctx))
|
|
|
|
}
|
|
|
|
|
2022-03-21 15:29:40 +03:00
|
|
|
vals = append(vals, reflect.ValueOf(msg.Body()))
|
2018-12-19 10:33:23 +03:00
|
|
|
|
|
|
|
returnValues := handler.method.Call(vals)
|
|
|
|
if err := returnValues[0].Interface(); err != nil {
|
|
|
|
return err.(error)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-04-23 22:21:27 +03:00
|
|
|
opts.Hooks.EachNext(func(hook options.Hook) {
|
|
|
|
if h, ok := hook.(server.HookSubHandler); ok {
|
|
|
|
fn = h(fn)
|
|
|
|
}
|
|
|
|
})
|
2018-12-19 10:33:23 +03:00
|
|
|
|
|
|
|
go func() {
|
2018-12-19 12:47:03 +03:00
|
|
|
results <- fn(ctx, &httpMessage{
|
2018-12-19 10:33:23 +03:00
|
|
|
topic: sb.topic,
|
|
|
|
contentType: ct,
|
|
|
|
payload: req.Interface(),
|
2020-10-10 00:38:35 +03:00
|
|
|
header: msg.Header,
|
2020-11-25 23:44:32 +03:00
|
|
|
codec: cf,
|
2018-12-19 10:33:23 +03:00
|
|
|
})
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
var errors []string
|
|
|
|
|
|
|
|
for i := 0; i < len(sb.handlers); i++ {
|
|
|
|
if err := <-results; err != nil {
|
|
|
|
errors = append(errors, err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(errors) > 0 {
|
|
|
|
return fmt.Errorf("subscriber error: %s", strings.Join(errors, "\n"))
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2016-06-30 22:21:57 +03:00
|
|
|
}
|
|
|
|
|
2018-12-19 12:47:03 +03:00
|
|
|
func (s *httpSubscriber) Topic() string {
|
2018-12-19 10:33:23 +03:00
|
|
|
return s.topic
|
2016-06-30 22:21:57 +03:00
|
|
|
}
|
|
|
|
|
2018-12-19 12:47:03 +03:00
|
|
|
func (s *httpSubscriber) Subscriber() interface{} {
|
2018-12-19 10:33:23 +03:00
|
|
|
return s.subscriber
|
2016-06-30 22:21:57 +03:00
|
|
|
}
|
|
|
|
|
2021-01-29 14:32:32 +03:00
|
|
|
func (s *httpSubscriber) Endpoints() []*register.Endpoint {
|
2018-12-19 10:33:23 +03:00
|
|
|
return s.endpoints
|
2016-06-30 22:21:57 +03:00
|
|
|
}
|
|
|
|
|
2018-12-19 12:47:03 +03:00
|
|
|
func (s *httpSubscriber) Options() server.SubscriberOptions {
|
2018-12-19 10:33:23 +03:00
|
|
|
return s.opts
|
2016-06-30 22:21:57 +03:00
|
|
|
}
|