event-time-tracking/main.go

197 lines
4.6 KiB
Go

package main
import (
"bufio"
"encoding/json"
"flag"
"github.com/rs/zerolog/log"
"net/http"
"os"
"strconv"
"strings"
"time"
)
type Event struct {
name string
eventTimestamp time.Time
}
var eventlog string
//Current State
var lastEvent Event
var currentState map[string]map[string]int64 //Per Name per Day in Secounds
func main() {
eventlogPath := flag.String("eventlog", "/var/ett/eventlog", "Where to store the eventlog file")
flag.Parse()
eventlog = *eventlogPath
log.Info().Msg("Start Time Tracking Service")
currentState = make(map[string]map[string]int64)
defer func() {
e := Event{
name: "Nothing",
eventTimestamp: time.Now(),
}
addEvent(e)
}()
readStateFromFile()
runHttpServer()
}
func runHttpServer() {
http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
w.Write([]byte("<h1>Time Tracking</h1>"))
w.Write([]byte("<h3>Today</h3>"))
for tag, _ := range currentState {
i := currentState[tag][time.Now().Format("02.01.06")]
s := strconv.FormatInt(i, 10)
line := tag+": "+s+"<br>"
w.Write([]byte(line))
}
w.Write([]byte("<h3>Last 7 Days</h3>"))
for tag, _ := range currentState {
var gi int64
for i := 0; i <= 7; i++ {
g := -1 * 24 * i
t := time.Now().Add(time.Duration(g) * time.Hour)
secounds := currentState[tag][t.Format("02.01.06")]
gi = gi + secounds
}
s := strconv.FormatInt(gi, 10)
line := tag+": "+s+"<br>"
w.Write([]byte(line))
}
})
http.HandleFunc("/tags", func(w http.ResponseWriter, r *http.Request) {
var tags []string
for s, _ := range currentState {
tags = append(tags, s)
}
res, err := json.Marshal(tags)
if err != nil {
log.Fatal().Err(err).Msg("Cant Marshal Tag list")
}
w.Write(res)
})
http.HandleFunc("/state", func(w http.ResponseWriter, r *http.Request) {
res, err := json.Marshal(currentState)
if err != nil {
log.Fatal().Err(err).Msg("Cant Marshal Tag list")
}
w.Write(res)
})
http.HandleFunc("/event", func(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
log.Warn().Err(err).Msg("Cant pars form Data from Request to add event")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Cant parse form Data"))
return
}
d := r.FormValue("time")
eventTimestamp := time.Now()
if d != "" {
eventTimestamp, err = time.Parse(time.RFC3339 , d)
if err != nil {
log.Warn().Err(err).Str("TimeString", d).Msg("Cant parse time from http get parameter")
}
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Cant parse date from get paremter, please use RFC3339 Data"))
return
}
name := r.FormValue("name")
e := Event{
name: name,
eventTimestamp: eventTimestamp,
}
addEvent(e)
})
http.ListenAndServe(":8080", nil)
}
func readStateFromFile() {
if _, err := os.Stat(eventlog); err == nil {
// path/to/whatever exists
file, err := os.Open(eventlog)
if err != nil {
log.Fatal().Err(err).Msg("Cant open file")
}
defer file.Close()
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
details := strings.Split(scanner.Text(), ";")
t, err := time.Parse(time.RFC3339 , details[0])
if err != nil {
log.Fatal().Err(err).Str("TimeString", details[0]).Msg("Cant parse time from eventlog")
}
e := Event{
name: details[1],
eventTimestamp: t,
}
handleEvent(e)
}
}
}
func saveEvent(e Event) {
var line string
line = e.eventTimestamp.Format(time.RFC3339)+";"+e.name+"\r\n"
f, err := os.OpenFile(eventlog, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
panic(err)
}
defer f.Close()
if _, err = f.WriteString(line); err != nil {
panic(err)
}
}
func addEvent(e Event) {
//Write Event to Log
saveEvent(e)
handleEvent(e)
}
func handleEvent(e Event) {
log.Debug().Msg("Handle New Event")
if lastEvent.name != "" {
duration := e.eventTimestamp.Sub(lastEvent.eventTimestamp)
log.Debug().Int64("Duration", int64(duration.Seconds())).Str("LastEventName", lastEvent.name).Msg("Calculatet Duration for last event")
//Add to state
currentDuration := currentState[lastEvent.name][lastEvent.eventTimestamp.Format("02.01.06")]
if len(currentState[lastEvent.name]) == 0 {
currentState[lastEvent.name] = make(map[string]int64)
}
currentDuration += int64(duration.Seconds())
log.Debug().Int64("Day Duration", currentDuration).Str("Day", lastEvent.eventTimestamp.Format("02.01.06")).Str("typ", lastEvent.name).Msg("Add Duration to Day")
currentState[lastEvent.name][lastEvent.eventTimestamp.Format("02.01.06")] = currentDuration
}
lastEvent = e
}