Intel2Noise/main.go
2022-10-17 19:39:06 +02:00

312 lines
7.7 KiB
Go
Raw Permalink Blame History

package main
import (
"flag"
"fmt"
"io/fs"
"log"
"os"
"runtime"
"strings"
"time"
"github.com/nxadm/tail"
)
// findPath Find the path in which the log files are stored.
func findPath(LogLocation string) (logPath string) {
if LogLocation != "" {
logPath = LogLocation
return
}
var err error
var homedir string
var Path string
var Paths []string
var PathsLinux []string
var PathsMac []string
var PathsWindows []string
// Determine the homedir of the user.
homedir, err = os.UserHomeDir()
if err != nil {
log.Fatal(err)
}
// Define Paths to check out
PathsLinux = append(PathsLinux, "/Documents/EVE/logs/")
PathsLinux = append(PathsLinux, "/.local/share/Steam/steamapps/compatdata/8500/pfx/drive_c/users/steamuser/My Documents/EVE/logs/Chatlogs/")
PathsMac = append(PathsMac, "/Documents/EVE/logs/")
PathsMac = append(PathsMac, "/Library/Application Support/EVE Online/p_drive/User/My Documents/EVE/")
PathsWindows = append(PathsWindows, "C:\\Users\\YourUserName\\Documents\\EVE\\logs")
PathsWindows = append(PathsWindows, "MyDocuments -> EVE -> Logs")
switch runtime.GOOS {
case "linux":
Paths = PathsLinux
case "darwin":
Paths = PathsMac
case "windows":
Paths = PathsWindows
}
for _, Path = range Paths {
if _, err := os.Stat(homedir + Path); !os.IsNotExist(err) {
logPath = homedir + Path
}
}
return
}
// OrchestrateIntelMonitoring routine to periodically check the logpath for the intel channels.
func OrchestrateIntelMonitoring(logPath string, intelChannel string, LogSystemsRaw string) {
// Declare variables
var files []fs.FileInfo
var lastName string
var tempName string
// Enter a for-loop that periodically checks.
for {
files = fetchFileListing(logPath)
tempName = findLatestLog(logPath, intelChannel, files)
if !strings.EqualFold(lastName, tempName) {
lastName = tempName
fmt.Println("Tracking file:" + lastName)
go TrackLogfile(lastName, LogSystemsRaw)
}
// Sleep a minute before we check again.
time.Sleep(time.Second * 60)
}
}
// TrackLogfile The actual work
func TrackLogfile(logPath string, LogSystemsRaw string) {
// Split the CSV string into different parts
LogSystems := strings.Split(LogSystemsRaw, ",")
// Do the main loop and start parsing the logfiles
t, err := tail.TailFile(logPath, tail.Config{Follow: true})
if err != nil {
panic(err)
}
for line := range t.Lines {
// Cast a line to a text, trim the trash
logLine := string(line.Text)
logLine = strings.Trim(logLine, "\n")
// Figure out if this is a message we want to deal with
// > is critical in this regard because it is the start of the message
// and everything behind it until it hits ] is the username
splitpos := strings.Index(logLine, ">")
if -1 == splitpos {
continue
}
// Somehow I cannot filter out this stuff.
// EVE System > Channel MOTD
LineDate, LineTime, LineUser, Payload := ParseChat(logLine)
if CompareElements(LogSystems, Payload) {
playBeep()
fmt.Println("[", LineDate, LineTime, "]", LineUser, ">", Payload)
}
}
// We should never reach this
}
// fetchFileListing As it says on the tin.
func fetchFileListing(logPath string) (files []fs.FileInfo) {
// Declare Variables
var err error
var folder *os.File
// Open the folder we need to open.
folder, err = os.Open(logPath)
if err != nil {
log.Fatal(err)
}
// Read the files UwU
files, err = folder.Readdir(-1)
folder.Close()
if err != nil {
log.Fatal(err)
}
// Off you go! \o/
return
}
// findLatestLog Find the last log-file based on the Internet
func findLatestLog(logPath string, intelChannel string, files []fs.FileInfo) (lastName string) {
// Declare Variables
var lastTime time.Time
var tempTime time.Time
for _, file := range files {
file, err := os.Stat(logPath + file.Name())
if err != nil {
log.Fatal(err)
}
if strings.EqualFold(intelChannel, file.Name()[:len(intelChannel)]) {
tempTime = file.ModTime()
if tempTime.After(lastTime) {
lastTime = tempTime
lastName = logPath + file.Name()
}
}
}
// And there you are (or not)
return
}
// StartIntelMonitoring -- The Main Loop!
func StartIntelMonitoring(intelChannels string, LogSystemsRaw string, LogLocation string) {
// Declare variables
var logPath string
var IntelChannelsSplit []string
var IntelChannel string
// Split the CSV string into different parts
IntelChannelsSplit = strings.Split(intelChannels, ",")
// Get the path we need to
logPath = findPath(LogLocation)
for _, IntelChannel = range IntelChannelsSplit {
IntelChannel = strings.ReplaceAll(IntelChannel, " ", "_")
go OrchestrateIntelMonitoring(logPath, IntelChannel, LogSystemsRaw)
}
}
// ParseChat Parses a string, returns the payload of the chat
// *sigh*
// This took effing forever to get right.
// "Lets start with Regex, cannot go wrong".
// You have this string:
// <20><>[ 2022.02.09 10:05:43 ] Kaysee Guru > EX-GBT clr nd
// Cool. Looks easy.
// .*\[ (.*?) (.*?) \] (.*?) > (.*)
// regex101.com says its good
// And no matter what I do just does not work for some magical reason.
//
// Lets do this with splitting by space and compare it with that. Do a bunch of ifs, it works in test aaaaaand....
// It doesn't work.
//
// By now I have a somewhat reliable version, but it fails to look for the word MOTD.
// I should prolly look into runes()
// This is terrible
func ParseChat(chatline string) (LineDate string, LineTime string, LineUser string, Payload []string) {
logLine := chatline[3:]
var LinePayload string
var splitpos int
splitpos = strings.Index(logLine, ">")
LineDate = logLine[2:23]
LineTime = logLine[25:41]
LineUser = logLine[46 : splitpos-2]
LinePayload = logLine[splitpos+4:]
LinePayload = shorten(LinePayload)
Payload = strings.Fields(LinePayload)
//fmt.Println(logLine)
//fmt.Println(LineDate)
//fmt.Println(LineTime)
//fmt.Println(LineUser)
//fmt.Println(splitpos)
//fmt.Println(LinePayload)
//fmt.Println(Payload)
return
}
func shorten(payload string) (logLine string) {
runes := []rune(payload)
for pos, char := range runes {
if pos%2 == 0 && char != 13 {
logLine = logLine + string(char)
}
}
return
}
// CompareElements Compares a log msg with systems we wish to track
func CompareElements(alerts []string, payload []string) bool {
for _, word := range payload {
for _, alert := range alerts {
if strings.EqualFold(word, alert) {
//fmt.Println("Found (EF): ", alert, "in", word)
return true
} //else {
// fmt.Println(word, "!=", alert)
//}
// In the odd case somebody links "C-V6DQ*"
if len(word) > 6 {
//alert = alert[:len(word)]
word = word[:6]
}
// In case of partials like "C-V"
if len(word) < 6 && len(word) >= 3 {
//word = word[:5]
alert = alert[:len(word)]
}
if strings.EqualFold(word, alert) {
//fmt.Println("Found: ", alert, "in", word)
return true
}
}
}
return false
}
// playBeep Play a beep
// Honestly, I tried to play alert.mp3, but after two executions I got a segfault and thought 0x07 it is!
func playBeep() {
fmt.Print("\a")
}
// main Something Importang. Dunno
func main() {
// Handle Parameters
var intelChannels = flag.String("i", "Etherium Intel,Bean-Intel", "Comma-separated list of intel channels.")
LogSystemsRaw := flag.String("s", "c-v6dq,1pf-bc,ex-gbt,z-fet0", "Comma-seperated list of systems to monitor for")
LogLocation := flag.String("l", "", "Location of the log-file to track.")
flag.Parse()
// Start the main loop
go StartIntelMonitoring(*intelChannels, *LogSystemsRaw, *LogLocation)
// Go into the eternal loop and sit this one out.
// But bug every hour, reminding them that you are still there.
for {
time.Sleep(time.Second * 3600)
fmt.Println("Hi. This is your hourly reminder that this program is still runnig and hasn't crashed!")
}
}