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 { imapConn *imapclient.Client username, password string } // 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 }