view auth/connection.go @ 204:3d0988d9f867

De-virtualize the connection pool implementation. The persistent connection pool implementation is a superset of the in-memory implementation. The only diffence in fact is that the in-memory variant does not store anything to file. So the persistent implementation is refactored in a way that it checks before each persistence operation if storage is given or not.
author Sascha L. Teichmann <teichmann@intevation.de>
date Sun, 22 Jul 2018 10:23:03 +0200
parents c20e86a3c073
children f345edb409b2
line wrap: on
line source

package auth

import (
	"database/sql"
	"encoding/binary"
	"errors"
	"io"
	"log"
	"sync"
	"time"

	"gemma.intevation.de/gemma/config"
)

var ErrNoSuchToken = errors.New("No such token")

var ConnPool = func() *ConnectionPool {
	cp, err := NewConnectionPool(config.Config.SessionStore)
	if err != nil {
		log.Panicf("Error with session store: %v\n", err)
	}
	return cp
}()

const (
	maxOpen   = 16
	maxDBIdle = time.Minute * 5
)

type Connection struct {
	session *Session

	access   time.Time
	db       *sql.DB
	refCount int

	mu sync.Mutex
}

func (c *Connection) serialize(w io.Writer) error {
	if err := c.session.serialize(w); err != nil {
		return err
	}
	access, err := c.last().MarshalText()
	if err == nil {
		err = binary.Write(w, binary.BigEndian, string(access))
	}
	return err
}

func (c *Connection) deserialize(r io.Reader) error {
	session := new(Session)
	if err := session.deserialize(r); err != nil {
		return err
	}

	var access string
	if err := binary.Read(r, binary.BigEndian, &access); err != nil {
		return err
	}

	var t time.Time
	if err := t.UnmarshalText([]byte(access)); err != nil {
		return err
	}

	*c = Connection{
		session: session,
		access:  t,
	}

	return nil
}

func (c *Connection) set(session *Session) {
	c.session = session
	c.touch()
}

func (c *Connection) touch() {
	c.mu.Lock()
	c.access = time.Now()
	c.mu.Unlock()
}

func (c *Connection) last() time.Time {
	c.mu.Lock()
	access := c.access
	c.mu.Unlock()
	return access
}

func (c *Connection) close() {
	if c.db != nil {
		if err := c.db.Close(); err != nil {
			log.Printf("warn: %v\n", err)
		}
		c.db = nil
	}
}