From efd401bfbf62b2216fe92b4d8be8c07e77b78482 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 9 Dec 2019 18:16:27 +0100 Subject: Rename ConnPool to SessionManager --- conn_pool.go | 91 ------------------------------------------------------------ handlers.go | 2 +- server.go | 8 +++--- session.go | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 96 deletions(-) delete mode 100644 conn_pool.go create mode 100644 session.go diff --git a/conn_pool.go b/conn_pool.go deleted file mode 100644 index 34c51bb..0000000 --- a/conn_pool.go +++ /dev/null @@ -1,91 +0,0 @@ -package koushin - -import ( - "crypto/rand" - "encoding/base64" - "errors" - "sync" - - imapclient "github.com/emersion/go-imap/client" -) - -func generateToken() (string, error) { - b := make([]byte, 32) - _, err := rand.Read(b) - if err != nil { - return "", err - } - return base64.URLEncoding.EncodeToString(b), nil -} - -var ErrSessionExpired = errors.New("session expired") - -type Session struct { - locker sync.Mutex - imapConn *imapclient.Client - 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 -type ConnPool struct { - locker sync.Mutex - sessions map[string]*Session -} - -func NewConnPool() *ConnPool { - return &ConnPool{ - sessions: make(map[string]*Session), - } -} - -func (pool *ConnPool) Get(token string) (*Session, error) { - pool.locker.Lock() - defer pool.locker.Unlock() - - session, ok := pool.sessions[token] - if !ok { - return nil, ErrSessionExpired - } - return session, nil -} - -func (pool *ConnPool) Put(imapConn *imapclient.Client, username, password string) (token string, err error) { - pool.locker.Lock() - defer pool.locker.Unlock() - - for { - var err error - token, err = generateToken() - if err != nil { - imapConn.Logout() - return "", err - } - - if _, ok := pool.sessions[token]; !ok { - break - } - } - - pool.sessions[token] = &Session{ - imapConn: imapConn, - username: username, - password: password, - } - - go func() { - <-imapConn.LoggedOut() - - pool.locker.Lock() - delete(pool.sessions, token) - pool.locker.Unlock() - }() - - return token, nil -} diff --git a/handlers.go b/handlers.go index 238b9ba..8dc3fbf 100644 --- a/handlers.go +++ b/handlers.go @@ -91,7 +91,7 @@ func handleLogin(ectx echo.Context) error { return ctx.Render(http.StatusOK, "login.html", nil) } - token, err := ctx.server.imap.pool.Put(conn, username, password) + token, err := ctx.server.sessions.Put(conn, username, password) if err != nil { return fmt.Errorf("failed to put connection in pool: %v", err) } diff --git a/server.go b/server.go index 501f503..a0ac1d3 100644 --- a/server.go +++ b/server.go @@ -15,12 +15,12 @@ const cookieName = "koushin_session" const messagesPerPage = 50 type Server struct { + sessions *SessionManager + imap struct { host string tls bool insecure bool - - pool *ConnPool } smtp struct { @@ -76,11 +76,11 @@ func (s *Server) parseSMTPURL(smtpURL string) error { func newServer(imapURL, smtpURL string) (*Server, error) { s := &Server{} + s.sessions = NewSessionManager() if err := s.parseIMAPURL(imapURL); err != nil { return nil, err } - s.imap.pool = NewConnPool() if smtpURL != "" { if err := s.parseSMTPURL(smtpURL); err != nil { @@ -166,7 +166,7 @@ func New(e *echo.Echo, options *Options) error { return err } - ctx.session, err = ctx.server.imap.pool.Get(cookie.Value) + ctx.session, err = ctx.server.sessions.Get(cookie.Value) if err == ErrSessionExpired { ctx.setToken("") return ctx.Redirect(http.StatusFound, "/login") diff --git a/session.go b/session.go new file mode 100644 index 0000000..0aa5d5f --- /dev/null +++ b/session.go @@ -0,0 +1,91 @@ +package koushin + +import ( + "crypto/rand" + "encoding/base64" + "errors" + "sync" + + imapclient "github.com/emersion/go-imap/client" +) + +func generateToken() (string, error) { + b := make([]byte, 32) + _, err := rand.Read(b) + if err != nil { + return "", err + } + return base64.URLEncoding.EncodeToString(b), nil +} + +var ErrSessionExpired = errors.New("session expired") + +type Session struct { + locker sync.Mutex + imapConn *imapclient.Client + 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 +type SessionManager struct { + locker sync.Mutex + sessions map[string]*Session +} + +func NewSessionManager() *SessionManager { + return &SessionManager{ + sessions: make(map[string]*Session), + } +} + +func (sm *SessionManager) Get(token string) (*Session, error) { + sm.locker.Lock() + defer sm.locker.Unlock() + + session, ok := sm.sessions[token] + if !ok { + return nil, ErrSessionExpired + } + return session, nil +} + +func (sm *SessionManager) Put(imapConn *imapclient.Client, username, password string) (token string, err error) { + sm.locker.Lock() + defer sm.locker.Unlock() + + for { + var err error + token, err = generateToken() + if err != nil { + imapConn.Logout() + return "", err + } + + if _, ok := sm.sessions[token]; !ok { + break + } + } + + sm.sessions[token] = &Session{ + imapConn: imapConn, + username: username, + password: password, + } + + go func() { + <-imapConn.LoggedOut() + + sm.locker.Lock() + delete(sm.sessions, token) + sm.locker.Unlock() + }() + + return token, nil +} -- cgit v1.2.3