ParseMessage parses a notification message string into a Message structure.
(ctx context.Context, in io.Reader)
| 27 | |
| 28 | // ParseMessage parses a notification message string into a Message structure. |
| 29 | func ParseMessage(ctx context.Context, in io.Reader) (*Message, error) { |
| 30 | var bodyLines []string |
| 31 | |
| 32 | // parse headers until we encounter "MarkdownBody:" or an empty line. |
| 33 | sr := bufio.NewScanner(in) |
| 34 | |
| 35 | msg := &Message{ |
| 36 | Headers: map[string]string{}, |
| 37 | } |
| 38 | |
| 39 | for sr.Scan() { |
| 40 | line := sr.Text() |
| 41 | |
| 42 | if line == "" { |
| 43 | // no more headers after that |
| 44 | break |
| 45 | } |
| 46 | |
| 47 | if strings.HasPrefix(line, "Subject:") { |
| 48 | msg.Subject = strings.TrimSpace(line[len("Subject:"):]) |
| 49 | continue |
| 50 | } |
| 51 | |
| 52 | // parse headers |
| 53 | const numParts = 2 |
| 54 | |
| 55 | parts := strings.SplitN(line, ":", numParts) |
| 56 | if len(parts) != numParts { |
| 57 | log(ctx).Warnw("invalid header line in notification template", "line", line) |
| 58 | continue |
| 59 | } |
| 60 | |
| 61 | msg.Headers[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1]) |
| 62 | } |
| 63 | |
| 64 | for sr.Scan() { |
| 65 | line := sr.Text() |
| 66 | bodyLines = append(bodyLines, line) |
| 67 | } |
| 68 | |
| 69 | msg.Body = strings.Join(bodyLines, "\n") |
| 70 | |
| 71 | if len(bodyLines) == 0 { |
| 72 | return nil, errors.New("no body found in message") |
| 73 | } |
| 74 | |
| 75 | return msg, errors.Wrap(sr.Err(), "error reading message") |
| 76 | } |
| 77 | |
| 78 | // ToString returns a string representation of the message. |
| 79 | func (m Message) ToString() string { |