func (s *Session) CommandRequest(cmd string, msg *Message) (*Message, error) {
	resp, err := s.sendRequest(cmd, msg)
	if err != nil {
		return nil, err
	}
	return resp, resp.Err()
}
CommandRequest sends a command request to the server, and returns the server's response.
The command is specified by cmd, and its arguments are provided by msg. If there is an
error communicating with the daemon, a nil Message and non-nil error are returned. If
the command fails, the response Message is returned along with the error returned by
Message.Err.
package vici
import (
	"context"
	"net"
	"sync"
)
type Session struct {
	mu  sync.Mutex
	ctr *transport
	el *eventListener
	*sessionOpts
}
func NewSession(opts ...SessionOption) (*Session, error) {
	s := &Session{
		sessionOpts: &sessionOpts{
			network: "unix",
			addr:    defaultSocketPath,
			dialer:  (&net.Dialer{}).DialContext,
			conn:    nil,
		},
	}
	for _, opt := range opts {
		opt.apply(s.sessionOpts)
	}
	ctr, err := s.newTransport()
	if err != nil {
		return nil, err
	}
	s.ctr = ctr
	elt, err := s.newTransport()
	if err != nil {
		return nil, err
	}
	s.el = newEventListener(elt)
	return s, nil
}
func (s *Session) newTransport() (*transport, error) {
	if s.conn != nil {
		return &transport{conn: s.conn}, nil
	}
	conn, err := s.dialer(context.Background(), s.network, s.addr)
	if err != nil {
		return nil, err
	}
	t := &transport{
		conn: conn,
	}
	return t, nil
}
func (s *Session) Close() error {
	if err := s.el.Close(); err != nil {
		return err
	}
	s.mu.Lock()
	if s.ctr != nil {
		if err := s.ctr.conn.Close(); err != nil {
			return err
		}
		s.ctr = nil
	}
	s.mu.Unlock()
	return nil
}
type SessionOption interface {
	apply(*sessionOpts)
}
type sessionOpts struct {
	network string
	addr    string
	dialer func(ctx context.Context, network, addr string) (net.Conn, error)
	conn net.Conn
}
type funcSessionOption struct {
	f func(*sessionOpts)
}
func (fso *funcSessionOption) apply(s *sessionOpts) {
	fso.f(s)
}
func newFuncSessionOption(f func(*sessionOpts)) *funcSessionOption {
	return &funcSessionOption{f}
}
func WithSocketPath(path string) SessionOption {
	return newFuncSessionOption(func(so *sessionOpts) {
		so.network = "unix"
		so.addr = path
	})
}
func WithAddr(network, addr string) SessionOption {
	return newFuncSessionOption(func(so *sessionOpts) {
		so.network = network
		so.addr = addr
	})
}
func WithDialContext(dialer func(ctx context.Context, network, addr string) (net.Conn, error)) SessionOption {
	return newFuncSessionOption(func(so *sessionOpts) {
		so.dialer = dialer
	})
}
func withTestConn(conn net.Conn) SessionOption {
	return newFuncSessionOption(func(so *sessionOpts) {
		so.conn = conn
	})
}