mirror of
https://github.com/muety/wakapi.git
synced 2025-12-05 22:20:24 -08:00
137 lines
3.7 KiB
Go
137 lines
3.7 KiB
Go
package models
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/cespare/xxhash/v2"
|
|
"github.com/gohugoio/hashstructure"
|
|
"github.com/muety/wakapi/models/lib"
|
|
"log/slog"
|
|
"strings"
|
|
"time"
|
|
"unicode"
|
|
)
|
|
|
|
// TODO: support multiple durations per time per user for different heartbeat timeouts
|
|
// see discussion at https://github.com/muety/wakapi/issues/675
|
|
type Duration struct {
|
|
ID int64 `json:"-" gorm:"primaryKey; autoIncrement"` // https://github.com/muety/wakapi/issues/777
|
|
UserID string `json:"user_id" gorm:"not null; index:idx_time_duration_user"`
|
|
Time CustomTime `json:"time" hash:"ignore" gorm:"not null; index:idx_time_duration_user"` // time of first heartbeat of this duration
|
|
Duration time.Duration `json:"duration" hash:"ignore" gorm:"not null"`
|
|
Project string `json:"project"`
|
|
Language string `json:"language"`
|
|
Editor string `json:"editor"`
|
|
OperatingSystem string `json:"operating_system"`
|
|
Machine string `json:"machine"`
|
|
Category string `json:"category"`
|
|
Branch string `json:"branch"`
|
|
Entity string `json:"Entity"`
|
|
NumHeartbeats int `json:"-" hash:"ignore"`
|
|
GroupHash string `json:"-" hash:"ignore" gorm:"type:varchar(17)"`
|
|
Timeout time.Duration `json:"-" gorm:"not null; default:600000000000"` // heartbeat timeout preference, see DefaultHeartbeatsTimeout
|
|
excludeEntity bool `json:"-" hash:"ignore"`
|
|
}
|
|
|
|
func (d *Duration) TimeEnd() time.Time {
|
|
return d.Time.T().Add(d.Duration)
|
|
}
|
|
|
|
func (d *Duration) HashInclude(field string, v interface{}) (bool, error) {
|
|
if field == "Entity" {
|
|
return !d.excludeEntity, nil
|
|
}
|
|
if field == "Time" ||
|
|
field == "Duration" ||
|
|
field == "NumHeartbeats" ||
|
|
field == "GroupHash" ||
|
|
field == "ID" ||
|
|
field == "Timeout" ||
|
|
unicode.IsLower(rune(field[0])) {
|
|
return false, nil
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func NewDurationFromHeartbeat(h *Heartbeat) *Duration {
|
|
var interval = DefaultHeartbeatsTimeout
|
|
if h.User != nil && h.User.HeartbeatsTimeout() > 0 {
|
|
interval = h.User.HeartbeatsTimeout()
|
|
}
|
|
|
|
d := &Duration{
|
|
UserID: h.UserID,
|
|
Time: h.Time,
|
|
Duration: 0,
|
|
Project: h.Project,
|
|
Language: h.Language,
|
|
Editor: h.Editor,
|
|
OperatingSystem: h.OperatingSystem,
|
|
Machine: h.Machine,
|
|
Category: h.Category,
|
|
Branch: h.Branch,
|
|
Entity: h.Entity,
|
|
NumHeartbeats: 1,
|
|
Timeout: interval,
|
|
}
|
|
return d
|
|
}
|
|
|
|
func (d *Duration) WithEntityIgnored() *Duration {
|
|
d.excludeEntity = true
|
|
return d
|
|
}
|
|
|
|
func (d *Duration) WithTimeout(interval time.Duration) *Duration {
|
|
d.Timeout = interval
|
|
return d
|
|
}
|
|
|
|
func (d *Duration) Hashed() *Duration {
|
|
hash, err := hashstructure.Hash(d, &hashstructure.HashOptions{Hasher: xxhash.New()})
|
|
if err != nil {
|
|
slog.Error("CRITICAL ERROR: failed to hash struct", "error", err)
|
|
}
|
|
d.GroupHash = fmt.Sprintf("%x", hash)
|
|
return d
|
|
}
|
|
|
|
func (d *Duration) Augmented(languageMappings map[string]string) *Duration {
|
|
for ext, targetLang := range languageMappings {
|
|
langs, ok := lib.LanguagesByExtension["."+ext]
|
|
if !ok {
|
|
continue
|
|
}
|
|
if lang := langs[0]; strings.ToLower(d.Language) == strings.ToLower(lang) {
|
|
d.Language = targetLang
|
|
}
|
|
}
|
|
return d
|
|
}
|
|
|
|
func (d *Duration) GetKey(t uint8) (key string) {
|
|
switch t {
|
|
case SummaryProject:
|
|
key = d.Project
|
|
case SummaryEditor:
|
|
key = d.Editor
|
|
case SummaryLanguage:
|
|
key = d.Language
|
|
case SummaryOS:
|
|
key = d.OperatingSystem
|
|
case SummaryMachine:
|
|
key = d.Machine
|
|
case SummaryBranch:
|
|
key = d.Branch
|
|
case SummaryEntity:
|
|
key = d.Entity
|
|
case SummaryCategory:
|
|
key = d.Category
|
|
}
|
|
|
|
if key == "" {
|
|
key = UnknownSummaryKey
|
|
}
|
|
|
|
return key
|
|
}
|