types.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package server
  2. import (
  3. "heckel.io/ntfy/util"
  4. "net/http"
  5. "time"
  6. )
  7. // List of possible events
  8. const (
  9. openEvent = "open"
  10. keepaliveEvent = "keepalive"
  11. messageEvent = "message"
  12. )
  13. const (
  14. messageIDLength = 10
  15. )
  16. // message represents a message published to a topic
  17. type message struct {
  18. ID string `json:"id"` // Random message ID
  19. Time int64 `json:"time"` // Unix time in seconds
  20. Event string `json:"event"` // One of the above
  21. Topic string `json:"topic"`
  22. Priority int `json:"priority,omitempty"`
  23. Tags []string `json:"tags,omitempty"`
  24. Click string `json:"click,omitempty"`
  25. Attachment *attachment `json:"attachment,omitempty"`
  26. Title string `json:"title,omitempty"`
  27. Message string `json:"message,omitempty"`
  28. Encoding string `json:"encoding,omitempty"` // empty for raw UTF-8, or "base64" for encoded bytes
  29. }
  30. type attachment struct {
  31. Name string `json:"name"`
  32. Type string `json:"type,omitempty"`
  33. Size int64 `json:"size,omitempty"`
  34. Expires int64 `json:"expires,omitempty"`
  35. URL string `json:"url"`
  36. Owner string `json:"-"` // IP address of uploader, used for rate limiting
  37. }
  38. // messageEncoder is a function that knows how to encode a message
  39. type messageEncoder func(msg *message) (string, error)
  40. // newMessage creates a new message with the current timestamp
  41. func newMessage(event, topic, msg string) *message {
  42. return &message{
  43. ID: util.RandomString(messageIDLength),
  44. Time: time.Now().Unix(),
  45. Event: event,
  46. Topic: topic,
  47. Priority: 0,
  48. Tags: nil,
  49. Title: "",
  50. Message: msg,
  51. }
  52. }
  53. // newOpenMessage is a convenience method to create an open message
  54. func newOpenMessage(topic string) *message {
  55. return newMessage(openEvent, topic, "")
  56. }
  57. // newKeepaliveMessage is a convenience method to create a keepalive message
  58. func newKeepaliveMessage(topic string) *message {
  59. return newMessage(keepaliveEvent, topic, "")
  60. }
  61. // newDefaultMessage is a convenience method to create a notification message
  62. func newDefaultMessage(topic, msg string) *message {
  63. return newMessage(messageEvent, topic, msg)
  64. }
  65. type sinceTime time.Time
  66. func (t sinceTime) IsAll() bool {
  67. return t == sinceAllMessages
  68. }
  69. func (t sinceTime) IsNone() bool {
  70. return t == sinceNoMessages
  71. }
  72. func (t sinceTime) Time() time.Time {
  73. return time.Time(t)
  74. }
  75. var (
  76. sinceAllMessages = sinceTime(time.Unix(0, 0))
  77. sinceNoMessages = sinceTime(time.Unix(1, 0))
  78. )
  79. type queryFilter struct {
  80. Message string
  81. Title string
  82. Tags []string
  83. Priority []int
  84. }
  85. func parseQueryFilters(r *http.Request) (*queryFilter, error) {
  86. messageFilter := readParam(r, "x-message", "message", "m")
  87. titleFilter := readParam(r, "x-title", "title", "t")
  88. tagsFilter := util.SplitNoEmpty(readParam(r, "x-tags", "tags", "tag", "ta"), ",")
  89. priorityFilter := make([]int, 0)
  90. for _, p := range util.SplitNoEmpty(readParam(r, "x-priority", "priority", "prio", "p"), ",") {
  91. priority, err := util.ParsePriority(p)
  92. if err != nil {
  93. return nil, err
  94. }
  95. priorityFilter = append(priorityFilter, priority)
  96. }
  97. return &queryFilter{
  98. Message: messageFilter,
  99. Title: titleFilter,
  100. Tags: tagsFilter,
  101. Priority: priorityFilter,
  102. }, nil
  103. }
  104. func (q *queryFilter) Pass(msg *message) bool {
  105. if msg.Event != messageEvent {
  106. return true // filters only apply to messages
  107. }
  108. if q.Message != "" && msg.Message != q.Message {
  109. return false
  110. }
  111. if q.Title != "" && msg.Title != q.Title {
  112. return false
  113. }
  114. messagePriority := msg.Priority
  115. if messagePriority == 0 {
  116. messagePriority = 3 // For query filters, default priority (3) is the same as "not set" (0)
  117. }
  118. if len(q.Priority) > 0 && !util.InIntList(q.Priority, messagePriority) {
  119. return false
  120. }
  121. if len(q.Tags) > 0 && !util.InStringListAll(msg.Tags, q.Tags) {
  122. return false
  123. }
  124. return true
  125. }