package main import ( "github.com/acarl005/stripansi" "github.com/hpcloud/tail" log "github.com/sirupsen/logrus" "meow.tf/residentsleeper/events" "meow.tf/residentsleeper/rcon" "os" "regexp" "strings" ) const ( timeThreadRegexp = "^\\[.*?\\]\\s\\[.*?\\/INFO\\]:\\s" ) var ( messageRegexp = regexp.MustCompile(timeThreadRegexp + "<(.*?)>\\s(.*)") joinedRegexp = regexp.MustCompile(timeThreadRegexp + "(.*?) joined the game$") leftRegexp = regexp.MustCompile(timeThreadRegexp + "(.*?) left the game$") stoppingRegexp = regexp.MustCompile(timeThreadRegexp + "Stopping server") rconRegexp = regexp.MustCompile(timeThreadRegexp + "RCON running on") loggedInRegexp = regexp.MustCompile(timeThreadRegexp + "(.*?)\\[(.*?)\\] logged in with entity id \\d+ at \\((.*?)\\)") startedRegexp = regexp.MustCompile(timeThreadRegexp + "Done \\(.*?\\)! For help, type \"help\"") authenticatedRegexp = regexp.MustCompile(timeThreadRegexp + "UUID of player (.*?) is (.*?)$") opRegexp = regexp.MustCompile("Made (.*?) a server operator") deopRegexp = regexp.MustCompile("Made (.*?) no longer a server operator") sourceRegexp = regexp.MustCompile(timeThreadRegexp + "\\[(.*?): (.*?)\\]") sleepRegexp = regexp.MustCompile("^z{3,}$") timeRegexp = regexp.MustCompile("(\\d+)$") ) func logParser(logPath string) { log.WithField("path", logPath).Info("Watching log path") stat, err := os.Stat(logPath) if err != nil { log.WithError(err).Fatalln("Unable to stat log file") } seek := &tail.SeekInfo{ Offset: stat.Size(), } // Start parsing file t, err := tail.TailFile(logPath, tail.Config{Location: seek, Follow: true, ReOpen: true}) if err != nil { log.WithError(err).Fatalln("Unable to open log file") } var m []string for line := range t.Lines { line.Text = stripansi.Strip(strings.TrimSpace(line.Text)) if debug { log.Println("Parsing line", line.Text) log.Println("Bytes:", []byte(line.Text)) } if m = messageRegexp.FindStringSubmatch(line.Text); m != nil { go events.Call(events.Message, m[1], m[2]) } else if m = loggedInRegexp.FindStringSubmatch(line.Text); m != nil { position, err := rcon.SliceToFloats(strings.Split(m[3], ", ")) if err != nil { position = []float64{0, 0, 0} } go events.Call(events.LoggedIn, m[1], m[2], position[0], position[1], position[2]) } else if m = authenticatedRegexp.FindStringSubmatch(line.Text); m != nil { go events.Call(events.Authenticated, m[1], m[2]) } else if m = joinedRegexp.FindStringSubmatch(line.Text); m != nil { go events.Call(events.Join, m[1]) } else if m = leftRegexp.FindStringSubmatch(line.Text); m != nil { go events.Call(events.Leave, m[1]) } else if m = opRegexp.FindStringSubmatch(line.Text); m != nil { source := "Server" subM := sourceRegexp.FindStringSubmatch(line.Text) if subM != nil { source = subM[1] } go events.Call(events.Op, m[1], source) } else if m = deopRegexp.FindStringSubmatch(line.Text); m != nil { source := "Server" subM := sourceRegexp.FindStringSubmatch(line.Text) if subM != nil { source = subM[1] } go events.Call(events.Deop, m[1], source) } else if stoppingRegexp.MatchString(line.Text) { go func() { events.Call(events.ServerClosing) client.Disconnect() }() } else if startedRegexp.MatchString(line.Text) { go events.Call(events.ServerStarted) } else if rconRegexp.MatchString(line.Text) { go events.Call(events.Init) } } }