2022-01-14 20:09:52 +00:00
package main
import (
"bufio"
"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"
"strconv"
"strings"
"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-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 ) {
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 ) )
}
} )
2022-01-14 21:48:29 +00:00
http . HandleFunc ( "/current" , func ( w http . ResponseWriter , r * http . Request ) {
res , err := json . Marshal ( currentState )
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
}