view auth/connection.go @ 196:b67208d82543

Make test output more comprehensive Running all tests in one transaction ensures the final output tells about any failing test, not just in the last transaction (i.e. test script). The price is that no traces of the tests are left in the database because we have to rollback in order to have no left-over test roles in the cluster.
author Tom Gottfried <tom@intevation.de>
date Fri, 20 Jul 2018 18:31:45 +0200
parents 1585c334e8a7
children e85413e5befa
line wrap: on
line source

package auth

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

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

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

type ConnectionPool interface {
	Delete(token string) bool
	Add(token string, session *Session) *Connection
	Renew(token string) (string, error)
	Do(token string, fn func(*sql.DB) error) error
	Session(token string) *Session
	Shutdown() error
}

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

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() []byte {
	var buf bytes.Buffer
	c.session.serialize(&buf)
	access, _ := c.last().MarshalText()
	binary.Write(&buf, binary.BigEndian, string(access))
	return buf.Bytes()
}

func (c *Connection) unserialize(r io.Reader) error {
	session := new(Session)
	if err := session.unserialize(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
	}
}