GraphQL API and utilities for the rpdata project
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.

98 lines
2.4 KiB

  1. package mirclike
  2. import (
  3. "errors"
  4. "strconv"
  5. "strings"
  6. "time"
  7. "git.aiterp.net/rpdata/api/models"
  8. )
  9. // ErrNotPost is returned by parsePost if the line is empty or not a post.
  10. var ErrNotPost = errors.New("not a post")
  11. // ParsePost parses a post from a mirc-like line. If the previous post is included (it can be empty), it will be used
  12. // to determine whether midnight has passed.
  13. func ParsePost(line string, date time.Time, prev models.Post) (models.Post, error) {
  14. // Do basic validation
  15. line = strings.Trim(line, "  \t\n\r")
  16. if len(line) == 0 || !strings.HasPrefix(line, "[") {
  17. return models.Post{}, ErrNotPost
  18. }
  19. // Parse timestamp
  20. tsEndIndex := strings.IndexByte(line, ']')
  21. if tsEndIndex == -1 || len(line) < tsEndIndex+5 {
  22. return models.Post{}, ErrNotPost
  23. }
  24. tsStr := line[1:tsEndIndex]
  25. tsSplit := strings.Split(tsStr, ":")
  26. tsUnits := make([]int, len(tsSplit))
  27. if len(tsSplit) < 2 {
  28. return models.Post{}, ErrNotPost
  29. }
  30. for i := range tsSplit {
  31. n, err := strconv.Atoi(tsSplit[i])
  32. if err != nil {
  33. return models.Post{}, ErrNotPost
  34. }
  35. tsUnits[i] = n
  36. }
  37. if len(tsUnits) == 2 {
  38. tsUnits = append(tsUnits, 0)
  39. }
  40. // Determine timestamp from parsed data and previous post.
  41. ts := time.Date(date.Year(), date.Month(), date.Day(), tsUnits[0], tsUnits[1], tsUnits[2], 0, date.Location())
  42. if !prev.Time.IsZero() && prev.Time.Sub(ts) > 30*time.Minute {
  43. ts = time.Date(prev.Time.Year(), prev.Time.Month(), prev.Time.Day()+1, tsUnits[0], tsUnits[1], tsUnits[2], 0, date.Location())
  44. }
  45. if line[tsEndIndex+2] == '*' {
  46. split := strings.SplitN(line[tsEndIndex+4:], " ", 2)
  47. if len(split) == 1 {
  48. return models.Post{}, ErrNotPost
  49. }
  50. post := models.Post{
  51. ID: "UNASSIGNED",
  52. LogID: "UNASSIGNED",
  53. Time: ts,
  54. Kind: "action",
  55. Nick: strings.TrimLeft(split[0], "+@!~"),
  56. Text: split[1],
  57. Position: prev.Position + 1,
  58. }
  59. if post.Nick[0] == '=' {
  60. post.Kind = "scene"
  61. }
  62. return post, nil
  63. } else if line[tsEndIndex+2] == '<' {
  64. split := strings.SplitN(line[tsEndIndex+2:], " ", 2)
  65. if len(split) == 1 {
  66. return models.Post{}, ErrNotPost
  67. }
  68. post := models.Post{
  69. ID: "UNASSIGNED",
  70. LogID: "UNASSIGNED",
  71. Time: ts,
  72. Kind: "text",
  73. Nick: strings.TrimLeft(split[0][1:len(split[0])-1], "+@!~"),
  74. Text: split[1],
  75. Position: prev.Position + 1,
  76. }
  77. if post.Nick[0] == '=' {
  78. post.Kind = "scene"
  79. }
  80. return post, nil
  81. } else {
  82. return models.Post{}, ErrNotPost
  83. }
  84. }