diff --git a/app.go b/app.go index 7312e83..bfed9f6 100644 --- a/app.go +++ b/app.go @@ -1,137 +1,146 @@ package writefreely import ( "database/sql" "flag" "fmt" _ "github.com/go-sql-driver/mysql" "net/http" "os" "os/signal" "syscall" "github.com/gorilla/mux" "github.com/gorilla/sessions" "github.com/writeas/web-core/log" "github.com/writeas/writefreely/config" ) const ( staticDir = "static/" serverSoftware = "Write Freely" softwareURL = "https://writefreely.org" softwareVer = "0.1" ) +var ( + debugging bool +) + type app struct { router *mux.Router db *datastore cfg *config.Config keys *keychain sessionStore *sessions.CookieStore } var shttp = http.NewServeMux() func Serve() { + debugPtr := flag.Bool("debug", false, "Enables debug logging.") createConfig := flag.Bool("create-config", false, "Creates a basic configuration and exits") doConfig := flag.Bool("config", false, "Run the configuration process") flag.Parse() + debugging = *debugPtr + if *createConfig { log.Info("Creating configuration...") c := config.New() log.Info("Saving configuration...") err := config.Save(c) if err != nil { log.Error("Unable to save configuration: %v", err) os.Exit(1) } os.Exit(0) } else if *doConfig { err := config.Configure() if err != nil { log.Error("Unable to configure: %v", err) os.Exit(1) } os.Exit(0) } log.Info("Initializing...") log.Info("Loading configuration...") cfg, err := config.Load() if err != nil { log.Error("Unable to load configuration: %v", err) os.Exit(1) } app := &app{ cfg: cfg, } + app.cfg.Server.Dev = *debugPtr + // Load keys log.Info("Loading encryption keys...") err = initKeys(app) if err != nil { log.Error("\n%s\n", err) } // Initialize modules app.sessionStore = initSession(app) // Check database configuration if app.cfg.Database.User == "" || app.cfg.Database.Password == "" { log.Error("Database user or password not set.") os.Exit(1) } if app.cfg.Database.Host == "" { app.cfg.Database.Host = "localhost" } if app.cfg.Database.Database == "" { app.cfg.Database.Database = "writeas" } log.Info("Connecting to database...") db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=true", app.cfg.Database.User, app.cfg.Database.Password, app.cfg.Database.Host, app.cfg.Database.Port, app.cfg.Database.Database)) if err != nil { log.Error("\n%s\n", err) os.Exit(1) } app.db = &datastore{db} defer shutdown(app) app.db.SetMaxOpenConns(50) r := mux.NewRouter() handler := NewHandler(app.sessionStore) // Handle app routes initRoutes(handler, r, app.cfg, app.db) // Handle static files fs := http.FileServer(http.Dir(staticDir)) shttp.Handle("/", fs) r.PathPrefix("/").Handler(fs) // Handle shutdown c := make(chan os.Signal, 2) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c log.Info("Shutting down...") shutdown(app) log.Info("Done.") os.Exit(0) }() // Start web application server http.Handle("/", r) log.Info("Serving on http://localhost:%d\n", app.cfg.Server.Port) log.Info("---") http.ListenAndServe(fmt.Sprintf(":%d", app.cfg.Server.Port), nil) } func shutdown(app *app) { log.Info("Closing database connection...") app.db.Close() } diff --git a/config/config.go b/config/config.go index d59543a..511356c 100644 --- a/config/config.go +++ b/config/config.go @@ -1,99 +1,101 @@ package config import ( "gopkg.in/ini.v1" ) const ( FileName = "config.ini" ) type ( ServerCfg struct { Port int `ini:"port"` + + Dev bool `ini:"-"` } DatabaseCfg struct { Type string `ini:"type"` User string `ini:"username"` Password string `ini:"password"` Database string `ini:"database"` Host string `ini:"host"` Port int `ini:"port"` } AppCfg struct { SiteName string `ini:"site_name"` Host string `ini:"host"` // Site appearance Theme string `ini:"theme"` JSDisabled bool `ini:"disable_js"` WebFonts bool `ini:"webfonts"` // Users SingleUser bool `ini:"single_user"` OpenRegistration bool `ini:"open_registration"` MinUsernameLen int `ini:"min_username_len"` MaxBlogs int `ini:"max_blogs"` // Federation Federation bool `ini:"federation"` PublicStats bool `ini:"public_stats"` Private bool `ini:"private"` } Config struct { Server ServerCfg `ini:"server"` Database DatabaseCfg `ini:"database"` App AppCfg `ini:"app"` } ) func New() *Config { return &Config{ Server: ServerCfg{ Port: 8080, }, Database: DatabaseCfg{ Type: "mysql", Host: "localhost", Port: 3306, }, App: AppCfg{ Host: "http://localhost:8080", Theme: "write", WebFonts: true, SingleUser: true, MinUsernameLen: 3, MaxBlogs: 1, Federation: true, PublicStats: true, }, } } func Load() (*Config, error) { cfg, err := ini.Load(FileName) if err != nil { return nil, err } // Parse INI file uc := &Config{} err = cfg.MapTo(uc) if err != nil { return nil, err } return uc, nil } func Save(uc *Config) error { cfg := ini.Empty() err := ini.ReflectFrom(cfg, uc) if err != nil { return err } return cfg.SaveTo(FileName) }