Files
go-hauk/model/share.go
Arkadiy Kukarkin a0290f6a6d add data models
2025-12-23 12:23:25 +01:00

204 lines
5.4 KiB
Go

package model
import (
"context"
"math/rand"
"strconv"
"time"
"github.com/parkan/go-hauk/store"
)
const (
PrefixLocdata = "locdata-"
PrefixGroupID = "groupid-"
ShareTypeAlone = 0
ShareTypeGroup = 1
GroupPinMin = 100000
GroupPinMax = 999999
)
type SoloShareData struct {
Type int `json:"type"`
Expire int64 `json:"expire"`
Host string `json:"host"`
Adoptable bool `json:"adoptable"`
}
type GroupShareData struct {
Type int `json:"type"`
Expire int64 `json:"expire"`
Hosts map[string]string `json:"hosts"`
GroupPin int `json:"groupPin"`
}
type SoloShare struct {
store store.Store
id string
data SoloShareData
publicURL string
}
type GroupShare struct {
store store.Store
id string
data GroupShareData
publicURL string
}
func NewSoloShare(s store.Store, publicURL string, linkGen func() (string, error)) (*SoloShare, error) {
id, err := linkGen()
if err != nil {
return nil, err
}
return &SoloShare{
store: s,
id: id,
publicURL: publicURL,
data: SoloShareData{
Type: ShareTypeAlone,
},
}, nil
}
func LoadSoloShare(ctx context.Context, s store.Store, id, publicURL string) (*SoloShare, error) {
share := &SoloShare{store: s, id: id, publicURL: publicURL}
err := s.Get(ctx, PrefixLocdata+id, &share.data)
if err != nil {
return nil, err
}
return share, nil
}
func (s *SoloShare) ID() string { return s.id }
func (s *SoloShare) Type() int { return s.data.Type }
func (s *SoloShare) Expire() time.Time { return time.Unix(s.data.Expire, 0) }
func (s *SoloShare) Host() string { return s.data.Host }
func (s *SoloShare) Adoptable() bool { return s.data.Adoptable }
func (s *SoloShare) ViewLink() string { return s.publicURL + "?" + s.id }
func (s *SoloShare) SetExpire(t time.Time) { s.data.Expire = t.Unix() }
func (s *SoloShare) SetHost(sid string) { s.data.Host = sid }
func (s *SoloShare) SetAdoptable(a bool) { s.data.Adoptable = a }
func (s *SoloShare) SetID(id string) { s.id = id }
func (s *SoloShare) Save(ctx context.Context) error {
return s.store.Set(ctx, PrefixLocdata+s.id, s.data, s.Expire())
}
func (s *SoloShare) Delete(ctx context.Context) error {
return s.store.Delete(ctx, PrefixLocdata+s.id)
}
func NewGroupShare(s store.Store, publicURL string, linkGen func() (string, error)) (*GroupShare, error) {
id, err := linkGen()
if err != nil {
return nil, err
}
pin := GroupPinMin + rand.Intn(GroupPinMax-GroupPinMin+1)
return &GroupShare{
store: s,
id: id,
publicURL: publicURL,
data: GroupShareData{
Type: ShareTypeGroup,
Hosts: make(map[string]string),
GroupPin: pin,
},
}, nil
}
func LoadGroupShare(ctx context.Context, s store.Store, id, publicURL string) (*GroupShare, error) {
share := &GroupShare{store: s, id: id, publicURL: publicURL}
err := s.Get(ctx, PrefixLocdata+id, &share.data)
if err != nil {
return nil, err
}
return share, nil
}
func LoadGroupShareByPin(ctx context.Context, s store.Store, pin int, publicURL string) (*GroupShare, error) {
var shareID string
err := s.Get(ctx, PrefixGroupID+strconv.Itoa(pin), &shareID)
if err != nil {
return nil, err
}
return LoadGroupShare(ctx, s, shareID, publicURL)
}
func (g *GroupShare) ID() string { return g.id }
func (g *GroupShare) Type() int { return g.data.Type }
func (g *GroupShare) Expire() time.Time { return time.Unix(g.data.Expire, 0) }
func (g *GroupShare) Hosts() map[string]string { return g.data.Hosts }
func (g *GroupShare) Pin() int { return g.data.GroupPin }
func (g *GroupShare) ViewLink() string { return g.publicURL + "?" + g.id }
func (g *GroupShare) SetExpire(t time.Time) { g.data.Expire = t.Unix() }
func (g *GroupShare) SetID(id string) { g.id = id }
func (g *GroupShare) AddHost(nick, sessionID string) {
g.data.Hosts[nick] = sessionID
}
func (g *GroupShare) RemoveHost(sessionID string) {
for nick, sid := range g.data.Hosts {
if sid == sessionID {
delete(g.data.Hosts, nick)
return
}
}
}
func (g *GroupShare) Save(ctx context.Context) error {
if err := g.store.Set(ctx, PrefixLocdata+g.id, g.data, g.Expire()); err != nil {
return err
}
return g.store.Set(ctx, PrefixGroupID+strconv.Itoa(g.data.GroupPin), g.id, g.Expire())
}
func (g *GroupShare) Delete(ctx context.Context) error {
g.store.Delete(ctx, PrefixGroupID+strconv.Itoa(g.data.GroupPin))
return g.store.Delete(ctx, PrefixLocdata+g.id)
}
func (g *GroupShare) GetAllPoints(ctx context.Context, since float64, maxPts int) (map[string][][]any, error) {
points := make(map[string][][]any)
for nick, sid := range g.data.Hosts {
sess, err := LoadSession(ctx, g.store, sid, maxPts)
if err != nil {
continue
}
points[nick] = sess.GetPoints(since)
}
return points, nil
}
func (g *GroupShare) GetAutoInterval(ctx context.Context, maxPts int) float64 {
min := float64(0)
for _, sid := range g.data.Hosts {
sess, err := LoadSession(ctx, g.store, sid, maxPts)
if err != nil {
continue
}
if min == 0 || sess.Interval() < min {
min = sess.Interval()
}
}
return min
}
type ShareType struct {
Type int `json:"type"`
}
func LoadShareType(ctx context.Context, s store.Store, id string) (int, error) {
var st ShareType
err := s.Get(ctx, PrefixLocdata+id, &st)
if err != nil {
return -1, err
}
return st.Type, nil
}