/vendor/github.com/micro/go-api/handler/event/event.go

https://github.com/pydio/cells · Go · 120 lines · 81 code · 22 blank · 17 comment · 12 complexity · b41f48744ee81a76cd24f73c7e4dad9d MD5 · raw file

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