Add session lock
HTTP requests can be processed in parallel, but we only have one IMAP connection per session. Closes: https://todo.sr.ht/~sircmpwn/koushin/12
This commit is contained in:
parent
ec03c60dff
commit
48d6d5d227
3 changed files with 45 additions and 16 deletions
|
@ -21,10 +21,18 @@ func generateToken() (string, error) {
|
||||||
var ErrSessionExpired = errors.New("session expired")
|
var ErrSessionExpired = errors.New("session expired")
|
||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
|
locker sync.Mutex
|
||||||
imapConn *imapclient.Client
|
imapConn *imapclient.Client
|
||||||
username, password string
|
username, password string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Session) Do(f func(*imapclient.Client) error) error {
|
||||||
|
s.locker.Lock()
|
||||||
|
defer s.locker.Unlock()
|
||||||
|
|
||||||
|
return f(s.imapConn)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: expiration timer
|
// TODO: expiration timer
|
||||||
type ConnPool struct {
|
type ConnPool struct {
|
||||||
locker sync.Mutex
|
locker sync.Mutex
|
||||||
|
|
45
server.go
45
server.go
|
@ -9,7 +9,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/emersion/go-imap"
|
||||||
imapclient "github.com/emersion/go-imap/client"
|
imapclient "github.com/emersion/go-imap/client"
|
||||||
|
"github.com/emersion/go-message"
|
||||||
"github.com/emersion/go-sasl"
|
"github.com/emersion/go-sasl"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
@ -95,7 +97,6 @@ type context struct {
|
||||||
echo.Context
|
echo.Context
|
||||||
server *Server
|
server *Server
|
||||||
session *Session
|
session *Session
|
||||||
conn *imapclient.Client
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var aLongTimeAgo = time.Unix(233431200, 0)
|
var aLongTimeAgo = time.Unix(233431200, 0)
|
||||||
|
@ -152,7 +153,15 @@ func handleGetPart(ctx *context, raw bool) error {
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, err)
|
return echo.NewHTTPError(http.StatusBadRequest, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
msg, part, err := getMessagePart(ctx.conn, mboxName, uid, partPath)
|
var msg *imapMessage
|
||||||
|
var part *message.Entity
|
||||||
|
var mbox *imap.MailboxStatus
|
||||||
|
err = ctx.session.Do(func(c *imapclient.Client) error {
|
||||||
|
var err error
|
||||||
|
msg, part, err = getMessagePart(c, mboxName, uid, partPath)
|
||||||
|
mbox = c.Mailbox()
|
||||||
|
return err
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -192,7 +201,7 @@ func handleGetPart(ctx *context, raw bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.Render(http.StatusOK, "message.html", map[string]interface{}{
|
return ctx.Render(http.StatusOK, "message.html", map[string]interface{}{
|
||||||
"Mailbox": ctx.conn.Mailbox(),
|
"Mailbox": mbox,
|
||||||
"Message": msg,
|
"Message": msg,
|
||||||
"Body": body,
|
"Body": body,
|
||||||
"PartPath": partPathString,
|
"PartPath": partPathString,
|
||||||
|
@ -290,7 +299,6 @@ func New(imapURL, smtpURL string) *echo.Echo {
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ctx.conn = ctx.session.imapConn
|
|
||||||
|
|
||||||
return next(ctx)
|
return next(ctx)
|
||||||
}
|
}
|
||||||
|
@ -304,18 +312,26 @@ func New(imapURL, smtpURL string) *echo.Echo {
|
||||||
e.GET("/mailbox/:mbox", func(ectx echo.Context) error {
|
e.GET("/mailbox/:mbox", func(ectx echo.Context) error {
|
||||||
ctx := ectx.(*context)
|
ctx := ectx.(*context)
|
||||||
|
|
||||||
mailboxes, err := listMailboxes(ctx.conn)
|
var mailboxes []*imap.MailboxInfo
|
||||||
if err != nil {
|
var msgs []imapMessage
|
||||||
return err
|
var mbox *imap.MailboxStatus
|
||||||
}
|
err = ctx.session.Do(func(c *imapclient.Client) error {
|
||||||
|
var err error
|
||||||
msgs, err := listMessages(ctx.conn, ctx.Param("mbox"))
|
if mailboxes, err = listMailboxes(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if msgs, err = listMessages(c, ctx.Param("mbox")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mbox = c.Mailbox()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.Render(http.StatusOK, "mailbox.html", map[string]interface{}{
|
return ctx.Render(http.StatusOK, "mailbox.html", map[string]interface{}{
|
||||||
"Mailbox": ctx.conn.Mailbox(),
|
"Mailbox": mbox,
|
||||||
"Mailboxes": mailboxes,
|
"Mailboxes": mailboxes,
|
||||||
"Messages": msgs,
|
"Messages": msgs,
|
||||||
})
|
})
|
||||||
|
@ -335,9 +351,14 @@ func New(imapURL, smtpURL string) *echo.Echo {
|
||||||
|
|
||||||
e.GET("/logout", func(ectx echo.Context) error {
|
e.GET("/logout", func(ectx echo.Context) error {
|
||||||
ctx := ectx.(*context)
|
ctx := ectx.(*context)
|
||||||
if err := ctx.conn.Logout(); err != nil {
|
|
||||||
|
err := ctx.session.Do(func(c *imapclient.Client) error {
|
||||||
|
return c.Logout()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
return fmt.Errorf("failed to logout: %v", err)
|
return fmt.Errorf("failed to logout: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.setToken("")
|
ctx.setToken("")
|
||||||
return ctx.Redirect(http.StatusFound, "/login")
|
return ctx.Redirect(http.StatusFound, "/login")
|
||||||
})
|
})
|
||||||
|
|
8
smtp.go
8
smtp.go
|
@ -2,8 +2,8 @@ package koushin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
"io"
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/emersion/go-message/mail"
|
"github.com/emersion/go-message/mail"
|
||||||
"github.com/emersion/go-smtp"
|
"github.com/emersion/go-smtp"
|
||||||
|
@ -34,10 +34,10 @@ func (s *Server) connectSMTP() (*smtp.Client, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type OutgoingMessage struct {
|
type OutgoingMessage struct {
|
||||||
From string
|
From string
|
||||||
To []string
|
To []string
|
||||||
Subject string
|
Subject string
|
||||||
Text string
|
Text string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *OutgoingMessage) WriteTo(w io.Writer) error {
|
func (msg *OutgoingMessage) WriteTo(w io.Writer) error {
|
||||||
|
|
Loading…
Reference in a new issue