diff options
| author | Bobby <[email protected]> | 2026-03-06 23:01:58 +0530 |
|---|---|---|
| committer | Bobby <[email protected]> | 2026-03-06 23:01:58 +0530 |
| commit | ed2a033d7c08e448f5c6fd035e2de8f51431b597 (patch) | |
| tree | abe46463fc761b2e4266aadedb6b88c5493ce29b | |
| parent | 3f07a4b6c745707f135a7a97e93b0fa770b67873 (diff) | |
| download | dove-ed2a033d7c08e448f5c6fd035e2de8f51431b597.tar.xz dove-ed2a033d7c08e448f5c6fd035e2de8f51431b597.zip | |
Implement database connection and routing system with HTTP method support
| -rw-r--r-- | config/config.go | 2 | ||||
| -rw-r--r-- | database/constants.go | 11 | ||||
| -rw-r--r-- | database/database.go | 36 | ||||
| -rw-r--r-- | database/functions.go | 22 | ||||
| -rw-r--r-- | enums/http.go | 13 | ||||
| -rw-r--r-- | go.mod | 22 | ||||
| -rw-r--r-- | go.sum | 39 | ||||
| -rw-r--r-- | messages/config.go | 5 | ||||
| -rw-r--r-- | messages/database.go | 7 | ||||
| -rw-r--r-- | utils/collections/types.go | 2 | ||||
| -rw-r--r-- | utils/toml/load.go | 4 | ||||
| -rw-r--r-- | utils/urls/attach.go | 35 | ||||
| -rw-r--r-- | utils/urls/functions.go | 30 | ||||
| -rw-r--r-- | utils/urls/path.go | 37 | ||||
| -rw-r--r-- | utils/urls/registry.go | 13 | ||||
| -rw-r--r-- | utils/urls/types.go | 25 |
16 files changed, 296 insertions, 7 deletions
diff --git a/config/config.go b/config/config.go index 358fe72..78eb6a8 100644 --- a/config/config.go +++ b/config/config.go @@ -33,4 +33,6 @@ func init() { logger.Fatalf(LOG_PREFIX, messages.ConfigSectionParseFailed, parseError) } } + + logger.Successf(LOG_PREFIX, messages.ConfigLoaded) } diff --git a/database/constants.go b/database/constants.go new file mode 100644 index 0000000..e16dcde --- /dev/null +++ b/database/constants.go @@ -0,0 +1,11 @@ +package database + +import "time" + +const ( + DATABASE_FILE_NAME = "dove.db" + LOG_PREFIX = "Database" + MAX_IDLE_CONNECTIONS = 5 + MAX_OPEN_CONNECTIONS = 25 + MAX_CONNECTION_LIFETIME = time.Hour +) diff --git a/database/database.go b/database/database.go new file mode 100644 index 0000000..27b99eb --- /dev/null +++ b/database/database.go @@ -0,0 +1,36 @@ +package database + +import ( + "dove/messages" + "dove/utils/logger" + + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +var DB *gorm.DB + +func init() { + databaseDSN := resolveDatabasePath() + dialector := sqlite.Open(databaseDSN) + + var connectionError error + DB, connectionError = gorm.Open(dialector, &gorm.Config{ + Logger: resolveGORMLogLevel(), + }) + + if connectionError != nil { + logger.Fatalf(LOG_PREFIX, messages.DatabaseConnectionFailed, connectionError) + } + + sqlDB, poolError := DB.DB() + if poolError != nil { + logger.Fatalf(LOG_PREFIX, messages.DatabasePoolConfigFailed, poolError) + } + + sqlDB.SetMaxOpenConns(MAX_OPEN_CONNECTIONS) + sqlDB.SetMaxIdleConns(MAX_IDLE_CONNECTIONS) + sqlDB.SetConnMaxLifetime(MAX_CONNECTION_LIFETIME) + + logger.Successf(LOG_PREFIX, messages.DatabaseConnected, databaseDSN) +} diff --git a/database/functions.go b/database/functions.go new file mode 100644 index 0000000..71723ca --- /dev/null +++ b/database/functions.go @@ -0,0 +1,22 @@ +package database + +import ( + "path/filepath" + + "dove/config" + + "gorm.io/gorm/logger" +) + +func resolveDatabasePath() string { + return filepath.Join(config.DataDir, DATABASE_FILE_NAME) +} + +func resolveGORMLogLevel() logger.Interface { + switch config.Server.Debug { + case true: + return logger.Default.LogMode(logger.Info) + default: + return logger.Default.LogMode(logger.Silent) + } +} diff --git a/enums/http.go b/enums/http.go new file mode 100644 index 0000000..fbd7591 --- /dev/null +++ b/enums/http.go @@ -0,0 +1,13 @@ +package enums + +type HTTPMethod string + +const ( + Delete HTTPMethod = "DELETE" + Get HTTPMethod = "GET" + Head HTTPMethod = "HEAD" + Options HTTPMethod = "OPTIONS" + Patch HTTPMethod = "PATCH" + Post HTTPMethod = "POST" + Put HTTPMethod = "PUT" +) @@ -5,6 +5,26 @@ go 1.25.0 require ( github.com/pelletier/go-toml/v2 v2.2.4 go.uber.org/zap v1.27.1 + gorm.io/driver/sqlite v1.6.0 + gorm.io/gorm v1.31.1 ) -require go.uber.org/multierr v1.10.0 // indirect +require ( + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/gofiber/fiber/v2 v2.52.12 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + go.uber.org/multierr v1.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.20.0 // indirect +) @@ -1,16 +1,55 @@ +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw= +github.com/gofiber/fiber/v2 v2.52.12/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= +gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8= +gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg= +gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= diff --git a/messages/config.go b/messages/config.go index fe44f45..fcb42c3 100644 --- a/messages/config.go +++ b/messages/config.go @@ -1,10 +1,9 @@ package messages const ( + ConfigFileLoadFailed = "failed to load config: %v" ConfigFileReadFailed = "failed to read config file %s: %s" - ConfigFileParseFailed = "failed to parse config file %s: %s" - ConfigSectionNotFound = "config section '%s' not found" + ConfigLoaded = "configuration loaded successfully" ConfigSectionInvalid = "config section '%s' has invalid data" - ConfigFileLoadFailed = "failed to load config: %v" ConfigSectionParseFailed = "failed to parse config section: %v" ) diff --git a/messages/database.go b/messages/database.go new file mode 100644 index 0000000..119bdef --- /dev/null +++ b/messages/database.go @@ -0,0 +1,7 @@ +package messages + +const ( + DatabaseConnected = "connected to %s" + DatabaseConnectionFailed = "failed to connect to database: %v" + DatabasePoolConfigFailed = "failed to configure connection pool: %v" +) diff --git a/utils/collections/types.go b/utils/collections/types.go index c75d1ea..ac84e76 100644 --- a/utils/collections/types.go +++ b/utils/collections/types.go @@ -1,3 +1,3 @@ package collections -type Record map[string]any +type Record[T any] map[string]T diff --git a/utils/toml/load.go b/utils/toml/load.go index a0cab4b..7b3c31a 100644 --- a/utils/toml/load.go +++ b/utils/toml/load.go @@ -8,7 +8,7 @@ import ( "dove/utils/errors" ) -var loadedData collections.Record +var loadedData collections.Record[any] func LoadFile(filePath string) error { fileContent, readError := os.ReadFile(filePath) @@ -16,6 +16,6 @@ func LoadFile(filePath string) error { return errors.Error(messages.ConfigFileReadFailed, filePath, readError.Error()) } - loadedData = make(collections.Record) + loadedData = make(collections.Record[any]) return unmarshalContent(fileContent, &loadedData) } diff --git a/utils/urls/attach.go b/utils/urls/attach.go new file mode 100644 index 0000000..df8a11a --- /dev/null +++ b/utils/urls/attach.go @@ -0,0 +1,35 @@ +package urls + +import ( + "dove/enums" + + "github.com/gofiber/fiber/v2" +) + +func Attach(application *fiber.App) { + registry.Mutex.Lock() + defer registry.Mutex.Unlock() + + for _, route := range registry.Routes { + bindRoute(application, route) + } +} + +func bindRoute(application *fiber.App, route registeredRoute) { + switch route.Method { + case enums.Delete: + application.Delete(route.FullPath, route.Handler) + case enums.Get: + application.Get(route.FullPath, route.Handler) + case enums.Head: + application.Head(route.FullPath, route.Handler) + case enums.Options: + application.Options(route.FullPath, route.Handler) + case enums.Patch: + application.Patch(route.FullPath, route.Handler) + case enums.Post: + application.Post(route.FullPath, route.Handler) + case enums.Put: + application.Put(route.FullPath, route.Handler) + } +} diff --git a/utils/urls/functions.go b/utils/urls/functions.go new file mode 100644 index 0000000..6561025 --- /dev/null +++ b/utils/urls/functions.go @@ -0,0 +1,30 @@ +package urls + +import "strings" + +func resolveFullName(namespace string, name string) string { + switch namespace { + case "": + return name + default: + return namespace + "." + name + } +} + +func resolveFullPath(namespace string, path string) string { + switch namespace { + case "": + return ensureLeadingSlash(path) + default: + return "/" + namespace + ensureLeadingSlash(path) + } +} + +func ensureLeadingSlash(path string) string { + switch strings.HasPrefix(path, "/") { + case true: + return path + default: + return "/" + path + } +} diff --git a/utils/urls/path.go b/utils/urls/path.go new file mode 100644 index 0000000..b865676 --- /dev/null +++ b/utils/urls/path.go @@ -0,0 +1,37 @@ +package urls + +import ( + "dove/enums" + + "github.com/gofiber/fiber/v2" +) + +func Path(method enums.HTTPMethod, path string, handler fiber.Handler, name string) { + registry.Mutex.Lock() + defer registry.Mutex.Unlock() + + namespace := registry.CurrentNamespace + fullName := resolveFullName(namespace, name) + fullPath := resolveFullPath(namespace, path) + + registry.Routes[fullName] = registeredRoute{ + Method: method, + Path: path, + Handler: handler, + Namespace: namespace, + Name: name, + FullPath: fullPath, + } +} + +func GetFullPath(routeName string) (string, bool) { + registry.Mutex.Lock() + defer registry.Mutex.Unlock() + + route, exists := registry.Routes[routeName] + if !exists { + return "", false + } + + return route.FullPath, true +} diff --git a/utils/urls/registry.go b/utils/urls/registry.go new file mode 100644 index 0000000..a713315 --- /dev/null +++ b/utils/urls/registry.go @@ -0,0 +1,13 @@ +package urls + +import "dove/utils/collections" + +var registry = &routeRegistry{ + Routes: make(collections.Record[registeredRoute]), +} + +func SetNamespace(namespace string) { + registry.Mutex.Lock() + defer registry.Mutex.Unlock() + registry.CurrentNamespace = namespace +} diff --git a/utils/urls/types.go b/utils/urls/types.go new file mode 100644 index 0000000..499635b --- /dev/null +++ b/utils/urls/types.go @@ -0,0 +1,25 @@ +package urls + +import ( + "sync" + + "dove/enums" + "dove/utils/collections" + + "github.com/gofiber/fiber/v2" +) + +type registeredRoute struct { + Method enums.HTTPMethod + Path string + Handler fiber.Handler + Namespace string + Name string + FullPath string +} + +type routeRegistry struct { + Mutex sync.Mutex + CurrentNamespace string + Routes collections.Record[registeredRoute] +} |
