package main
import (
"crypto/tls"
"database/sql"
"html/template"
"log/slog"
"net/http"
"os"
"time"
"coffey.dad/internal/models"
"github.com/alexedwards/scs/mysqlstore"
"github.com/alexedwards/scs/v2"
"github.com/go-playground/form/v4"
_ "github.com/go-sql-driver/mysql"
"github.com/joho/godotenv"
)
type application struct {
logger *slog.Logger
posts *models.PostModel
users *models.UserModel
repos *models.RepoModel
templateCache map[string]*template.Template
sessionManager *scs.SessionManager
formDecoder *form.Decoder
}
func main() {
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
}))
err := godotenv.Load()
if err != nil {
logger.Error(err.Error())
os.Exit(1)
}
addr := os.Getenv("ADDR")
dsn := os.Getenv("DSN")
tlsCert := os.Getenv("TLSC")
tlsKey := os.Getenv("TLSK")
repoDir := os.Getenv("REPODIR")
db, err := openDB(dsn)
if err != nil {
logger.Error(err.Error())
os.Exit(1)
}
defer db.Close()
templateCache, err := newTemplateCache()
if err != nil {
logger.Error(err.Error())
os.Exit(1)
}
formDecoder := form.NewDecoder()
sessionManager := scs.New()
sessionManager.Store = mysqlstore.New(db)
sessionManager.Lifetime = 12 * time.Hour
sessionManager.Cookie.Secure = true
app := &application{
logger: logger,
posts: &models.PostModel{DB: db},
users: &models.UserModel{DB: db},
repos: &models.RepoModel{RepoDir: repoDir},
templateCache: templateCache,
sessionManager: sessionManager,
formDecoder: formDecoder,
}
tlsConfig := &tls.Config{
CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256},
GetCertificate: func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
cert, err := tls.LoadX509KeyPair(tlsCert, tlsKey)
if err != nil {
return nil, err
}
return &cert, nil
},
}
srv := &http.Server{
Addr: addr,
Handler: app.routes(),
ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
TLSConfig: tlsConfig,
IdleTimeout: time.Minute,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
logger.Info("starting server", "addr", addr)
err = srv.ListenAndServeTLS("", "")
logger.Error(err.Error())
os.Exit(1)
}
func openDB(dsn string) (*sql.DB, error) {
db, err := sql.Open("mysql", dsn)
if err != nil {
return nil, err
}
if err = db.Ping(); err != nil {
return nil, err
}
return db, nil
}