func NewSimpleRouter(fe, be core.Stream) Router {
	return &simpleRouter{
		backendPid: 0,
		secretKey:  0,
		fe:         fe,
		be:         be,
	}
}
Make a new Router that captures cancellation data and ferries
messages back and forth for the two streams. Flush the "to" stream
when no more messages are available on the "from" stream, in both
directions.
package femebe
import (
	"crypto/tls"
	"errors"
	"fmt"
	"github.com/uhoh-itsmaciek/femebe/core"
	"github.com/uhoh-itsmaciek/femebe/proto"
	"github.com/uhoh-itsmaciek/femebe/util"
	"sync"
)
type SessionManager interface {
	RunSession(session Session) error
	Cancel(backendPid, secretKey uint32) error
}
type BackendKeyHolder interface {
	BackendKeyData() (uint32, uint32)
}
type Router interface {
	BackendKeyHolder
	RouteFrontend() error
	RouteBackend() error
}
type Resolver interface {
	Resolve(params map[string]string) Connector
}
type Canceller interface {
	Cancel(backendPid, secretKey uint32) error
}
type Connector interface {
	Canceller
	Startup() (core.Stream, error)
}
type Session interface {
	BackendKeyHolder
	Canceller
	Run() error
}
type simpleSessionManager struct {
	sessions    []Session
	sessionLock sync.Mutex
}
func NewSimpleSessionManager() SessionManager {
	return &simpleSessionManager{}
}
func (s *simpleSessionManager) RunSession(session Session) error {
	s.sessionLock.Lock()
	s.sessions = append(s.sessions, session)
	s.sessionLock.Unlock()
	err := session.Run()
	s.sessionLock.Lock()
	for i, si := range s.sessions {
		if si == session {
			copy(s.sessions[i:], s.sessions[i+1:])
			s.sessions[len(s.sessions)-1] = nil
			s.sessions = s.sessions[:len(s.sessions)-1]
			break
		}
	}
	s.sessionLock.Unlock()
	return err
}
func (s *simpleSessionManager) Cancel(backendPid, secretKey uint32) error {
	for _, session := range s.sessions {
		if p, k := session.BackendKeyData(); p == backendPid && k == secretKey {
			s.sessionLock.Lock()
			defer s.sessionLock.Unlock()
			return session.Cancel(backendPid, secretKey)
		}
	}
	return errors.New("not found")
}
type simpleConnector struct {
	backendAddr string
	opts        map[string]string
}
func NewSimpleConnector(target string, options map[string]string) Connector {
	return &simpleConnector{backendAddr: target, opts: options}
}
func (c *simpleConnector) dial() (core.Stream, error) {
	bareConn, err := util.AutoDial(c.backendAddr)
	if err != nil {
		return nil, fmt.Errorf("could not connect to %v: %v", c.backendAddr, err)
	}
	beConn, err := util.NegotiateTLS(bareConn, &util.SSLConfig{
		Mode:   util.SSLPrefer,
		Config: tls.Config{InsecureSkipVerify: true},
	})
	if err != nil {
		return nil, fmt.Errorf("could not negotiate TLS: %v", err)
	}
	return core.NewBackendStream(beConn), nil
}
func (c *simpleConnector) Startup() (core.Stream, error) {
	beStream, err := c.dial()
	if err != nil {
		return nil, err
	}
	var startup core.Message
	proto.InitStartupMessage(&startup, c.opts)
	err = beStream.Send(&startup)
	if err != nil {
		return nil, err
	}
	return beStream, nil
}
func (c *simpleConnector) Cancel(backendPid, secretKey uint32) error {
	beStream, err := c.dial()
	defer beStream.Close()
	if err != nil {
		return err
	}
	var cancel core.Message
	proto.InitCancelRequest(&cancel, backendPid, secretKey)
	return beStream.Send(&cancel)
}
type simpleRouter struct {
	backendPid uint32
	secretKey  uint32
	fe         core.Stream
	be         core.Stream
	feBuf      core.Message
	beBuf      core.Message
}