isolate cache, simplify list of auth providers

This commit is contained in:
Umputun
2018-01-15 00:58:10 -06:00
parent d9c8e53834
commit 4ec94b5f85
6 changed files with 69 additions and 66 deletions
+26 -26
View File
@@ -14,6 +14,7 @@ import (
"github.com/umputun/remark/app/migrator"
"github.com/umputun/remark/app/rest"
"github.com/umputun/remark/app/rest/auth"
"github.com/umputun/remark/app/rest/common"
"github.com/umputun/remark/app/store"
)
@@ -39,6 +40,8 @@ var opts struct {
GithubCSEC string `long:"github-csec" env:"REMARK_GITHUB_CSEC" description:"Github OAuth client secret"`
FacebookCID string `long:"facebook-cid" env:"REMARK_FACEBOOK_CID" description:"Facebook OAuth client ID"`
FacebookCSEC string `long:"facebook-csec" env:"REMARK_FACEBOOK_CSEC" description:"Facebook OAuth client secret"`
Port int `long:"port" env:"REMARK_PORT" default:"8080" description:"port"`
} `command:"server" description:"run server"`
ImportCommand struct {
@@ -80,36 +83,33 @@ func main() {
return
}
srvOpts := opts.ServerCommand
dataService := store.Service{Interface: dataStore, EditDuration: 5 * time.Minute}
sessionStore := sessions.NewFilesystemStore(opts.ServerCommand.SessionStore, []byte(opts.ServerCommand.StoreKey))
sessionStore := sessions.NewFilesystemStore(srvOpts.SessionStore, []byte(srvOpts.StoreKey))
sessionStore.Options.HttpOnly = true
exporter := migrator.Remark{DataStore: dataStore}
authProviders := []auth.Provider{
auth.NewGoogle(auth.Params{
Cid: srvOpts.GoogleCID, Csecret: srvOpts.GoogleCSEC, SessionStore: sessionStore, RemarkURL: opts.RemarkURL,
}),
auth.NewGithub(auth.Params{
Cid: srvOpts.GithubCID, Csecret: srvOpts.GithubCSEC, SessionStore: sessionStore, RemarkURL: opts.RemarkURL,
}),
auth.NewFacebook(auth.Params{
Cid: srvOpts.FacebookCID, Csecret: srvOpts.FacebookCSEC, SessionStore: sessionStore, RemarkURL: opts.RemarkURL,
}),
}
srv := rest.Server{
Version: revision,
DataService: dataService,
SessionStore: sessionStore,
Admins: opts.Admins,
DevMode: opts.DevMode,
Exporter: &exporter,
AuthGoogle: auth.NewGoogle(auth.Params{
Cid: opts.ServerCommand.GoogleCID,
Csecret: opts.ServerCommand.GoogleCSEC,
SessionStore: sessionStore,
RemarkURL: opts.RemarkURL,
}),
AuthGithub: auth.NewGithub(auth.Params{
Cid: opts.ServerCommand.GithubCID,
Csecret: opts.ServerCommand.GithubCSEC,
SessionStore: sessionStore,
RemarkURL: opts.RemarkURL,
}),
AuthFacebook: auth.NewFacebook(auth.Params{
Cid: opts.ServerCommand.FacebookCID,
Csecret: opts.ServerCommand.FacebookCSEC,
SessionStore: sessionStore,
RemarkURL: opts.RemarkURL,
}),
Version: revision,
DataService: dataService,
SessionStore: sessionStore,
Admins: opts.Admins,
DevMode: opts.DevMode,
Exporter: &exporter,
Cache: common.NewLoadingCache(4*time.Hour, 15*time.Minute),
AuthProviders: authProviders,
}
if opts.DevMode {
@@ -126,7 +126,7 @@ func main() {
}.Do()
}
srv.Run(8080)
srv.Run(srvOpts.Port)
}
// makeBoltStore creates store for all sites
+5 -5
View File
@@ -22,7 +22,7 @@ type admin struct {
dataService store.Service
exporter migrator.Exporter
importer migrator.Importer
respCache *loadingCache
cache common.LoadingCache
}
func (a *admin) routes() chi.Router {
@@ -48,7 +48,7 @@ func (a *admin) deleteCommentCtrl(w http.ResponseWriter, r *http.Request) {
common.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't delete comment")
return
}
a.respCache.flush()
a.cache.Flush()
render.Status(r, http.StatusOK)
render.JSON(w, r, JSON{"id": id, "loc": locator})
}
@@ -63,7 +63,7 @@ func (a *admin) setBlockCtrl(w http.ResponseWriter, r *http.Request) {
common.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't set blocking status")
return
}
a.respCache.flush()
a.cache.Flush()
render.JSON(w, r, JSON{"user_id": userID, "site_id": siteID, "block": blockStatus})
}
@@ -78,7 +78,7 @@ func (a *admin) setPinCtrl(w http.ResponseWriter, r *http.Request) {
common.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't set pin status")
return
}
a.respCache.flush()
a.cache.Flush()
render.JSON(w, r, JSON{"id": commentID, "loc": locator, "pin": pinStatus})
}
@@ -107,7 +107,7 @@ func (a *admin) importCtrl(w http.ResponseWriter, r *http.Request) {
if err := a.importer.Import(r.Body, siteID); err != nil {
common.SendErrorJSON(w, r, http.StatusBadRequest, err, "import failed")
}
a.respCache.flush()
a.cache.Flush()
}
func (a *admin) checkBlocked(siteID string, user store.User) bool {
+2 -2
View File
@@ -43,7 +43,7 @@ type Params struct {
}
// newProvider makes auth for given provider
func initProvider(p Params, provider Provider) *Provider {
func initProvider(p Params, provider Provider) Provider {
log.Printf("[INFO] create %s auth, id=%s, redir: %s", provider.Name, p.Cid, provider.RedirectURL)
conf := oauth2.Config{
@@ -56,7 +56,7 @@ func initProvider(p Params, provider Provider) *Provider {
provider.conf = &conf
provider.Store = p.SessionStore
return &provider
return provider
}
// Routes returns auth routes for given provider
+3 -3
View File
@@ -12,7 +12,7 @@ import (
)
// NewGoogle makes google oauth2 provider
func NewGoogle(p Params) *Provider {
func NewGoogle(p Params) Provider {
return initProvider(p, Provider{
Name: "google",
Endpoint: google.Endpoint,
@@ -37,7 +37,7 @@ func NewGoogle(p Params) *Provider {
}
// NewGithub makes github oauth2 provider
func NewGithub(p Params) *Provider {
func NewGithub(p Params) Provider {
return initProvider(p, Provider{
Name: "github",
Endpoint: github.Endpoint,
@@ -62,7 +62,7 @@ func NewGithub(p Params) *Provider {
}
// NewFacebook makes facebook oauth2 provider
func NewFacebook(p Params) *Provider {
func NewFacebook(p Params) Provider {
return initProvider(p, Provider{
Name: "facebook",
Endpoint: facebook.Endpoint,
+12 -4
View File
@@ -1,4 +1,4 @@
package rest
package common
import (
"log"
@@ -7,15 +7,23 @@ import (
cache "github.com/patrickmn/go-cache"
)
// LoadingCache defines interface for caching
type LoadingCache interface {
Get(key string, ttl time.Duration, fn func() ([]byte, error)) (data []byte, err error)
Flush()
}
// loadingCache implements LoadingCache interface on top of cache.Cache
type loadingCache struct {
bytesCache *cache.Cache
}
func newLoadingCache(defaultExpiration, cleanupInterval time.Duration) *loadingCache {
// NewLoadingCache makes loadingCache implementation
func NewLoadingCache(defaultExpiration, cleanupInterval time.Duration) LoadingCache {
return &loadingCache{bytesCache: cache.New(defaultExpiration, cleanupInterval)}
}
func (lc *loadingCache) get(key string, ttl time.Duration, fn func() ([]byte, error)) (data []byte, err error) {
func (lc *loadingCache) Get(key string, ttl time.Duration, fn func() ([]byte, error)) (data []byte, err error) {
if b, ok := lc.bytesCache.Get(key); ok {
log.Printf("[DEBUG] cache hit %s", key)
return b.([]byte), nil
@@ -29,6 +37,6 @@ func (lc *loadingCache) get(key string, ttl time.Duration, fn func() ([]byte, er
return data, nil
}
func (lc *loadingCache) flush() {
func (lc *loadingCache) Flush() {
lc.bytesCache.Flush()
}
+21 -26
View File
@@ -17,30 +17,28 @@ import (
"github.com/gorilla/context"
"github.com/gorilla/sessions"
"github.com/pkg/errors"
"gopkg.in/russross/blackfriday.v2"
"github.com/umputun/remark/app/migrator"
"github.com/umputun/remark/app/rest/auth"
"github.com/umputun/remark/app/rest/common"
"github.com/umputun/remark/app/rest/format"
"github.com/umputun/remark/app/store"
"gopkg.in/russross/blackfriday.v2"
)
// Server is a rest access server
type Server struct {
Version string
DataService store.Service
Admins []string
AuthGoogle *auth.Provider
AuthGithub *auth.Provider
AuthFacebook *auth.Provider
SessionStore *sessions.FilesystemStore
Exporter migrator.Exporter
DevMode bool
Version string
DataService store.Service
Admins []string
AuthProviders []auth.Provider
SessionStore *sessions.FilesystemStore
Exporter migrator.Exporter
Cache common.LoadingCache
DevMode bool
httpServer *http.Server
mod admin
respCache *loadingCache
}
// Run the lister and request's router, activate rest server
@@ -60,9 +58,6 @@ func (s *Server) Run(port int) {
log.Printf("[DEBUG] admins %+v", s.Admins)
}
// cache for responses. Flushes completely on any modification
s.respCache = newLoadingCache(4*time.Hour, 15*time.Minute)
router := chi.NewRouter()
router.Use(middleware.RealIP, Recoverer)
router.Use(middleware.Throttle(1000), middleware.Timeout(60*time.Second))
@@ -73,10 +68,10 @@ func (s *Server) Run(port int) {
// auth routes for all providers
router.Route("/auth", func(r chi.Router) {
r.Mount("/google", s.AuthGoogle.Routes())
r.Mount("/github", s.AuthGithub.Routes())
r.Mount("/facebook", s.AuthFacebook.Routes())
r.Get("/logout", s.AuthGoogle.LogoutHandler) // shortcut, can be any of providers, all logouts do the same
for _, provider := range s.AuthProviders {
r.Mount("/"+provider.Name, provider.Routes())
}
r.Get("/logout", s.AuthProviders[0].LogoutHandler) // shortcut, can be any of providers, all logouts do the same
})
// api routes
@@ -96,7 +91,7 @@ func (s *Server) Run(port int) {
rauth.Put("/vote/{id}", s.voteCtrl)
// admin routes, admin users only
s.mod = admin{dataService: s.DataService, exporter: s.Exporter, respCache: s.respCache}
s.mod = admin{dataService: s.DataService, exporter: s.Exporter, cache: s.Cache}
rauth.Mount("/admin", s.mod.routes())
})
})
@@ -157,7 +152,7 @@ func (s *Server) createCommentCtrl(w http.ResponseWriter, r *http.Request) {
return
}
s.respCache.flush() // reset all caches
s.Cache.Flush() // reset all caches
render.Status(r, http.StatusCreated)
render.JSON(w, r, JSON{"id": id, "loc": comment.Locator})
@@ -206,7 +201,7 @@ func (s *Server) updateCommentCtrl(w http.ResponseWriter, r *http.Request) {
return
}
s.respCache.flush() // reset all caches
s.Cache.Flush() // reset all caches
render.JSON(w, r, res)
}
@@ -216,7 +211,7 @@ func (s *Server) findCommentsCtrl(w http.ResponseWriter, r *http.Request) {
locator := store.Locator{SiteID: r.URL.Query().Get("site"), URL: r.URL.Query().Get("url")}
log.Printf("[DEBUG] get comments for %+v", locator)
data, err := s.respCache.get(r.URL.String(), time.Hour, func() ([]byte, error) {
data, err := s.Cache.Get(r.URL.String(), time.Hour, func() ([]byte, error) {
comments, e := s.DataService.Find(locator, r.URL.Query().Get("sort"))
if e != nil {
return nil, e
@@ -249,7 +244,7 @@ func (s *Server) lastCommentsCtrl(w http.ResponseWriter, r *http.Request) {
max = 0
}
data, err := s.respCache.get(r.URL.String(), time.Hour, func() ([]byte, error) {
data, err := s.Cache.Get(r.URL.String(), time.Hour, func() ([]byte, error) {
comments, e := s.DataService.Last(r.URL.Query().Get("site"), max)
if e != nil {
return nil, e
@@ -291,7 +286,7 @@ func (s *Server) findUserCommentsCtrl(w http.ResponseWriter, r *http.Request) {
log.Printf("[DEBUG] get comments for userID %s, %s", userID, siteID)
data, err := s.respCache.get(r.URL.String(), time.Hour, func() ([]byte, error) {
data, err := s.Cache.Get(r.URL.String(), time.Hour, func() ([]byte, error) {
comments, e := s.DataService.User(siteID, userID)
if e != nil {
return nil, e
@@ -331,7 +326,7 @@ func (s *Server) countCtrl(w http.ResponseWriter, r *http.Request) {
func (s *Server) listCtrl(w http.ResponseWriter, r *http.Request) {
siteID := r.URL.Query().Get("site")
data, err := s.respCache.get(r.URL.String(), 8*time.Hour, func() ([]byte, error) {
data, err := s.Cache.Get(r.URL.String(), 8*time.Hour, func() ([]byte, error) {
posts, e := s.DataService.List(siteID)
if e != nil {
return nil, e
@@ -365,7 +360,7 @@ func (s *Server) voteCtrl(w http.ResponseWriter, r *http.Request) {
common.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't vote for comment")
return
}
s.respCache.flush()
s.Cache.Flush()
render.JSON(w, r, JSON{"id": comment.ID, "score": comment.Score})
}