diff options
| author | r <r@freesoftwareextremist.com> | 2020-05-24 04:38:34 +0000 | 
|---|---|---|
| committer | r <r@freesoftwareextremist.com> | 2020-05-24 04:38:34 +0000 | 
| commit | fd2a353770a5f3cea773a5c4465bf0fc2a2818d3 (patch) | |
| tree | 91c13956af929b8cd0015b9169c7ce11b70b7023 | |
| parent | 4b255673726a1b36fc0b99c3fd6cfcd4c949d372 (diff) | |
| download | bloat-fd2a353770a5f3cea773a5c4465bf0fc2a2818d3.tar.gz bloat-fd2a353770a5f3cea773a5c4465bf0fc2a2818d3.zip | |
Refactor things
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | main.go | 6 | ||||
| -rw-r--r-- | migrations/csrfToken/main.go | 85 | ||||
| -rw-r--r-- | model/client.go | 6 | ||||
| -rw-r--r-- | service/auth.go | 283 | ||||
| -rw-r--r-- | service/logging.go | 149 | ||||
| -rw-r--r-- | service/service.go | 219 | ||||
| -rw-r--r-- | service/transport.go | 317 | 
8 files changed, 458 insertions, 610 deletions
| @@ -35,9 +35,6 @@ install: bloat  	cp -r static/* $(SHAREPATH)/static  	chmod 0644 $(SHAREPATH)/static/* -tags: $(SRC) -	gotags $(SRC) > tags -  uninstall:  	rm -f $(BINPATH)/bloat  	rm -fr $(SHAREPATH)/templates @@ -4,12 +4,10 @@ import (  	"errors"  	"fmt"  	"log" -	"math/rand"  	"net/http"  	"os"  	"path/filepath"  	"strings" -	"time"  	"bloat/config"  	"bloat/kv" @@ -23,10 +21,6 @@ var (  	configFile = "/etc/bloat.conf"  ) -func init() { -	rand.Seed(time.Now().Unix()) -} -  func errExit(err error) {  	fmt.Fprintln(os.Stderr, err.Error())  	os.Exit(1) diff --git a/migrations/csrfToken/main.go b/migrations/csrfToken/main.go deleted file mode 100644 index 3d9526d..0000000 --- a/migrations/csrfToken/main.go +++ /dev/null @@ -1,85 +0,0 @@ -package main - -import ( -	"log" -	"math/rand" -	"os" -	"path/filepath" -	"time" - -	"bloat/config" -	"bloat/kv" -	"bloat/repository" -	"bloat/util" -) - -var ( -	configFile = "bloat.conf" -) - -func init() { -	rand.Seed(time.Now().Unix()) -} - -func getKeys(sessionRepoPath string) (keys []string, err error) { -	f, err := os.Open(sessionRepoPath) -	if err != nil { -		return -	} -	return f.Readdirnames(0) -} - -func main() { -	opts, _, err := util.Getopts(os.Args, "f:") -	if err != nil { -		log.Fatal(err) -	} - -	for _, opt := range opts { -		switch opt.Option { -		case 'f': -			configFile = opt.Value -		} -	} - -	config, err := config.ParseFile(configFile) -	if err != nil { -		log.Fatal(err) -	} - -	if !config.IsValid() { -		log.Fatal("invalid config") -	} - -	sessionRepoPath := filepath.Join(config.DatabasePath, "session") -	sessionDB, err := kv.NewDatabse(sessionRepoPath) -	if err != nil { -		log.Fatal(err) -	} - -	sessionRepo := repository.NewSessionRepository(sessionDB) - -	sessionIDs, err := getKeys(sessionRepoPath) -	if err != nil { -		log.Fatal(err) -	} - -	for _, id := range sessionIDs { -		s, err := sessionRepo.Get(id) -		if err != nil { -			log.Println(id, err) -			continue -		} -		s.CSRFToken, err = util.NewCSRFToken() -		if err != nil { -			log.Println(id, err) -			continue -		} -		err = sessionRepo.Add(s) -		if err != nil { -			log.Println(id, err) -			continue -		} -	} - -} diff --git a/model/client.go b/model/client.go index f0cd59d..931ddaa 100644 --- a/model/client.go +++ b/model/client.go @@ -6,8 +6,14 @@ import (  	"bloat/mastodon"  ) +type ClientCtx struct { +	SessionID string +	CSRFToken string +} +  type Client struct {  	*mastodon.Client  	Writer  io.Writer +	Ctx     ClientCtx  	Session Session  } diff --git a/service/auth.go b/service/auth.go index a7c4c15..d16fab9 100644 --- a/service/auth.go +++ b/service/auth.go @@ -1,7 +1,6 @@  package service  import ( -	"context"  	"errors"  	"mime/multipart" @@ -24,178 +23,174 @@ func NewAuthService(sessionRepo model.SessionRepo, appRepo model.AppRepo, s Serv  	return &as{sessionRepo, appRepo, s}  } -func (s *as) authenticateClient(ctx context.Context, c *model.Client) (err error) { -	sessionID, ok := ctx.Value("session_id").(string) -	if !ok || len(sessionID) < 1 { +func (s *as) authenticateClient(c *model.Client) (err error) { +	if len(c.Ctx.SessionID) < 1 {  		return errInvalidSession  	} -	session, err := s.sessionRepo.Get(sessionID) +	session, err := s.sessionRepo.Get(c.Ctx.SessionID)  	if err != nil {  		return errInvalidSession  	} -	client, err := s.appRepo.Get(session.InstanceDomain) +	app, err := s.appRepo.Get(session.InstanceDomain)  	if err != nil {  		return  	}  	mc := mastodon.NewClient(&mastodon.Config{ -		Server:       client.InstanceURL, -		ClientID:     client.ClientID, -		ClientSecret: client.ClientSecret, +		Server:       app.InstanceURL, +		ClientID:     app.ClientID, +		ClientSecret: app.ClientSecret,  		AccessToken:  session.AccessToken,  	}) -	if c == nil { -		c = &model.Client{} -	}  	c.Client = mc  	c.Session = session  	return nil  } -func checkCSRF(ctx context.Context, c *model.Client) (err error) { -	token, ok := ctx.Value("csrf_token").(string) -	if !ok || token != c.Session.CSRFToken { +func checkCSRF(c *model.Client) (err error) { +	if c.Ctx.CSRFToken != c.Session.CSRFToken {  		return errInvalidCSRFToken  	}  	return nil  } -func (s *as) ServeErrorPage(ctx context.Context, c *model.Client, err error) { -	s.authenticateClient(ctx, c) -	s.Service.ServeErrorPage(ctx, c, err) +func (s *as) ServeErrorPage(c *model.Client, err error) { +	s.authenticateClient(c) +	s.Service.ServeErrorPage(c, err)  } -func (s *as) ServeSigninPage(ctx context.Context, c *model.Client) (err error) { -	return s.Service.ServeSigninPage(ctx, c) +func (s *as) ServeSigninPage(c *model.Client) (err error) { +	return s.Service.ServeSigninPage(c)  } -func (s *as) ServeRootPage(ctx context.Context, c *model.Client) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) ServeRootPage(c *model.Client) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	return s.Service.ServeRootPage(ctx, c) +	return s.Service.ServeRootPage(c)  } -func (s *as) ServeNavPage(ctx context.Context, c *model.Client) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) ServeNavPage(c *model.Client) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	return s.Service.ServeNavPage(ctx, c) +	return s.Service.ServeNavPage(c)  } -func (s *as) ServeTimelinePage(ctx context.Context, c *model.Client, tType string, +func (s *as) ServeTimelinePage(c *model.Client, tType string,  	maxID string, minID string) (err error) { -	err = s.authenticateClient(ctx, c) +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	return s.Service.ServeTimelinePage(ctx, c, tType, maxID, minID) +	return s.Service.ServeTimelinePage(c, tType, maxID, minID)  } -func (s *as) ServeThreadPage(ctx context.Context, c *model.Client, id string, reply bool) (err error) { -	err = s.authenticateClient(ctx, c) +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(ctx, c, id, reply) +	return s.Service.ServeThreadPage(c, id, reply)  } -func (s *as) ServeLikedByPage(ctx context.Context, c *model.Client, id string) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) ServeLikedByPage(c *model.Client, id string) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	return s.Service.ServeLikedByPage(ctx, c, id) +	return s.Service.ServeLikedByPage(c, id)  } -func (s *as) ServeRetweetedByPage(ctx context.Context, c *model.Client, id string) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) ServeRetweetedByPage(c *model.Client, id string) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	return s.Service.ServeRetweetedByPage(ctx, c, id) +	return s.Service.ServeRetweetedByPage(c, id)  } -func (s *as) ServeNotificationPage(ctx context.Context, c *model.Client, +func (s *as) ServeNotificationPage(c *model.Client,  	maxID string, minID string) (err error) { -	err = s.authenticateClient(ctx, c) +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	return s.Service.ServeNotificationPage(ctx, c, maxID, minID) +	return s.Service.ServeNotificationPage(c, maxID, minID)  } -func (s *as) ServeUserPage(ctx context.Context, c *model.Client, id string, +func (s *as) ServeUserPage(c *model.Client, id string,  	pageType string, maxID string, minID string) (err error) { -	err = s.authenticateClient(ctx, c) +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	return s.Service.ServeUserPage(ctx, c, id, pageType, maxID, minID) +	return s.Service.ServeUserPage(c, id, pageType, maxID, minID)  } -func (s *as) ServeAboutPage(ctx context.Context, c *model.Client) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) ServeAboutPage(c *model.Client) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	return s.Service.ServeAboutPage(ctx, c) +	return s.Service.ServeAboutPage(c)  } -func (s *as) ServeEmojiPage(ctx context.Context, c *model.Client) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) ServeEmojiPage(c *model.Client) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	return s.Service.ServeEmojiPage(ctx, c) +	return s.Service.ServeEmojiPage(c)  } -func (s *as) ServeSearchPage(ctx context.Context, c *model.Client, q string, +func (s *as) ServeSearchPage(c *model.Client, q string,  	qType string, offset int) (err error) { -	err = s.authenticateClient(ctx, c) +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	return s.Service.ServeSearchPage(ctx, c, q, qType, offset) +	return s.Service.ServeSearchPage(c, q, qType, offset)  } -func (s *as) ServeUserSearchPage(ctx context.Context, c *model.Client, +func (s *as) ServeUserSearchPage(c *model.Client,  	id string, q string, offset int) (err error) { -	err = s.authenticateClient(ctx, c) +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	return s.Service.ServeUserSearchPage(ctx, c, id, q, offset) +	return s.Service.ServeUserSearchPage(c, id, q, offset)  } -func (s *as) ServeSettingsPage(ctx context.Context, c *model.Client) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) ServeSettingsPage(c *model.Client) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	return s.Service.ServeSettingsPage(ctx, c) +	return s.Service.ServeSettingsPage(c)  } -func (s *as) NewSession(ctx context.Context, instance string) (redirectUrl string, +func (s *as) NewSession(instance string) (redirectUrl string,  	sessionID string, err error) { -	return s.Service.NewSession(ctx, instance) +	return s.Service.NewSession(instance)  } -func (s *as) Signin(ctx context.Context, c *model.Client, sessionID string, +func (s *as) Signin(c *model.Client, sessionID string,  	code string) (token string, userID string, err error) { -	err = s.authenticateClient(ctx, c) +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	token, userID, err = s.Service.Signin(ctx, c, c.Session.ID, code) +	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 @@ -204,247 +199,247 @@ func (s *as) Signin(ctx context.Context, c *model.Client, sessionID string,  	return  } -func (s *as) Signout(ctx context.Context, c *model.Client) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) Signout(c *model.Client) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	s.Service.Signout(ctx, c) +	s.Service.Signout(c)  	return  } -func (s *as) Post(ctx context.Context, c *model.Client, content string, +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(ctx, c) +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.Post(ctx, c, content, replyToID, format, visibility, isNSFW, files) +	return s.Service.Post(c, content, replyToID, format, visibility, isNSFW, files)  } -func (s *as) Like(ctx context.Context, c *model.Client, id string) (count int64, err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) Like(c *model.Client, id string) (count int64, err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.Like(ctx, c, id) +	return s.Service.Like(c, id)  } -func (s *as) UnLike(ctx context.Context, c *model.Client, id string) (count int64, err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) UnLike(c *model.Client, id string) (count int64, err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.UnLike(ctx, c, id) +	return s.Service.UnLike(c, id)  } -func (s *as) Retweet(ctx context.Context, c *model.Client, id string) (count int64, err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) Retweet(c *model.Client, id string) (count int64, err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.Retweet(ctx, c, id) +	return s.Service.Retweet(c, id)  } -func (s *as) UnRetweet(ctx context.Context, c *model.Client, id string) (count int64, err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) UnRetweet(c *model.Client, id string) (count int64, err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.UnRetweet(ctx, c, id) +	return s.Service.UnRetweet(c, id)  } -func (s *as) Vote(ctx context.Context, c *model.Client, id string, +func (s *as) Vote(c *model.Client, id string,  	choices []string) (err error) { -	err = s.authenticateClient(ctx, c) +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.Vote(ctx, c, id, choices) +	return s.Service.Vote(c, id, choices)  } -func (s *as) Follow(ctx context.Context, c *model.Client, id string, reblogs *bool) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) Follow(c *model.Client, id string, reblogs *bool) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.Follow(ctx, c, id, reblogs) +	return s.Service.Follow(c, id, reblogs)  } -func (s *as) UnFollow(ctx context.Context, c *model.Client, id string) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) UnFollow(c *model.Client, id string) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.UnFollow(ctx, c, id) +	return s.Service.UnFollow(c, id)  } -func (s *as) Mute(ctx context.Context, c *model.Client, id string) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) Mute(c *model.Client, id string) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.Mute(ctx, c, id) +	return s.Service.Mute(c, id)  } -func (s *as) UnMute(ctx context.Context, c *model.Client, id string) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) UnMute(c *model.Client, id string) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.UnMute(ctx, c, id) +	return s.Service.UnMute(c, id)  } -func (s *as) Block(ctx context.Context, c *model.Client, id string) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) Block(c *model.Client, id string) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.Block(ctx, c, id) +	return s.Service.Block(c, id)  } -func (s *as) UnBlock(ctx context.Context, c *model.Client, id string) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) UnBlock(c *model.Client, id string) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.UnBlock(ctx, c, id) +	return s.Service.UnBlock(c, id)  } -func (s *as) Subscribe(ctx context.Context, c *model.Client, id string) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) Subscribe(c *model.Client, id string) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.Subscribe(ctx, c, id) +	return s.Service.Subscribe(c, id)  } -func (s *as) UnSubscribe(ctx context.Context, c *model.Client, id string) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) UnSubscribe(c *model.Client, id string) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.UnSubscribe(ctx, c, id) +	return s.Service.UnSubscribe(c, id)  } -func (s *as) SaveSettings(ctx context.Context, c *model.Client, settings *model.Settings) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) SaveSettings(c *model.Client, settings *model.Settings) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.SaveSettings(ctx, c, settings) +	return s.Service.SaveSettings(c, settings)  } -func (s *as) MuteConversation(ctx context.Context, c *model.Client, id string) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) MuteConversation(c *model.Client, id string) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.MuteConversation(ctx, c, id) +	return s.Service.MuteConversation(c, id)  } -func (s *as) UnMuteConversation(ctx context.Context, c *model.Client, id string) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) UnMuteConversation(c *model.Client, id string) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.UnMuteConversation(ctx, c, id) +	return s.Service.UnMuteConversation(c, id)  } -func (s *as) Delete(ctx context.Context, c *model.Client, id string) (err error) { -	err = s.authenticateClient(ctx, c) +func (s *as) Delete(c *model.Client, id string) (err error) { +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.Delete(ctx, c, id) +	return s.Service.Delete(c, id)  } -func (s *as) ReadNotifications(ctx context.Context, c *model.Client, +func (s *as) ReadNotifications(c *model.Client,  	maxID string) (err error) { -	err = s.authenticateClient(ctx, c) +	err = s.authenticateClient(c)  	if err != nil {  		return  	} -	err = checkCSRF(ctx, c) +	err = checkCSRF(c)  	if err != nil {  		return  	} -	return s.Service.ReadNotifications(ctx, c, maxID) +	return s.Service.ReadNotifications(c, maxID)  } diff --git a/service/logging.go b/service/logging.go index 16279cc..7df03de 100644 --- a/service/logging.go +++ b/service/logging.go @@ -1,7 +1,6 @@  package service  import ( -	"context"  	"log"  	"mime/multipart"  	"time" @@ -18,310 +17,310 @@ func NewLoggingService(logger *log.Logger, s Service) Service {  	return &ls{logger, s}  } -func (s *ls) ServeErrorPage(ctx context.Context, c *model.Client, err error) { +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(ctx, c, err) +	s.Service.ServeErrorPage(c, err)  } -func (s *ls) ServeSigninPage(ctx context.Context, c *model.Client) (err error) { +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(ctx, c) +	return s.Service.ServeSigninPage(c)  } -func (s *ls) ServeRootPage(ctx context.Context, c *model.Client) (err error) { +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(ctx, c) +	return s.Service.ServeRootPage(c)  } -func (s *ls) ServeNavPage(ctx context.Context, c *model.Client) (err error) { +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(ctx, c) +	return s.Service.ServeNavPage(c)  } -func (s *ls) ServeTimelinePage(ctx context.Context, c *model.Client, tType string, +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(ctx, c, tType, maxID, minID) +	return s.Service.ServeTimelinePage(c, tType, maxID, minID)  } -func (s *ls) ServeThreadPage(ctx context.Context, c *model.Client, id string, +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(ctx, c, id, reply) +	return s.Service.ServeThreadPage(c, id, reply)  } -func (s *ls) ServeLikedByPage(ctx context.Context, c *model.Client, id string) (err error) { +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(ctx, c, id) +	return s.Service.ServeLikedByPage(c, id)  } -func (s *ls) ServeRetweetedByPage(ctx context.Context, c *model.Client, id string) (err error) { +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(ctx, c, id) +	return s.Service.ServeRetweetedByPage(c, id)  } -func (s *ls) ServeNotificationPage(ctx context.Context, c *model.Client, +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(ctx, c, maxID, minID) +	return s.Service.ServeNotificationPage(c, maxID, minID)  } -func (s *ls) ServeUserPage(ctx context.Context, c *model.Client, id string, +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(ctx, c, id, pageType, maxID, minID) +	return s.Service.ServeUserPage(c, id, pageType, maxID, minID)  } -func (s *ls) ServeAboutPage(ctx context.Context, c *model.Client) (err error) { +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(ctx, c) +	return s.Service.ServeAboutPage(c)  } -func (s *ls) ServeEmojiPage(ctx context.Context, c *model.Client) (err error) { +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(ctx, c) +	return s.Service.ServeEmojiPage(c)  } -func (s *ls) ServeSearchPage(ctx context.Context, c *model.Client, q string, +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(ctx, c, q, qType, offset) +	return s.Service.ServeSearchPage(c, q, qType, offset)  } -func (s *ls) ServeUserSearchPage(ctx context.Context, c *model.Client, +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(ctx, c, id, q, offset) +	return s.Service.ServeUserSearchPage(c, id, q, offset)  } -func (s *ls) ServeSettingsPage(ctx context.Context, c *model.Client) (err error) { +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(ctx, c) +	return s.Service.ServeSettingsPage(c)  } -func (s *ls) NewSession(ctx context.Context, instance string) (redirectUrl string, +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(ctx, instance) +	return s.Service.NewSession(instance)  } -func (s *ls) Signin(ctx context.Context, c *model.Client, sessionID string, +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(ctx, c, sessionID, code) +	return s.Service.Signin(c, sessionID, code)  } -func (s *ls) Signout(ctx context.Context, c *model.Client) (err error) { +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(ctx, c) +	return s.Service.Signout(c)  } -func (s *ls) Post(ctx context.Context, c *model.Client, content string, +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(ctx, c, content, replyToID, format, +	return s.Service.Post(c, content, replyToID, format,  		visibility, isNSFW, files)  } -func (s *ls) Like(ctx context.Context, c *model.Client, id string) (count int64, err error) { +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(ctx, c, id) +	return s.Service.Like(c, id)  } -func (s *ls) UnLike(ctx context.Context, c *model.Client, id string) (count int64, err error) { +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(ctx, c, id) +	return s.Service.UnLike(c, id)  } -func (s *ls) Retweet(ctx context.Context, c *model.Client, id string) (count int64, err error) { +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(ctx, c, id) +	return s.Service.Retweet(c, id)  } -func (s *ls) UnRetweet(ctx context.Context, c *model.Client, id string) (count int64, err error) { +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(ctx, c, id) +	return s.Service.UnRetweet(c, id)  } -func (s *ls) Vote(ctx context.Context, c *model.Client, id string, choices []string) (err error) { +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(ctx, c, id, choices) +	return s.Service.Vote(c, id, choices)  } -func (s *ls) Follow(ctx context.Context, c *model.Client, id string, reblogs *bool) (err error) { +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(ctx, c, id, reblogs) +	return s.Service.Follow(c, id, reblogs)  } -func (s *ls) UnFollow(ctx context.Context, c *model.Client, id string) (err error) { +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(ctx, c, id) +	return s.Service.UnFollow(c, id)  } -func (s *ls) Mute(ctx context.Context, c *model.Client, id string) (err error) { +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(ctx, c, id) +	return s.Service.Mute(c, id)  } -func (s *ls) UnMute(ctx context.Context, c *model.Client, id string) (err error) { +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(ctx, c, id) +	return s.Service.UnMute(c, id)  } -func (s *ls) Block(ctx context.Context, c *model.Client, id string) (err error) { +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(ctx, c, id) +	return s.Service.Block(c, id)  } -func (s *ls) UnBlock(ctx context.Context, c *model.Client, id string) (err error) { +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(ctx, c, id) +	return s.Service.UnBlock(c, id)  } -func (s *ls) Subscribe(ctx context.Context, c *model.Client, id string) (err error) { +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(ctx, c, id) +	return s.Service.Subscribe(c, id)  } -func (s *ls) UnSubscribe(ctx context.Context, c *model.Client, id string) (err error) { +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(ctx, c, id) +	return s.Service.UnSubscribe(c, id)  } -func (s *ls) SaveSettings(ctx context.Context, c *model.Client, settings *model.Settings) (err error) { +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(ctx, c, settings) +	return s.Service.SaveSettings(c, settings)  } -func (s *ls) MuteConversation(ctx context.Context, c *model.Client, id string) (err error) { +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(ctx, c, id) +	return s.Service.MuteConversation(c, id)  } -func (s *ls) UnMuteConversation(ctx context.Context, c *model.Client, id string) (err error) { +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(ctx, c, id) +	return s.Service.UnMuteConversation(c, id)  } -func (s *ls) Delete(ctx context.Context, c *model.Client, id string) (err error) { +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(ctx, c, id) +	return s.Service.Delete(c, id)  } -func (s *ls) ReadNotifications(ctx context.Context, c *model.Client, +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(ctx, c, maxID) +	return s.Service.ReadNotifications(c, maxID)  } diff --git a/service/service.go b/service/service.go index d6ff192..063624c 100644 --- a/service/service.go +++ b/service/service.go @@ -15,51 +15,53 @@ import (  )  var ( +	ctx                = context.Background()  	errInvalidArgument = errors.New("invalid argument")  )  type Service interface { -	ServeErrorPage(ctx context.Context, c *model.Client, err error) -	ServeSigninPage(ctx context.Context, c *model.Client) (err error) -	ServeRootPage(ctx context.Context, c *model.Client) (err error) -	ServeNavPage(ctx context.Context, c *model.Client) (err error) -	ServeTimelinePage(ctx context.Context, c *model.Client, tType string, maxID string, minID string) (err error) -	ServeThreadPage(ctx context.Context, c *model.Client, id string, reply bool) (err error) -	ServeLikedByPage(ctx context.Context, c *model.Client, id string) (err error) -	ServeRetweetedByPage(ctx context.Context, c *model.Client, id string) (err error) -	ServeNotificationPage(ctx context.Context, c *model.Client, maxID string, minID string) (err error) -	ServeUserPage(ctx context.Context, c *model.Client, id string, pageType string, -		maxID string, minID string) (err error) -	ServeAboutPage(ctx context.Context, c *model.Client) (err error) -	ServeEmojiPage(ctx context.Context, c *model.Client) (err error) -	ServeSearchPage(ctx context.Context, c *model.Client, q string, qType string, offset int) (err error) -	ServeUserSearchPage(ctx context.Context, c *model.Client, id string, q string, offset int) (err error) -	ServeSettingsPage(ctx context.Context, c *model.Client) (err error) -	SingleInstance(ctx context.Context) (instance string, ok bool) -	NewSession(ctx context.Context, instance string) (redirectUrl string, sessionID string, err error) -	Signin(ctx context.Context, c *model.Client, sessionID string, -		code string) (token string, userID string, err error) -	Signout(ctx context.Context, c *model.Client) (err error) -	Post(ctx context.Context, c *model.Client, content string, replyToID string, format string, -		visibility string, isNSFW bool, files []*multipart.FileHeader) (id string, err error) -	Like(ctx context.Context, c *model.Client, id string) (count int64, err error) -	UnLike(ctx context.Context, c *model.Client, id string) (count int64, err error) -	Retweet(ctx context.Context, c *model.Client, id string) (count int64, err error) -	UnRetweet(ctx context.Context, c *model.Client, id string) (count int64, err error) -	Vote(ctx context.Context, c *model.Client, id string, choices []string) (err error) -	Follow(ctx context.Context, c *model.Client, id string, reblogs *bool) (err error) -	UnFollow(ctx context.Context, c *model.Client, id string) (err error) -	Mute(ctx context.Context, c *model.Client, id string) (err error) -	UnMute(ctx context.Context, c *model.Client, id string) (err error) -	Block(ctx context.Context, c *model.Client, id string) (err error) -	UnBlock(ctx context.Context, c *model.Client, id string) (err error) -	Subscribe(ctx context.Context, c *model.Client, id string) (err error) -	UnSubscribe(ctx context.Context, c *model.Client, id string) (err error) -	SaveSettings(ctx context.Context, c *model.Client, settings *model.Settings) (err error) -	MuteConversation(ctx context.Context, c *model.Client, id string) (err error) -	UnMuteConversation(ctx context.Context, c *model.Client, id string) (err error) -	Delete(ctx context.Context, c *model.Client, id string) (err error) -	ReadNotifications(ctx context.Context, c *model.Client, maxID string) (err error) +	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)  }  type service struct { @@ -136,8 +138,9 @@ func addToReplyMap(m map[string][]mastodon.ReplyInfo, key interface{},  	m[keyStr] = append(m[keyStr], mastodon.ReplyInfo{val, number})  } -func (svc *service) getCommonData(ctx context.Context, c *model.Client, +func (svc *service) getCommonData(c *model.Client,  	title string) (data *renderer.CommonData) { +  	data = &renderer.CommonData{  		Title:     title + " - " + svc.clientName,  		CustomCSS: svc.customCSS, @@ -148,13 +151,13 @@ func (svc *service) getCommonData(ctx context.Context, c *model.Client,  	return  } -func (svc *service) ServeErrorPage(ctx context.Context, c *model.Client, err error) { +func (svc *service) ServeErrorPage(c *model.Client, err error) {  	var errStr string  	if err != nil {  		errStr = err.Error()  	} -	commonData := svc.getCommonData(ctx, nil, "error") +	commonData := svc.getCommonData(nil, "error")  	data := &renderer.ErrorData{  		CommonData: commonData,  		Error:      errStr, @@ -164,10 +167,8 @@ func (svc *service) ServeErrorPage(ctx context.Context, c *model.Client, err err  	svc.renderer.Render(rCtx, c.Writer, renderer.ErrorPage, data)  } -func (svc *service) ServeSigninPage(ctx context.Context, c *model.Client) ( -	err error) { - -	commonData := svc.getCommonData(ctx, nil, "signin") +func (svc *service) ServeSigninPage(c *model.Client) (err error) { +	commonData := svc.getCommonData(nil, "signin")  	data := &renderer.SigninData{  		CommonData: commonData,  	} @@ -176,7 +177,7 @@ func (svc *service) ServeSigninPage(ctx context.Context, c *model.Client) (  	return svc.renderer.Render(rCtx, c.Writer, renderer.SigninPage, data)  } -func (svc *service) ServeRootPage(ctx context.Context, c *model.Client) (err error) { +func (svc *service) ServeRootPage(c *model.Client) (err error) {  	data := &renderer.RootData{  		Title: svc.clientName,  	} @@ -185,7 +186,7 @@ func (svc *service) ServeRootPage(ctx context.Context, c *model.Client) (err err  	return svc.renderer.Render(rCtx, c.Writer, renderer.RootPage, data)  } -func (svc *service) ServeNavPage(ctx context.Context, c *model.Client) (err error) { +func (svc *service) ServeNavPage(c *model.Client) (err error) {  	u, err := c.GetAccountCurrentUser(ctx)  	if err != nil {  		return @@ -196,7 +197,7 @@ func (svc *service) ServeNavPage(ctx context.Context, c *model.Client) (err erro  		Formats:           svc.postFormats,  	} -	commonData := svc.getCommonData(ctx, c, "Nav") +	commonData := svc.getCommonData(c, "Nav")  	commonData.Target = "main"  	data := &renderer.NavData{  		User:        u, @@ -208,8 +209,8 @@ func (svc *service) ServeNavPage(ctx context.Context, c *model.Client) (err erro  	return svc.renderer.Render(rCtx, c.Writer, renderer.NavPage, data)  } -func (svc *service) ServeTimelinePage(ctx context.Context, c *model.Client, -	tType string, maxID string, minID string) (err error) { +func (svc *service) ServeTimelinePage(c *model.Client, tType string, +	maxID string, minID string) (err error) {  	var nextLink, prevLink, title string  	var statuses []*mastodon.Status @@ -273,7 +274,7 @@ func (svc *service) ServeTimelinePage(ctx context.Context, c *model.Client,  		nextLink = fmt.Sprintf("/timeline/%s?max_id=%s", tType, pg.MaxID)  	} -	commonData := svc.getCommonData(ctx, c, tType+" timeline ") +	commonData := svc.getCommonData(c, tType+" timeline ")  	data := &renderer.TimelineData{  		Title:      title,  		Statuses:   statuses, @@ -286,9 +287,7 @@ func (svc *service) ServeTimelinePage(ctx context.Context, c *model.Client,  	return svc.renderer.Render(rCtx, c.Writer, renderer.TimelinePage, data)  } -func (svc *service) ServeThreadPage(ctx context.Context, c *model.Client, -	id string, reply bool) (err error) { - +func (svc *service) ServeThreadPage(c *model.Client, id string, reply bool) (err error) {  	var postContext model.PostContext  	status, err := c.GetStatus(ctx, id) @@ -351,7 +350,7 @@ func (svc *service) ServeThreadPage(ctx context.Context, c *model.Client,  		addToReplyMap(replies, statuses[i].InReplyToID, statuses[i].ID, i+1)  	} -	commonData := svc.getCommonData(ctx, c, "post by "+status.Account.DisplayName) +	commonData := svc.getCommonData(c, "post by "+status.Account.DisplayName)  	data := &renderer.ThreadData{  		Statuses:    statuses,  		PostContext: postContext, @@ -363,15 +362,13 @@ func (svc *service) ServeThreadPage(ctx context.Context, c *model.Client,  	return svc.renderer.Render(rCtx, c.Writer, renderer.ThreadPage, data)  } -func (svc *service) ServeLikedByPage(ctx context.Context, c *model.Client, -	id string) (err error) { - +func (svc *service) ServeLikedByPage(c *model.Client, id string) (err error) {  	likers, err := c.GetFavouritedBy(ctx, id, nil)  	if err != nil {  		return  	} -	commonData := svc.getCommonData(ctx, c, "likes") +	commonData := svc.getCommonData(c, "likes")  	data := &renderer.LikedByData{  		CommonData: commonData,  		Users:      likers, @@ -381,15 +378,13 @@ func (svc *service) ServeLikedByPage(ctx context.Context, c *model.Client,  	return svc.renderer.Render(rCtx, c.Writer, renderer.LikedByPage, data)  } -func (svc *service) ServeRetweetedByPage(ctx context.Context, c *model.Client, -	id string) (err error) { - +func (svc *service) ServeRetweetedByPage(c *model.Client, id string) (err error) {  	retweeters, err := c.GetRebloggedBy(ctx, id, nil)  	if err != nil {  		return  	} -	commonData := svc.getCommonData(ctx, c, "retweets") +	commonData := svc.getCommonData(c, "retweets")  	data := &renderer.RetweetedByData{  		CommonData: commonData,  		Users:      retweeters, @@ -399,8 +394,8 @@ func (svc *service) ServeRetweetedByPage(ctx context.Context, c *model.Client,  	return svc.renderer.Render(rCtx, c.Writer, renderer.RetweetedByPage, data)  } -func (svc *service) ServeNotificationPage(ctx context.Context, c *model.Client, -	maxID string, minID string) (err error) { +func (svc *service) ServeNotificationPage(c *model.Client, maxID string, +	minID string) (err error) {  	var nextLink string  	var unreadCount int @@ -430,7 +425,7 @@ func (svc *service) ServeNotificationPage(ctx context.Context, c *model.Client,  		nextLink = "/notifications?max_id=" + pg.MaxID  	} -	commonData := svc.getCommonData(ctx, c, "notifications") +	commonData := svc.getCommonData(c, "notifications")  	commonData.AutoRefresh = c.Session.Settings.AutoRefreshNotifications  	commonData.Target = "main"  	commonData.Count = unreadCount @@ -445,8 +440,8 @@ func (svc *service) ServeNotificationPage(ctx context.Context, c *model.Client,  	return svc.renderer.Render(rCtx, c.Writer, renderer.NotificationPage, data)  } -func (svc *service) ServeUserPage(ctx context.Context, c *model.Client, -	id string, pageType string, maxID string, minID string) (err error) { +func (svc *service) ServeUserPage(c *model.Client, id string, pageType string, +	maxID string, minID string) (err error) {  	var nextLink string  	var statuses []*mastodon.Status @@ -503,7 +498,7 @@ func (svc *service) ServeUserPage(ctx context.Context, c *model.Client,  		return errInvalidArgument  	} -	commonData := svc.getCommonData(ctx, c, user.DisplayName) +	commonData := svc.getCommonData(c, user.DisplayName)  	data := &renderer.UserData{  		User:       user,  		IsCurrent:  c.Session.UserID == user.ID, @@ -517,7 +512,7 @@ func (svc *service) ServeUserPage(ctx context.Context, c *model.Client,  	return svc.renderer.Render(rCtx, c.Writer, renderer.UserPage, data)  } -func (svc *service) ServeUserSearchPage(ctx context.Context, c *model.Client, +func (svc *service) ServeUserSearchPage(c *model.Client,  	id string, q string, offset int) (err error) {  	var nextLink string @@ -542,7 +537,7 @@ func (svc *service) ServeUserSearchPage(ctx context.Context, c *model.Client,  		title += " \"" + q + "\""  	} -	commonData := svc.getCommonData(ctx, c, title) +	commonData := svc.getCommonData(c, title)  	data := &renderer.UserSearchData{  		CommonData: commonData,  		User:       user, @@ -555,8 +550,8 @@ func (svc *service) ServeUserSearchPage(ctx context.Context, c *model.Client,  	return svc.renderer.Render(rCtx, c.Writer, renderer.UserSearchPage, data)  } -func (svc *service) ServeAboutPage(ctx context.Context, c *model.Client) (err error) { -	commonData := svc.getCommonData(ctx, c, "about") +func (svc *service) ServeAboutPage(c *model.Client) (err error) { +	commonData := svc.getCommonData(c, "about")  	data := &renderer.AboutData{  		CommonData: commonData,  	} @@ -565,13 +560,13 @@ func (svc *service) ServeAboutPage(ctx context.Context, c *model.Client) (err er  	return svc.renderer.Render(rCtx, c.Writer, renderer.AboutPage, data)  } -func (svc *service) ServeEmojiPage(ctx context.Context, c *model.Client) (err error) { +func (svc *service) ServeEmojiPage(c *model.Client) (err error) {  	emojis, err := c.GetInstanceEmojis(ctx)  	if err != nil {  		return  	} -	commonData := svc.getCommonData(ctx, c, "emojis") +	commonData := svc.getCommonData(c, "emojis")  	data := &renderer.EmojiData{  		Emojis:     emojis,  		CommonData: commonData, @@ -581,7 +576,7 @@ func (svc *service) ServeEmojiPage(ctx context.Context, c *model.Client) (err er  	return svc.renderer.Render(rCtx, c.Writer, renderer.EmojiPage, data)  } -func (svc *service) ServeSearchPage(ctx context.Context, c *model.Client, +func (svc *service) ServeSearchPage(c *model.Client,  	q string, qType string, offset int) (err error) {  	var nextLink string @@ -602,7 +597,7 @@ func (svc *service) ServeSearchPage(ctx context.Context, c *model.Client,  		title += " \"" + q + "\""  	} -	commonData := svc.getCommonData(ctx, c, title) +	commonData := svc.getCommonData(c, title)  	data := &renderer.SearchData{  		CommonData: commonData,  		Q:          q, @@ -616,8 +611,8 @@ func (svc *service) ServeSearchPage(ctx context.Context, c *model.Client,  	return svc.renderer.Render(rCtx, c.Writer, renderer.SearchPage, data)  } -func (svc *service) ServeSettingsPage(ctx context.Context, c *model.Client) (err error) { -	commonData := svc.getCommonData(ctx, c, "settings") +func (svc *service) ServeSettingsPage(c *model.Client) (err error) { +	commonData := svc.getCommonData(c, "settings")  	data := &renderer.SettingsData{  		CommonData: commonData,  		Settings:   &c.Session.Settings, @@ -627,7 +622,7 @@ func (svc *service) ServeSettingsPage(ctx context.Context, c *model.Client) (err  	return svc.renderer.Render(rCtx, c.Writer, renderer.SettingsPage, data)  } -func (svc *service) SingleInstance(ctx context.Context) (instance string, ok bool) { +func (svc *service) SingleInstance() (instance string, ok bool) {  	if len(svc.singleInstance) > 0 {  		instance = svc.singleInstance  		ok = true @@ -635,7 +630,7 @@ func (svc *service) SingleInstance(ctx context.Context) (instance string, ok boo  	return  } -func (svc *service) NewSession(ctx context.Context, instance string) ( +func (svc *service) NewSession(instance string) (  	redirectUrl string, sessionID string, err error) {  	var instanceURL string @@ -715,8 +710,8 @@ func (svc *service) NewSession(ctx context.Context, instance string) (  	return  } -func (svc *service) Signin(ctx context.Context, c *model.Client, -	sessionID string, code string) (token string, userID string, err error) { +func (svc *service) Signin(c *model.Client, sessionID string, +	code string) (token string, userID string, err error) {  	if len(code) < 1 {  		err = errInvalidArgument @@ -738,12 +733,12 @@ func (svc *service) Signin(ctx context.Context, c *model.Client,  	return  } -func (svc *service) Signout(ctx context.Context, c *model.Client) (err error) { +func (svc *service) Signout(c *model.Client) (err error) {  	svc.sessionRepo.Remove(c.Session.ID)  	return  } -func (svc *service) Post(ctx context.Context, c *model.Client, content string, +func (svc *service) Post(c *model.Client, content string,  	replyToID string, format string, visibility string, isNSFW bool,  	files []*multipart.FileHeader) (id string, err error) { @@ -773,8 +768,7 @@ func (svc *service) Post(ctx context.Context, c *model.Client, content string,  	return s.ID, nil  } -func (svc *service) Like(ctx context.Context, c *model.Client, id string) ( -	count int64, err error) { +func (svc *service) Like(c *model.Client, id string) (count int64, err error) {  	s, err := c.Favourite(ctx, id)  	if err != nil {  		return @@ -783,8 +777,7 @@ func (svc *service) Like(ctx context.Context, c *model.Client, id string) (  	return  } -func (svc *service) UnLike(ctx context.Context, c *model.Client, id string) ( -	count int64, err error) { +func (svc *service) UnLike(c *model.Client, id string) (count int64, err error) {  	s, err := c.Unfavourite(ctx, id)  	if err != nil {  		return @@ -793,8 +786,7 @@ func (svc *service) UnLike(ctx context.Context, c *model.Client, id string) (  	return  } -func (svc *service) Retweet(ctx context.Context, c *model.Client, id string) ( -	count int64, err error) { +func (svc *service) Retweet(c *model.Client, id string) (count int64, err error) {  	s, err := c.Reblog(ctx, id)  	if err != nil {  		return @@ -805,7 +797,7 @@ func (svc *service) Retweet(ctx context.Context, c *model.Client, id string) (  	return  } -func (svc *service) UnRetweet(ctx context.Context, c *model.Client, id string) ( +func (svc *service) UnRetweet(c *model.Client, id string) (  	count int64, err error) {  	s, err := c.Unreblog(ctx, id)  	if err != nil { @@ -815,8 +807,7 @@ func (svc *service) UnRetweet(ctx context.Context, c *model.Client, id string) (  	return  } -func (svc *service) Vote(ctx context.Context, c *model.Client, id string, -	choices []string) (err error) { +func (svc *service) Vote(c *model.Client, id string, choices []string) (err error) {  	_, err = c.Vote(ctx, id, choices)  	if err != nil {  		return @@ -824,76 +815,70 @@ func (svc *service) Vote(ctx context.Context, c *model.Client, id string,  	return  } -func (svc *service) Follow(ctx context.Context, c *model.Client, id string, reblogs *bool) (err error) { +func (svc *service) Follow(c *model.Client, id string, reblogs *bool) (err error) {  	_, err = c.AccountFollow(ctx, id, reblogs)  	return  } -func (svc *service) UnFollow(ctx context.Context, c *model.Client, id string) (err error) { +func (svc *service) UnFollow(c *model.Client, id string) (err error) {  	_, err = c.AccountUnfollow(ctx, id)  	return  } -func (svc *service) Mute(ctx context.Context, c *model.Client, id string) (err error) { +func (svc *service) Mute(c *model.Client, id string) (err error) {  	_, err = c.AccountMute(ctx, id)  	return  } -func (svc *service) UnMute(ctx context.Context, c *model.Client, id string) (err error) { +func (svc *service) UnMute(c *model.Client, id string) (err error) {  	_, err = c.AccountUnmute(ctx, id)  	return  } -func (svc *service) Block(ctx context.Context, c *model.Client, id string) (err error) { +func (svc *service) Block(c *model.Client, id string) (err error) {  	_, err = c.AccountBlock(ctx, id)  	return  } -func (svc *service) UnBlock(ctx context.Context, c *model.Client, id string) (err error) { +func (svc *service) UnBlock(c *model.Client, id string) (err error) {  	_, err = c.AccountUnblock(ctx, id)  	return  } -func (svc *service) Subscribe(ctx context.Context, c *model.Client, id string) (err error) { +func (svc *service) Subscribe(c *model.Client, id string) (err error) {  	_, err = c.Subscribe(ctx, id)  	return  } -func (svc *service) UnSubscribe(ctx context.Context, c *model.Client, id string) (err error) { +func (svc *service) UnSubscribe(c *model.Client, id string) (err error) {  	_, err = c.UnSubscribe(ctx, id)  	return  } -func (svc *service) SaveSettings(ctx context.Context, c *model.Client, -	settings *model.Settings) (err error) { - +func (svc *service) SaveSettings(c *model.Client, s *model.Settings) (err error) {  	session, err := svc.sessionRepo.Get(c.Session.ID)  	if err != nil {  		return  	} -	session.Settings = *settings +	session.Settings = *s  	return svc.sessionRepo.Add(session)  } -func (svc *service) MuteConversation(ctx context.Context, c *model.Client, -	id string) (err error) { +func (svc *service) MuteConversation(c *model.Client, id string) (err error) {  	_, err = c.MuteConversation(ctx, id)  	return  } -func (svc *service) UnMuteConversation(ctx context.Context, c *model.Client, -	id string) (err error) { +func (svc *service) UnMuteConversation(c *model.Client, id string) (err error) {  	_, err = c.UnmuteConversation(ctx, id)  	return  } -func (svc *service) Delete(ctx context.Context, c *model.Client, -	id string) (err error) { +func (svc *service) Delete(c *model.Client, id string) (err error) {  	return c.DeleteStatus(ctx, id)  } -func (svc *service) ReadNotifications(ctx context.Context, c *model.Client, -	maxID string) (err error) { +func (svc *service) ReadNotifications(c *model.Client, maxID string) (err error) {  	return c.ReadNotifications(ctx, maxID)  } diff --git a/service/transport.go b/service/transport.go index 840f4cc..8dccd92 100644 --- a/service/transport.go +++ b/service/transport.go @@ -1,7 +1,6 @@  package service  import ( -	"context"  	"encoding/json"  	"io"  	"mime/multipart" @@ -18,9 +17,20 @@ const (  	sessionExp = 365 * 24 * time.Hour  ) -func newClient(w io.Writer) *model.Client { +func newClient(w io.Writer, req *http.Request, csrfToken string) *model.Client { +	var sessionID string +	if req != nil { +		c, err := req.Cookie("session_id") +		if err == nil { +			sessionID = c.Value +		} +	}  	return &model.Client{  		Writer: w, +		Ctx: model.ClientCtx{ +			SessionID: sessionID, +			CSRFToken: csrfToken, +		},  	}  } @@ -32,20 +42,6 @@ func setSessionCookie(w http.ResponseWriter, sessionID string, exp time.Duration  	})  } -func newCtxWithSesion(req *http.Request) context.Context { -	ctx := context.Background() -	sessionID, err := req.Cookie("session_id") -	if err != nil { -		return ctx -	} -	return context.WithValue(ctx, "session_id", sessionID.Value) -} - -func newCtxWithSesionCSRF(req *http.Request, csrfToken string) context.Context { -	ctx := newCtxWithSesion(req) -	return context.WithValue(ctx, "csrf_token", csrfToken) -} -  func getMultipartFormValue(mf *multipart.Form, key string) (val string) {  	vals, ok := mf.Value[key]  	if !ok { @@ -77,12 +73,11 @@ func NewHandler(s Service, staticDir string) http.Handler {  	rootPage := func(w http.ResponseWriter, req *http.Request) {  		sessionID, _ := req.Cookie("session_id")  		if sessionID != nil && len(sessionID.Value) > 0 { -			c := newClient(w) -			ctx := newCtxWithSesion(req) -			err := s.ServeRootPage(ctx, c) +			c := newClient(w, req, "") +			err := s.ServeRootPage(c)  			if err != nil {  				w.WriteHeader(http.StatusInternalServerError) -				s.ServeErrorPage(ctx, c, err) +				s.ServeErrorPage(c, err)  				return  			}  		} else { @@ -92,25 +87,23 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	navPage := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesion(req) -		err := s.ServeNavPage(ctx, c) +		c := newClient(w, req, "") +		err := s.ServeNavPage(c)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		}  	}  	signinPage := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := context.Background() -		instance, ok := s.SingleInstance(ctx) +		c := newClient(w, nil, "") +		instance, ok := s.SingleInstance()  		if ok { -			url, sessionID, err := s.NewSession(ctx, instance) +			url, sessionID, err := s.NewSession(instance)  			if err != nil {  				w.WriteHeader(http.StatusInternalServerError) -				s.ServeErrorPage(ctx, c, err) +				s.ServeErrorPage(c, err)  				return  			} @@ -118,108 +111,101 @@ func NewHandler(s Service, staticDir string) http.Handler {  			w.Header().Add("Location", url)  			w.WriteHeader(http.StatusFound)  		} else { -			err := s.ServeSigninPage(ctx, c) +			err := s.ServeSigninPage(c)  			if err != nil {  				w.WriteHeader(http.StatusInternalServerError) -				s.ServeErrorPage(ctx, c, err) +				s.ServeErrorPage(c, err)  				return  			}  		}  	}  	timelinePage := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesion(req) +		c := newClient(w, req, "")  		tType, _ := mux.Vars(req)["type"]  		maxID := req.URL.Query().Get("max_id")  		minID := req.URL.Query().Get("min_id") -		err := s.ServeTimelinePage(ctx, c, tType, maxID, minID) +		err := s.ServeTimelinePage(c, tType, maxID, minID)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		}  	} -	timelineOldPage := func(w http.ResponseWriter, req *http.Request) { +	defaultTimelinePage := func(w http.ResponseWriter, req *http.Request) {  		w.Header().Add("Location", "/timeline/home")  		w.WriteHeader(http.StatusFound)  	}  	threadPage := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesion(req) +		c := newClient(w, req, "")  		id, _ := mux.Vars(req)["id"]  		reply := req.URL.Query().Get("reply") -		err := s.ServeThreadPage(ctx, c, id, len(reply) > 1) +		err := s.ServeThreadPage(c, id, len(reply) > 1)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		}  	}  	likedByPage := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesion(req) +		c := newClient(w, req, "")  		id, _ := mux.Vars(req)["id"] -		err := s.ServeLikedByPage(ctx, c, id) +		err := s.ServeLikedByPage(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		}  	}  	retweetedByPage := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesion(req) +		c := newClient(w, req, "")  		id, _ := mux.Vars(req)["id"] -		err := s.ServeRetweetedByPage(ctx, c, id) +		err := s.ServeRetweetedByPage(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		}  	}  	notificationsPage := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesion(req) +		c := newClient(w, req, "")  		maxID := req.URL.Query().Get("max_id")  		minID := req.URL.Query().Get("min_id") -		err := s.ServeNotificationPage(ctx, c, maxID, minID) +		err := s.ServeNotificationPage(c, maxID, minID)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		}  	}  	userPage := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesion(req) +		c := newClient(w, req, "")  		id, _ := mux.Vars(req)["id"]  		pageType, _ := mux.Vars(req)["type"]  		maxID := req.URL.Query().Get("max_id")  		minID := req.URL.Query().Get("min_id") -		err := s.ServeUserPage(ctx, c, id, pageType, maxID, minID) +		err := s.ServeUserPage(c, id, pageType, maxID, minID)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		}  	}  	userSearchPage := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesion(req) +		c := newClient(w, req, "")  		id, _ := mux.Vars(req)["id"]  		q := req.URL.Query().Get("q")  		offsetStr := req.URL.Query().Get("offset") @@ -230,46 +216,43 @@ func NewHandler(s Service, staticDir string) http.Handler {  			offset, err = strconv.Atoi(offsetStr)  			if err != nil {  				w.WriteHeader(http.StatusInternalServerError) -				s.ServeErrorPage(ctx, c, err) +				s.ServeErrorPage(c, err)  				return  			}  		} -		err = s.ServeUserSearchPage(ctx, c, id, q, offset) +		err = s.ServeUserSearchPage(c, id, q, offset)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		}  	}  	aboutPage := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesion(req) +		c := newClient(w, req, "") -		err := s.ServeAboutPage(ctx, c) +		err := s.ServeAboutPage(c)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		}  	}  	emojisPage := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesion(req) +		c := newClient(w, req, "") -		err := s.ServeEmojiPage(ctx, c) +		err := s.ServeEmojiPage(c)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		}  	}  	searchPage := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesion(req) +		c := newClient(w, req, "")  		q := req.URL.Query().Get("q")  		qType := req.URL.Query().Get("type")  		offsetStr := req.URL.Query().Get("offset") @@ -280,40 +263,38 @@ func NewHandler(s Service, staticDir string) http.Handler {  			offset, err = strconv.Atoi(offsetStr)  			if err != nil {  				w.WriteHeader(http.StatusInternalServerError) -				s.ServeErrorPage(ctx, c, err) +				s.ServeErrorPage(c, err)  				return  			}  		} -		err = s.ServeSearchPage(ctx, c, q, qType, offset) +		err = s.ServeSearchPage(c, q, qType, offset)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		}  	}  	settingsPage := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesion(req) +		c := newClient(w, req, "") -		err := s.ServeSettingsPage(ctx, c) +		err := s.ServeSettingsPage(c)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		}  	}  	signin := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := context.Background() +		c := newClient(w, nil, "")  		instance := req.FormValue("instance") -		url, sessionID, err := s.NewSession(ctx, instance) +		url, sessionID, err := s.NewSession(instance)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -323,14 +304,13 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	oauthCallback := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesion(req) +		c := newClient(w, req, "")  		token := req.URL.Query().Get("code") -		_, _, err := s.Signin(ctx, c, "", token) +		_, _, err := s.Signin(c, "", token)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -339,15 +319,15 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	post := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) +		c := newClient(w, req, "")  		err := req.ParseMultipartForm(4 << 20)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(context.Background(), c, err) +			s.ServeErrorPage(c, err)  			return  		} -		ctx := newCtxWithSesionCSRF(req, +		c = newClient(w, req,  			getMultipartFormValue(req.MultipartForm, "csrf_token"))  		content := getMultipartFormValue(req.MultipartForm, "content")  		replyToID := getMultipartFormValue(req.MultipartForm, "reply_to_id") @@ -356,10 +336,10 @@ func NewHandler(s Service, staticDir string) http.Handler {  		isNSFW := "on" == getMultipartFormValue(req.MultipartForm, "is_nsfw")  		files := req.MultipartForm.File["attachments"] -		id, err := s.Post(ctx, c, content, replyToID, format, visibility, isNSFW, files) +		id, err := s.Post(c, content, replyToID, format, visibility, isNSFW, files)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -372,15 +352,14 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	like := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"]  		retweetedByID := req.FormValue("retweeted_by_id") -		_, err := s.Like(ctx, c, id) +		_, err := s.Like(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -393,15 +372,14 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	unlike := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"]  		retweetedByID := req.FormValue("retweeted_by_id") -		_, err := s.UnLike(ctx, c, id) +		_, err := s.UnLike(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -414,15 +392,14 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	retweet := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"]  		retweetedByID := req.FormValue("retweeted_by_id") -		_, err := s.Retweet(ctx, c, id) +		_, err := s.Retweet(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -435,15 +412,14 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	unretweet := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"]  		retweetedByID := req.FormValue("retweeted_by_id") -		_, err := s.UnRetweet(ctx, c, id) +		_, err := s.UnRetweet(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -457,16 +433,15 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	vote := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"]  		statusID := req.FormValue("status_id")  		choices, _ := req.PostForm["choices"] -		err := s.Vote(ctx, c, id, choices) +		err := s.Vote(c, id, choices)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -475,8 +450,7 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	follow := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"]  		var reblogs *bool @@ -486,10 +460,10 @@ func NewHandler(s Service, staticDir string) http.Handler {  			*reblogs = r[0] == "true"  		} -		err := s.Follow(ctx, c, id, reblogs) +		err := s.Follow(c, id, reblogs)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -498,14 +472,13 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	unfollow := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"] -		err := s.UnFollow(ctx, c, id) +		err := s.UnFollow(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -514,14 +487,13 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	mute := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"] -		err := s.Mute(ctx, c, id) +		err := s.Mute(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -530,14 +502,13 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	unMute := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"] -		err := s.UnMute(ctx, c, id) +		err := s.UnMute(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -546,14 +517,13 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	block := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"] -		err := s.Block(ctx, c, id) +		err := s.Block(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -562,14 +532,13 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	unBlock := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"] -		err := s.UnBlock(ctx, c, id) +		err := s.UnBlock(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -578,14 +547,13 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	subscribe := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"] -		err := s.Subscribe(ctx, c, id) +		err := s.Subscribe(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -594,14 +562,13 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	unSubscribe := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"] -		err := s.UnSubscribe(ctx, c, id) +		err := s.UnSubscribe(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -610,8 +577,7 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	settings := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		visibility := req.FormValue("visibility")  		copyScope := req.FormValue("copy_scope") == "true"  		threadInNewTab := req.FormValue("thread_in_new_tab") == "true" @@ -632,10 +598,10 @@ func NewHandler(s Service, staticDir string) http.Handler {  			DarkMode:                 darkMode,  		} -		err := s.SaveSettings(ctx, c, settings) +		err := s.SaveSettings(c, settings)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -644,14 +610,13 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	muteConversation := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"] -		err := s.MuteConversation(ctx, c, id) +		err := s.MuteConversation(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -660,14 +625,13 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	unMuteConversation := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"] -		err := s.UnMuteConversation(ctx, c, id) +		err := s.UnMuteConversation(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -676,14 +640,13 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	delete := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"] -		err := s.Delete(ctx, c, id) +		err := s.Delete(c, id)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -692,14 +655,13 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	readNotifications := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		maxID := req.URL.Query().Get("max_id") -		err := s.ReadNotifications(ctx, c, maxID) +		err := s.ReadNotifications(c, maxID)  		if err != nil {  			w.WriteHeader(http.StatusInternalServerError) -			s.ServeErrorPage(ctx, c, err) +			s.ServeErrorPage(c, err)  			return  		} @@ -708,10 +670,9 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	signout := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token")) -		s.Signout(ctx, c) +		s.Signout(c)  		setSessionCookie(w, "", 0)  		w.Header().Add("Location", "/") @@ -719,11 +680,10 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	fLike := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"] -		count, err := s.Like(ctx, c, id) +		count, err := s.Like(c, id)  		if err != nil {  			serveJsonError(w, err)  			return @@ -737,10 +697,10 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	fUnlike := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"] -		count, err := s.UnLike(ctx, c, id) + +		count, err := s.UnLike(c, id)  		if err != nil {  			serveJsonError(w, err)  			return @@ -754,11 +714,10 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	fRetweet := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"] -		count, err := s.Retweet(ctx, c, id) +		count, err := s.Retweet(c, id)  		if err != nil {  			serveJsonError(w, err)  			return @@ -772,11 +731,10 @@ func NewHandler(s Service, staticDir string) http.Handler {  	}  	fUnretweet := func(w http.ResponseWriter, req *http.Request) { -		c := newClient(w) -		ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token")) +		c := newClient(w, req, req.FormValue("csrf_token"))  		id, _ := mux.Vars(req)["id"] -		count, err := s.UnRetweet(ctx, c, id) +		count, err := s.UnRetweet(c, id)  		if err != nil {  			serveJsonError(w, err)  			return @@ -792,9 +750,8 @@ func NewHandler(s Service, staticDir string) http.Handler {  	r.HandleFunc("/", rootPage).Methods(http.MethodGet)  	r.HandleFunc("/nav", navPage).Methods(http.MethodGet)  	r.HandleFunc("/signin", signinPage).Methods(http.MethodGet) -	r.HandleFunc("//{type}", timelinePage).Methods(http.MethodGet)  	r.HandleFunc("/timeline/{type}", timelinePage).Methods(http.MethodGet) -	r.HandleFunc("/timeline", timelineOldPage).Methods(http.MethodGet) +	r.HandleFunc("/timeline", defaultTimelinePage).Methods(http.MethodGet)  	r.HandleFunc("/thread/{id}", threadPage).Methods(http.MethodGet)  	r.HandleFunc("/likedby/{id}", likedByPage).Methods(http.MethodGet)  	r.HandleFunc("/retweetedby/{id}", retweetedByPage).Methods(http.MethodGet) | 
