|
- 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"
- "github.com/writeas/writefreely/page"
- )
-
- 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
- }
-
- func pageForReq(app *app, r *http.Request) page.StaticPage {
- p := page.StaticPage{
- AppCfg: app.cfg.App,
- Path: r.URL.Path,
- Version: "v" + softwareVer,
- }
-
- // Add user information, if given
- var u *User
- accessToken := r.FormValue("t")
- if accessToken != "" {
- userID := app.db.GetUserID(accessToken)
- if userID != -1 {
- var err error
- u, err = app.db.GetUserByID(userID)
- if err == nil {
- p.Username = u.Username
- }
- }
- } else {
- u = getUserSession(app, r)
- if u != nil {
- p.Username = u.Username
- }
- }
-
- return p
- }
-
- 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
-
- initTemplates()
-
- // 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)
- handler.SetErrorPages(&ErrorPages{
- NotFound: pages["404-general.tmpl"],
- Gone: pages["410.tmpl"],
- InternalServerError: pages["500.tmpl"],
- Blank: pages["blank.tmpl"],
- })
-
- // 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()
- }
|