github.com/status-im/status-go@v1.1.0/centralizedmetrics/sqlite_persistence.go (about) 1 package centralizedmetrics 2 3 import ( 4 "context" 5 "database/sql" 6 "encoding/json" 7 "fmt" 8 "time" 9 10 "github.com/google/uuid" 11 12 "github.com/status-im/status-go/centralizedmetrics/common" 13 ) 14 15 type SQLiteMetricRepository struct { 16 db *sql.DB 17 } 18 19 func NewSQLiteMetricRepository(db *sql.DB) *SQLiteMetricRepository { 20 return &SQLiteMetricRepository{db: db} 21 } 22 23 func (r *SQLiteMetricRepository) Poll() ([]common.Metric, error) { 24 tx, err := r.db.BeginTx(context.Background(), &sql.TxOptions{}) 25 if err != nil { 26 return nil, err 27 } 28 29 defer func() { 30 if err == nil { 31 err = tx.Commit() 32 return 33 } 34 // don't shadow original error 35 _ = tx.Rollback() 36 }() 37 38 userID, err := r.UserID(tx) 39 if err != nil { 40 return nil, err 41 } 42 43 rows, err := tx.Query("SELECT id, event_name, event_value, platform, app_version, timestamp FROM centralizedmetrics_metrics limit 10") 44 if err != nil { 45 return nil, err 46 } 47 defer rows.Close() 48 49 var metrics []common.Metric 50 for rows.Next() { 51 var metric common.Metric 52 var eventValue string 53 54 if err := rows.Scan(&metric.ID, &metric.EventName, &eventValue, &metric.Platform, &metric.AppVersion, &metric.Timestamp); err != nil { 55 return nil, err 56 } 57 58 // Deserialize eventValue 59 if err := json.Unmarshal([]byte(eventValue), &metric.EventValue); err != nil { 60 return nil, err 61 } 62 63 metric.UserID = userID 64 65 metrics = append(metrics, metric) 66 } 67 68 return metrics, rows.Err() 69 } 70 71 func (r *SQLiteMetricRepository) Delete(metrics []common.Metric) error { 72 tx, err := r.db.BeginTx(context.Background(), nil) 73 if err != nil { 74 return err 75 } 76 defer func() { 77 if err == nil { 78 err = tx.Commit() 79 return 80 } 81 // don't shadow original error 82 _ = tx.Rollback() 83 }() 84 85 stmt, err := tx.Prepare("DELETE FROM centralizedmetrics_metrics WHERE id = ?") 86 if err != nil { 87 return err 88 } 89 90 defer stmt.Close() 91 92 for _, metric := range metrics { 93 if _, err := stmt.Exec(metric.ID); err != nil { 94 return err 95 } 96 } 97 98 return tx.Commit() 99 } 100 101 func (r *SQLiteMetricRepository) Add(metric common.Metric) error { 102 eventValue, err := json.Marshal(metric.EventValue) 103 if err != nil { 104 return err 105 } 106 107 _, err = r.db.Exec("INSERT INTO centralizedmetrics_metrics (id, event_name, event_value, platform, app_version, timestamp) VALUES (?, ?, ?, ?, ?, ?)", 108 metric.ID, metric.EventName, string(eventValue), metric.Platform, metric.AppVersion, time.Now().UnixNano()/int64(time.Millisecond)) 109 return err 110 } 111 112 func (r *SQLiteMetricRepository) UserID(tx *sql.Tx) (string, error) { 113 var err error 114 if tx == nil { 115 tx, err = r.db.BeginTx(context.Background(), &sql.TxOptions{}) 116 if err != nil { 117 return "", err 118 } 119 defer func() { 120 if err == nil { 121 err = tx.Commit() 122 return 123 } 124 // don't shadow original error 125 _ = tx.Rollback() 126 }() 127 } 128 129 var userID string 130 131 // Check if a UUID already exists in the table 132 err = tx.QueryRow("SELECT uuid FROM centralizedmetrics_uuid LIMIT 1").Scan(&userID) 133 if err != nil { 134 if err == sql.ErrNoRows { 135 // clean up err 136 err = nil 137 // Generate a new UUID 138 newUUID := uuid.New().String() 139 140 // Insert the new UUID into the table 141 _, err := tx.Exec("INSERT INTO centralizedmetrics_uuid (uuid) VALUES (?)", newUUID) 142 if err != nil { 143 return "", fmt.Errorf("failed to insert new UUID: %v", err) 144 } 145 146 return newUUID, nil 147 } 148 return "", fmt.Errorf("failed to query for existing UUID: %v", err) 149 } 150 151 return userID, nil 152 } 153 154 func (r *SQLiteMetricRepository) ToggleEnabled(enabled bool) error { 155 tx, err := r.db.BeginTx(context.Background(), &sql.TxOptions{}) 156 if err != nil { 157 return err 158 } 159 160 defer func() { 161 if err == nil { 162 err = tx.Commit() 163 return 164 } 165 // don't shadow original error 166 _ = tx.Rollback() 167 }() 168 169 // make sure row is present 170 userID, err := r.UserID(tx) 171 if err != nil { 172 return err 173 } 174 _, err = tx.Exec("UPDATE centralizedmetrics_uuid SET enabled = ?, user_confirmed = 1 WHERE uuid = ?", enabled, userID) 175 if err != nil { 176 return err 177 } 178 179 // if we are enabling them, nothing else to do 180 if enabled { 181 return nil 182 } 183 184 // otherwise clean up metrics that might have been collected in the meantime 185 _, err = tx.Exec("DELETE FROM centralizedmetrics_metrics") 186 return err 187 188 } 189 190 func (r *SQLiteMetricRepository) Info() (*MetricsInfo, error) { 191 info := MetricsInfo{} 192 err := r.db.QueryRow("SELECT enabled,user_confirmed FROM centralizedmetrics_uuid LIMIT 1").Scan(&info.Enabled, &info.UserConfirmed) 193 if err == sql.ErrNoRows { 194 return &info, nil 195 } 196 197 if err != nil { 198 return nil, err 199 } 200 return &info, nil 201 }