package main import ( "errors" "fmt" "log" "net/http" "os" "path/filepath" "strconv" "time" "arimelody-web/admin" "arimelody-web/api" "arimelody-web/global" "arimelody-web/templates" "arimelody-web/view" "github.com/jmoiron/sqlx" _ "github.com/lib/pq" ) const DEFAULT_PORT int64 = 8080 func main() { // initialise database connection var dbHost = os.Getenv("ARIMELODY_DB_HOST") var dbName = os.Getenv("ARIMELODY_DB_NAME") var dbUser = os.Getenv("ARIMELODY_DB_USER") var dbPass = os.Getenv("ARIMELODY_DB_PASS") if dbHost == "" { fmt.Fprintf(os.Stderr, "FATAL: ARIMELODY_DB_HOST not provided! Exiting...\n") os.Exit(1) } if dbName == "" { fmt.Fprintf(os.Stderr, "FATAL: ARIMELODY_DB_NAME not provided! Exiting...\n") os.Exit(1) } if dbUser == "" { fmt.Fprintf(os.Stderr, "FATAL: ARIMELODY_DB_USER not provided! Exiting...\n") os.Exit(1) } if dbPass == "" { fmt.Fprintf(os.Stderr, "FATAL: ARIMELODY_DB_PASS not provided! Exiting...\n") os.Exit(1) } var err error global.DB, err = sqlx.Connect("postgres", fmt.Sprintf("host=%s user=%s dbname=%s password=%s sslmode=disable", dbHost, dbUser, dbName, dbPass)) if err != nil { fmt.Fprintf(os.Stderr, "FATAL: Unable to create database connection pool: %v\n", err) os.Exit(1) } global.DB.SetConnMaxLifetime(time.Minute * 3) global.DB.SetMaxOpenConns(10) global.DB.SetMaxIdleConns(10) defer global.DB.Close() // start the web server! mux := createServeMux() port, err := strconv.ParseInt(os.Getenv("ARIMELODY_PORT"), 10, 0) if err != nil { port = DEFAULT_PORT } fmt.Printf("Now serving at http://127.0.0.1:%d\n", port) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), global.HTTPLog(mux))) } func createServeMux() *http.ServeMux { mux := http.NewServeMux() mux.Handle("/admin/", http.StripPrefix("/admin", admin.Handler())) mux.Handle("/api/", http.StripPrefix("/api", api.Handler())) mux.Handle("/music/", http.StripPrefix("/music", view.MusicHandler())) mux.Handle("/uploads/", http.StripPrefix("/uploads", staticHandler(filepath.Join(global.DATA_DIR, "uploads")))) mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" || r.URL.Path == "/index.html" { err := templates.Pages["index"].Execute(w, nil) if err != nil { http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } return } staticHandler("public").ServeHTTP(w, r) })) return mux } func staticHandler(directory string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { info, err := os.Stat(filepath.Join(directory, filepath.Clean(r.URL.Path))) // does the file exist? if err != nil { if errors.Is(err, os.ErrNotExist) { http.NotFound(w, r) return } } // is thjs a directory? (forbidden) if info.IsDir() { http.NotFound(w, r) return } http.FileServer(http.Dir(directory)).ServeHTTP(w, r) }) }