event-time-tracking/main.go

257 lines
6 KiB
Go
Raw Permalink Normal View History

2022-01-14 20:09:52 +00:00
package main
import (
"bufio"
2022-01-15 23:41:43 +00:00
_ "embed"
2022-01-14 20:09:52 +00:00
"encoding/json"
2022-01-14 20:57:07 +00:00
"flag"
2022-01-14 20:09:52 +00:00
"github.com/rs/zerolog/log"
"net/http"
"os"
2022-01-15 23:45:34 +00:00
"sort"
2022-01-14 20:09:52 +00:00
"strconv"
"strings"
2022-01-15 23:41:43 +00:00
"text/template"
2022-01-14 20:09:52 +00:00
"time"
)
type Event struct {
2022-01-14 21:48:29 +00:00
Name string
EventTimestamp time.Time
2022-01-14 20:09:52 +00:00
}
2022-01-14 20:57:07 +00:00
var eventlog string
2022-01-15 23:41:43 +00:00
//go:embed webpage.tmpl
var templateContent []byte
2022-01-14 20:09:52 +00:00
//Current State
var lastEvent Event
var currentState map[string]map[string]int64 //Per Name per Day in Secounds
func main() {
2022-01-14 20:57:07 +00:00
eventlogPath := flag.String("eventlog", "/var/ett/eventlog", "Where to store the eventlog file")
flag.Parse()
eventlog = *eventlogPath
2022-01-14 20:09:52 +00:00
log.Info().Msg("Start Time Tracking Service")
currentState = make(map[string]map[string]int64)
defer func() {
e := Event{
2022-01-14 21:48:29 +00:00
Name: "Nothing",
EventTimestamp: time.Now(),
2022-01-14 20:09:52 +00:00
}
addEvent(e)
}()
readStateFromFile()
runHttpServer()
}
func runHttpServer() {
http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
2022-01-15 23:41:43 +00:00
var taglist []string
for s, _ := range currentState {
taglist = append(taglist, s)
}
2022-01-15 23:45:34 +00:00
sort.Strings(taglist)
2022-01-15 23:41:43 +00:00
var daylist []string
2022-01-15 23:50:31 +00:00
for i := 0; i < 7; i++ {
2022-01-15 23:41:43 +00:00
g := -1 * 24 * i
t := time.Now().Add(time.Duration(g) * time.Hour)
daylist = append(daylist, t.Format("02.01.06"))
}
fm := template.FuncMap{"tominute": func(a int64) int64 {
return a / 60
}}
week := map[string]interface{}{}
for tag, _ := range currentState {
var gi int64
2022-01-15 23:50:31 +00:00
for i := 0; i < 7; i++ {
2022-01-15 23:41:43 +00:00
g := -1 * 24 * i
t := time.Now().Add(time.Duration(g) * time.Hour)
secounds := currentState[tag][t.Format("02.01.06")]
gi = gi + secounds
}
gi = gi / 60
s := strconv.FormatInt(gi, 10)
week[tag] = s
}
templ := template.Must(template.New("page").Funcs(fm).Parse(string(templateContent)))
templ.Execute(w, map[string]interface{}{
"lastEvent": lastEvent,
"taglist": taglist,
"daylist": daylist,
"currentState": currentState,
"weeklist": week,
})
/*w.Write([]byte("<h1>Time Tracking</h1>"))
2022-01-14 21:57:29 +00:00
w.Write([]byte("Doing "+lastEvent.Name+" since "+lastEvent.EventTimestamp.Format(time.RFC3339)+"<br>"))
2022-01-14 20:09:52 +00:00
w.Write([]byte("<h3>Today</h3>"))
for tag, _ := range currentState {
2022-01-14 22:19:39 +00:00
i := currentState[tag][time.Now().Format("02.01.06")]
2022-01-14 22:17:44 +00:00
i = i / 60
2022-01-14 20:09:52 +00:00
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
}
2022-01-14 22:17:44 +00:00
gi = gi / 60
2022-01-14 20:09:52 +00:00
s := strconv.FormatInt(gi, 10)
line := tag+": "+s+"<br>"
w.Write([]byte(line))
}
2022-01-15 23:41:43 +00:00
*/
2022-01-14 20:09:52 +00:00
})
2022-01-14 21:48:29 +00:00
http.HandleFunc("/current", func(w http.ResponseWriter, r *http.Request) {
2022-01-14 21:50:03 +00:00
res, err := json.Marshal(lastEvent)
2022-01-14 21:48:29 +00:00
if err != nil {
log.Fatal().Err(err).Msg("Cant Marshal Current State")
}
w.Write(res)
})
2022-01-14 20:09:52 +00:00
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{
2022-01-14 21:48:29 +00:00
Name: name,
EventTimestamp: eventTimestamp,
2022-01-14 20:09:52 +00:00
}
addEvent(e)
})
http.ListenAndServe(":8080", nil)
}
func readStateFromFile() {
2022-01-14 20:57:07 +00:00
if _, err := os.Stat(eventlog); err == nil {
2022-01-14 20:09:52 +00:00
// path/to/whatever exists
2022-01-14 20:57:07 +00:00
file, err := os.Open(eventlog)
2022-01-14 20:09:52 +00:00
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{
2022-01-14 21:48:29 +00:00
Name: details[1],
EventTimestamp: t,
2022-01-14 20:09:52 +00:00
}
handleEvent(e)
}
}
}
func saveEvent(e Event) {
var line string
2022-01-14 21:48:29 +00:00
line = e.EventTimestamp.Format(time.RFC3339)+";"+e.Name +"\r\n"
2022-01-14 20:57:07 +00:00
f, err := os.OpenFile(eventlog, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
2022-01-14 20:09:52 +00:00
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")
2022-01-14 21:48:29 +00:00
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")
2022-01-14 20:09:52 +00:00
//Add to state
2022-01-14 21:48:29 +00:00
currentDuration := currentState[lastEvent.Name][lastEvent.EventTimestamp.Format("02.01.06")]
if len(currentState[lastEvent.Name]) == 0 {
currentState[lastEvent.Name] = make(map[string]int64)
2022-01-14 20:09:52 +00:00
}
currentDuration += int64(duration.Seconds())
2022-01-14 21:48:29 +00:00
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
2022-01-14 20:09:52 +00:00
}
lastEvent = e
}