144 lines
3.6 KiB
Go
144 lines
3.6 KiB
Go
package httpapp
|
|
|
|
import (
|
|
"fmt"
|
|
"html/template"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"gitea.avt.data-center.id/othman.suseno/atlas/internal/audit"
|
|
"gitea.avt.data-center.id/othman.suseno/atlas/internal/auth"
|
|
"gitea.avt.data-center.id/othman.suseno/atlas/internal/db"
|
|
"gitea.avt.data-center.id/othman.suseno/atlas/internal/job"
|
|
"gitea.avt.data-center.id/othman.suseno/atlas/internal/snapshot"
|
|
"gitea.avt.data-center.id/othman.suseno/atlas/internal/storage"
|
|
"gitea.avt.data-center.id/othman.suseno/atlas/internal/zfs"
|
|
)
|
|
|
|
type Config struct {
|
|
Addr string
|
|
TemplatesDir string
|
|
StaticDir string
|
|
DatabasePath string // Path to SQLite database (empty = in-memory mode)
|
|
}
|
|
|
|
type App struct {
|
|
cfg Config
|
|
tmpl *template.Template
|
|
mux *http.ServeMux
|
|
zfs *zfs.Service
|
|
snapshotPolicy *snapshot.PolicyStore
|
|
jobManager *job.Manager
|
|
scheduler *snapshot.Scheduler
|
|
authService *auth.Service
|
|
userStore *auth.UserStore
|
|
auditStore *audit.Store
|
|
smbStore *storage.SMBStore
|
|
nfsStore *storage.NFSStore
|
|
iscsiStore *storage.ISCSIStore
|
|
database *db.DB // Optional database connection
|
|
}
|
|
|
|
func New(cfg Config) (*App, error) {
|
|
if cfg.TemplatesDir == "" {
|
|
cfg.TemplatesDir = "web/templates"
|
|
}
|
|
if cfg.StaticDir == "" {
|
|
cfg.StaticDir = "web/static"
|
|
}
|
|
|
|
tmpl, err := parseTemplates(cfg.TemplatesDir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
zfsService := zfs.New()
|
|
policyStore := snapshot.NewPolicyStore()
|
|
jobMgr := job.NewManager()
|
|
scheduler := snapshot.NewScheduler(policyStore, zfsService, jobMgr)
|
|
|
|
// Initialize database (optional)
|
|
var database *db.DB
|
|
if cfg.DatabasePath != "" {
|
|
dbConn, err := db.New(cfg.DatabasePath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("init database: %w", err)
|
|
}
|
|
database = dbConn
|
|
}
|
|
|
|
// Initialize auth
|
|
jwtSecret := os.Getenv("ATLAS_JWT_SECRET")
|
|
authService := auth.New(jwtSecret)
|
|
userStore := auth.NewUserStore(authService)
|
|
|
|
// Initialize audit logging (keep last 10000 logs)
|
|
auditStore := audit.NewStore(10000)
|
|
|
|
// Initialize storage services
|
|
smbStore := storage.NewSMBStore()
|
|
nfsStore := storage.NewNFSStore()
|
|
iscsiStore := storage.NewISCSIStore()
|
|
|
|
a := &App{
|
|
cfg: cfg,
|
|
tmpl: tmpl,
|
|
mux: http.NewServeMux(),
|
|
zfs: zfsService,
|
|
snapshotPolicy: policyStore,
|
|
jobManager: jobMgr,
|
|
scheduler: scheduler,
|
|
authService: authService,
|
|
userStore: userStore,
|
|
auditStore: auditStore,
|
|
smbStore: smbStore,
|
|
nfsStore: nfsStore,
|
|
iscsiStore: iscsiStore,
|
|
database: database,
|
|
}
|
|
|
|
// Start snapshot scheduler (runs every 15 minutes)
|
|
scheduler.Start(15 * time.Minute)
|
|
|
|
a.routes()
|
|
return a, nil
|
|
}
|
|
|
|
func (a *App) Router() http.Handler {
|
|
// Wrap the mux with middleware chain: requestID -> logging -> audit -> auth
|
|
return requestID(logging(a.auditMiddleware(a.authMiddleware(a.mux))))
|
|
}
|
|
|
|
// StopScheduler stops the snapshot scheduler (for graceful shutdown)
|
|
func (a *App) StopScheduler() {
|
|
if a.scheduler != nil {
|
|
a.scheduler.Stop()
|
|
}
|
|
// Close database connection if present
|
|
if a.database != nil {
|
|
a.database.Close()
|
|
}
|
|
}
|
|
|
|
// routes() is now in routes.go
|
|
|
|
func parseTemplates(dir string) (*template.Template, error) {
|
|
pattern := filepath.Join(dir, "*.html")
|
|
files, err := filepath.Glob(pattern)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(files) == 0 {
|
|
return nil, fmt.Errorf("no templates found at %s", pattern)
|
|
}
|
|
|
|
funcs := template.FuncMap{
|
|
"nowRFC3339": func() string { return time.Now().Format(time.RFC3339) },
|
|
}
|
|
|
|
t := template.New("root").Funcs(funcs)
|
|
return t.ParseFiles(files...)
|
|
}
|