You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

responsebuffer.go 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
  2. // released under the MIT license
  3. package irc
  4. import (
  5. "time"
  6. "github.com/goshuirc/irc-go/ircmsg"
  7. "github.com/oragono/oragono/irc/caps"
  8. )
  9. // ResponseBuffer - put simply - buffers messages and then outputs them to a given client.
  10. //
  11. // Using a ResponseBuffer lets you really easily implement labeled-response, since the
  12. // buffer will silently create a batch if required and label the outgoing messages as
  13. // necessary (or leave it off and simply tag the outgoing message).
  14. type ResponseBuffer struct {
  15. Label string
  16. target *Client
  17. messages []ircmsg.IrcMessage
  18. }
  19. // GetLabel returns the label from the given message.
  20. func GetLabel(msg ircmsg.IrcMessage) string {
  21. return msg.Tags[caps.LabelTagName].Value
  22. }
  23. // NewResponseBuffer returns a new ResponseBuffer.
  24. func NewResponseBuffer(target *Client) *ResponseBuffer {
  25. return &ResponseBuffer{
  26. target: target,
  27. }
  28. }
  29. // Add adds a standard new message to our queue.
  30. func (rb *ResponseBuffer) Add(tags *map[string]ircmsg.TagValue, prefix string, command string, params ...string) {
  31. message := ircmsg.MakeMessage(tags, prefix, command, params...)
  32. rb.messages = append(rb.messages, message)
  33. }
  34. // AddFromClient adds a new message from a specific client to our queue.
  35. func (rb *ResponseBuffer) AddFromClient(msgid string, from *Client, tags *map[string]ircmsg.TagValue, command string, params ...string) {
  36. // attach account-tag
  37. if rb.target.capabilities.Has(caps.AccountTag) && from.LoggedIntoAccount() {
  38. if tags == nil {
  39. tags = ircmsg.MakeTags("account", from.AccountName())
  40. } else {
  41. (*tags)["account"] = ircmsg.MakeTagValue(from.AccountName())
  42. }
  43. }
  44. // attach message-id
  45. if len(msgid) > 0 && rb.target.capabilities.Has(caps.MessageTags) {
  46. if tags == nil {
  47. tags = ircmsg.MakeTags("draft/msgid", msgid)
  48. } else {
  49. (*tags)["draft/msgid"] = ircmsg.MakeTagValue(msgid)
  50. }
  51. }
  52. rb.Add(tags, from.nickMaskString, command, params...)
  53. }
  54. // AddSplitMessageFromClient adds a new split message from a specific client to our queue.
  55. func (rb *ResponseBuffer) AddSplitMessageFromClient(msgid string, from *Client, tags *map[string]ircmsg.TagValue, command string, target string, message SplitMessage) {
  56. if rb.target.capabilities.Has(caps.MaxLine) {
  57. rb.AddFromClient(msgid, from, tags, command, target, message.ForMaxLine)
  58. } else {
  59. for _, str := range message.For512 {
  60. rb.AddFromClient(msgid, from, tags, command, target, str)
  61. }
  62. }
  63. }
  64. // Send sends the message to our target client.
  65. func (rb *ResponseBuffer) Send() error {
  66. // fall out if no messages to send
  67. if len(rb.messages) == 0 {
  68. return nil
  69. }
  70. // make batch and all if required
  71. var batch *Batch
  72. useLabel := rb.target.capabilities.Has(caps.LabeledResponse) && rb.Label != ""
  73. if useLabel && 1 < len(rb.messages) && rb.target.capabilities.Has(caps.Batch) {
  74. batch = rb.target.server.batches.New("draft/labeled-response")
  75. }
  76. // if label but no batch, add label to first message
  77. if useLabel && batch == nil {
  78. message := rb.messages[0]
  79. message.Tags[caps.LabelTagName] = ircmsg.MakeTagValue(rb.Label)
  80. rb.messages[0] = message
  81. }
  82. // start batch if required
  83. if batch != nil {
  84. batch.Start(rb.target, ircmsg.MakeTags(caps.LabelTagName, rb.Label))
  85. }
  86. // send each message out
  87. for _, message := range rb.messages {
  88. // attach server-time if needed
  89. if rb.target.capabilities.Has(caps.ServerTime) {
  90. t := time.Now().UTC().Format("2006-01-02T15:04:05.999Z")
  91. message.Tags["time"] = ircmsg.MakeTagValue(t)
  92. }
  93. // attach batch ID
  94. if batch != nil {
  95. message.Tags["batch"] = ircmsg.MakeTagValue(batch.ID)
  96. }
  97. // send message out
  98. rb.target.SendRawMessage(message)
  99. }
  100. // end batch if required
  101. if batch != nil {
  102. batch.End(rb.target)
  103. }
  104. // clear out any existing messages
  105. rb.messages = []ircmsg.IrcMessage{}
  106. return nil
  107. }
  108. // Notice sends the client the given notice from the server.
  109. func (rb *ResponseBuffer) Notice(text string) {
  110. rb.Add(nil, rb.target.server.name, "NOTICE", rb.target.nick, text)
  111. }