Browse Source

Refactor things

- Remove separate auth/logging and merge them into transport.go
- Add helper function for http handlers
master
r 10 months ago
parent
commit
fa27d9c6eb
  1. 2
      config/config.go
  2. 9
      main.go
  3. 19
      model/client.go
  4. 1
      model/post.go
  5. 6
      repo/appRepo.go
  6. 6
      repo/sessionRepo.go
  7. 480
      service/auth.go
  8. 341
      service/logging.go
  9. 313
      service/service.go
  10. 1026
      service/transport.go
  11. 2
      util/kv.go

2
config/config.go

@ -101,7 +101,7 @@ func Parse(r io.Reader) (c *config, err error) {
case "log_file":
c.LogFile = val
default:
return nil, errors.New("invliad config key " + key)
return nil, errors.New("invalid config key " + key)
}
}

9
main.go

@ -12,7 +12,6 @@ import (
"time"
"bloat/config"
"bloat/kv"
"bloat/renderer"
"bloat/repo"
"bloat/service"
@ -76,13 +75,13 @@ func main() {
}
sessionDBPath := filepath.Join(config.DatabasePath, "session")
sessionDB, err := kv.NewDatabse(sessionDBPath)
sessionDB, err := util.NewDatabse(sessionDBPath)
if err != nil {
errExit(err)
}
appDBPath := filepath.Join(config.DatabasePath, "app")
appDB, err := kv.NewDatabse(appDBPath)
appDB, err := util.NewDatabse(appDBPath)
if err != nil {
errExit(err)
}
@ -114,9 +113,7 @@ func main() {
s := service.NewService(config.ClientName, config.ClientScope,
config.ClientWebsite, customCSS, config.PostFormats, renderer,
sessionRepo, appRepo, config.SingleInstance)
s = service.NewAuthService(sessionRepo, appRepo, s)
s = service.NewLoggingService(logger, s)
handler := service.NewHandler(s, config.StaticDirectory)
handler := service.NewHandler(s, logger, config.StaticDirectory)
logger.Println("listening on", config.ListenAddress)
err = http.ListenAndServe(config.ListenAddress, handler)

19
model/client.go

@ -1,19 +0,0 @@
package model
import (
"io"
"bloat/mastodon"
)
type ClientCtx struct {
SessionID string
CSRFToken string
}
type Client struct {
*mastodon.Client
Writer io.Writer
Ctx ClientCtx
Session Session
}

1
model/post.go

@ -10,7 +10,6 @@ type PostContext struct {
DefaultFormat string
ReplyContext *ReplyContext
Formats []PostFormat
DarkMode bool
}
type ReplyContext struct {

6
repo/appRepo.go

@ -3,15 +3,15 @@ package repo
import (
"encoding/json"
"bloat/kv"
"bloat/util"
"bloat/model"
)
type appRepo struct {
db *kv.Database
db *util.Database
}
func NewAppRepo(db *kv.Database) *appRepo {
func NewAppRepo(db *util.Database) *appRepo {
return &appRepo{
db: db,
}

6
repo/sessionRepo.go

@ -3,15 +3,15 @@ package repo
import (
"encoding/json"
"bloat/kv"
"bloat/util"
"bloat/model"
)
type sessionRepo struct {
db *kv.Database
db *util.Database
}
func NewSessionRepo(db *kv.Database) *sessionRepo {
func NewSessionRepo(db *util.Database) *sessionRepo {
return &sessionRepo{
db: db,
}

480
service/auth.go

@ -1,480 +0,0 @@
package service
import (
"errors"
"mime/multipart"
"bloat/mastodon"
"bloat/model"
)
var (
errInvalidSession = errors.New("invalid session")
errInvalidAccessToken = errors.New("invalid access token")
errInvalidCSRFToken = errors.New("invalid csrf token")
)
type as struct {
sessionRepo model.SessionRepo
appRepo model.AppRepo
Service
}
func NewAuthService(sessionRepo model.SessionRepo, appRepo model.AppRepo, s Service) Service {
return &as{sessionRepo, appRepo, s}
}
func (s *as) initClient(c *model.Client) (err error) {
if len(c.Ctx.SessionID) < 1 {
return errInvalidSession
}
session, err := s.sessionRepo.Get(c.Ctx.SessionID)
if err != nil {
return errInvalidSession
}
app, err := s.appRepo.Get(session.InstanceDomain)
if err != nil {
return
}
mc := mastodon.NewClient(&mastodon.Config{
Server: app.InstanceURL,
ClientID: app.ClientID,
ClientSecret: app.ClientSecret,
AccessToken: session.AccessToken,
})
c.Client = mc
c.Session = session
return nil
}
func (s *as) authenticateClient(c *model.Client) (err error) {
err = s.initClient(c)
if err != nil {
return
}
if len(c.Session.AccessToken) < 1 {
return errInvalidAccessToken
}
return nil
}
func checkCSRF(c *model.Client) (err error) {
if c.Ctx.CSRFToken != c.Session.CSRFToken {
return errInvalidCSRFToken
}
return nil
}
func (s *as) ServeErrorPage(c *model.Client, err error) {
s.authenticateClient(c)
s.Service.ServeErrorPage(c, err)
}
func (s *as) ServeSigninPage(c *model.Client) (err error) {
return s.Service.ServeSigninPage(c)
}
func (s *as) ServeRootPage(c *model.Client) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
return s.Service.ServeRootPage(c)
}
func (s *as) ServeNavPage(c *model.Client) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
return s.Service.ServeNavPage(c)
}
func (s *as) ServeTimelinePage(c *model.Client, tType string,
maxID string, minID string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
return s.Service.ServeTimelinePage(c, tType, maxID, minID)
}
func (s *as) ServeThreadPage(c *model.Client, id string, reply bool) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
return s.Service.ServeThreadPage(c, id, reply)
}
func (s *as) ServeLikedByPage(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
return s.Service.ServeLikedByPage(c, id)
}
func (s *as) ServeRetweetedByPage(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
return s.Service.ServeRetweetedByPage(c, id)
}
func (s *as) ServeNotificationPage(c *model.Client,
maxID string, minID string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
return s.Service.ServeNotificationPage(c, maxID, minID)
}
func (s *as) ServeUserPage(c *model.Client, id string,
pageType string, maxID string, minID string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
return s.Service.ServeUserPage(c, id, pageType, maxID, minID)
}
func (s *as) ServeAboutPage(c *model.Client) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
return s.Service.ServeAboutPage(c)
}
func (s *as) ServeEmojiPage(c *model.Client) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
return s.Service.ServeEmojiPage(c)
}
func (s *as) ServeSearchPage(c *model.Client, q string,
qType string, offset int) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
return s.Service.ServeSearchPage(c, q, qType, offset)
}
func (s *as) ServeUserSearchPage(c *model.Client,
id string, q string, offset int) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
return s.Service.ServeUserSearchPage(c, id, q, offset)
}
func (s *as) ServeSettingsPage(c *model.Client) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
return s.Service.ServeSettingsPage(c)
}
func (s *as) NewSession(instance string) (redirectUrl string,
sessionID string, err error) {
return s.Service.NewSession(instance)
}
func (s *as) Signin(c *model.Client, sessionID string,
code string) (token string, userID string, err error) {
err = s.authenticateClient(c)
if err != nil && err != errInvalidAccessToken {
return
}
token, userID, err = s.Service.Signin(c, c.Session.ID, code)
if err != nil {
return
}
c.Session.AccessToken = token
c.Session.UserID = userID
err = s.sessionRepo.Add(c.Session)
if err != nil {
return
}
return
}
func (s *as) Signout(c *model.Client) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
s.Service.Signout(c)
return
}
func (s *as) Post(c *model.Client, content string,
replyToID string, format string, visibility string, isNSFW bool,
files []*multipart.FileHeader) (id string, err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.Post(c, content, replyToID, format, visibility, isNSFW, files)
}
func (s *as) Like(c *model.Client, id string) (count int64, err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.Like(c, id)
}
func (s *as) UnLike(c *model.Client, id string) (count int64, err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.UnLike(c, id)
}
func (s *as) Retweet(c *model.Client, id string) (count int64, err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.Retweet(c, id)
}
func (s *as) UnRetweet(c *model.Client, id string) (count int64, err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.UnRetweet(c, id)
}
func (s *as) Vote(c *model.Client, id string,
choices []string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.Vote(c, id, choices)
}
func (s *as) Follow(c *model.Client, id string, reblogs *bool) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.Follow(c, id, reblogs)
}
func (s *as) UnFollow(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.UnFollow(c, id)
}
func (s *as) Mute(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.Mute(c, id)
}
func (s *as) UnMute(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.UnMute(c, id)
}
func (s *as) Block(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.Block(c, id)
}
func (s *as) UnBlock(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.UnBlock(c, id)
}
func (s *as) Subscribe(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.Subscribe(c, id)
}
func (s *as) UnSubscribe(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.UnSubscribe(c, id)
}
func (s *as) SaveSettings(c *model.Client, settings *model.Settings) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.SaveSettings(c, settings)
}
func (s *as) MuteConversation(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.MuteConversation(c, id)
}
func (s *as) UnMuteConversation(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.UnMuteConversation(c, id)
}
func (s *as) Delete(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.Delete(c, id)
}
func (s *as) ReadNotifications(c *model.Client, maxID string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.ReadNotifications(c, maxID)
}
func (s *as) Bookmark(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.Bookmark(c, id)
}
func (s *as) UnBookmark(c *model.Client, id string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
}
err = checkCSRF(c)
if err != nil {
return
}
return s.Service.UnBookmark(c, id)
}

341
service/logging.go

@ -1,341 +0,0 @@
package service
import (
"log"
"mime/multipart"
"time"
"bloat/model"
)
type ls struct {
logger *log.Logger
Service
}
func NewLoggingService(logger *log.Logger, s Service) Service {
return &ls{logger, s}
}
func (s *ls) ServeErrorPage(c *model.Client, err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, err=%v, took=%v\n",
"ServeErrorPage", err, time.Since(begin))
}(time.Now())
s.Service.ServeErrorPage(c, err)
}
func (s *ls) ServeSigninPage(c *model.Client) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, took=%v, err=%v\n",
"ServeSigninPage", time.Since(begin), err)
}(time.Now())
return s.Service.ServeSigninPage(c)
}
func (s *ls) ServeRootPage(c *model.Client) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, took=%v, err=%v\n",
"ServeRootPage", time.Since(begin), err)
}(time.Now())
return s.Service.ServeRootPage(c)
}
func (s *ls) ServeNavPage(c *model.Client) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, took=%v, err=%v\n",
"ServeNavPage", time.Since(begin), err)
}(time.Now())
return s.Service.ServeNavPage(c)
}
func (s *ls) ServeTimelinePage(c *model.Client, tType string,
maxID string, minID string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, type=%v, took=%v, err=%v\n",
"ServeTimelinePage", tType, time.Since(begin), err)
}(time.Now())
return s.Service.ServeTimelinePage(c, tType, maxID, minID)
}
func (s *ls) ServeThreadPage(c *model.Client, id string,
reply bool) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"ServeThreadPage", id, time.Since(begin), err)
}(time.Now())
return s.Service.ServeThreadPage(c, id, reply)
}
func (s *ls) ServeLikedByPage(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"ServeLikedByPage", id, time.Since(begin), err)
}(time.Now())
return s.Service.ServeLikedByPage(c, id)
}
func (s *ls) ServeRetweetedByPage(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"ServeRetweetedByPage", id, time.Since(begin), err)
}(time.Now())
return s.Service.ServeRetweetedByPage(c, id)
}
func (s *ls) ServeNotificationPage(c *model.Client,
maxID string, minID string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, took=%v, err=%v\n",
"ServeNotificationPage", time.Since(begin), err)
}(time.Now())
return s.Service.ServeNotificationPage(c, maxID, minID)
}
func (s *ls) ServeUserPage(c *model.Client, id string,
pageType string, maxID string, minID string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, type=%v, took=%v, err=%v\n",
"ServeUserPage", id, pageType, time.Since(begin), err)
}(time.Now())
return s.Service.ServeUserPage(c, id, pageType, maxID, minID)
}
func (s *ls) ServeAboutPage(c *model.Client) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, took=%v, err=%v\n",
"ServeAboutPage", time.Since(begin), err)
}(time.Now())
return s.Service.ServeAboutPage(c)
}
func (s *ls) ServeEmojiPage(c *model.Client) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, took=%v, err=%v\n",
"ServeEmojiPage", time.Since(begin), err)
}(time.Now())
return s.Service.ServeEmojiPage(c)
}
func (s *ls) ServeSearchPage(c *model.Client, q string,
qType string, offset int) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, took=%v, err=%v\n",
"ServeSearchPage", time.Since(begin), err)
}(time.Now())
return s.Service.ServeSearchPage(c, q, qType, offset)
}
func (s *ls) ServeUserSearchPage(c *model.Client,
id string, q string, offset int) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, took=%v, err=%v\n",
"ServeUserSearchPage", time.Since(begin), err)
}(time.Now())
return s.Service.ServeUserSearchPage(c, id, q, offset)
}
func (s *ls) ServeSettingsPage(c *model.Client) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, took=%v, err=%v\n",
"ServeSettingsPage", time.Since(begin), err)
}(time.Now())
return s.Service.ServeSettingsPage(c)
}
func (s *ls) NewSession(instance string) (redirectUrl string,
sessionID string, err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, instance=%v, took=%v, err=%v\n",
"NewSession", instance, time.Since(begin), err)
}(time.Now())
return s.Service.NewSession(instance)
}
func (s *ls) Signin(c *model.Client, sessionID string,
code string) (token string, userID string, err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, session_id=%v, took=%v, err=%v\n",
"Signin", sessionID, time.Since(begin), err)
}(time.Now())
return s.Service.Signin(c, sessionID, code)
}
func (s *ls) Signout(c *model.Client) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, took=%v, err=%v\n",
"Signout", time.Since(begin), err)
}(time.Now())
return s.Service.Signout(c)
}
func (s *ls) Post(c *model.Client, content string,
replyToID string, format string, visibility string, isNSFW bool,
files []*multipart.FileHeader) (id string, err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, took=%v, err=%v\n",
"Post", time.Since(begin), err)
}(time.Now())
return s.Service.Post(c, content, replyToID, format,
visibility, isNSFW, files)
}
func (s *ls) Like(c *model.Client, id string) (count int64, err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"Like", id, time.Since(begin), err)
}(time.Now())
return s.Service.Like(c, id)
}
func (s *ls) UnLike(c *model.Client, id string) (count int64, err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"UnLike", id, time.Since(begin), err)
}(time.Now())
return s.Service.UnLike(c, id)
}
func (s *ls) Retweet(c *model.Client, id string) (count int64, err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"Retweet", id, time.Since(begin), err)
}(time.Now())
return s.Service.Retweet(c, id)
}
func (s *ls) UnRetweet(c *model.Client, id string) (count int64, err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"UnRetweet", id, time.Since(begin), err)
}(time.Now())
return s.Service.UnRetweet(c, id)
}
func (s *ls) Vote(c *model.Client, id string, choices []string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"Vote", id, time.Since(begin), err)
}(time.Now())
return s.Service.Vote(c, id, choices)
}
func (s *ls) Follow(c *model.Client, id string, reblogs *bool) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"Follow", id, time.Since(begin), err)
}(time.Now())
return s.Service.Follow(c, id, reblogs)
}
func (s *ls) UnFollow(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"UnFollow", id, time.Since(begin), err)
}(time.Now())
return s.Service.UnFollow(c, id)
}
func (s *ls) Mute(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"Mute", id, time.Since(begin), err)
}(time.Now())
return s.Service.Mute(c, id)
}
func (s *ls) UnMute(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"UnMute", id, time.Since(begin), err)
}(time.Now())
return s.Service.UnMute(c, id)
}
func (s *ls) Block(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"Block", id, time.Since(begin), err)
}(time.Now())
return s.Service.Block(c, id)
}
func (s *ls) UnBlock(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"UnBlock", id, time.Since(begin), err)
}(time.Now())
return s.Service.UnBlock(c, id)
}
func (s *ls) Subscribe(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"Subscribe", id, time.Since(begin), err)
}(time.Now())
return s.Service.Subscribe(c, id)
}
func (s *ls) UnSubscribe(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"UnSubscribe", id, time.Since(begin), err)
}(time.Now())
return s.Service.UnSubscribe(c, id)
}
func (s *ls) SaveSettings(c *model.Client, settings *model.Settings) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, took=%v, err=%v\n",
"SaveSettings", time.Since(begin), err)
}(time.Now())
return s.Service.SaveSettings(c, settings)
}
func (s *ls) MuteConversation(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"MuteConversation", id, time.Since(begin), err)
}(time.Now())
return s.Service.MuteConversation(c, id)
}
func (s *ls) UnMuteConversation(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"UnMuteConversation", id, time.Since(begin), err)
}(time.Now())
return s.Service.UnMuteConversation(c, id)
}
func (s *ls) Delete(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"Delete", id, time.Since(begin), err)
}(time.Now())
return s.Service.Delete(c, id)
}
func (s *ls) ReadNotifications(c *model.Client, maxID string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, max_id=%v, took=%v, err=%v\n",
"ReadNotifications", maxID, time.Since(begin), err)
}(time.Now())
return s.Service.ReadNotifications(c, maxID)
}
func (s *ls) Bookmark(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"Bookmark", id, time.Since(begin), err)
}(time.Now())
return s.Service.Bookmark(c, id)
}
func (s *ls) UnBookmark(c *model.Client, id string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
"UnBookmark", id, time.Since(begin), err)
}(time.Now())
return s.Service.UnBookmark(c, id)
}

313
service/service.go

@ -20,53 +20,6 @@ var (
errInvalidArgument = errors.New("invalid argument")
)
type Service interface {
ServeErrorPage(c *model.Client, err error)
ServeSigninPage(c *model.Client) (err error)
ServeRootPage(c *model.Client) (err error)
ServeNavPage(c *model.Client) (err error)
ServeTimelinePage(c *model.Client, tType string, maxID string,
minID string) (err error)
ServeThreadPage(c *model.Client, id string, reply bool) (err error)
ServeLikedByPage(c *model.Client, id string) (err error)
ServeRetweetedByPage(c *model.Client, id string) (err error)
ServeNotificationPage(c *model.Client, maxID string, minID string) (err error)
ServeUserPage(c *model.Client, id string, pageType string, maxID string,
minID string) (err error)
ServeAboutPage(c *model.Client) (err error)
ServeEmojiPage(c *model.Client) (err error)
ServeSearchPage(c *model.Client, q string, qType string, offset int) (err error)
ServeUserSearchPage(c *model.Client, id string, q string, offset int) (err error)
ServeSettingsPage(c *model.Client) (err error)
SingleInstance() (instance string, ok bool)
NewSession(instance string) (redirectUrl string, sessionID string, err error)
Signin(c *model.Client, sessionID string, code string) (token string,
userID string, err error)
Signout(c *model.Client) (err error)
Post(c *model.Client, content string, replyToID string, format string, visibility string,
isNSFW bool, files []*multipart.FileHeader) (id string, err error)
Like(c *model.Client, id string) (count int64, err error)
UnLike(c *model.Client, id string) (count int64, err error)
Retweet(c *model.Client, id string) (count int64, err error)
UnRetweet(c *model.Client, id string) (count int64, err error)
Vote(c *model.Client, id string, choices []string) (err error)
Follow(c *model.Client, id string, reblogs *bool) (err error)
UnFollow(c *model.Client, id string) (err error)
Mute(c *model.Client, id string) (err error)
UnMute(c *model.Client, id string) (err error)
Block(c *model.Client, id string) (err error)
UnBlock(c *model.Client, id string) (err error)
Subscribe(c *model.Client, id string) (err error)
UnSubscribe(c *model.Client, id string) (err error)
SaveSettings(c *model.Client, settings *model.Settings) (err error)
MuteConversation(c *model.Client, id string) (err error)
UnMuteConversation(c *model.Client, id string) (err error)
Delete(c *model.Client, id string) (err error)
ReadNotifications(c *model.Client, maxID string) (err error)
Bookmark(c *model.Client, id string) (err error)
UnBookmark(c *model.Client, id string) (err error)
}
type service struct {
clientName string
clientScope string
@ -88,7 +41,7 @@ func NewService(clientName string,
sessionRepo model.SessionRepo,
appRepo model.AppRepo,
singleInstance string,
) Service {
) *service {
return &service{
clientName: clientName,
clientScope: clientScope,
@ -102,7 +55,7 @@ func NewService(clientName string,
}
}
func getRendererContext(c *model.Client) *renderer.Context {
func getRendererContext(c *client) *renderer.Context {
var settings model.Settings
var session model.Session
if c != nil {
@ -128,26 +81,21 @@ func addToReplyMap(m map[string][]mastodon.ReplyInfo, key interface{},
if key == nil {
return
}
keyStr, ok := key.(string)
if !ok {
return
}
_, ok = m[keyStr]
if !ok {
m[keyStr] = []mastodon.ReplyInfo{}
}
m[keyStr] = append(m[keyStr], mastodon.ReplyInfo{val, number})
}
func (svc *service) getCommonData(c *model.Client,
title string) (data *renderer.CommonData) {
func (s *service) getCommonData(c *client, title string) (data *renderer.CommonData) {
data = &renderer.CommonData{
Title: title + " - " + svc.clientName,
CustomCSS: svc.customCSS,
Title: title + " - " + s.clientName,
CustomCSS: s.customCSS,
}
if c != nil && c.Session.IsLoggedIn() {
data.CSRFToken = c.Session.CSRFToken
@ -155,66 +103,59 @@ func (svc *service) getCommonData(c *model.Client,
return
}
func (svc *service) ServeErrorPage(c *model.Client, err error) {
func (s *service) ErrorPage(c *client, err error) {
var errStr string
if err != nil {
errStr = err.Error()
}
commonData := svc.getCommonData(nil, "error")
commonData := s.getCommonData(nil, "error")
data := &renderer.ErrorData{
CommonData: commonData,
Error: errStr,
}
rCtx := getRendererContext(c)
svc.renderer.Render(rCtx, c.Writer, renderer.ErrorPage, data)
s.renderer.Render(rCtx, c, renderer.ErrorPage, data)
}
func (svc *service) ServeSigninPage(c *model.Client) (err error) {
commonData := svc.getCommonData(nil, "signin")
func (s *service) SigninPage(c *client) (err error) {
commonData := s.getCommonData(nil, "signin")
data := &renderer.SigninData{
CommonData: commonData,
}
rCtx := getRendererContext(nil)
return svc.renderer.Render(rCtx, c.Writer, renderer.SigninPage, data)
return s.renderer.Render(rCtx, c, renderer.SigninPage, data)
}
func (svc *service) ServeRootPage(c *model.Client) (err error) {
func (s *service) RootPage(c *client) (err error) {
data := &renderer.RootData{
Title: svc.clientName,
Title: s.clientName,
}
rCtx := getRendererContext(c)
return svc.renderer.Render(rCtx, c.Writer, renderer.RootPage, data)
return s.renderer.Render(rCtx, c, renderer.RootPage, data)
}
func (svc *service) ServeNavPage(c *model.Client) (err error) {
func (s *service) NavPage(c *client) (err error) {
u, err := c.GetAccountCurrentUser(ctx)
if err != nil {
return
}
postContext := model.PostContext{
DefaultVisibility: c.Session.Settings.DefaultVisibility,
DefaultFormat: c.Session.Settings.DefaultFormat,
Formats: svc.postFormats,
Formats: s.postFormats,
}
commonData := svc.getCommonData(c, "Nav")
commonData := s.getCommonData(c, "nav")
commonData.Target = "main"
data := &renderer.NavData{
User: u,
CommonData: commonData,
PostContext: postContext,
}
rCtx := getRendererContext(c)
return svc.renderer.Render(rCtx, c.Writer, renderer.NavPage, data)
return s.renderer.Render(rCtx, c, renderer.NavPage, data)
}
func (svc *service) ServeTimelinePage(c *model.Client, tType string,
func (s *service) TimelinePage(c *client, tType string,
maxID string, minID string) (err error) {
var nextLink, prevLink, title string
@ -279,7 +220,7 @@ func (svc *service) ServeTimelinePage(c *model.Client, tType string,
nextLink = fmt.Sprintf("/timeline/%s?max_id=%s", tType, pg.MaxID)
}
commonData := svc.getCommonData(c, tType+" timeline ")
commonData := s.getCommonData(c, tType+" timeline ")
data := &renderer.TimelineData{
Title: title,
Statuses: statuses,
@ -289,10 +230,10 @@ func (svc *service) ServeTimelinePage(c *model.Client, tType string,
}
rCtx := getRendererContext(c)
return svc.renderer.Render(rCtx, c.Writer, renderer.TimelinePage, data)
return s.renderer.Render(rCtx, c, renderer.TimelinePage, data)
}
func (svc *service) ServeThreadPage(c *model.Client, id string, reply bool) (err error) {
func (s *service) ThreadPage(c *client, id string, reply bool) (err error) {
var postContext model.PostContext
status, err := c.GetStatus(ctx, id)
@ -323,14 +264,13 @@ func (svc *service) ServeThreadPage(c *model.Client, id string, reply bool) (err
postContext = model.PostContext{
DefaultVisibility: visibility,
DefaultFormat: c.Session.Settings.DefaultFormat,
Formats: svc.postFormats,
Formats: s.postFormats,
ReplyContext: &model.ReplyContext{
InReplyToID: id,
InReplyToName: status.Account.Acct,
ReplyContent: content,
ForceVisibility: isDirect,
},
DarkMode: c.Session.Settings.DarkMode,
}
}
@ -353,7 +293,7 @@ func (svc *service) ServeThreadPage(c *model.Client, id string, reply bool) (err
addToReplyMap(replies, statuses[i].InReplyToID, statuses[i].ID, i+1)
}
commonData := svc.getCommonData(c, "post by "+status.Account.DisplayName)
commonData := s.getCommonData(c, "post by "+status.Account.DisplayName)
data := &renderer.ThreadData{
Statuses: statuses,
PostContext: postContext,
@ -362,42 +302,38 @@ func (svc *service) ServeThreadPage(c *model.Client, id string, reply bool) (err
}
rCtx := getRendererContext(c)
return svc.renderer.Render(rCtx, c.Writer, renderer.ThreadPage, data)
return s.renderer.Render(rCtx, c, renderer.ThreadPage, data)
}
func (svc *service) ServeLikedByPage(c *model.Client, id string) (err error) {
func (s *service) LikedByPage(c *client, id string) (err error) {
likers, err := c.GetFavouritedBy(ctx, id, nil)
if err != nil {
return
}
commonData := svc.getCommonData(c, "likes")
commonData := s.getCommonData(c, "likes")
data := &renderer.LikedByData{
CommonData: commonData,
Users: likers,
}
rCtx := getRendererContext(c)
return svc.renderer.Render(rCtx, c.Writer, renderer.LikedByPage, data)
return s.renderer.Render(rCtx, c, renderer.LikedByPage, data)
}
func (svc *service) ServeRetweetedByPage(c *model.Client, id string) (err error) {
func (s *service) RetweetedByPage(c *client, id string) (err error) {
retweeters, err := c.GetRebloggedBy(ctx, id, nil)
if err != nil {
return
}
commonData := svc.getCommonData(c, "retweets")
commonData := s.getCommonData(c, "retweets")
data := &renderer.RetweetedByData{
CommonData: commonData,
Users: retweeters,
}
rCtx := getRendererContext(c)
return svc.renderer.Render(rCtx, c.Writer, renderer.RetweetedByPage, data)
return s.renderer.Render(rCtx, c, renderer.RetweetedByPage, data)
}
func (svc *service) ServeNotificationPage(c *model.Client, maxID string,
func (s *service) NotificationPage(c *client, maxID string,
minID string) (err error) {
var nextLink string
@ -428,12 +364,11 @@ func (svc *service) ServeNotificationPage(c *model.Client, maxID string,
if unreadCount > 0 {
readID = notifications[0].ID
}
if len(notifications) == 20 && len(pg.MaxID) > 0 {
nextLink = "/notifications?max_id=" + pg.MaxID
}
commonData := svc.getCommonData(c, "notifications")
commonData := s.getCommonData(c, "notifications")
commonData.RefreshInterval = c.Session.Settings.NotificationInterval
commonData.Target = "main"
commonData.Count = unreadCount
@ -445,10 +380,10 @@ func (svc *service) ServeNotificationPage(c *model.Client, maxID string,
CommonData: commonData,
}
rCtx := getRendererContext(c)
return svc.renderer.Render(rCtx, c.Writer, renderer.NotificationPage, data)
return s.renderer.Render(rCtx, c, renderer.NotificationPage, data)
}
func (svc *service) ServeUserPage(c *model.Client, id string, pageType string,
func (s *service) UserPage(c *client, id string, pageType string,
maxID string, minID string) (err error) {
var nextLink string
@ -561,7 +496,7 @@ func (svc *service) ServeUserPage(c *model.Client, id string, pageType string,
}
}
commonData := svc.getCommonData(c, user.DisplayName)
commonData := s.getCommonData(c, user.DisplayName)
data := &renderer.UserData{
User: user,
IsCurrent: isCurrent,
@ -572,10 +507,10 @@ func (svc *service) ServeUserPage(c *model.Client, id string, pageType string,
CommonData: commonData,
}
rCtx := getRendererContext(c)
return svc.renderer.Render(rCtx, c.Writer, renderer.UserPage, data)
return s.renderer.Render(rCtx, c, renderer.UserPage, data)
}
func (svc *service) ServeUserSearchPage(c *model.Client,
func (s *service) UserSearchPage(c *client,
id string, q string, offset int) (err error) {
var nextLink string
@ -598,7 +533,8 @@ func (svc *service) ServeUserSearchPage(c *model.Client,
if len(results.Statuses) == 20 {
offset += 20
nextLink = fmt.Sprintf("/usersearch/%s?q=%s&offset=%d", id, url.QueryEscape(q), offset)
nextLink = fmt.Sprintf("/usersearch/%s?q=%s&offset=%d", id,
url.QueryEscape(q), offset)
}
qq := template.HTMLEscapeString(q)
@ -606,7 +542,7 @@ func (svc *service) ServeUserSearchPage(c *model.Client,
title += " \"" + qq + "\""
}
commonData := svc.getCommonData(c, title)
commonData := s.getCommonData(c, title)
data := &renderer.UserSearchData{
CommonData: commonData,
User: user,
@ -614,38 +550,34 @@ func (svc *service) ServeUserSearchPage(c *model.Client,
Statuses: results.Statuses,
NextLink: nextLink,
}
rCtx := getRendererContext(c)
return svc.renderer.Render(rCtx, c.Writer, renderer.UserSearchPage, data)
return s.renderer.Render(rCtx, c, renderer.UserSearchPage, data)
}
func (svc *service) ServeAboutPage(c *model.Client) (err error) {
commonData := svc.getCommonData(c, "about")
func (s *service) AboutPage(c *client) (err error) {
commonData := s.getCommonData(c, "about")
data := &renderer.AboutData{
CommonData: commonData,
}
rCtx := getRendererContext(c)
return svc.renderer.Render(rCtx, c.Writer, renderer.AboutPage, data)
return s.renderer.Render(rCtx, c, renderer.AboutPage, data)
}
func (svc *service) ServeEmojiPage(c *model.Client) (err error) {
func (s *service) EmojiPage(c *client) (err error) {
emojis, err := c.GetInstanceEmojis(ctx)
if err != nil {
return
}
commonData := svc.getCommonData(c, "emojis")
commonData := s.getCommonData(c, "emojis")
data := &renderer.EmojiData{
Emojis: emojis,
CommonData: commonData,
}
rCtx := getRendererContext(c)
return svc.renderer.Render(rCtx, c.Writer, renderer.EmojiPage, data)
return s.renderer.Render(rCtx, c, renderer.EmojiPage, data)
}
func (svc *service) ServeSearchPage(c *model.Client,
func (s *service) SearchPage(c *client,
q string, qType string, offset int) (err error) {
var nextLink string
@ -664,7 +596,8 @@ func (svc *service) ServeSearchPage(c *model.Client,
if (qType == "accounts" && len(results.Accounts) == 20) ||
(qType == "statuses" && len(results.Statuses) == 20) {
offset += 20
nextLink = fmt.Sprintf("/search?q=%s&type=%s&offset=%d", url.QueryEscape(q), qType, offset)
nextLink = fmt.Sprintf("/search?q=%s&type=%s&offset=%d",
url.QueryEscape(q), qType, offset)
}
qq := template.HTMLEscapeString(q)
@ -672,7 +605,7 @@ func (svc *service) ServeSearchPage(c *model.Client,
title += " \"" + qq + "\""
}
commonData := svc.getCommonData(c, title)
commonData := s.getCommonData(c, title)
data := &renderer.SearchData{
CommonData: commonData,
Q: qq,
@ -681,34 +614,30 @@ func (svc *service) ServeSearchPage(c *model.Client,
Statuses: results.Statuses,
NextLink: nextLink,
}
rCtx := getRendererContext(c)
return svc.renderer.Render(rCtx, c.Writer, renderer.SearchPage, data)
return s.renderer.Render(rCtx, c, renderer.SearchPage, data)
}
func (svc *service) ServeSettingsPage(c *model.Client) (err error) {
commonData := svc.getCommonData(c, "settings")
func (s *service) SettingsPage(c *client) (err error) {
commonData := s.getCommonData(c, "settings")
data := &renderer.SettingsData{
CommonData: commonData,
Settings: &c.Session.Settings,
PostFormats: svc.postFormats,
PostFormats: s.postFormats,
}
rCtx := getRendererContext(c)
return svc.renderer.Render(rCtx, c.Writer, renderer.SettingsPage, data)
return s.renderer.Render(rCtx, c, renderer.SettingsPage, data)
}
func (svc *service) SingleInstance() (instance string, ok bool) {
if len(svc.singleInstance) > 0 {
instance = svc.singleInstance
func (s *service) SingleInstance() (instance string, ok bool) {
if len(s.singleInstance) > 0 {
instance = s.singleInstance
ok = true
}
return
}
func (svc *service) NewSession(instance string) (
redirectUrl string, sessionID string, err error) {
func (s *service) NewSession(instance string) (rurl string, sid string, err error) {
var instanceURL string
if strings.HasPrefix(instance, "https://") {
instanceURL = instance
@ -717,53 +646,48 @@ func (svc *service) NewSession(instance string) (
instanceURL = "https://" + instance
}
sessionID, err = util.NewSessionID()
sid, err = util.NewSessionID()
if err != nil {
return
}
csrfToken, err := util.NewCSRFToken()
if err != nil {
return
}
session := model.Session{
ID: sessionID,
ID: sid,
InstanceDomain: instance,
CSRFToken: csrfToken,
Settings: *model.NewSettings(),
}
err = svc.sessionRepo.Add(session)
err = s.sessionRepo.Add(session)
if err != nil {
return
}