4f2dc018da
deliberately skipping salting and encrypting passwords at this point. intending to approach this in tandem with authenication. also starting to want db migrations, but trying not to get distracted.
111 lines
2.5 KiB
Go
111 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"database/sql"
|
|
"flag"
|
|
"html/template"
|
|
"log/slog"
|
|
"net/http"
|
|
"regexp"
|
|
"os"
|
|
"time"
|
|
|
|
"snippetbox.chaosfem.tw/internal/models"
|
|
|
|
"github.com/alexedwards/scs/mysqlstore"
|
|
"github.com/alexedwards/scs/v2"
|
|
"github.com/go-playground/form/v4"
|
|
_ "github.com/go-sql-driver/mysql"
|
|
)
|
|
|
|
// for application wide dependencies
|
|
type application struct {
|
|
logger *slog.Logger
|
|
snippets *models.SnippetModel
|
|
users *models.UserModel
|
|
templateCache map[string]*template.Template
|
|
formDecoder *form.Decoder
|
|
sessionManager *scs.SessionManager
|
|
}
|
|
|
|
// main it's the snippetbox webapp
|
|
func main() {
|
|
// configuration
|
|
addr := flag.String("addr", ":4000", "HTTP network address")
|
|
dsn := flag.String("dsn", "web:dbpass@/snippetbox?parseTime=true", "DB data source name")
|
|
logfmt := flag.String("logfmt", "text", "Log output format")
|
|
loglevel := flag.String("loglevel", "INFO", "Log level: DEBUG, INFO, WARN, or ERROR")
|
|
flag.Parse()
|
|
|
|
logger := loggerBuilder(logfmt, loglevel)
|
|
|
|
db, err := openDB(*dsn, logger)
|
|
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
|
|
|
|
// setup the application
|
|
app := &application{
|
|
logger: logger,
|
|
snippets: &models.SnippetModel{DB: db},
|
|
users: &models.UserModel{DB: db},
|
|
templateCache: templateCache,
|
|
formDecoder: formDecoder,
|
|
sessionManager: sessionManager,
|
|
}
|
|
|
|
tlsConfig := &tls.Config{
|
|
CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256},
|
|
}
|
|
|
|
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", slog.String("addr", srv.Addr))
|
|
|
|
err = srv.ListenAndServeTLS("./tls/cert.pem", "./tls/key.pem")
|
|
|
|
logger.Error(err.Error())
|
|
os.Exit(1)
|
|
}
|
|
|
|
func openDB(dsn string, logger *slog.Logger) (*sql.DB, error) {
|
|
db, err := sql.Open("mysql", dsn)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = db.Ping()
|
|
if err != nil {
|
|
db.Close()
|
|
return nil, err
|
|
}
|
|
passRegexp := regexp.MustCompile(":\\S+@")
|
|
logger.Info("Opened DB connection pool", slog.String("adapter", "mysql"), slog.String("dsn", passRegexp.ReplaceAllString(dsn, ":<REDACTED>@")))
|
|
|
|
return db, nil
|
|
}
|