glsl-sandbox/server/cmd/glslsandbox/main.go

137 lines
3.0 KiB
Go

package main
import (
"crypto/md5"
"crypto/rand"
"encoding/hex"
"fmt"
"os"
"path/filepath"
"github.com/jmoiron/sqlx"
"github.com/kelseyhightower/envconfig"
"github.com/mrdoob/glsl-sandbox/server"
"github.com/mrdoob/glsl-sandbox/server/store"
"github.com/uptrace/bun/driver/sqliteshim"
)
const dbName = "glslsandbox.db"
type Config struct {
DataPath string `envconfig:"DATA_PATH" default:"./data"`
Import string `envconfig:"IMPORT"`
AuthSecret string `envconfig:"AUTH_SECRET" default:"secret"`
Addr string `envconfig:"ADDR" default:":8888"`
TLSAddr string `envconfig:"TLS_ADDR"`
Domains string `envconfig:"DOMAINS" default:"www.glslsandbox.com,glslsandbox.com"`
Dev bool `envconfig:"DEV" default:"true"`
ReadOnly bool `envconfig:"READ_ONLY" default:"false"`
}
func main() {
err := start()
if err != nil {
panic(err)
}
}
func start() error {
var cfg Config
if err := envconfig.Process("GLSL_", &cfg); err != nil {
return fmt.Errorf("could not read environment config: %w", err)
}
err := os.MkdirAll(filepath.Join(cfg.DataPath, "thumbs"), 0770)
if err != nil {
return fmt.Errorf("could not create data directory: %w", err)
}
db, err := sqlx.Open(sqliteshim.ShimName, dbURL(cfg.DataPath))
if err != nil {
return fmt.Errorf("could not open database: %w", err)
}
effects, err := store.NewEffects(db)
if err != nil {
return fmt.Errorf("could not initialize effects database: %w", err)
}
users, err := store.NewUsers(db)
if err != nil {
return fmt.Errorf("could not initialize users database: %w", err)
}
auth := server.NewAuth(users, cfg.AuthSecret)
err = createUser(auth, users)
if err != nil {
return err
}
if cfg.Import != "" {
err = importDatabase(effects, cfg.Import)
if err != nil {
return fmt.Errorf("could not import database: %w", err)
}
}
s, err := server.New(
cfg.Addr,
cfg.TLSAddr,
cfg.Domains,
effects,
auth,
cfg.DataPath,
cfg.Dev,
cfg.ReadOnly,
)
if err != nil {
return fmt.Errorf("could not create server: %w", err)
}
return s.Start()
}
func dbURL(path string) string {
file := filepath.Join(path, dbName)
// return fmt.Sprintf("file:%s?_journal_mode=WAL", file)
return fmt.Sprintf("file:%s", file)
}
func importDatabase(effects *store.Effects, file string) error {
f, err := os.Open(file)
if err != nil {
return fmt.Errorf("could not open import file: %w", err)
}
defer f.Close()
err = store.Import(f, effects)
if err != nil {
return fmt.Errorf("could not import effects: %w", err)
}
return nil
}
func createUser(auth *server.Auth, users *store.Users) error {
_, err := users.User("admin")
if err == nil {
return nil
}
b := make([]byte, 16)
_, err = rand.Read(b)
if err != nil {
return fmt.Errorf("could not generate password: %w", err)
}
m := md5.Sum(b)
password := hex.EncodeToString(m[:])
err = auth.Add("admin", password, "", store.RoleAdmin)
if err != nil {
return fmt.Errorf("could not create admin user: %w", err)
}
fmt.Printf("created user 'admin' with password '%s'", password)
return nil
}