Files
api/cmd/rpdata-logpaste/post.go
T
2018-11-07 19:31:51 +01:00

127 lines
2.6 KiB
Go
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"bufio"
"errors"
"io"
"strconv"
"strings"
"time"
)
// ErrNotPost is returned by parsePost if the line is empty or not a post.
var ErrNotPost = errors.New("not a post")
// ErrTooShort is returned by parsePost if the line too short to be a post.
var ErrTooShort = errors.New("post too short")
// ErrInvalidTimestamp is returned by parsePost if the line is empty or not a post.
var ErrInvalidTimestamp = errors.New("invalid timestamp")
// A Post is a part of a log.
type Post struct {
Time time.Time
Kind string
Nick string
Text string
}
func parsePosts(reader io.Reader, date time.Time) ([]Post, error) {
prev := Post{}
posts := make([]Post, 0, 8)
bufReader := bufio.NewReader(reader)
for {
line, err := bufReader.ReadString('\n')
if err != nil && err != io.EOF {
return nil, err
}
if len(line) > 8 {
post, err := parsePost(strings.Trim(line, "  \n\r"), date, prev)
if err != nil {
return nil, err
}
posts = append(posts, post)
prev = post
}
if err == io.EOF {
break
}
}
return posts, nil
}
func parsePost(line string, date time.Time, prev Post) (Post, error) {
// Do basic validation
line = strings.Trim(line, "  \t\n\r")
if len(line) == 0 || !strings.HasPrefix(line, "[") {
return Post{}, ErrNotPost
}
// Parse timestamp
tsEndIndex := strings.IndexByte(line, ']')
if tsEndIndex == -1 || len(line) < tsEndIndex+5 {
return Post{}, ErrNotPost
}
tsStr := line[1:tsEndIndex]
tsSplit := strings.Split(tsStr, ":")
tsUnits := make([]int, len(tsSplit))
if len(tsSplit) < 2 {
return Post{}, ErrNotPost
}
for i := range tsSplit {
n, err := strconv.Atoi(tsSplit[i])
if err != nil {
return Post{}, ErrNotPost
}
tsUnits[i] = n
}
if len(tsUnits) == 2 {
tsUnits = append(tsUnits, 0)
}
ts := time.Date(date.Year(), date.Month(), date.Day(), tsUnits[0], tsUnits[1], tsUnits[2], 0, date.Location())
if !prev.Time.IsZero() && prev.Time.After(ts) {
ts = ts.AddDate(0, 0, 1)
}
if line[tsEndIndex+2] == '*' {
split := strings.SplitN(line[tsEndIndex+4:], " ", 2)
post := Post{
Time: ts,
Kind: "action",
Nick: strings.TrimLeft(split[0], "+@!~"),
Text: split[1],
}
if post.Nick[0] == '=' {
post.Kind = "scene"
}
return post, nil
} else if line[tsEndIndex+2] == '<' {
split := strings.SplitN(line[tsEndIndex+2:], " ", 2)
post := Post{
Time: ts,
Kind: "text",
Nick: strings.TrimLeft(split[0][1:len(split[0])-1], "+@!~"),
Text: split[1],
}
if post.Nick[0] == '=' {
post.Kind = "scene"
}
return post, nil
} else {
return Post{}, ErrNotPost
}
}