mirror of
https://github.com/AmanTahiliani/FHIR-Sandbox.git
synced 2026-08-07 11:53:56 -04:00
122 lines
4.2 KiB
Go
122 lines
4.2 KiB
Go
// main.go is the application entry point. Its only job is to:
|
|
// 1. Load configuration.
|
|
// 2. Initialize the database store.
|
|
// 3. Expose the embedded template FS to the handlers package.
|
|
// 4. Wire all dependencies into handlers and middleware.
|
|
// 5. Register routes and start the HTTP server.
|
|
//
|
|
// No business logic lives here. All behaviour is delegated to the
|
|
// handlers, db, fhir, config, and middleware packages.
|
|
package main
|
|
|
|
import (
|
|
"embed"
|
|
"fmt"
|
|
"io/fs"
|
|
"log"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/AmanTahiliani/FHIR-Sandbox/app/config"
|
|
"github.com/AmanTahiliani/FHIR-Sandbox/app/db"
|
|
"github.com/AmanTahiliani/FHIR-Sandbox/app/handlers"
|
|
"github.com/AmanTahiliani/FHIR-Sandbox/app/middleware"
|
|
)
|
|
|
|
//go:embed templates/*.html
|
|
var embeddedTemplates embed.FS
|
|
|
|
func main() {
|
|
// -------------------------------------------------------------------------
|
|
// Configuration
|
|
// -------------------------------------------------------------------------
|
|
cfg := &config.AppConfig{
|
|
DBPath: "fhir_sandbox.db",
|
|
Server: config.ServerConfig{
|
|
Port: 8080,
|
|
},
|
|
SMART: config.SMARTConfig{
|
|
RedirectURL: "http://localhost:8080/auth-redirect",
|
|
Scopes: []string{"openid", "profile", "launch", "patient/*.read", "user/*.read"},
|
|
},
|
|
EHRs: []config.EHRConfig{
|
|
{
|
|
Name: "SmartHealthIT Sandbox (R4)",
|
|
FHIRURL: "https://launch.smarthealthit.org/v/r4/fhir",
|
|
ClientID: "abcdefghijklmnopqrst",
|
|
ClientSecret: "ehr_a_client_secret",
|
|
},
|
|
// Add additional EHR configurations here as needed.
|
|
},
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Database
|
|
// -------------------------------------------------------------------------
|
|
store, err := db.New(cfg.DBPath)
|
|
if err != nil {
|
|
log.Fatalf("main: database init failed: %v", err)
|
|
}
|
|
defer store.Close()
|
|
log.Printf("main: database ready at %q", cfg.DBPath)
|
|
|
|
// Purge expired sessions on startup so the table doesn't accumulate stale rows.
|
|
if n, err := store.DeleteExpiredSessions(); err != nil {
|
|
log.Printf("main: warning — could not purge expired sessions: %v", err)
|
|
} else if n > 0 {
|
|
log.Printf("main: purged %d expired session(s)", n)
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Templates
|
|
// Sub the embed.FS to strip the "templates/" prefix so handlers can
|
|
// reference files as "base.html", "dashboard.html", etc.
|
|
// -------------------------------------------------------------------------
|
|
templateFS, err := fs.Sub(embeddedTemplates, "templates")
|
|
if err != nil {
|
|
log.Fatalf("main: template FS sub failed: %v", err)
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Handlers & middleware
|
|
// -------------------------------------------------------------------------
|
|
h := handlers.New(store, cfg, templateFS, handlers.TemplateFuncs())
|
|
sessionMW := middleware.NewSessionMiddleware(store)
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Routes
|
|
// -------------------------------------------------------------------------
|
|
mux := http.NewServeMux()
|
|
|
|
// Public routes
|
|
mux.HandleFunc("/", h.HandleRoot)
|
|
mux.HandleFunc("/launch", h.HandleLaunch)
|
|
mux.HandleFunc("/auth-redirect", h.HandleAuthRedirect)
|
|
|
|
// Session-required routes — wrapped with the hard-gate middleware.
|
|
mux.Handle("/dashboard", sessionMW.RequireSession(http.HandlerFunc(h.HandleDashboard)))
|
|
mux.Handle("/dashboard/sync", sessionMW.RequireSession(http.HandlerFunc(h.HandleSync)))
|
|
mux.Handle("/logout", sessionMW.RequireSession(http.HandlerFunc(h.HandleLogout)))
|
|
|
|
// Apply the soft session loader to every request so templates can always
|
|
// read the current user from context.
|
|
root := sessionMW.LoadSession(mux)
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Server
|
|
// -------------------------------------------------------------------------
|
|
addr := fmt.Sprintf(":%d", cfg.Server.Port)
|
|
srv := &http.Server{
|
|
Addr: addr,
|
|
Handler: root,
|
|
ReadTimeout: 15 * time.Second,
|
|
WriteTimeout: 30 * time.Second,
|
|
IdleTimeout: 60 * time.Second,
|
|
}
|
|
|
|
log.Printf("main: starting FHIR platform on http://localhost%s", addr)
|
|
if err := srv.ListenAndServe(); err != nil {
|
|
log.Fatalf("main: server error: %v", err)
|
|
}
|
|
}
|