feat: initial open-source release of Pipely
OTA update server designed for high-concurrency, low-bandwidth deployments. GORM-backed PostgreSQL, JWT auth, device management, artefact versioning, deployment rollout with gated rate-limited downloads, and a React admin panel.
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
|
||||
"onixbyte.com/message-converter-manifest/internal/model"
|
||||
)
|
||||
|
||||
// Connect opens a PostgreSQL connection via GORM. If the target database does
|
||||
// not exist it is created automatically. Tables are then migrated.
|
||||
func Connect(databaseURL string) (*gorm.DB, error) {
|
||||
dbName, err := ensureDatabase(databaseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db, err := gorm.Open(postgres.Open(databaseURL), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Warn),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open database: %w", err)
|
||||
}
|
||||
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get underlying sql.DB: %w", err)
|
||||
}
|
||||
sqlDB.SetMaxOpenConns(50)
|
||||
sqlDB.SetMaxIdleConns(10)
|
||||
|
||||
log.Printf("[database] Connected to PostgreSQL database: %s", dbName)
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// AutoMigrate creates or updates tables to match the model definitions.
|
||||
func AutoMigrate(db *gorm.DB) error {
|
||||
return db.AutoMigrate(
|
||||
&model.AdminUser{},
|
||||
&model.Device{},
|
||||
&model.Artefact{},
|
||||
&model.Deployment{},
|
||||
&model.DeploymentDevice{},
|
||||
)
|
||||
}
|
||||
|
||||
// ensureDatabase creates the target database if it does not exist.
|
||||
func ensureDatabase(databaseURL string) (string, error) {
|
||||
u, err := url.Parse(databaseURL)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid database URL: %w", err)
|
||||
}
|
||||
dbName := strings.TrimPrefix(u.Path, "/")
|
||||
|
||||
adminURL := *u
|
||||
adminURL.Path = "/postgres"
|
||||
|
||||
db, err := gorm.Open(postgres.Open(adminURL.String()), &gorm.Config{})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to connect to admin database: %w", err)
|
||||
}
|
||||
|
||||
var exists bool
|
||||
db.Raw("SELECT EXISTS(SELECT 1 FROM pg_database WHERE datname = ?)", dbName).Scan(&exists)
|
||||
if !exists {
|
||||
if err := db.Exec(fmt.Sprintf(`CREATE DATABASE "%s"`, dbName)).Error; err != nil {
|
||||
return "", fmt.Errorf("failed to create database %s: %w", dbName, err)
|
||||
}
|
||||
log.Printf("[database] Created database: %s", dbName)
|
||||
}
|
||||
|
||||
sqlDB, _ := db.DB()
|
||||
if sqlDB != nil {
|
||||
sqlDB.Close()
|
||||
}
|
||||
return dbName, nil
|
||||
}
|
||||
Reference in New Issue
Block a user