Files
go-cart-actor/tcp-client.go
matst80 170a51fad9
Some checks failed
Build and Publish / BuildAndDeployAmd64 (push) Failing after 27s
Build and Publish / BuildAndDeploy (push) Successful in 2m16s
use persisted connections and handle died
2024-11-12 17:30:19 +01:00

126 lines
2.4 KiB
Go

package main
import (
"encoding/binary"
"fmt"
"log"
"net"
"time"
)
type Client struct {
*TCPClient
}
func Dial(address string) (*Client, error) {
mux, err := NewTCPClient(address)
if err != nil {
return nil, err
}
client := &Client{
TCPClient: mux,
}
return client, nil
}
type TCPClient struct {
*PersistentConnection
ErrorCount int
address string
*PacketQueue
}
type PersistentConnection struct {
net.Conn
Died chan bool
Dead bool
address string
}
func NewPersistentConnection(address string) (*PersistentConnection, error) {
connection, err := net.Dial("tcp", address)
if err != nil {
return nil, err
}
return &PersistentConnection{
Conn: connection,
Died: make(chan bool, 1),
Dead: false,
address: address,
}, nil
}
func (m *PersistentConnection) Connect() error {
if !m.Dead {
connection, err := net.Dial("tcp", m.address)
if err != nil {
m.Died <- true
m.Dead = true
return err
}
m.Conn = connection
}
return nil
}
func (m *PersistentConnection) Close() {
m.Conn.Close()
m.Died <- true
m.Dead = true
}
func (m *PersistentConnection) HandleConnectionError(err error) error {
if err != nil {
m.Conn.Close()
m.Connect()
}
return err
}
func NewTCPClient(address string) (*TCPClient, error) {
connection, err := NewPersistentConnection(address)
if err != nil {
return nil, err
}
return &TCPClient{
ErrorCount: 0,
PersistentConnection: connection,
address: address,
PacketQueue: NewPacketQueue(connection),
}, nil
}
func (m *TCPClient) SendPacket(messageType uint32, data []byte) error {
err := binary.Write(m.Conn, binary.LittleEndian, Packet{
Version: CurrentPacketVersion,
MessageType: messageType,
StatusCode: 0,
DataLength: uint32(len(data)),
})
if err != nil {
return m.HandleConnectionError(err)
}
_, err = m.Conn.Write(data)
return m.HandleConnectionError(err)
}
func (m *TCPClient) Call(messageType uint32, responseType uint32, data []byte) (*CallResult, error) {
packetChan := m.Expect(responseType)
err := m.SendPacket(messageType, data)
if err != nil {
m.RemoveListeners()
return nil, m.HandleConnectionError(err)
}
select {
case ret := <-packetChan:
return &ret, nil
case <-time.After(time.Second):
log.Printf("Timeout waiting for cart response to message type %d\n", responseType)
return nil, m.HandleConnectionError(fmt.Errorf("timeout"))
}
}