mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-18 21:02:00 +01:00
a121bd4bb5
* break out telemetry and playbook * break out bookmarks * add license disclaimers
154 lines
4.6 KiB
Go
154 lines
4.6 KiB
Go
// Copyright 2024, Command Line Inc.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package telemetry
|
|
|
|
import (
|
|
"context"
|
|
"database/sql/driver"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/wavetermdev/waveterm/wavesrv/pkg/dbutil"
|
|
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbase"
|
|
"github.com/wavetermdev/waveterm/wavesrv/pkg/sstore"
|
|
)
|
|
|
|
const MaxTzNameLen = 50
|
|
|
|
type ActivityUpdate struct {
|
|
FgMinutes int
|
|
ActiveMinutes int
|
|
OpenMinutes int
|
|
NumCommands int
|
|
ClickShared int
|
|
HistoryView int
|
|
BookmarksView int
|
|
NumConns int
|
|
WebShareLimit int
|
|
ReinitBashErrors int
|
|
ReinitZshErrors int
|
|
BuildTime string
|
|
}
|
|
|
|
type ActivityType struct {
|
|
Day string `json:"day"`
|
|
Uploaded bool `json:"-"`
|
|
TData TelemetryData `json:"tdata"`
|
|
TzName string `json:"tzname"`
|
|
TzOffset int `json:"tzoffset"`
|
|
ClientVersion string `json:"clientversion"`
|
|
ClientArch string `json:"clientarch"`
|
|
BuildTime string `json:"buildtime"`
|
|
DefaultShell string `json:"defaultshell"`
|
|
OSRelease string `json:"osrelease"`
|
|
}
|
|
|
|
type TelemetryData struct {
|
|
NumCommands int `json:"numcommands"`
|
|
ActiveMinutes int `json:"activeminutes"`
|
|
FgMinutes int `json:"fgminutes"`
|
|
OpenMinutes int `json:"openminutes"`
|
|
ClickShared int `json:"clickshared,omitempty"`
|
|
HistoryView int `json:"historyview,omitempty"`
|
|
BookmarksView int `json:"bookmarksview,omitempty"`
|
|
NumConns int `json:"numconns"`
|
|
WebShareLimit int `json:"websharelimit,omitempty"`
|
|
ReinitBashErrors int `json:"reinitbasherrors,omitempty"`
|
|
ReinitZshErrors int `json:"reinitzsherrors,omitempty"`
|
|
}
|
|
|
|
func (tdata TelemetryData) Value() (driver.Value, error) {
|
|
return dbutil.QuickValueJson(tdata)
|
|
}
|
|
|
|
func (tdata *TelemetryData) Scan(val interface{}) error {
|
|
return dbutil.QuickScanJson(tdata, val)
|
|
}
|
|
|
|
// Wraps UpdateCurrentActivity, but ignores errors
|
|
func UpdateActivityWrap(ctx context.Context, update ActivityUpdate, debugStr string) {
|
|
err := UpdateCurrentActivity(ctx, update)
|
|
if err != nil {
|
|
// ignore error, just log, since this is not critical
|
|
log.Printf("error updating current activity (%s): %v\n", debugStr, err)
|
|
}
|
|
}
|
|
|
|
func GetCurDayStr() string {
|
|
now := time.Now()
|
|
dayStr := now.Format("2006-01-02")
|
|
return dayStr
|
|
}
|
|
|
|
func UpdateCurrentActivity(ctx context.Context, update ActivityUpdate) error {
|
|
now := time.Now()
|
|
dayStr := GetCurDayStr()
|
|
txErr := sstore.WithTx(ctx, func(tx *sstore.TxWrap) error {
|
|
var tdata TelemetryData
|
|
query := `SELECT tdata FROM activity WHERE day = ?`
|
|
found := tx.Get(&tdata, query, dayStr)
|
|
if !found {
|
|
query = `INSERT INTO activity (day, uploaded, tdata, tzname, tzoffset, clientversion, clientarch, buildtime, osrelease)
|
|
VALUES (?, 0, ?, ?, ?, ?, ? , ? , ?)`
|
|
tzName, tzOffset := now.Zone()
|
|
if len(tzName) > MaxTzNameLen {
|
|
tzName = tzName[0:MaxTzNameLen]
|
|
}
|
|
tx.Exec(query, dayStr, tdata, tzName, tzOffset, scbase.WaveVersion, scbase.ClientArch(), scbase.BuildTime, scbase.UnameKernelRelease())
|
|
}
|
|
tdata.NumCommands += update.NumCommands
|
|
tdata.FgMinutes += update.FgMinutes
|
|
tdata.ActiveMinutes += update.ActiveMinutes
|
|
tdata.OpenMinutes += update.OpenMinutes
|
|
tdata.ClickShared += update.ClickShared
|
|
tdata.HistoryView += update.HistoryView
|
|
tdata.BookmarksView += update.BookmarksView
|
|
tdata.ReinitBashErrors += update.ReinitBashErrors
|
|
tdata.ReinitZshErrors += update.ReinitZshErrors
|
|
if update.NumConns > 0 {
|
|
tdata.NumConns = update.NumConns
|
|
}
|
|
query = `UPDATE activity
|
|
SET tdata = ?,
|
|
clientversion = ?,
|
|
buildtime = ?
|
|
WHERE day = ?`
|
|
tx.Exec(query, tdata, scbase.WaveVersion, scbase.BuildTime, dayStr)
|
|
return nil
|
|
})
|
|
if txErr != nil {
|
|
return txErr
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetNonUploadedActivity(ctx context.Context) ([]*ActivityType, error) {
|
|
var rtn []*ActivityType
|
|
txErr := sstore.WithTx(ctx, func(tx *sstore.TxWrap) error {
|
|
query := `SELECT * FROM activity WHERE uploaded = 0 ORDER BY day DESC LIMIT 30`
|
|
tx.Select(&rtn, query)
|
|
return nil
|
|
})
|
|
if txErr != nil {
|
|
return nil, txErr
|
|
}
|
|
return rtn, nil
|
|
}
|
|
|
|
// note, will not mark the current day as uploaded
|
|
func MarkActivityAsUploaded(ctx context.Context, activityArr []*ActivityType) error {
|
|
dayStr := GetCurDayStr()
|
|
txErr := sstore.WithTx(ctx, func(tx *sstore.TxWrap) error {
|
|
query := `UPDATE activity SET uploaded = 1 WHERE day = ?`
|
|
for _, activity := range activityArr {
|
|
if activity.Day == dayStr {
|
|
continue
|
|
}
|
|
tx.Exec(query, activity.Day)
|
|
}
|
|
return nil
|
|
})
|
|
return txErr
|
|
}
|