func (m *TunnelMap) Remove(uuid string) (*LastAccessedTunnel, bool) {
	m.Lock()
	defer m.Unlock()
	v, ok := m.tunnelMap[uuid]
	if ok {
		delete(m.tunnelMap, uuid)
	}
	return v, ok
}
Remove removes the Tunnel having the given UUID, if such a tunnel exists. The original tunnel is returned.
package guac
import (
	"github.com/sirupsen/logrus"
	"sync"
	"time"
)
type LastAccessedTunnel struct {
	sync.RWMutex
	Tunnel
	lastAccessedTime time.Time
}
func NewLastAccessedTunnel(tunnel Tunnel) (ret LastAccessedTunnel) {
	ret.Tunnel = tunnel
	ret.Access()
	return
}
func (t *LastAccessedTunnel) Access() {
	t.Lock()
	t.lastAccessedTime = time.Now()
	t.Unlock()
}
func (t *LastAccessedTunnel) GetLastAccessedTime() time.Time {
	t.RLock()
	defer t.RUnlock()
	return t.lastAccessedTime
}
const TunnelTimeout = 15 * time.Second
type TunnelMap struct {
	sync.RWMutex
	ticker *time.Ticker
	tunnelTimeout time.Duration
	tunnelMap     map[string]*LastAccessedTunnel
}
func NewTunnelMap() *TunnelMap {
	tunnelMap := &TunnelMap{
		ticker:        time.NewTicker(TunnelTimeout),
		tunnelMap:     make(map[string]*LastAccessedTunnel),
		tunnelTimeout: TunnelTimeout,
	}
	go tunnelMap.tunnelTimeoutTask()
	return tunnelMap
}
func (m *TunnelMap) tunnelTimeoutTask() {
	for {
		_, ok := <-m.ticker.C
		if !ok {
			break
		}
		m.tunnelTimeoutTaskRun()
	}
}
func (m *TunnelMap) tunnelTimeoutTaskRun() {
	timeLine := time.Now().Add(0 - m.tunnelTimeout)
	type pair struct {
		uuid   string
		tunnel *LastAccessedTunnel
	}
	var removeIDs []pair
	m.RLock()
	for uuid, tunnel := range m.tunnelMap {
		if tunnel.GetLastAccessedTime().Before(timeLine) {
			removeIDs = append(removeIDs, pair{uuid: uuid, tunnel: tunnel})
		}
	}
	m.RUnlock()
	m.Lock()
	for _, double := range removeIDs {
		logrus.Debugf("HTTP tunnel \"%v\" has timed out.", double.uuid)
		delete(m.tunnelMap, double.uuid)
		if double.tunnel != nil {
			err := double.tunnel.Close()
			if err != nil {
				logrus.Debug("Unable to close expired HTTP tunnel.", err)
			}
		}
	}
	m.Unlock()
	return
}
func (m *TunnelMap) Get(uuid string) (tunnel *LastAccessedTunnel, ok bool) {
	m.RLock()
	tunnel, ok = m.tunnelMap[uuid]
	m.RUnlock()
	if ok && tunnel != nil {
		tunnel.Access()
	} else {
		ok = false
	}
	return
}
func (m *TunnelMap) Put(uuid string, tunnel Tunnel) {
	m.Lock()
	one := NewLastAccessedTunnel(tunnel)
	m.tunnelMap[uuid] = &one
	m.Unlock()
}