gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/api/handler/event/event.go (about) 1 // Package event provides a handler which publishes an event 2 package event 3 4 import ( 5 "encoding/json" 6 "fmt" 7 "io/ioutil" 8 "net/http" 9 "path" 10 "regexp" 11 "strings" 12 "time" 13 14 "github.com/google/uuid" 15 "gitee.com/liuxuezhan/go-micro-v1.18.0/api/handler" 16 proto "gitee.com/liuxuezhan/go-micro-v1.18.0/api/proto" 17 "gitee.com/liuxuezhan/go-micro-v1.18.0/util/ctx" 18 ) 19 20 type event struct { 21 options handler.Options 22 } 23 24 var ( 25 Handler = "event" 26 versionRe = regexp.MustCompilePOSIX("^v[0-9]+$") 27 ) 28 29 func eventName(parts []string) string { 30 return strings.Join(parts, ".") 31 } 32 33 func evRoute(ns, p string) (string, string) { 34 p = path.Clean(p) 35 p = strings.TrimPrefix(p, "/") 36 37 if len(p) == 0 { 38 return ns, "event" 39 } 40 41 parts := strings.Split(p, "/") 42 43 // no path 44 if len(parts) == 0 { 45 // topic: namespace 46 // action: event 47 return strings.Trim(ns, "."), "event" 48 } 49 50 // Treat /v[0-9]+ as versioning 51 // /v1/foo/bar => topic: v1.foo action: bar 52 if len(parts) >= 2 && versionRe.Match([]byte(parts[0])) { 53 topic := ns + "." + strings.Join(parts[:2], ".") 54 action := eventName(parts[1:]) 55 return topic, action 56 } 57 58 // /foo => topic: ns.foo action: foo 59 // /foo/bar => topic: ns.foo action: bar 60 topic := ns + "." + strings.Join(parts[:1], ".") 61 action := eventName(parts[1:]) 62 63 return topic, action 64 } 65 66 func (e *event) ServeHTTP(w http.ResponseWriter, r *http.Request) { 67 // request to topic:event 68 // create event 69 // publish to topic 70 71 topic, action := evRoute(e.options.Namespace, r.URL.Path) 72 73 // create event 74 ev := &proto.Event{ 75 Name: action, 76 // TODO: dedupe event 77 Id: fmt.Sprintf("%s-%s-%s", topic, action, uuid.New().String()), 78 Header: make(map[string]*proto.Pair), 79 Timestamp: time.Now().Unix(), 80 } 81 82 // set headers 83 for key, vals := range r.Header { 84 header, ok := ev.Header[key] 85 if !ok { 86 header = &proto.Pair{ 87 Key: key, 88 } 89 ev.Header[key] = header 90 } 91 header.Values = vals 92 } 93 94 // set body 95 if r.Method == "GET" { 96 bytes, _ := json.Marshal(r.URL.Query()) 97 ev.Data = string(bytes) 98 } else { 99 b, err := ioutil.ReadAll(r.Body) 100 if err != nil { 101 http.Error(w, err.Error(), 500) 102 return 103 } 104 ev.Data = string(b) 105 } 106 107 // get client 108 c := e.options.Service.Client() 109 110 // create publication 111 p := c.NewMessage(topic, ev) 112 113 // publish event 114 if err := c.Publish(ctx.FromRequest(r), p); err != nil { 115 http.Error(w, err.Error(), 500) 116 return 117 } 118 } 119 120 func (e *event) String() string { 121 return "event" 122 } 123 124 func NewHandler(opts ...handler.Option) handler.Handler { 125 return &event{ 126 options: handler.NewOptions(opts...), 127 } 128 }