package main import ( "encoding/binary" "fmt" "log" "sync" "time" ) type CartClient struct { *CartTCPClient } func CartDial(address string) (*CartClient, error) { mux, err := NewCartTCPClient(address) if err != nil { return nil, err } client := &CartClient{ CartTCPClient: mux, } return client, nil } func (c *Client) Close() { log.Printf("Closing connection to %s\n", c.PersistentConnection.address) c.PersistentConnection.Close() } type CartTCPClient struct { PersistentConnection *PersistentConnection sendMux sync.Mutex ErrorCount int address string *CartPacketQueue } func NewCartTCPClient(address string) (*CartTCPClient, error) { connection, err := NewPersistentConnection(address) if err != nil { return nil, err } return &CartTCPClient{ ErrorCount: 0, PersistentConnection: connection, address: address, CartPacketQueue: NewCartPacketQueue(connection), }, nil } func (m *CartTCPClient) SendPacket(messageType CartMessage, id CartId, data []byte) error { m.sendMux.Lock() defer m.sendMux.Unlock() m.PersistentConnection.Conn.Write(header[:]) err := binary.Write(m.PersistentConnection, binary.LittleEndian, CartPacket{ Version: CurrentPacketVersion, MessageType: messageType, DataLength: uint32(len(data)), Id: id, }) if err != nil { return m.PersistentConnection.HandleConnectionError(err) } _, err = m.PersistentConnection.Write(data) return m.PersistentConnection.HandleConnectionError(err) } func (m *CartTCPClient) Call(messageType CartMessage, id CartId, responseType CartMessage, data []byte) (*CallResult, error) { packetChan := m.Expect(responseType, id) err := m.SendPacket(messageType, id, data) if err != nil { return nil, m.PersistentConnection.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.PersistentConnection.HandleConnectionError(fmt.Errorf("timeout")) } }