package core import ( "fmt" "net/http" "path/filepath" "github.com/gorilla/mux" "github.com/gorilla/sessions" "github.com/kirsle/blog/core/caches" "github.com/kirsle/blog/core/caches/null" "github.com/kirsle/blog/core/caches/redis" "github.com/kirsle/blog/core/jsondb" "github.com/kirsle/blog/core/models/comments" "github.com/kirsle/blog/core/models/posts" "github.com/kirsle/blog/core/models/settings" "github.com/kirsle/blog/core/models/users" "github.com/shurcooL/github_flavored_markdown/gfmstyle" "github.com/urfave/negroni" ) // Blog is the root application object that maintains the app configuration // and helper objects. type Blog struct { Debug bool // DocumentRoot is the core static files root; UserRoot masks over it. DocumentRoot string UserRoot string DB *jsondb.DB Cache caches.Cacher // Web app objects. n *negroni.Negroni // Negroni middleware manager r *mux.Router // Router store sessions.Store } // New initializes the Blog application. func New(documentRoot, userRoot string) *Blog { blog := &Blog{ DocumentRoot: documentRoot, UserRoot: userRoot, DB: jsondb.New(filepath.Join(userRoot, ".private")), Cache: null.New(), } // Load the site config, or start with defaults if not found. settings.DB = blog.DB config, err := settings.Load() if err != nil { config = settings.Defaults() } // Initialize the session cookie store. blog.store = sessions.NewCookieStore([]byte(config.Security.SecretKey)) users.HashCost = config.Security.HashCost // Initialize the rest of the models. posts.DB = blog.DB users.DB = blog.DB comments.DB = blog.DB // Redis cache? if config.Redis.Enabled { addr := fmt.Sprintf("%s:%d", config.Redis.Host, config.Redis.Port) log.Info("Connecting to Redis at %s/%d", addr, config.Redis.DB) cache, err := redis.New( addr, config.Redis.DB, config.Redis.Prefix, ) if err != nil { log.Error("Redis init error: %s", err.Error()) } else { blog.Cache = cache blog.DB.Cache = cache } } // Initialize the router. r := mux.NewRouter() r.HandleFunc("/initial-setup", blog.SetupHandler) r.HandleFunc("/login", blog.LoginHandler) r.HandleFunc("/logout", blog.LogoutHandler) blog.AdminRoutes(r) blog.ContactRoutes(r) blog.BlogRoutes(r) blog.CommentRoutes(r) // GitHub Flavored Markdown CSS. r.Handle("/css/gfm.css", http.StripPrefix("/css", http.FileServer(gfmstyle.Assets))) r.PathPrefix("/").HandlerFunc(blog.PageHandler) r.NotFoundHandler = http.HandlerFunc(blog.PageHandler) n := negroni.New( negroni.NewRecovery(), negroni.NewLogger(), negroni.HandlerFunc(blog.SessionLoader), negroni.HandlerFunc(blog.CSRFMiddleware), negroni.HandlerFunc(blog.AuthMiddleware), ) n.UseHandler(r) // Keep references handy elsewhere in the app. blog.n = n blog.r = r return blog } // ListenAndServe begins listening on the given bind address. func (b *Blog) ListenAndServe(address string) { log.Info("Listening on %s", address) http.ListenAndServe(address, b.n) }