func (c *Sync) Error() error {
	return c.error.Load()
}
Error returns the error that caused the frisbee.Sync to close or go into a paused state
package frisbee
import (
	"bytes"
	"crypto/tls"
	"encoding/binary"
	"github.com/loopholelabs/frisbee/internal/errors"
	"github.com/loopholelabs/frisbee/internal/protocol"
	"github.com/rs/zerolog"
	"go.uber.org/atomic"
	"io"
	"net"
	"os"
	"sync"
	"time"
)
type Sync struct {
	sync.Mutex
	conn   net.Conn
	state  *atomic.Int32
	logger *zerolog.Logger
	error  *atomic.Error
}
func ConnectSync(addr string, keepAlive time.Duration, logger *zerolog.Logger, TLSConfig *tls.Config) (*Sync, error) {
	var conn net.Conn
	var err error
	if TLSConfig != nil {
		conn, err = tls.Dial("tcp", addr, TLSConfig)
	} else {
		conn, err = net.Dial("tcp", addr)
		_ = conn.(*net.TCPConn).SetKeepAlive(true)
		_ = conn.(*net.TCPConn).SetKeepAlivePeriod(keepAlive)
	}
	if err != nil {
		return nil, errors.WithContext(err, DIAL)
	}
	return NewSync(conn, logger), nil
}
func NewSync(c net.Conn, logger *zerolog.Logger) (conn *Sync) {
	conn = &Sync{
		conn:   c,
		state:  atomic.NewInt32(CONNECTED),
		logger: logger,
		error:  atomic.NewError(nil),
	}
	if logger == nil {
		conn.logger = &defaultLogger
	}
	return
}
func (c *Sync) SetDeadline(t time.Time) error {
	return c.conn.SetDeadline(t)
}
func (c *Sync) SetReadDeadline(t time.Time) error {
	return c.conn.SetReadDeadline(t)
}
func (c *Sync) SetWriteDeadline(t time.Time) error {
	return c.conn.SetWriteDeadline(t)
}
func (c *Sync) ConnectionState() (tls.ConnectionState, error) {
	if tlsConn, ok := c.conn.(*tls.Conn); ok {
		return tlsConn.ConnectionState(), nil
	}
	return tls.ConnectionState{}, NotTLSConnectionError
}
func (c *Sync) LocalAddr() net.Addr {
	return c.conn.LocalAddr()
}
func (c *Sync) RemoteAddr() net.Addr {
	return c.conn.RemoteAddr()
}
func (c *Sync) WriteMessage(message *Message, content *[]byte) error {
	if content != nil && int(message.ContentLength) != len(*content) {
		return InvalidContentLength
	}
	encodedMessage := [protocol.MessageSize]byte{protocol.ReservedBytes[0], protocol.ReservedBytes[1], protocol.ReservedBytes[2], protocol.ReservedBytes[3]}
	binary.BigEndian.PutUint32(encodedMessage[protocol.FromOffset:protocol.FromOffset+protocol.FromSize], message.From)
	binary.BigEndian.PutUint32(encodedMessage[protocol.ToOffset:protocol.ToOffset+protocol.ToSize], message.To)
	binary.BigEndian.PutUint64(encodedMessage[protocol.IdOffset:protocol.IdOffset+protocol.IdSize], message.Id)
	binary.BigEndian.PutUint32(encodedMessage[protocol.OperationOffset:protocol.OperationOffset+protocol.OperationSize], message.Operation)
	binary.BigEndian.PutUint64(encodedMessage[protocol.ContentLengthOffset:protocol.ContentLengthOffset+protocol.ContentLengthSize], message.ContentLength)
	c.Lock()
	if c.state.Load() != CONNECTED {
		c.Unlock()
		return c.Error()
	}
	_, err := c.conn.Write(encodedMessage[:])
	if err != nil {
		c.Unlock()
		if c.state.Load() != CONNECTED {
			err = c.Error()
			c.logger.Error().Msgf(errors.WithContext(err, WRITE).Error())
			return errors.WithContext(err, WRITE)
		}
		c.logger.Error().Msgf(errors.WithContext(err, WRITE).Error())
		return c.closeWithError(err)
	}
	if content != nil {
		_, err = c.conn.Write(*content)
		if err != nil {
			c.Unlock()
			if c.state.Load() != CONNECTED {
				err = c.Error()
				c.logger.Error().Msgf(errors.WithContext(err, WRITE).Error())
				return errors.WithContext(err, WRITE)
			}
			c.logger.Error().Msgf(errors.WithContext(err, WRITE).Error())
			return c.closeWithError(err)
		}
	}
	c.Unlock()
	return nil
}
func (c *Sync) ReadMessage() (*Message, *[]byte, error) {
	if c.state.Load() != CONNECTED {
		return nil, nil, c.Error()
	}
	var encodedMessage [protocol.MessageSize]byte
	_, err := io.ReadAtLeast(c.conn, encodedMessage[:], protocol.MessageSize)
	if err != nil {
		if c.state.Load() != CONNECTED {
			err = c.Error()
			c.logger.Error().Msgf(errors.WithContext(err, POP).Error())
			return nil, nil, errors.WithContext(err, POP)
		}
		c.logger.Error().Msgf(errors.WithContext(err, POP).Error())
		return nil, nil, errors.WithContext(c.closeWithError(err), POP)
	}
	message := new(Message)
	if !bytes.Equal(encodedMessage[protocol.ReservedOffset:protocol.ReservedOffset+protocol.ReservedSize], protocol.ReservedBytes) {
		if c.state.Load() != CONNECTED {
			err = c.Error()
			c.logger.Error().Msgf(errors.WithContext(err, POP).Error())
			return nil, nil, errors.WithContext(err, POP)
		}
		c.logger.Error().Msgf(errors.WithContext(protocol.InvalidMessageVersion, POP).Error())
		return nil, nil, errors.WithContext(c.closeWithError(protocol.InvalidMessageVersion), POP)
	}
	message.From = binary.BigEndian.Uint32(encodedMessage[protocol.FromOffset : protocol.FromOffset+protocol.FromSize])
	message.To = binary.BigEndian.Uint32(encodedMessage[protocol.ToOffset : protocol.ToOffset+protocol.ToSize])
	message.Id = binary.BigEndian.Uint64(encodedMessage[protocol.IdOffset : protocol.IdOffset+protocol.IdSize])
	message.Operation = binary.BigEndian.Uint32(encodedMessage[protocol.OperationOffset : protocol.OperationOffset+protocol.OperationSize])
	message.ContentLength = binary.BigEndian.Uint64(encodedMessage[protocol.ContentLengthOffset : protocol.ContentLengthOffset+protocol.ContentLengthSize])
	if message.ContentLength > 0 {
		content := make([]byte, message.ContentLength)
		_, err = io.ReadAtLeast(c.conn, content, int(message.ContentLength))
		if err != nil {
			if c.state.Load() != CONNECTED {
				err = c.Error()
				c.logger.Error().Msgf(errors.WithContext(err, POP).Error())
				return nil, nil, errors.WithContext(err, POP)
			}
			c.logger.Error().Msgf(errors.WithContext(err, POP).Error())
			return nil, nil, errors.WithContext(c.closeWithError(err), POP)
		}
		return message, &content, nil
	}
	return message, nil, nil
}
func (c *Sync) Logger() *zerolog.Logger {
	return c.logger
}