remove direct db instructions from apiRegisterHandler and statsHandler

This commit is contained in:
Sergio Moura 2023-09-07 16:48:34 -04:00
parent 382f234c09
commit 0d6aa081d8
3 changed files with 147 additions and 34 deletions

View File

@ -125,29 +125,27 @@ func usageStatsHandler(w http.ResponseWriter, r *http.Request) {
}
func statsHandler(w http.ResponseWriter, r *http.Request) {
var numDevices int64 = 0
checkGormResult(GLOBAL_DB.WithContext(r.Context()).Model(&shared.Device{}).Count(&numDevices))
type numEntriesProcessed struct {
Total int
}
nep := numEntriesProcessed{}
checkGormResult(GLOBAL_DB.WithContext(r.Context()).Model(&shared.UsageData{}).Select("SUM(num_entries_handled) as total").Find(&nep))
var numDbEntries int64 = 0
checkGormResult(GLOBAL_DB.WithContext(r.Context()).Model(&shared.EncHistoryEntry{}).Count(&numDbEntries))
numDevices, err := GLOBAL_DB.DevicesCount(r.Context())
checkGormError(err, 0)
numEntriesProcessed, err := GLOBAL_DB.UsageDataTotal(r.Context())
checkGormError(err, 0)
numDbEntries, err := GLOBAL_DB.EncHistoryEntryCount(r.Context())
checkGormError(err, 0)
oneWeek := time.Hour * 24 * 7
weeklyActiveInstalls, err := GLOBAL_DB.WeeklyActiveInstalls(r.Context(), oneWeek)
checkGormError(err, 0)
weeklyQueryUsers, err := GLOBAL_DB.WeeklyQueryUsers(r.Context(), oneWeek)
checkGormError(err, 0)
lastRegistration, err := GLOBAL_DB.LastRegistration(r.Context())
checkGormError(err, 0)
lastWeek := time.Now().AddDate(0, 0, -7)
var weeklyActiveInstalls int64 = 0
checkGormResult(GLOBAL_DB.WithContext(r.Context()).Model(&shared.UsageData{}).Where("last_used > ?", lastWeek).Count(&weeklyActiveInstalls))
var weeklyQueryUsers int64 = 0
checkGormResult(GLOBAL_DB.WithContext(r.Context()).Model(&shared.UsageData{}).Where("last_queried > ?", lastWeek).Count(&weeklyQueryUsers))
var lastRegistration string = ""
row := GLOBAL_DB.WithContext(r.Context()).Raw("select to_char(max(registration_date), 'DD Month YYYY HH24:MI') from devices").Row()
err := row.Scan(&lastRegistration)
if err != nil {
panic(err)
}
_, _ = fmt.Fprintf(w, "Num devices: %d\n", numDevices)
_, _ = fmt.Fprintf(w, "Num history entries processed: %d\n", nep.Total)
_, _ = fmt.Fprintf(w, "Num history entries processed: %d\n", numEntriesProcessed)
_, _ = fmt.Fprintf(w, "Num DB entries: %d\n", numDbEntries)
_, _ = fmt.Fprintf(w, "Weekly active installs: %d\n", weeklyActiveInstalls)
_, _ = fmt.Fprintf(w, "Weekly active queries: %d\n", weeklyQueryUsers)
@ -275,11 +273,9 @@ func getRemoteAddr(r *http.Request) string {
func apiRegisterHandler(w http.ResponseWriter, r *http.Request) {
if getMaximumNumberOfAllowedUsers() < math.MaxInt {
row := GLOBAL_DB.WithContext(r.Context()).Raw("SELECT COUNT(DISTINCT devices.user_id) FROM devices").Row()
var numDistinctUsers int64 = 0
err := row.Scan(&numDistinctUsers)
numDistinctUsers, err := GLOBAL_DB.DistinctUsers(r.Context())
if err != nil {
panic(err)
panic(fmt.Errorf("db.DistinctUsers: %w", err))
}
if numDistinctUsers >= int64(getMaximumNumberOfAllowedUsers()) {
panic(fmt.Sprintf("Refusing to allow registration of new device since there are currently %d users and this server allows a max of %d users", numDistinctUsers, getMaximumNumberOfAllowedUsers()))
@ -287,14 +283,21 @@ func apiRegisterHandler(w http.ResponseWriter, r *http.Request) {
}
userId := getRequiredQueryParam(r, "user_id")
deviceId := getRequiredQueryParam(r, "device_id")
var existingDevicesCount int64 = -1
checkGormResult(GLOBAL_DB.WithContext(r.Context()).Model(&shared.Device{}).Where("user_id = ?", userId).Count(&existingDevicesCount))
existingDevicesCount, err := GLOBAL_DB.DevicesCountForUser(r.Context(), userId)
checkGormError(err, 0)
fmt.Printf("apiRegisterHandler: existingDevicesCount=%d\n", existingDevicesCount)
checkGormResult(GLOBAL_DB.WithContext(r.Context()).Create(&shared.Device{UserId: userId, DeviceId: deviceId, RegistrationIp: getRemoteAddr(r), RegistrationDate: time.Now()}))
if existingDevicesCount > 0 {
checkGormResult(GLOBAL_DB.WithContext(r.Context()).Create(&shared.DumpRequest{UserId: userId, RequestingDeviceId: deviceId, RequestTime: time.Now()}))
if err := GLOBAL_DB.DeviceCreate(r.Context(), &shared.Device{UserId: userId, DeviceId: deviceId, RegistrationIp: getRemoteAddr(r), RegistrationDate: time.Now()}); err != nil {
checkGormError(err, 0)
}
if existingDevicesCount > 0 {
err := GLOBAL_DB.DumpRequestCreate(r.Context(), &shared.DumpRequest{UserId: userId, RequestingDeviceId: deviceId, RequestTime: time.Now()})
checkGormError(err, 0)
}
if err := updateUsageData(r, userId, deviceId, 0, false); err != nil {
fmt.Printf("updateUsageData: %v\n", err)
}
updateUsageData(r, userId, deviceId, 0, false)
if GLOBAL_STATSD != nil {
GLOBAL_STATSD.Incr("hishtory.register", []string{}, 1.0)
@ -959,10 +962,16 @@ func main() {
}
func checkGormResult(result *gorm.DB) {
if result.Error != nil {
_, filename, line, _ := runtime.Caller(1)
panic(fmt.Sprintf("DB error at %s:%d: %v", filename, line, result.Error))
checkGormError(result.Error, 1)
}
func checkGormError(err error, skip int) {
if err == nil {
return
}
_, filename, line, _ := runtime.Caller(skip + 1)
panic(fmt.Sprintf("DB error at %s:%d: %v", filename, line, err))
}
func getMaximumNumberOfAllowedUsers() int {

View File

@ -1,6 +1,7 @@
package database
import (
"context"
"database/sql"
"fmt"
"github.com/ddworken/hishtory/shared"
@ -93,3 +94,62 @@ func (db *DB) Stats() (sql.DBStats, error) {
return rawDB.Stats(), nil
}
func (db *DB) DistinctUsers(ctx context.Context) (int64, error) {
row := db.WithContext(ctx).Raw("SELECT COUNT(DISTINCT devices.user_id) FROM devices").Row()
var numDistinctUsers int64
err := row.Scan(&numDistinctUsers)
if err != nil {
return 0, fmt.Errorf("row.Scan: %w", err)
}
return numDistinctUsers, nil
}
func (db *DB) DevicesCountForUser(ctx context.Context, userID string) (int64, error) {
var existingDevicesCount int64
tx := db.WithContext(ctx).Model(&shared.Device{}).Where("user_id = ?", userID).Count(&existingDevicesCount)
if tx.Error != nil {
return 0, fmt.Errorf("tx.Error: %w", tx.Error)
}
return existingDevicesCount, nil
}
func (db *DB) DevicesCount(ctx context.Context) (int64, error) {
var numDevices int64 = 0
tx := db.WithContext(ctx).Model(&shared.Device{}).Count(&numDevices)
if tx.Error != nil {
return 0, fmt.Errorf("tx.Error: %w", tx.Error)
}
return numDevices, nil
}
func (db *DB) DeviceCreate(ctx context.Context, device *shared.Device) error {
tx := db.WithContext(ctx).Create(device)
if tx.Error != nil {
return fmt.Errorf("tx.Error: %w", tx.Error)
}
return nil
}
func (db *DB) DumpRequestCreate(ctx context.Context, req *shared.DumpRequest) error {
tx := db.WithContext(ctx).Create(req)
if tx.Error != nil {
return fmt.Errorf("tx.Error: %w", tx.Error)
}
return nil
}
func (db *DB) EncHistoryEntryCount(ctx context.Context) (int64, error) {
var numDbEntries int64
tx := db.WithContext(ctx).Model(&shared.EncHistoryEntry{}).Count(&numDbEntries)
if tx.Error != nil {
return 0, fmt.Errorf("tx.Error: %w", tx.Error)
}
return numDbEntries, nil
}

View File

@ -133,3 +133,47 @@ func (db *DB) UsageDataStats(ctx context.Context) ([]*UsageDataStats, error) {
return resp, nil
}
func (db *DB) UsageDataTotal(ctx context.Context) (int64, error) {
type numEntriesProcessed struct {
Total int
}
nep := numEntriesProcessed{}
tx := db.WithContext(ctx).Model(&shared.UsageData{}).Select("SUM(num_entries_handled) as total").Find(&nep)
if tx.Error != nil {
return 0, fmt.Errorf("tx.Error: %w", tx.Error)
}
return int64(nep.Total), nil
}
func (db *DB) WeeklyActiveInstalls(ctx context.Context, since time.Duration) (int64, error) {
var weeklyActiveInstalls int64
tx := db.WithContext(ctx).Model(&shared.UsageData{}).Where("last_used > ?", time.Now().Add(-since)).Count(&weeklyActiveInstalls)
if tx.Error != nil {
return 0, fmt.Errorf("tx.Error: %w", tx.Error)
}
return weeklyActiveInstalls, nil
}
func (db *DB) WeeklyQueryUsers(ctx context.Context, since time.Duration) (int64, error) {
var weeklyQueryUsers int64
tx := db.WithContext(ctx).Model(&shared.UsageData{}).Where("last_queried > ?", time.Now().Add(-since)).Count(&weeklyQueryUsers)
if tx.Error != nil {
return 0, fmt.Errorf("tx.Error: %w", tx.Error)
}
return weeklyQueryUsers, nil
}
func (db *DB) LastRegistration(ctx context.Context) (string, error) {
var lastRegistration string
row := db.WithContext(ctx).Raw("SELECT to_char(max(registration_date), 'DD Month YYYY HH24:MI') FROM devices").Row()
if err := row.Scan(&lastRegistration); err != nil {
return "", fmt.Errorf("row.Scan: %w", err)
}
return lastRegistration, nil
}