mirror of
https://github.com/status-im/status-go.git
synced 2025-01-10 14:47:06 +00:00
9a59d6a459
This commit adds support for centralized metrics. There are two providers as of now, and we haven't quite decided which one to go for, so for the time being both are supported. It also introduces a new endpoint InitializeApplication that replaces OpenAccounts
202 lines
4.4 KiB
Go
202 lines
4.4 KiB
Go
package centralizedmetrics
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/status-im/status-go/centralizedmetrics/common"
|
|
)
|
|
|
|
type SQLiteMetricRepository struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func NewSQLiteMetricRepository(db *sql.DB) *SQLiteMetricRepository {
|
|
return &SQLiteMetricRepository{db: db}
|
|
}
|
|
|
|
func (r *SQLiteMetricRepository) Poll() ([]common.Metric, error) {
|
|
tx, err := r.db.BeginTx(context.Background(), &sql.TxOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer func() {
|
|
if err == nil {
|
|
err = tx.Commit()
|
|
return
|
|
}
|
|
// don't shadow original error
|
|
_ = tx.Rollback()
|
|
}()
|
|
|
|
userID, err := r.UserID(tx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rows, err := tx.Query("SELECT id, event_name, event_value, platform, app_version, timestamp FROM centralizedmetrics_metrics limit 10")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var metrics []common.Metric
|
|
for rows.Next() {
|
|
var metric common.Metric
|
|
var eventValue string
|
|
|
|
if err := rows.Scan(&metric.ID, &metric.EventName, &eventValue, &metric.Platform, &metric.AppVersion, &metric.Timestamp); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Deserialize eventValue
|
|
if err := json.Unmarshal([]byte(eventValue), &metric.EventValue); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
metric.UserID = userID
|
|
|
|
metrics = append(metrics, metric)
|
|
}
|
|
|
|
return metrics, rows.Err()
|
|
}
|
|
|
|
func (r *SQLiteMetricRepository) Delete(metrics []common.Metric) error {
|
|
tx, err := r.db.BeginTx(context.Background(), nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
if err == nil {
|
|
err = tx.Commit()
|
|
return
|
|
}
|
|
// don't shadow original error
|
|
_ = tx.Rollback()
|
|
}()
|
|
|
|
stmt, err := tx.Prepare("DELETE FROM centralizedmetrics_metrics WHERE id = ?")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer stmt.Close()
|
|
|
|
for _, metric := range metrics {
|
|
if _, err := stmt.Exec(metric.ID); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
func (r *SQLiteMetricRepository) Add(metric common.Metric) error {
|
|
eventValue, err := json.Marshal(metric.EventValue)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = r.db.Exec("INSERT INTO centralizedmetrics_metrics (id, event_name, event_value, platform, app_version, timestamp) VALUES (?, ?, ?, ?, ?, ?)",
|
|
metric.ID, metric.EventName, string(eventValue), metric.Platform, metric.AppVersion, time.Now().UnixNano()/int64(time.Millisecond))
|
|
return err
|
|
}
|
|
|
|
func (r *SQLiteMetricRepository) UserID(tx *sql.Tx) (string, error) {
|
|
var err error
|
|
if tx == nil {
|
|
tx, err = r.db.BeginTx(context.Background(), &sql.TxOptions{})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer func() {
|
|
if err == nil {
|
|
err = tx.Commit()
|
|
return
|
|
}
|
|
// don't shadow original error
|
|
_ = tx.Rollback()
|
|
}()
|
|
}
|
|
|
|
var userID string
|
|
|
|
// Check if a UUID already exists in the table
|
|
err = tx.QueryRow("SELECT uuid FROM centralizedmetrics_uuid LIMIT 1").Scan(&userID)
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
// clean up err
|
|
err = nil
|
|
// Generate a new UUID
|
|
newUUID := uuid.New().String()
|
|
|
|
// Insert the new UUID into the table
|
|
_, err := tx.Exec("INSERT INTO centralizedmetrics_uuid (uuid) VALUES (?)", newUUID)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to insert new UUID: %v", err)
|
|
}
|
|
|
|
return newUUID, nil
|
|
}
|
|
return "", fmt.Errorf("failed to query for existing UUID: %v", err)
|
|
}
|
|
|
|
return userID, nil
|
|
}
|
|
|
|
func (r *SQLiteMetricRepository) ToggleEnabled(enabled bool) error {
|
|
tx, err := r.db.BeginTx(context.Background(), &sql.TxOptions{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer func() {
|
|
if err == nil {
|
|
err = tx.Commit()
|
|
return
|
|
}
|
|
// don't shadow original error
|
|
_ = tx.Rollback()
|
|
}()
|
|
|
|
// make sure row is present
|
|
userID, err := r.UserID(tx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = tx.Exec("UPDATE centralizedmetrics_uuid SET enabled = ?, user_confirmed = 1 WHERE uuid = ?", enabled, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// if we are enabling them, nothing else to do
|
|
if enabled {
|
|
return nil
|
|
}
|
|
|
|
// otherwise clean up metrics that might have been collected in the meantime
|
|
_, err = tx.Exec("DELETE FROM centralizedmetrics_metrics")
|
|
return err
|
|
|
|
}
|
|
|
|
func (r *SQLiteMetricRepository) Info() (*MetricsInfo, error) {
|
|
info := MetricsInfo{}
|
|
err := r.db.QueryRow("SELECT enabled,user_confirmed FROM centralizedmetrics_uuid LIMIT 1").Scan(&info.Enabled, &info.UserConfirmed)
|
|
if err == sql.ErrNoRows {
|
|
return &info, nil
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &info, nil
|
|
}
|