mirror of
https://github.com/netbirdio/netbird.git
synced 2026-03-31 06:34:14 -04:00
This PR showcases the implementation of additional linter rules. I've updated the golangci-lint GitHub Actions to the latest available version. This update makes sure that the tool works the same way locally - assuming being updated regularly - and with the GitHub Actions. I've also taken care of keeping all the GitHub Actions up to date, which helps our code stay current. But there's one part, goreleaser that's a bit tricky to test on our computers. So, it's important to take a close look at that. To make it easier to understand what I've done, I've made separate changes for each thing that the new linters found. This should help the people reviewing the changes see what's going on more clearly. Some of the changes might not be obvious at first glance. Things to consider for the future CI runs on Ubuntu so the static analysis only happens for Linux. Consider running it for the rest: Darwin, Windows
166 lines
3.9 KiB
Go
166 lines
3.9 KiB
Go
package sqlite
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
|
|
"github.com/netbirdio/netbird/management/server/activity"
|
|
|
|
// sqlite driver
|
|
"path/filepath"
|
|
"time"
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
|
)
|
|
|
|
const (
|
|
//eventSinkDB is the default name of the events database
|
|
eventSinkDB = "events.db"
|
|
createTableQuery = "CREATE TABLE IF NOT EXISTS events " +
|
|
"(id INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
|
"activity INTEGER, " +
|
|
"timestamp DATETIME, " +
|
|
"initiator_id TEXT," +
|
|
"account_id TEXT," +
|
|
"meta TEXT," +
|
|
" target_id TEXT);"
|
|
|
|
selectDescQuery = "SELECT id, activity, timestamp, initiator_id, target_id, account_id, meta" +
|
|
" FROM events WHERE account_id = ? ORDER BY timestamp DESC LIMIT ? OFFSET ?;"
|
|
selectAscQuery = "SELECT id, activity, timestamp, initiator_id, target_id, account_id, meta" +
|
|
" FROM events WHERE account_id = ? ORDER BY timestamp ASC LIMIT ? OFFSET ?;"
|
|
insertQuery = "INSERT INTO events(activity, timestamp, initiator_id, target_id, account_id, meta) " +
|
|
"VALUES(?, ?, ?, ?, ?, ?)"
|
|
)
|
|
|
|
// Store is the implementation of the activity.Store interface backed by SQLite
|
|
type Store struct {
|
|
db *sql.DB
|
|
insertStatement *sql.Stmt
|
|
selectAscStatement *sql.Stmt
|
|
selectDescStatement *sql.Stmt
|
|
}
|
|
|
|
// NewSQLiteStore creates a new Store with an event table if not exists.
|
|
func NewSQLiteStore(dataDir string) (*Store, error) {
|
|
dbFile := filepath.Join(dataDir, eventSinkDB)
|
|
db, err := sql.Open("sqlite3", dbFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
_, err = db.Exec(createTableQuery)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
insertStmt, err := db.Prepare(insertQuery)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
selectDescStmt, err := db.Prepare(selectDescQuery)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
selectAscStmt, err := db.Prepare(selectAscQuery)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Store{
|
|
db: db,
|
|
insertStatement: insertStmt,
|
|
selectDescStatement: selectDescStmt,
|
|
selectAscStatement: selectAscStmt,
|
|
}, nil
|
|
}
|
|
|
|
func processResult(result *sql.Rows) ([]*activity.Event, error) {
|
|
events := make([]*activity.Event, 0)
|
|
for result.Next() {
|
|
var id int64
|
|
var operation activity.Activity
|
|
var timestamp time.Time
|
|
var initiator string
|
|
var target string
|
|
var account string
|
|
var jsonMeta string
|
|
err := result.Scan(&id, &operation, ×tamp, &initiator, &target, &account, &jsonMeta)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
meta := make(map[string]any)
|
|
if jsonMeta != "" {
|
|
err = json.Unmarshal([]byte(jsonMeta), &meta)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
events = append(events, &activity.Event{
|
|
Timestamp: timestamp,
|
|
Activity: operation,
|
|
ID: uint64(id),
|
|
InitiatorID: initiator,
|
|
TargetID: target,
|
|
AccountID: account,
|
|
Meta: meta,
|
|
})
|
|
}
|
|
|
|
return events, nil
|
|
}
|
|
|
|
// Get returns "limit" number of events from index ordered descending or ascending by a timestamp
|
|
func (store *Store) Get(accountID string, offset, limit int, descending bool) ([]*activity.Event, error) {
|
|
stmt := store.selectDescStatement
|
|
if !descending {
|
|
stmt = store.selectAscStatement
|
|
}
|
|
|
|
result, err := stmt.Query(accountID, limit, offset)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer result.Close() //nolint
|
|
return processResult(result)
|
|
}
|
|
|
|
// Save an event in the SQLite events table
|
|
func (store *Store) Save(event *activity.Event) (*activity.Event, error) {
|
|
var jsonMeta string
|
|
if event.Meta != nil {
|
|
metaBytes, err := json.Marshal(event.Meta)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
jsonMeta = string(metaBytes)
|
|
}
|
|
|
|
result, err := store.insertStatement.Exec(event.Activity, event.Timestamp, event.InitiatorID, event.TargetID, event.AccountID, jsonMeta)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
id, err := result.LastInsertId()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
eventCopy := event.Copy()
|
|
eventCopy.ID = uint64(id)
|
|
return eventCopy, nil
|
|
}
|
|
|
|
// Close the Store
|
|
func (store *Store) Close() error {
|
|
if store.db != nil {
|
|
return store.db.Close()
|
|
}
|
|
return nil
|
|
}
|