package main import ( "context" "log" "strings" "expvar" "runtime" //"html/template" "flag" "net/http" "fmt" "github.com/gorilla/websocket" "os" "time" "database/sql" _ "github.com/lib/pq" "party.at/party/internal/data" "party.at/party/internal/mailer" "party.at/party/internal/jsonlog" ) var version string var buildTime string type config struct { port int env string db struct { dsn string maxOpenConns int maxIdleConns int maxIdleTime string } limiter struct { rps float64 burst int enabled bool } smtp struct { host string port int username string password string sender string } cors struct { trustedOrigins []string } } type application struct { config config logger *jsonlog.Logger models data.Models mailer mailer.Mailer } type Message struct { Type string `json:"type"` Timestamp string `json:"timestamp"` Random float64 `json:"random"` } //var page_template = template.Must(template.ParseFiles("../../ui/html/index.html")) var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, // allow all origins } func main() { fmt.Printf("Full Args: %v\n", os.Args) var cfg config flag.IntVar(&cfg.port, "port", 4000, "API server port") flag.StringVar(&cfg.env, "env", "development", "Environment (development|staging|production)") flag.StringVar(&cfg.db.dsn, "db-dsn", os.Getenv("PARTY_DB_DSN"), "PostgreSQL DSN") //addr := flag.String("addr", ":8443", "HTTP network address") flag.IntVar(&cfg.db.maxOpenConns, "db-max-open-conns", 25, "PostgreSQL max open connections") flag.IntVar(&cfg.db.maxIdleConns, "db-max-idle-conns", 25, "PostgreSQL max idle connections") flag.StringVar(&cfg.db.maxIdleTime, "db-max-idle-time", "15m", "PostgreSQL max connection idle time") flag.StringVar(&cfg.smtp.host, "smtp-host", "smtp.mailtrap.io", "SMTP host") flag.IntVar(&cfg.smtp.port, "smtp-port", 25, "SMTP port") flag.StringVar(&cfg.smtp.username, "smtp-username", "98cf60028d7fcb", "SMTP username") flag.StringVar(&cfg.smtp.password, "smtp-password", "b9d4a35372e971", "SMTP password") flag.StringVar(&cfg.smtp.sender, "smtp-sender", "Greenlight ", "SMTP sender") flag.Float64Var(&cfg.limiter.rps, "limiter-rps", 2, "Rate limiter maximum requests per second") flag.IntVar(&cfg.limiter.burst, "limiter-burst", 4, "Rate limiter maximum burst") flag.BoolVar(&cfg.limiter.enabled, "limiter-enabled", true, "Enable rate limiter") flag.Func("cors-trusted-origins", "Trusted CORS origins (space separated)", func(val string) error { cfg.cors.trustedOrigins = strings.Fields(val) return nil }) displayVersion := flag.Bool("version", false, "Display version and exit") flag.Parse() if *displayVersion { fmt.Printf("Version:\t%s\n", version) fmt.Printf("Build time:\t%s\n", buildTime) os.Exit(0) } logger := jsonlog.New(os.Stdout, jsonlog.LevelInfo) log.Printf("%s\n", cfg.db.dsn) db, err := openDB(cfg) if err != nil { logger.PrintFatal(err, nil) } defer db.Close() expvar.NewString("version").Set(version) expvar.Publish("goroutines", expvar.Func(func() interface{} { return runtime.NumGoroutine() })) expvar.Publish("database", expvar.Func(func() interface{} { return db.Stats() })) expvar.Publish("timestamp", expvar.Func(func() interface{} { return time.Now().Unix() })) app := &application{ config: cfg, logger: logger, models: data.NewModels(db), mailer: mailer.New(cfg.smtp.host, cfg.smtp.port, cfg.smtp.username, cfg.smtp.password, cfg.smtp.sender), } log.Println("Hello, Sailor!") err = app.serve() if err != nil { logger.PrintFatal(err, nil) } } func openDB(cfg config) (*sql.DB, error) { db, err := sql.Open("postgres", cfg.db.dsn) if err != nil { return nil, err } db.SetMaxOpenConns(cfg.db.maxOpenConns) db.SetMaxIdleConns(cfg.db.maxIdleConns) duration, err := time.ParseDuration(cfg.db.maxIdleTime) if err != nil { return nil, err } db.SetConnMaxIdleTime(duration) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // Use PingContext() to establish a new connection to the database, passing in the // context we created above as a parameter. If the connection couldn't be // established successfully within the 5 second deadline, then this will return an // error. err = db.PingContext(ctx) if err != nil { return nil, err } return db, nil }