package eventlogger import ( "database/sql" "encoding/json" "fmt" "os" "path/filepath" "sync" "git.warky.dev/wdevs/whatshooked/internal/config" "git.warky.dev/wdevs/whatshooked/internal/events" _ "github.com/mattn/go-sqlite3" // SQLite driver ) // SQLiteTarget logs events to SQLite database type SQLiteTarget struct { db *sql.DB tableName string mu sync.Mutex } // NewSQLiteTarget creates a new SQLite logging target func NewSQLiteTarget(dbConfig config.DatabaseConfig, tableName string) (*SQLiteTarget, error) { // Use the SQLite path from config (defaults to "./data/events.db") dbPath := dbConfig.SQLitePath // Create directory if needed dir := filepath.Dir(dbPath) if err := os.MkdirAll(dir, 0755); err != nil { return nil, fmt.Errorf("failed to create database directory: %w", err) } // Open SQLite connection db, err := sql.Open("sqlite3", dbPath) if err != nil { return nil, fmt.Errorf("failed to open SQLite database: %w", err) } target := &SQLiteTarget{ db: db, tableName: tableName, } // Create table if it doesn't exist if err := target.createTable(); err != nil { db.Close() return nil, err } return target, nil } // createTable creates the event logs table if it doesn't exist func (st *SQLiteTarget) createTable() error { query := fmt.Sprintf(` CREATE TABLE IF NOT EXISTS %s ( id INTEGER PRIMARY KEY AUTOINCREMENT, event_type TEXT NOT NULL, timestamp DATETIME NOT NULL, data TEXT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) `, st.tableName) if _, err := st.db.Exec(query); err != nil { return fmt.Errorf("failed to create table: %w", err) } // Create index on event_type and timestamp indexQuery := fmt.Sprintf(` CREATE INDEX IF NOT EXISTS idx_%s_type_timestamp ON %s(event_type, timestamp) `, st.tableName, st.tableName) if _, err := st.db.Exec(indexQuery); err != nil { return fmt.Errorf("failed to create index: %w", err) } return nil } // Log writes an event to SQLite database func (st *SQLiteTarget) Log(event events.Event) error { st.mu.Lock() defer st.mu.Unlock() // Marshal event data to JSON data, err := json.Marshal(event.Data) if err != nil { return fmt.Errorf("failed to marshal event data: %w", err) } query := fmt.Sprintf(` INSERT INTO %s (event_type, timestamp, data) VALUES (?, ?, ?) `, st.tableName) _, err = st.db.Exec(query, string(event.Type), event.Timestamp, string(data)) if err != nil { return fmt.Errorf("failed to insert event: %w", err) } return nil } // Close closes the SQLite database connection func (st *SQLiteTarget) Close() error { return st.db.Close() }