detached d276230

Refactor to use disk-based SQLite database instead of in-memory

- Modified main.go to initialize the disk-based SQLite database and removed handling of in-memory database.
- Removed sqlite_test.go since we no longer have the in-memory database.
- Simplified sqliteclose.go to only close the disk-based SQLite database.
- Refactored sqliteinit.go to support disk-based SQLite database initialization.
commit
d276230715f81de82a84f40ff905ade426cc4ae8
author
bnema · · 2023-10-16 15:26 UTC
parent
f2713b0
signature
unsigned
5 files · +51 -377
M cmd/srv/main.go +9 -9
@@ -1,7 +1,6 @@
11 package main
22
33 import (
4- "database/sql"
54 "fmt"
65 "log"
76 "os"
@@ -15,23 +14,24 @@ import (
1514 "github.com/bnema/gordon/pkg/docker"
1615 )
1716
18-func cleanup(a *app.App, memDb *sql.DB) {
19- if err := app.CloseAndBackupDB(a, memDb); err != nil {
17+func cleanup(a *app.App) {
18+ if err := app.CloseDB(a); err != nil {
2019 log.Fatal("Failed to close and backup database:", err)
2120 }
2221 }
2322
2423 func main() {
2524 a := app.NewApp()
26- // Initialize database
27- memDb, err := app.InitializeDB(a)
25+
26+ _, err := app.InitializeDB(a)
2827 if err != nil {
2928 log.Fatal("Failed to initialize database:", err)
3029 }
31- // Pass memDb to the app with the rest of the configs
32- a.DB = memDb
3330
34- a.HandleNewTokenInitialization()
31+ _, err = app.HandleNewTokenInitialization(a)
32+ if err != nil {
33+ log.Fatal("Failed to initialize new token:", err)
34+ }
3535
3636 dockerClient := &docker.DockerClient{}
3737 err = dockerClient.InitializeClient(a.Config.NewDockerConfig())
@@ -46,7 +46,7 @@ func main() {
4646 go func() {
4747 sig := <-sigs
4848 log.Println("Received signal:", sig)
49- cleanup(a, memDb) // <- Call the cleanup function
49+ cleanup(a) // <- Call the cleanup function
5050 os.Exit(0)
5151 }()
5252
@@ -1,7 +1,6 @@
1 package main1 package main
2 2
3 import (3 import (
4- "database/sql"
5 "fmt"4 "fmt"
6 "log"5 "log"
7 "os"6 "os"
@@ -15,23 +14,24 @@ import (
15 "github.com/bnema/gordon/pkg/docker"14 "github.com/bnema/gordon/pkg/docker"
16 )15 )
17 16
18-func cleanup(a *app.App, memDb *sql.DB) {17+func cleanup(a *app.App) {
19- if err := app.CloseAndBackupDB(a, memDb); err != nil {18+ if err := app.CloseDB(a); err != nil {
20 log.Fatal("Failed to close and backup database:", err)19 log.Fatal("Failed to close and backup database:", err)
21 }20 }
22 }21 }
23 22
24 func main() {23 func main() {
25 a := app.NewApp()24 a := app.NewApp()
26- // Initialize database25+
27- memDb, err := app.InitializeDB(a)26+ _, err := app.InitializeDB(a)
28 if err != nil {27 if err != nil {
29 log.Fatal("Failed to initialize database:", err)28 log.Fatal("Failed to initialize database:", err)
30 }29 }
31- // Pass memDb to the app with the rest of the configs
32- a.DB = memDb
33 30
34- a.HandleNewTokenInitialization()31+ _, err = app.HandleNewTokenInitialization(a)
32+ if err != nil {
33+ log.Fatal("Failed to initialize new token:", err)
34+ }
35 35
36 dockerClient := &docker.DockerClient{}36 dockerClient := &docker.DockerClient{}
37 err = dockerClient.InitializeClient(a.Config.NewDockerConfig())37 err = dockerClient.InitializeClient(a.Config.NewDockerConfig())
@@ -46,7 +46,7 @@ func main() {
46 go func() {46 go func() {
47 sig := <-sigs47 sig := <-sigs
48 log.Println("Received signal:", sig)48 log.Println("Received signal:", sig)
49- cleanup(a, memDb) // <- Call the cleanup function49+ cleanup(a) // <- Call the cleanup function
50 os.Exit(0)50 os.Exit(0)
51 }()51 }()
52 52
D internal/app/sqlite_test.go +0 -146
@@ -1,146 +0,0 @@
1-package app_test
2-
3-import (
4- "database/sql"
5- "os"
6- "testing"
7-
8- "github.com/bnema/gordon/internal/app"
9-)
10-
11-// test for CloseAndBackupDB with database modifications (checksum should be different and backup file should be created)
12-func TestCloseAndBackupDBWithModifications(t *testing.T) {
13- // Ensure the directory exists
14- err := os.MkdirAll("./tmp/data", 0755)
15- if err != nil {
16- t.Fatalf("Failed to create directory: %v", err)
17- }
18-
19- // Create a temporary file for testing
20- tempFile, err := os.CreateTemp("./tmp/data", "sqlite.db")
21- if err != nil {
22- t.Fatalf("Failed to create temp file: %v", err)
23- }
24- tempFile.Close()
25-
26- app := &app.App{
27- DBFilename: tempFile.Name(),
28- DBTables: app.DBTables{},
29- }
30-
31- // Initialize in-memory database
32- memDb, err := sql.Open("sqlite3", ":memory:")
33- if err != nil {
34- t.Fatalf("Failed to open in-memory database: %v", err)
35- }
36-
37- // Initialize the DB field in the App struct
38- app.DB = memDb
39- defer memDb.Close()
40-
41- // Create table and insert some data
42- _, err = memDb.Exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
43- if err != nil {
44- t.Fatalf("Failed to create table: %v", err)
45- }
46- _, err = memDb.Exec("INSERT INTO users (name) VALUES ('Alice'), ('Bob')")
47- if err != nil {
48- t.Fatalf("Failed to insert data: %v", err)
49- }
50-
51- // Generate initial checksum
52- initialChecksum, err := app.GenerateDBChecksum(memDb, app)
53- if err != nil {
54- t.Fatalf("Failed to generate initial checksum: %v", err)
55- }
56-
57- // Validate: Checksum should remain the same
58- finalChecksum, err := GenerateDBChecksum(memDb, app)
59- if err != nil {
60- t.Fatalf("Failed to generate final checksum: %v", err)
61- }
62- if initialChecksum != finalChecksum {
63- t.Fatalf("Checksum mismatch. Expected: %s, Got: %s", initialChecksum, finalChecksum)
64- }
65-
66- // Modify the database
67- _, err = memDb.Exec("INSERT INTO users (name) VALUES ('Charlie')")
68- if err != nil {
69- t.Fatalf("Failed to insert data: %v", err)
70- }
71-
72- // Validate: Checksum should be different
73- finalChecksum, err = GenerateDBChecksum(memDb, app)
74- if err != nil {
75- t.Fatalf("Failed to generate final checksum: %v", err)
76- }
77- if initialChecksum == finalChecksum {
78- t.Fatalf("Checksum mismatch. Expected: %s, Got: %s", initialChecksum, finalChecksum)
79- }
80-
81- // Test: CloseAndBackupDB with modification
82- err = CloseAndBackupDB(app, memDb)
83- if err != nil {
84- t.Fatalf("Failed in CloseAndBackupDB: %v", err)
85- }
86-
87-}
88-
89-// test for CloseAndBackupDB with NO database modifications (checksum should remain the same and no backup file should be created)
90-func TestCloseAndBackupDBWithNoModifications(t *testing.T) {
91- // Ensure the directory exists
92- err := os.MkdirAll("./tmp/data", 0755)
93- if err != nil {
94- t.Fatalf("Failed to create directory: %v", err)
95- }
96-
97- // Create a temporary file for testing
98- tempFile, err := os.CreateTemp("./tmp/data", "sqlite.db")
99- if err != nil {
100- t.Fatalf("Failed to create temp file: %v", err)
101- }
102- tempFile.Close()
103-
104- app := &App{
105- DBFilename: tempFile.Name(),
106- }
107-
108- // Initialize in-memory database
109- memDb, err := sql.Open("sqlite3", ":memory:")
110- if err != nil {
111- t.Fatalf("Failed to open in-memory database: %v", err)
112- }
113- defer memDb.Close()
114-
115- // Create table and insert some data
116- _, err = memDb.Exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
117- if err != nil {
118- t.Fatalf("Failed to create table: %v", err)
119- }
120- _, err = memDb.Exec("INSERT INTO users (name) VALUES ('Alice'), ('Bob')")
121- if err != nil {
122- t.Fatalf("Failed to insert data: %v", err)
123- }
124-
125- // Generate initial checksum
126- initialChecksum, err := GenerateDBChecksum(memDb, app)
127- if err != nil {
128- t.Fatalf("Failed to generate initial checksum: %v", err)
129- }
130-
131- // Validate: Checksum should remain the same
132- finalChecksum, err := GenerateDBChecksum(memDb, app)
133- if err != nil {
134- t.Fatalf("Failed to generate final checksum: %v", err)
135- }
136- if initialChecksum != finalChecksum {
137- t.Fatalf("Checksum mismatch. Expected: %s, Got: %s", initialChecksum, finalChecksum)
138- }
139-
140- // Test: CloseAndBackupDB with modification
141- err = CloseAndBackupDB(app, memDb)
142- if err != nil {
143- t.Fatalf("Failed in CloseAndBackupDB: %v", err)
144- }
145-
146-}
@@ -1,146 +0,0 @@
1-package app_test
2-
3-import (
4- "database/sql"
5- "os"
6- "testing"
7-
8- "github.com/bnema/gordon/internal/app"
9-)
10-
11-// test for CloseAndBackupDB with database modifications (checksum should be different and backup file should be created)
12-func TestCloseAndBackupDBWithModifications(t *testing.T) {
13- // Ensure the directory exists
14- err := os.MkdirAll("./tmp/data", 0755)
15- if err != nil {
16- t.Fatalf("Failed to create directory: %v", err)
17- }
18-
19- // Create a temporary file for testing
20- tempFile, err := os.CreateTemp("./tmp/data", "sqlite.db")
21- if err != nil {
22- t.Fatalf("Failed to create temp file: %v", err)
23- }
24- tempFile.Close()
25-
26- app := &app.App{
27- DBFilename: tempFile.Name(),
28- DBTables: app.DBTables{},
29- }
30-
31- // Initialize in-memory database
32- memDb, err := sql.Open("sqlite3", ":memory:")
33- if err != nil {
34- t.Fatalf("Failed to open in-memory database: %v", err)
35- }
36-
37- // Initialize the DB field in the App struct
38- app.DB = memDb
39- defer memDb.Close()
40-
41- // Create table and insert some data
42- _, err = memDb.Exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
43- if err != nil {
44- t.Fatalf("Failed to create table: %v", err)
45- }
46- _, err = memDb.Exec("INSERT INTO users (name) VALUES ('Alice'), ('Bob')")
47- if err != nil {
48- t.Fatalf("Failed to insert data: %v", err)
49- }
50-
51- // Generate initial checksum
52- initialChecksum, err := app.GenerateDBChecksum(memDb, app)
53- if err != nil {
54- t.Fatalf("Failed to generate initial checksum: %v", err)
55- }
56-
57- // Validate: Checksum should remain the same
58- finalChecksum, err := GenerateDBChecksum(memDb, app)
59- if err != nil {
60- t.Fatalf("Failed to generate final checksum: %v", err)
61- }
62- if initialChecksum != finalChecksum {
63- t.Fatalf("Checksum mismatch. Expected: %s, Got: %s", initialChecksum, finalChecksum)
64- }
65-
66- // Modify the database
67- _, err = memDb.Exec("INSERT INTO users (name) VALUES ('Charlie')")
68- if err != nil {
69- t.Fatalf("Failed to insert data: %v", err)
70- }
71-
72- // Validate: Checksum should be different
73- finalChecksum, err = GenerateDBChecksum(memDb, app)
74- if err != nil {
75- t.Fatalf("Failed to generate final checksum: %v", err)
76- }
77- if initialChecksum == finalChecksum {
78- t.Fatalf("Checksum mismatch. Expected: %s, Got: %s", initialChecksum, finalChecksum)
79- }
80-
81- // Test: CloseAndBackupDB with modification
82- err = CloseAndBackupDB(app, memDb)
83- if err != nil {
84- t.Fatalf("Failed in CloseAndBackupDB: %v", err)
85- }
86-
87-}
88-
89-// test for CloseAndBackupDB with NO database modifications (checksum should remain the same and no backup file should be created)
90-func TestCloseAndBackupDBWithNoModifications(t *testing.T) {
91- // Ensure the directory exists
92- err := os.MkdirAll("./tmp/data", 0755)
93- if err != nil {
94- t.Fatalf("Failed to create directory: %v", err)
95- }
96-
97- // Create a temporary file for testing
98- tempFile, err := os.CreateTemp("./tmp/data", "sqlite.db")
99- if err != nil {
100- t.Fatalf("Failed to create temp file: %v", err)
101- }
102- tempFile.Close()
103-
104- app := &App{
105- DBFilename: tempFile.Name(),
106- }
107-
108- // Initialize in-memory database
109- memDb, err := sql.Open("sqlite3", ":memory:")
110- if err != nil {
111- t.Fatalf("Failed to open in-memory database: %v", err)
112- }
113- defer memDb.Close()
114-
115- // Create table and insert some data
116- _, err = memDb.Exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
117- if err != nil {
118- t.Fatalf("Failed to create table: %v", err)
119- }
120- _, err = memDb.Exec("INSERT INTO users (name) VALUES ('Alice'), ('Bob')")
121- if err != nil {
122- t.Fatalf("Failed to insert data: %v", err)
123- }
124-
125- // Generate initial checksum
126- initialChecksum, err := GenerateDBChecksum(memDb, app)
127- if err != nil {
128- t.Fatalf("Failed to generate initial checksum: %v", err)
129- }
130-
131- // Validate: Checksum should remain the same
132- finalChecksum, err := GenerateDBChecksum(memDb, app)
133- if err != nil {
134- t.Fatalf("Failed to generate final checksum: %v", err)
135- }
136- if initialChecksum != finalChecksum {
137- t.Fatalf("Checksum mismatch. Expected: %s, Got: %s", initialChecksum, finalChecksum)
138- }
139-
140- // Test: CloseAndBackupDB with modification
141- err = CloseAndBackupDB(app, memDb)
142- if err != nil {
143- t.Fatalf("Failed in CloseAndBackupDB: %v", err)
144- }
145-
146-}
M internal/app/sqliteclose.go +7 -70
@@ -1,77 +1,14 @@
11 package app
22
3-import (
4- "database/sql"
5- "fmt"
6- "os"
7- "reflect"
8-)
9-
10-// GetTableNames returns a list of table names in the database.
11-func getTableNames(a *App) []string {
12- var tableNames []string
13- v := reflect.ValueOf(a.DBTables)
14- t := v.Type()
15- for i := 0; i < v.NumField(); i++ {
16- field := t.Field(i)
17- sqlTag := field.Tag.Get("sql")
18- if sqlTag != "" {
19- tableNames = append(tableNames, sqlTag)
20- } else {
21- // Use the field name as a fallback
22- tableNames = append(tableNames, field.Name)
23- }
3+// CloseAndSaveDB closes the in-memory database and backup the database file if there is any modification.
4+func CloseDB(a *App) error {
5+ if a.DB != nil {
6+ saveDB(a)
7+ a.DB.Close()
248 }
25- return tableNames
9+ return nil
2610 }
2711
28-// CloseAndBackupDB closes the in-memory database and backup the database file if there is any modification.
29-func CloseAndBackupDB(a *App, memDb *sql.DB) error {
30- currentChecksum, err := GenerateDBChecksum(memDb, a)
31- if err != nil {
32- return err
33- }
34- fmt.Printf("Current checksum: %s\n", currentChecksum)
35- fmt.Printf("Initial checksum: %s\n", a.InitialChecksum)
36-
37- if currentChecksum != a.InitialChecksum {
38- fmt.Printf("Modification has been found in the database. Current checksum: %s\n", currentChecksum)
39-
40- // Backup the current db file
41- backupPath := a.GetDiskDBFilePath() + ".backup"
42- if err := os.Rename(a.GetDiskDBFilePath(), backupPath); err != nil {
43- return err
44- }
45- fmt.Printf("Backup file has been created: %s\n", backupPath)
46-
47- // Save the in-memory database to disk
48- _, err = memDb.Exec("ATTACH DATABASE '" + a.GetDiskDBFilePath() + "' AS diskdb")
49- if err != nil {
50- return err
51- }
52-
53- tables := getTableNames(a)
54-
55- for _, table := range tables {
56- query := fmt.Sprintf("CREATE TABLE diskdb.%s AS SELECT * FROM main.%s", table, table)
57- _, err = memDb.Exec(query)
58- if err != nil {
59- return err
60- }
61- }
62-
63- _, err = memDb.Exec("DETACH DATABASE diskdb")
64- if err != nil {
65- return err
66- }
67- } else {
68- fmt.Printf("No modification has been found in the database.\n")
69- }
70-
71- if err := memDb.Close(); err != nil {
72- return err
73- }
74- fmt.Printf("In-memory database has been closed gracefully.\n")
75-
12+func saveDB(a *App) error {
7613 return nil
7714 }
@@ -1,77 +1,14 @@
1 package app1 package app
2 2
3-import (3+// CloseAndSaveDB closes the in-memory database and backup the database file if there is any modification.
4- "database/sql"4+func CloseDB(a *App) error {
5- "fmt"5+ if a.DB != nil {
6- "os"6+ saveDB(a)
7- "reflect"7+ a.DB.Close()
8-)
9-
10-// GetTableNames returns a list of table names in the database.
11-func getTableNames(a *App) []string {
12- var tableNames []string
13- v := reflect.ValueOf(a.DBTables)
14- t := v.Type()
15- for i := 0; i < v.NumField(); i++ {
16- field := t.Field(i)
17- sqlTag := field.Tag.Get("sql")
18- if sqlTag != "" {
19- tableNames = append(tableNames, sqlTag)
20- } else {
21- // Use the field name as a fallback
22- tableNames = append(tableNames, field.Name)
23- }
24 }8 }
25- return tableNames9+ return nil
26 }10 }
27 11
28-// CloseAndBackupDB closes the in-memory database and backup the database file if there is any modification.12+func saveDB(a *App) error {
29-func CloseAndBackupDB(a *App, memDb *sql.DB) error {
30- currentChecksum, err := GenerateDBChecksum(memDb, a)
31- if err != nil {
32- return err
33- }
34- fmt.Printf("Current checksum: %s\n", currentChecksum)
35- fmt.Printf("Initial checksum: %s\n", a.InitialChecksum)
36-
37- if currentChecksum != a.InitialChecksum {
38- fmt.Printf("Modification has been found in the database. Current checksum: %s\n", currentChecksum)
39-
40- // Backup the current db file
41- backupPath := a.GetDiskDBFilePath() + ".backup"
42- if err := os.Rename(a.GetDiskDBFilePath(), backupPath); err != nil {
43- return err
44- }
45- fmt.Printf("Backup file has been created: %s\n", backupPath)
46-
47- // Save the in-memory database to disk
48- _, err = memDb.Exec("ATTACH DATABASE '" + a.GetDiskDBFilePath() + "' AS diskdb")
49- if err != nil {
50- return err
51- }
52-
53- tables := getTableNames(a)
54-
55- for _, table := range tables {
56- query := fmt.Sprintf("CREATE TABLE diskdb.%s AS SELECT * FROM main.%s", table, table)
57- _, err = memDb.Exec(query)
58- if err != nil {
59- return err
60- }
61- }
62-
63- _, err = memDb.Exec("DETACH DATABASE diskdb")
64- if err != nil {
65- return err
66- }
67- } else {
68- fmt.Printf("No modification has been found in the database.\n")
69- }
70-
71- if err := memDb.Close(); err != nil {
72- return err
73- }
74- fmt.Printf("In-memory database has been closed gracefully.\n")
75-
76 return nil13 return nil
77 }14 }
M internal/app/sqliteinit.go +28 -145
@@ -1,16 +1,13 @@
11 package app
22
33 import (
4- "context"
5- "crypto/md5"
64 "database/sql"
7- "encoding/hex"
85 "fmt"
96 "os"
107 "path/filepath"
118
129 pkgsqlite "github.com/bnema/gordon/pkg/sqlite"
13- "github.com/mattn/go-sqlite3"
10+ _ "github.com/mattn/go-sqlite3"
1411 )
1512
1613 const (
@@ -18,18 +15,38 @@ const (
1815 DBFilename = "sqlite.db"
1916 )
2017
21-func (a *App) GetDiskDBFilePath() string {
18+func (a *App) getDiskDBFilePath() string {
2219 DiskDBfilepath := filepath.Join(a.DBDir, a.DBFilename)
2320 return DiskDBfilepath
2421 }
2522
23+// ensureDBDir ensures that the database directory exists.
24+func (a *App) ensureDBDir() error {
25+ if _, err := os.Stat(a.DBDir); os.IsNotExist(err) {
26+ if err := os.MkdirAll(a.DBDir, 0755); err != nil {
27+ return err
28+ }
29+ }
30+ return nil
31+}
32+
33+// checkDBFile checks if the database file exists.
34+func (a *App) checkDBFile(dbPath string) (bool, error) {
35+ if _, err := os.Stat(dbPath); os.IsNotExist(err) {
36+ return false, nil
37+ } else if err != nil {
38+ return false, err
39+ }
40+ return true, nil
41+}
42+
2643 // InitializeDB initializes the database
2744 func InitializeDB(a *App) (*sql.DB, error) {
2845 if err := a.ensureDBDir(); err != nil {
2946 return nil, fmt.Errorf("failed to ensure DB directory: %w", err)
3047 }
3148
32- dbPath := a.GetDiskDBFilePath()
49+ dbPath := a.getDiskDBFilePath()
3350
3451 dbExists, err := a.checkDBFile(dbPath)
3552 if err != nil {
@@ -41,39 +58,15 @@ func InitializeDB(a *App) (*sql.DB, error) {
4158 return nil, fmt.Errorf("failed to bootstrap DB: %w", err)
4259 }
4360 }
44- memDb, err := loadDBToMemory(dbPath)
45- if err != nil {
46- return nil, fmt.Errorf("failed to load DB to memory: %w", err)
47- }
48- // Here we can generate the initial checksum
49- a.InitialChecksum, err = GenerateDBChecksum(memDb, a)
61+
62+ db, err := sql.Open("sqlite3", dbPath)
5063 if err != nil {
51- return nil, fmt.Errorf("failed to generate initial checksum: %w", err)
64+ return nil, fmt.Errorf("failed to open disk DB: %w", err)
5265 }
53- // Initialize the DB field in the App struct
54- a.DB = memDb
5566
56- return memDb, nil
57-}
67+ a.DB = db
5868
59-// ensureDBDir ensures that the database directory exists.
60-func (a *App) ensureDBDir() error {
61- if _, err := os.Stat(a.DBDir); os.IsNotExist(err) {
62- if err := os.MkdirAll(a.DBDir, 0755); err != nil {
63- return err
64- }
65- }
66- return nil
67-}
68-
69-// checkDBFile checks if the database file exists.
70-func (a *App) checkDBFile(dbPath string) (bool, error) {
71- if _, err := os.Stat(dbPath); os.IsNotExist(err) {
72- return false, nil
73- } else if err != nil {
74- return false, err
75- }
76- return true, nil
69+ return db, nil
7770 }
7871
7972 func bootstrapDB(dbPath string, app *App) error {
@@ -100,113 +93,3 @@ func bootstrapDB(dbPath string, app *App) error {
10093
10194 return nil
10295 }
103-
104-// loadDBToMemory loads the database from disk to memory.
105-func loadDBToMemory(dbPath string) (*sql.DB, error) {
106- memDb, err := sql.Open("sqlite3", ":memory:")
107- if err != nil {
108- return nil, err
109- }
110-
111- diskDb, err := sql.Open("sqlite3", dbPath)
112- if err != nil {
113- return nil, err
114- }
115- defer diskDb.Close()
116-
117- // Get a single connection from each *sql.DB
118- memConn, err := memDb.Conn(context.Background())
119- if err != nil {
120- return nil, err
121- }
122- defer memConn.Close()
123-
124- diskConn, err := diskDb.Conn(context.Background())
125- if err != nil {
126- return nil, err
127- }
128- defer diskConn.Close()
129-
130- err = memConn.Raw(func(driverConn interface{}) error {
131- memSqliteConn, ok := driverConn.(*sqlite3.SQLiteConn)
132- if !ok {
133- return fmt.Errorf("failed to cast to *sqlite3.SQLiteConn")
134- }
135-
136- return diskConn.Raw(func(driverConn interface{}) error {
137- diskSqliteConn, ok := driverConn.(*sqlite3.SQLiteConn)
138- if !ok {
139- return fmt.Errorf("failed to cast to *sqlite3.SQLiteConn")
140- }
141-
142- backup, err := memSqliteConn.Backup("main", diskSqliteConn, "main")
143- if err != nil {
144- return err
145- }
146- defer backup.Close()
147-
148- done, err := backup.Step(-1)
149- if err != nil {
150- return err
151- }
152- if !done {
153- return fmt.Errorf("backup not fully completed")
154- }
155-
156- return backup.Finish()
157- })
158- })
159-
160- if err != nil {
161- return nil, err
162- }
163-
164- return memDb, nil
165-}
166-
167-// GenerateDBChecksum generates a checksum of the database.
168-func GenerateDBChecksum(db *sql.DB, a *App) (string, error) {
169- tables := getTableNames(a)
170- var finalChecksum []byte
171-
172- for _, table := range tables {
173- hasher := md5.New() // Create a new hasher for each table
174-
175- rows, err := db.Query("SELECT * FROM " + table)
176- if err != nil {
177- return "", err
178- }
179-
180- for rows.Next() {
181- cols, err := rows.Columns()
182- if err != nil {
183- return "", err
184- }
185-
186- vals := make([]interface{}, len(cols))
187- for i := range cols {
188- vals[i] = new(sql.RawBytes)
189- }
190-
191- err = rows.Scan(vals...)
192- if err != nil {
193- return "", err
194- }
195-
196- for i := range vals {
197- hasher.Write(*vals[i].(*sql.RawBytes))
198- }
199- }
200-
201- if err := rows.Err(); err != nil {
202- rows.Close()
203- return "", err
204- }
205-
206- rows.Close()
207-
208- finalChecksum = append(finalChecksum, hasher.Sum(nil)...)
209- }
210-
211- return hex.EncodeToString(finalChecksum), nil
212-}
@@ -1,16 +1,13 @@
1 package app1 package app
2 2
3 import (3 import (
4- "context"
5- "crypto/md5"
6 "database/sql"4 "database/sql"
7- "encoding/hex"
8 "fmt"5 "fmt"
9 "os"6 "os"
10 "path/filepath"7 "path/filepath"
11 8
12 pkgsqlite "github.com/bnema/gordon/pkg/sqlite"9 pkgsqlite "github.com/bnema/gordon/pkg/sqlite"
13- "github.com/mattn/go-sqlite3"10+ _ "github.com/mattn/go-sqlite3"
14 )11 )
15 12
16 const (13 const (
@@ -18,18 +15,38 @@ const (
18 DBFilename = "sqlite.db"15 DBFilename = "sqlite.db"
19 )16 )
20 17
21-func (a *App) GetDiskDBFilePath() string {18+func (a *App) getDiskDBFilePath() string {
22 DiskDBfilepath := filepath.Join(a.DBDir, a.DBFilename)19 DiskDBfilepath := filepath.Join(a.DBDir, a.DBFilename)
23 return DiskDBfilepath20 return DiskDBfilepath
24 }21 }
25 22
23+// ensureDBDir ensures that the database directory exists.
24+func (a *App) ensureDBDir() error {
25+ if _, err := os.Stat(a.DBDir); os.IsNotExist(err) {
26+ if err := os.MkdirAll(a.DBDir, 0755); err != nil {
27+ return err
28+ }
29+ }
30+ return nil
31+}
32+
33+// checkDBFile checks if the database file exists.
34+func (a *App) checkDBFile(dbPath string) (bool, error) {
35+ if _, err := os.Stat(dbPath); os.IsNotExist(err) {
36+ return false, nil
37+ } else if err != nil {
38+ return false, err
39+ }
40+ return true, nil
41+}
42+
26 // InitializeDB initializes the database43 // InitializeDB initializes the database
27 func InitializeDB(a *App) (*sql.DB, error) {44 func InitializeDB(a *App) (*sql.DB, error) {
28 if err := a.ensureDBDir(); err != nil {45 if err := a.ensureDBDir(); err != nil {
29 return nil, fmt.Errorf("failed to ensure DB directory: %w", err)46 return nil, fmt.Errorf("failed to ensure DB directory: %w", err)
30 }47 }
31 48
32- dbPath := a.GetDiskDBFilePath()49+ dbPath := a.getDiskDBFilePath()
33 50
34 dbExists, err := a.checkDBFile(dbPath)51 dbExists, err := a.checkDBFile(dbPath)
35 if err != nil {52 if err != nil {
@@ -41,39 +58,15 @@ func InitializeDB(a *App) (*sql.DB, error) {
41 return nil, fmt.Errorf("failed to bootstrap DB: %w", err)58 return nil, fmt.Errorf("failed to bootstrap DB: %w", err)
42 }59 }
43 }60 }
44- memDb, err := loadDBToMemory(dbPath)61+
45- if err != nil {62+ db, err := sql.Open("sqlite3", dbPath)
46- return nil, fmt.Errorf("failed to load DB to memory: %w", err)
47- }
48- // Here we can generate the initial checksum
49- a.InitialChecksum, err = GenerateDBChecksum(memDb, a)
50 if err != nil {63 if err != nil {
51- return nil, fmt.Errorf("failed to generate initial checksum: %w", err)64+ return nil, fmt.Errorf("failed to open disk DB: %w", err)
52 }65 }
53- // Initialize the DB field in the App struct
54- a.DB = memDb
55 66
56- return memDb, nil67+ a.DB = db
57-}
58 68
59-// ensureDBDir ensures that the database directory exists.69+ return db, nil
60-func (a *App) ensureDBDir() error {
61- if _, err := os.Stat(a.DBDir); os.IsNotExist(err) {
62- if err := os.MkdirAll(a.DBDir, 0755); err != nil {
63- return err
64- }
65- }
66- return nil
67-}
68-
69-// checkDBFile checks if the database file exists.
70-func (a *App) checkDBFile(dbPath string) (bool, error) {
71- if _, err := os.Stat(dbPath); os.IsNotExist(err) {
72- return false, nil
73- } else if err != nil {
74- return false, err
75- }
76- return true, nil
77 }70 }
78 71
79 func bootstrapDB(dbPath string, app *App) error {72 func bootstrapDB(dbPath string, app *App) error {
@@ -100,113 +93,3 @@ func bootstrapDB(dbPath string, app *App) error {
100 93
101 return nil94 return nil
102 }95 }
103-
104-// loadDBToMemory loads the database from disk to memory.
105-func loadDBToMemory(dbPath string) (*sql.DB, error) {
106- memDb, err := sql.Open("sqlite3", ":memory:")
107- if err != nil {
108- return nil, err
109- }
110-
111- diskDb, err := sql.Open("sqlite3", dbPath)
112- if err != nil {
113- return nil, err
114- }
115- defer diskDb.Close()
116-
117- // Get a single connection from each *sql.DB
118- memConn, err := memDb.Conn(context.Background())
119- if err != nil {
120- return nil, err
121- }
122- defer memConn.Close()
123-
124- diskConn, err := diskDb.Conn(context.Background())
125- if err != nil {
126- return nil, err
127- }
128- defer diskConn.Close()
129-
130- err = memConn.Raw(func(driverConn interface{}) error {
131- memSqliteConn, ok := driverConn.(*sqlite3.SQLiteConn)
132- if !ok {
133- return fmt.Errorf("failed to cast to *sqlite3.SQLiteConn")
134- }
135-
136- return diskConn.Raw(func(driverConn interface{}) error {
137- diskSqliteConn, ok := driverConn.(*sqlite3.SQLiteConn)
138- if !ok {
139- return fmt.Errorf("failed to cast to *sqlite3.SQLiteConn")
140- }
141-
142- backup, err := memSqliteConn.Backup("main", diskSqliteConn, "main")
143- if err != nil {
144- return err
145- }
146- defer backup.Close()
147-
148- done, err := backup.Step(-1)
149- if err != nil {
150- return err
151- }
152- if !done {
153- return fmt.Errorf("backup not fully completed")
154- }
155-
156- return backup.Finish()
157- })
158- })
159-
160- if err != nil {
161- return nil, err
162- }
163-
164- return memDb, nil
165-}
166-
167-// GenerateDBChecksum generates a checksum of the database.
168-func GenerateDBChecksum(db *sql.DB, a *App) (string, error) {
169- tables := getTableNames(a)
170- var finalChecksum []byte
171-
172- for _, table := range tables {
173- hasher := md5.New() // Create a new hasher for each table
174-
175- rows, err := db.Query("SELECT * FROM " + table)
176- if err != nil {
177- return "", err
178- }
179-
180- for rows.Next() {
181- cols, err := rows.Columns()
182- if err != nil {
183- return "", err
184- }
185-
186- vals := make([]interface{}, len(cols))
187- for i := range cols {
188- vals[i] = new(sql.RawBytes)
189- }
190-
191- err = rows.Scan(vals...)
192- if err != nil {
193- return "", err
194- }
195-
196- for i := range vals {
197- hasher.Write(*vals[i].(*sql.RawBytes))
198- }
199- }
200-
201- if err := rows.Err(); err != nil {
202- rows.Close()
203- return "", err
204- }
205-
206- rows.Close()
207-
208- finalChecksum = append(finalChecksum, hasher.Sum(nil)...)
209- }
210-
211- return hex.EncodeToString(finalChecksum), nil
212-}
M internal/app/tokeninit.go +7 -7
@@ -6,19 +6,19 @@ import (
66 "fmt"
77 )
88
9-// HandleNewInitialization checks if an admin user exists in db, and if not, generates a token for the initial login and stores it in the config file
10-func (a *App) HandleNewTokenInitialization() (string, error) {
11- // Query to check if a user with id=1 exists
12- query := `SELECT COUNT(id) FROM user WHERE id = "1"`
9+// HandleNewInitialization checks if there is ANY user in the database.
10+func HandleNewTokenInitialization(a *App) (string, error) {
11+ // Check if there is any user in the database
12+ query := "SELECT COUNT(*) FROM user"
1313 var count int
1414 err := a.DB.QueryRow(query).Scan(&count)
1515 if err != nil {
1616 return "", fmt.Errorf("failed to check for admin user: %v", err)
1717 }
1818
19- // If count is 1, it means admin user already exists
20- if count == 1 {
21- return "", nil
19+ // If count is greater than 0, it means there is at least one user in the database
20+ if count > 0 {
21+ return "", fmt.Errorf("admin user already exists")
2222 }
2323
2424 // If we reach here, it means admin does not exist, so we generate a token
@@ -6,19 +6,19 @@ import (
6 "fmt"6 "fmt"
7 )7 )
8 8
9-// HandleNewInitialization checks if an admin user exists in db, and if not, generates a token for the initial login and stores it in the config file9+// HandleNewInitialization checks if there is ANY user in the database.
10-func (a *App) HandleNewTokenInitialization() (string, error) {10+func HandleNewTokenInitialization(a *App) (string, error) {
11- // Query to check if a user with id=1 exists11+ // Check if there is any user in the database
12- query := `SELECT COUNT(id) FROM user WHERE id = "1"`12+ query := "SELECT COUNT(*) FROM user"
13 var count int13 var count int
14 err := a.DB.QueryRow(query).Scan(&count)14 err := a.DB.QueryRow(query).Scan(&count)
15 if err != nil {15 if err != nil {
16 return "", fmt.Errorf("failed to check for admin user: %v", err)16 return "", fmt.Errorf("failed to check for admin user: %v", err)
17 }17 }
18 18
19- // If count is 1, it means admin user already exists19+ // If count is greater than 0, it means there is at least one user in the database
20- if count == 1 {20+ if count > 0 {
21- return "", nil21+ return "", fmt.Errorf("admin user already exists")
22 }22 }
23 23
24 // If we reach here, it means admin does not exist, so we generate a token24 // If we reach here, it means admin does not exist, so we generate a token

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close