migrate from envars to toml config
This commit is contained in:
parent
5284b8a7cc
commit
04f7f97b62
|
@ -7,7 +7,7 @@ tmp_dir = "tmp"
|
||||||
bin = "./tmp/main"
|
bin = "./tmp/main"
|
||||||
cmd = "go build -o ./tmp/main ."
|
cmd = "go build -o ./tmp/main ."
|
||||||
delay = 1000
|
delay = 1000
|
||||||
exclude_dir = ["admin/static", "public", "uploads", "test", "db"]
|
exclude_dir = ["admin/static", "admin\\static", "public", "uploads", "test", "db", "res"]
|
||||||
exclude_file = []
|
exclude_file = []
|
||||||
exclude_regex = ["_test.go"]
|
exclude_regex = ["_test.go"]
|
||||||
exclude_unchanged = false
|
exclude_unchanged = false
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,3 +5,4 @@ tmp/
|
||||||
test/
|
test/
|
||||||
uploads/
|
uploads/
|
||||||
docker-compose-test.yml
|
docker-compose-test.yml
|
||||||
|
config*.toml
|
||||||
|
|
37
README.md
37
README.md
|
@ -4,29 +4,36 @@ home to your local SPACEGIRL! 💫
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
built up from the initial [static](https://git.arimelody.me/ari/arimelody.me-static) branch, this powerful, server-side rendered version comes complete with live updates, powered by a new database and super handy admin panel!
|
built up from the initial [static](https://git.arimelody.me/ari/arimelody.me-static)
|
||||||
|
branch, this powerful, server-side rendered version comes complete with live
|
||||||
|
updates, powered by a new database and handy admin panel!
|
||||||
|
|
||||||
the admin panel currently facilitates live updating of my music discography, though i plan to expand it towards art portfolio and blog posts in the future. if all goes well, i'd like to later separate these components into their own library for others to use in their own sites. exciting stuff!
|
the admin panel currently facilitates live updating of my music discography,
|
||||||
|
though i plan to expand it towards art portfolio and blog posts in the future.
|
||||||
|
if all goes well, i'd like to later separate these components into their own
|
||||||
|
library for others to use in their own sites. exciting stuff!
|
||||||
|
|
||||||
## build
|
## build
|
||||||
|
|
||||||
easy! just `git clone` this repo and `go build` from the root. `arimelody-web(.exe)` should be generated.
|
- `git clone` this repo, and `cd` into it.
|
||||||
|
- `go build -o arimelody-web .`
|
||||||
|
|
||||||
## running
|
## running
|
||||||
|
|
||||||
the webserver depends on some environment variables (don't worry about forgetting some; it'll be sure to bug you about them):
|
the server should be run once to generate a default `config.toml` file.
|
||||||
|
configure as needed. note that a valid DB connection is required, and the admin
|
||||||
|
panel will be disabled without valid discord app credentials (this can however
|
||||||
|
be bypassed by running the server with `-adminBypass`).
|
||||||
|
|
||||||
- `ARIMELODY_HTTP_DOMAIN`: the domain the webserver will use for generating oauth redirect URIs (default `https://arimelody.me`)
|
the configuration may be overridden using environment variables in the format
|
||||||
- `ARIMELODY_DB_HOST`: the host address of a postgres database.
|
`ARIMELODY_<SECTION>_<KEY>`. for example, `db.host` in the config may be
|
||||||
- `ARIMELODY_DB_NAME`: the name of the database.
|
overridden with `ARIMELODY_DB_HOST`.
|
||||||
- `ARIMELODY_DB_USER`: the username for the database.
|
|
||||||
- `ARIMELODY_DB_PASS`: the password for the database.
|
|
||||||
- `DISCORD_ADMIN`[^1]: the user ID of your discord account (discord auth is intended to be temporary, and will be replaced with its own auth system later)
|
|
||||||
- `DISCORD_CLIENT`[^1]: the client ID of your discord OAuth application.
|
|
||||||
- `DISCORD_SECRET`[^1]: the client secret of your discord OAuth application.
|
|
||||||
|
|
||||||
[^1]: not required, but the admin panel will be **disabled** if these are not provided.
|
the location of the configuration file can also be overridden with
|
||||||
|
`ARIMELODY_CONFIG`.
|
||||||
|
|
||||||
the webserver requires a database to run. in this case, postgres.
|
## database
|
||||||
|
|
||||||
the [docker compose script](docker-compose.yml) contains the basic requirements to get you up and running, though it does not currently initialise the schema on first run. you'll need to `docker compose exec -it arimelody.me-db-1` to access the database container while it's running, run `psql -U arimelody` to get a postgres shell, and copy/paste the contents of [schema.sql](schema.sql) to initialise the database. i'll build an automated initialisation script later ;p
|
the server requires a postgres database to run. you can use the
|
||||||
|
[schema.sql](schema.sql) provided in this repo to generate the required tables.
|
||||||
|
automatic schema building/migration may come in a future update.
|
||||||
|
|
|
@ -29,9 +29,10 @@ var ADMIN_BYPASS = func() bool {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var ADMIN_ID_DISCORD = func() string {
|
var ADMIN_ID_DISCORD = func() string {
|
||||||
id := os.Getenv("DISCORD_ADMIN")
|
id := os.Getenv("DISCORD_ADMIN_ID")
|
||||||
|
if id == "" { id = global.Config.Discord.AdminID }
|
||||||
if id == "" {
|
if id == "" {
|
||||||
fmt.Printf("WARN: Discord admin ID (DISCORD_ADMIN) was not provided. Admin login will be unavailable.\n")
|
fmt.Printf("WARN: discord.admin_id not provided. Admin login will be unavailable.\n")
|
||||||
}
|
}
|
||||||
return id
|
return id
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -154,10 +154,6 @@ func LoginHandler() http.Handler {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(discord.CLIENT_ID)
|
|
||||||
fmt.Println(discord.API_ENDPOINT)
|
|
||||||
fmt.Println(discord.REDIRECT_URI)
|
|
||||||
|
|
||||||
code := r.URL.Query().Get("code")
|
code := r.URL.Query().Get("code")
|
||||||
|
|
||||||
if code == "" {
|
if code == "" {
|
||||||
|
@ -194,7 +190,7 @@ func LoginHandler() http.Handler {
|
||||||
cookie.Name = "token"
|
cookie.Name = "token"
|
||||||
cookie.Value = session.Token
|
cookie.Value = session.Token
|
||||||
cookie.Expires = time.Now().Add(24 * time.Hour)
|
cookie.Expires = time.Now().Add(24 * time.Hour)
|
||||||
if strings.HasPrefix(global.HTTP_DOMAIN, "https") {
|
if strings.HasPrefix(global.Config.BaseUrl, "https") {
|
||||||
cookie.Secure = true
|
cookie.Secure = true
|
||||||
}
|
}
|
||||||
cookie.HttpOnly = true
|
cookie.HttpOnly = true
|
||||||
|
|
|
@ -16,7 +16,7 @@ func HandleImageUpload(data *string, directory string, filename string) (string,
|
||||||
header := split[0]
|
header := split[0]
|
||||||
imageData, err := base64.StdEncoding.DecodeString(split[1])
|
imageData, err := base64.StdEncoding.DecodeString(split[1])
|
||||||
ext, _ := strings.CutPrefix(header, "data:image/")
|
ext, _ := strings.CutPrefix(header, "data:image/")
|
||||||
directory = filepath.Join(global.DATA_DIR, directory)
|
directory = filepath.Join(global.Config.DataDirectory, directory)
|
||||||
|
|
||||||
switch ext {
|
switch ext {
|
||||||
case "png":
|
case "png":
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"arimelody-web/global"
|
"arimelody-web/global"
|
||||||
|
@ -16,22 +15,22 @@ const API_ENDPOINT = "https://discord.com/api/v10"
|
||||||
|
|
||||||
var CREDENTIALS_PROVIDED = true
|
var CREDENTIALS_PROVIDED = true
|
||||||
var CLIENT_ID = func() string {
|
var CLIENT_ID = func() string {
|
||||||
id := os.Getenv("DISCORD_CLIENT")
|
id := global.Config.Discord.ClientID
|
||||||
if id == "" {
|
if id == "" {
|
||||||
fmt.Printf("WARN: Discord client ID (DISCORD_CLIENT) was not provided. Admin login will be unavailable.\n")
|
fmt.Printf("WARN: discord.client_id was not provided. Admin login will be unavailable.\n")
|
||||||
CREDENTIALS_PROVIDED = false
|
CREDENTIALS_PROVIDED = false
|
||||||
}
|
}
|
||||||
return id
|
return id
|
||||||
}()
|
}()
|
||||||
var CLIENT_SECRET = func() string {
|
var CLIENT_SECRET = func() string {
|
||||||
secret := os.Getenv("DISCORD_SECRET")
|
secret := global.Config.Discord.Secret
|
||||||
if secret == "" {
|
if secret == "" {
|
||||||
fmt.Printf("WARN: Discord secret (DISCORD_SECRET) was not provided. Admin login will be unavailable.\n")
|
fmt.Printf("WARN: discord.secret not provided. Admin login will be unavailable.\n")
|
||||||
CREDENTIALS_PROVIDED = false
|
CREDENTIALS_PROVIDED = false
|
||||||
}
|
}
|
||||||
return secret
|
return secret
|
||||||
}()
|
}()
|
||||||
var OAUTH_CALLBACK_URI = fmt.Sprintf("%s/admin/login", global.HTTP_DOMAIN)
|
var OAUTH_CALLBACK_URI = fmt.Sprintf("%s/admin/login", global.Config.BaseUrl)
|
||||||
var REDIRECT_URI = fmt.Sprintf("https://discord.com/oauth2/authorize?client_id=%s&response_type=code&redirect_uri=%s&scope=identify", CLIENT_ID, OAUTH_CALLBACK_URI)
|
var REDIRECT_URI = fmt.Sprintf("https://discord.com/oauth2/authorize?client_id=%s&response_type=code&redirect_uri=%s&scope=identify", CLIENT_ID, OAUTH_CALLBACK_URI)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|
121
global/config.go
Normal file
121
global/config.go
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
package global
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"github.com/pelletier/go-toml/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
dbConfig struct {
|
||||||
|
Host string `toml:"host"`
|
||||||
|
Name string `toml:"name"`
|
||||||
|
User string `toml:"user"`
|
||||||
|
Pass string `toml:"pass"`
|
||||||
|
}
|
||||||
|
|
||||||
|
discordConfig struct {
|
||||||
|
AdminID string `toml:"admin_id" comment:"NOTE: admin_id to be deprecated in favour of local accounts and SSO."`
|
||||||
|
ClientID string `toml:"client_id"`
|
||||||
|
Secret string `toml:"secret"`
|
||||||
|
}
|
||||||
|
|
||||||
|
config struct {
|
||||||
|
BaseUrl string `toml:"base_url" comment:"Used for OAuth redirects."`
|
||||||
|
Port int64 `toml:"port"`
|
||||||
|
DataDirectory string `toml:"data_dir"`
|
||||||
|
DB dbConfig `toml:"db"`
|
||||||
|
Discord discordConfig `toml:"discord"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var Config = func() config {
|
||||||
|
configFile := os.Getenv("ARIMELODY_CONFIG")
|
||||||
|
if configFile == "" {
|
||||||
|
configFile = "config.toml"
|
||||||
|
}
|
||||||
|
|
||||||
|
config := config{
|
||||||
|
BaseUrl: "https://arimelody.me",
|
||||||
|
Port: 8080,
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := os.ReadFile(configFile)
|
||||||
|
if err != nil {
|
||||||
|
configOut, _ := toml.Marshal(&config)
|
||||||
|
os.WriteFile(configFile, configOut, os.ModePerm)
|
||||||
|
fmt.Printf(
|
||||||
|
"A default config.toml has been created. " +
|
||||||
|
"Please configure before running again!\n")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = toml.Unmarshal([]byte(data), &config)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "FATAL: Failed to parse configuration file: %s\n", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = handleConfigOverrides(&config)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "FATAL: Failed to parse environment variable %s\n", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
}()
|
||||||
|
|
||||||
|
func handleConfigOverrides(config *config) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if env, has := os.LookupEnv("ARIMELODY_BASE_URL"); has { config.BaseUrl = env }
|
||||||
|
if env, has := os.LookupEnv("ARIMELODY_PORT"); has {
|
||||||
|
config.Port, err = strconv.ParseInt(env, 10, 0)
|
||||||
|
if err != nil { return errors.New("ARIMELODY_PORT: " + err.Error()) }
|
||||||
|
}
|
||||||
|
if env, has := os.LookupEnv("ARIMELODY_DATA_DIR"); has { config.DataDirectory = env }
|
||||||
|
|
||||||
|
if env, has := os.LookupEnv("ARIMELODY_DB_HOST"); has { config.DB.Host = env }
|
||||||
|
if env, has := os.LookupEnv("ARIMELODY_DB_NAME"); has { config.DB.Name = env }
|
||||||
|
if env, has := os.LookupEnv("ARIMELODY_DB_USER"); has { config.DB.User = env }
|
||||||
|
if env, has := os.LookupEnv("ARIMELODY_DB_PASS"); has { config.DB.Pass = env }
|
||||||
|
|
||||||
|
if env, has := os.LookupEnv("ARIMELODY_DISCORD_ADMIN_ID"); has { config.Discord.AdminID = env }
|
||||||
|
if env, has := os.LookupEnv("ARIMELODY_DISCORD_CLIENT_ID"); has { config.Discord.ClientID = env }
|
||||||
|
if env, has := os.LookupEnv("ARIMELODY_DISCORD_SECRET"); has { config.Discord.Secret = env }
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var Args = func() map[string]string {
|
||||||
|
args := map[string]string{}
|
||||||
|
|
||||||
|
index := 0
|
||||||
|
for index < len(os.Args[1:]) {
|
||||||
|
arg := os.Args[index + 1]
|
||||||
|
if !strings.HasPrefix(arg, "-") {
|
||||||
|
fmt.Printf("FATAL: Parameters must follow an argument (%s).\n", arg)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if index + 3 > len(os.Args) || strings.HasPrefix(os.Args[index + 2], "-") {
|
||||||
|
args[arg[1:]] = "true"
|
||||||
|
index += 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val := os.Args[index + 2]
|
||||||
|
args[arg[1:]] = val
|
||||||
|
// fmt.Printf("%s: %s\n", arg[1:], val)
|
||||||
|
index += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}()
|
||||||
|
|
||||||
|
var DB *sqlx.DB
|
|
@ -1,65 +0,0 @@
|
||||||
package global
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Args = func() map[string]string {
|
|
||||||
args := map[string]string{}
|
|
||||||
|
|
||||||
index := 0
|
|
||||||
for index < len(os.Args[1:]) {
|
|
||||||
arg := os.Args[index + 1]
|
|
||||||
if !strings.HasPrefix(arg, "-") {
|
|
||||||
fmt.Printf("FATAL: Parameters must follow an argument (%s).\n", arg)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if index + 3 > len(os.Args) || strings.HasPrefix(os.Args[index + 2], "-") {
|
|
||||||
args[arg[1:]] = "true"
|
|
||||||
index += 1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
val := os.Args[index + 2]
|
|
||||||
args[arg[1:]] = val
|
|
||||||
// fmt.Printf("%s: %s\n", arg[1:], val)
|
|
||||||
index += 2
|
|
||||||
}
|
|
||||||
|
|
||||||
return args
|
|
||||||
}()
|
|
||||||
|
|
||||||
var HTTP_DOMAIN = func() string {
|
|
||||||
domain := os.Getenv("ARIMELODY_HTTP_DOMAIN")
|
|
||||||
if domain == "" {
|
|
||||||
return "https://arimelody.me"
|
|
||||||
}
|
|
||||||
return domain
|
|
||||||
}()
|
|
||||||
|
|
||||||
var DATA_DIR = func() string {
|
|
||||||
dir, err := filepath.Abs(os.Getenv("ARIMELODY_DATA_DIR"))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("FATAL: Failed to get working directory: %s\n", err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
if dir != "" {
|
|
||||||
os.MkdirAll(dir, os.ModePerm)
|
|
||||||
} else {
|
|
||||||
var err error
|
|
||||||
dir, err = os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("FATAL: Failed to get working directory: %s\n", err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dir
|
|
||||||
}()
|
|
||||||
|
|
||||||
var DB *sqlx.DB
|
|
2
go.mod
2
go.mod
|
@ -6,3 +6,5 @@ require (
|
||||||
github.com/jmoiron/sqlx v1.4.0
|
github.com/jmoiron/sqlx v1.4.0
|
||||||
github.com/lib/pq v1.10.9
|
github.com/lib/pq v1.10.9
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -8,3 +8,5 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||||
|
|
37
main.go
37
main.go
|
@ -24,29 +24,38 @@ const DEFAULT_PORT int64 = 8080
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// initialise database connection
|
// initialise database connection
|
||||||
var dbHost = os.Getenv("ARIMELODY_DB_HOST")
|
if env := os.Getenv("ARIMELODY_DB_HOST"); env != "" { global.Config.DB.Host = env }
|
||||||
var dbName = os.Getenv("ARIMELODY_DB_NAME")
|
if env := os.Getenv("ARIMELODY_DB_NAME"); env != "" { global.Config.DB.Name = env }
|
||||||
var dbUser = os.Getenv("ARIMELODY_DB_USER")
|
if env := os.Getenv("ARIMELODY_DB_USER"); env != "" { global.Config.DB.User = env }
|
||||||
var dbPass = os.Getenv("ARIMELODY_DB_PASS")
|
if env := os.Getenv("ARIMELODY_DB_PASS"); env != "" { global.Config.DB.Pass = env }
|
||||||
if dbHost == "" {
|
if global.Config.DB.Host == "" {
|
||||||
fmt.Fprintf(os.Stderr, "FATAL: ARIMELODY_DB_HOST not provided! Exiting...\n")
|
fmt.Fprintf(os.Stderr, "FATAL: db.host not provided! Exiting...\n")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if dbName == "" {
|
if global.Config.DB.Name == "" {
|
||||||
fmt.Fprintf(os.Stderr, "FATAL: ARIMELODY_DB_NAME not provided! Exiting...\n")
|
fmt.Fprintf(os.Stderr, "FATAL: db.name not provided! Exiting...\n")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if dbUser == "" {
|
if global.Config.DB.User == "" {
|
||||||
fmt.Fprintf(os.Stderr, "FATAL: ARIMELODY_DB_USER not provided! Exiting...\n")
|
fmt.Fprintf(os.Stderr, "FATAL: db.user not provided! Exiting...\n")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if dbPass == "" {
|
if global.Config.DB.Pass == "" {
|
||||||
fmt.Fprintf(os.Stderr, "FATAL: ARIMELODY_DB_PASS not provided! Exiting...\n")
|
fmt.Fprintf(os.Stderr, "FATAL: db.pass not provided! Exiting...\n")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
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))
|
global.DB, err = sqlx.Connect(
|
||||||
|
"postgres",
|
||||||
|
fmt.Sprintf(
|
||||||
|
"host=%s user=%s dbname=%s password='%s' sslmode=disable",
|
||||||
|
global.Config.DB.Host,
|
||||||
|
global.Config.DB.User,
|
||||||
|
global.Config.DB.Name,
|
||||||
|
global.Config.DB.Pass,
|
||||||
|
),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "FATAL: Unable to create database connection pool: %v\n", err)
|
fmt.Fprintf(os.Stderr, "FATAL: Unable to create database connection pool: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -72,7 +81,7 @@ func createServeMux() *http.ServeMux {
|
||||||
mux.Handle("/admin/", http.StripPrefix("/admin", admin.Handler()))
|
mux.Handle("/admin/", http.StripPrefix("/admin", admin.Handler()))
|
||||||
mux.Handle("/api/", http.StripPrefix("/api", api.Handler()))
|
mux.Handle("/api/", http.StripPrefix("/api", api.Handler()))
|
||||||
mux.Handle("/music/", http.StripPrefix("/music", view.MusicHandler()))
|
mux.Handle("/music/", http.StripPrefix("/music", view.MusicHandler()))
|
||||||
mux.Handle("/uploads/", http.StripPrefix("/uploads", staticHandler(filepath.Join(global.DATA_DIR, "uploads"))))
|
mux.Handle("/uploads/", http.StripPrefix("/uploads", staticHandler(filepath.Join(global.Config.DataDirectory, "uploads"))))
|
||||||
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.URL.Path == "/" || r.URL.Path == "/index.html" {
|
if r.URL.Path == "/" || r.URL.Path == "/index.html" {
|
||||||
err := templates.Pages["index"].Execute(w, nil)
|
err := templates.Pages["index"].Execute(w, nil)
|
||||||
|
|
Loading…
Reference in a new issue