use persistent connections
This commit is contained in:
@@ -2,9 +2,8 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"io"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -18,7 +17,7 @@ const CurrentPacketVersion = 2
|
|||||||
|
|
||||||
type CartListener map[CartId]Listener
|
type CartListener map[CartId]Listener
|
||||||
|
|
||||||
func NewCartPacketQueue(connection net.Conn) *CartPacketQueue {
|
func NewCartPacketQueue(connection *PersistentConnection) *CartPacketQueue {
|
||||||
|
|
||||||
queue := &CartPacketQueue{
|
queue := &CartPacketQueue{
|
||||||
expectedPackages: make(map[uint32]*CartListener),
|
expectedPackages: make(map[uint32]*CartListener),
|
||||||
@@ -38,7 +37,7 @@ func (p *CartPacketQueue) RemoveListeners() {
|
|||||||
p.expectedPackages = make(map[uint32]*CartListener)
|
p.expectedPackages = make(map[uint32]*CartListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *CartPacketQueue) HandleConnection(connection net.Conn) error {
|
func (p *CartPacketQueue) HandleConnection(connection *PersistentConnection) error {
|
||||||
defer p.RemoveListeners()
|
defer p.RemoveListeners()
|
||||||
defer connection.Close()
|
defer connection.Close()
|
||||||
var packet CartPacket
|
var packet CartPacket
|
||||||
@@ -47,15 +46,13 @@ func (p *CartPacketQueue) HandleConnection(connection net.Conn) error {
|
|||||||
for {
|
for {
|
||||||
err := ReadCartPacket(reader, &packet)
|
err := ReadCartPacket(reader, &packet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
log.Printf("Error receiving packet: %v\n", err)
|
log.Printf("Error receiving packet: %v\n", err)
|
||||||
return err
|
return connection.HandleConnectionError(err)
|
||||||
}
|
}
|
||||||
if packet.Version != CurrentPacketVersion {
|
if packet.Version != CurrentPacketVersion {
|
||||||
log.Printf("Incorrect version: %v\n", packet.Version)
|
log.Printf("Incorrect version: %v\n", packet.Version)
|
||||||
return nil
|
return connection.HandleConnectionError(fmt.Errorf("incorrect version: %d", packet.Version))
|
||||||
}
|
}
|
||||||
if packet.DataLength == 0 {
|
if packet.DataLength == 0 {
|
||||||
go p.HandleData(packet.MessageType, packet.Id, CallResult{
|
go p.HandleData(packet.MessageType, packet.Id, CallResult{
|
||||||
@@ -67,7 +64,7 @@ func (p *CartPacketQueue) HandleConnection(connection net.Conn) error {
|
|||||||
data, err := GetPacketData(reader, packet.DataLength)
|
data, err := GetPacketData(reader, packet.DataLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error receiving packet data: %v\n", err)
|
log.Printf("Error receiving packet data: %v\n", err)
|
||||||
return err
|
return connection.HandleConnectionError(err)
|
||||||
}
|
}
|
||||||
go p.HandleData(packet.MessageType, packet.Id, CallResult{
|
go p.HandleData(packet.MessageType, packet.Id, CallResult{
|
||||||
StatusCode: packet.StatusCode,
|
StatusCode: packet.StatusCode,
|
||||||
@@ -121,106 +118,3 @@ func (p *CartPacketQueue) Expect(messageType uint32, id CartId) <-chan CallResul
|
|||||||
return ch
|
return ch
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// package main
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "fmt"
|
|
||||||
// "io"
|
|
||||||
// "log"
|
|
||||||
// "net"
|
|
||||||
// "sync"
|
|
||||||
// "time"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// type CartPacketWithData struct {
|
|
||||||
// MessageType uint32
|
|
||||||
// Id CartId
|
|
||||||
// Added time.Time
|
|
||||||
// Consumed bool
|
|
||||||
// Data []byte
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type CartPacketQueue struct {
|
|
||||||
// mu sync.RWMutex
|
|
||||||
// Packets []CartPacketWithData
|
|
||||||
// //connection net.Conn
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const cartCap = 150
|
|
||||||
|
|
||||||
// func NewCartPacketQueue(connection net.Conn) *CartPacketQueue {
|
|
||||||
|
|
||||||
// queue := &CartPacketQueue{
|
|
||||||
// Packets: make([]CartPacketWithData, 0, cartCap),
|
|
||||||
// //connection: connection,
|
|
||||||
// }
|
|
||||||
// go func() {
|
|
||||||
// defer connection.Close()
|
|
||||||
// var packet CartPacket
|
|
||||||
// for {
|
|
||||||
// err := ReadCartPacket(connection, &packet)
|
|
||||||
// if err != nil {
|
|
||||||
// if err == io.EOF {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// log.Printf("Error receiving packet: %v\n", err)
|
|
||||||
// //return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// data, err := GetPacketData(connection, packet.DataLength)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Printf("Error receiving packet data: %v\n", err)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// go queue.HandleData(packet.MessageType, packet.Id, data)
|
|
||||||
// }
|
|
||||||
// }()
|
|
||||||
// return queue
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (p *CartPacketQueue) HandleData(t uint32, id CartId, data []byte) {
|
|
||||||
// ts := time.Now()
|
|
||||||
// l := make([]CartPacketWithData, 0, cartCap)
|
|
||||||
// p.mu.RLock()
|
|
||||||
// breakAt := ts.Add(-time.Millisecond * 250)
|
|
||||||
// for _, packet := range p.Packets {
|
|
||||||
// if !packet.Consumed && packet.Added.After(breakAt) {
|
|
||||||
// l = append(l, packet)
|
|
||||||
// if len(l) >= cartCap {
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// p.mu.RUnlock()
|
|
||||||
// p.mu.Lock()
|
|
||||||
// p.Packets = append([]CartPacketWithData{
|
|
||||||
// {
|
|
||||||
// MessageType: t,
|
|
||||||
// Id: id,
|
|
||||||
// Added: ts,
|
|
||||||
// Data: data,
|
|
||||||
// },
|
|
||||||
// }, l...)
|
|
||||||
// p.mu.Unlock()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (p *CartPacketQueue) Expect(messageType uint32, id CartId, timeToWait time.Duration) (*CartPacketWithData, error) {
|
|
||||||
// start := time.Now().Add(-time.Millisecond)
|
|
||||||
|
|
||||||
// for {
|
|
||||||
// if time.Since(start) > timeToWait {
|
|
||||||
// return nil, fmt.Errorf("timeout waiting for message type %d", messageType)
|
|
||||||
// }
|
|
||||||
// p.mu.RLock()
|
|
||||||
// for _, packet := range p.Packets {
|
|
||||||
// if !packet.Consumed && packet.MessageType == messageType && packet.Id == id && packet.Added.After(start) {
|
|
||||||
// packet.Consumed = true
|
|
||||||
// p.mu.RUnlock()
|
|
||||||
// return &packet, nil
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// p.mu.RUnlock()
|
|
||||||
// time.Sleep(time.Millisecond * 2)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|||||||
@@ -3,11 +3,8 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type PacketQueue struct {
|
type PacketQueue struct {
|
||||||
@@ -25,7 +22,7 @@ type Listener struct {
|
|||||||
Chan chan CallResult
|
Chan chan CallResult
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPacketQueue(connection net.Conn) *PacketQueue {
|
func NewPacketQueue(connection *PersistentConnection) *PacketQueue {
|
||||||
queue := &PacketQueue{
|
queue := &PacketQueue{
|
||||||
expectedPackages: make(map[uint32]*Listener),
|
expectedPackages: make(map[uint32]*Listener),
|
||||||
}
|
}
|
||||||
@@ -42,24 +39,20 @@ func (p *PacketQueue) RemoveListeners() {
|
|||||||
p.expectedPackages = make(map[uint32]*Listener)
|
p.expectedPackages = make(map[uint32]*Listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PacketQueue) HandleConnection(connection net.Conn) error {
|
func (p *PacketQueue) HandleConnection(connection *PersistentConnection) error {
|
||||||
defer connection.Close()
|
defer connection.Close()
|
||||||
defer p.RemoveListeners()
|
defer p.RemoveListeners()
|
||||||
var packet Packet
|
var packet Packet
|
||||||
reader := bufio.NewReader(connection)
|
reader := bufio.NewReader(connection)
|
||||||
connection.SetReadDeadline(time.Now().Add(time.Millisecond * 200))
|
|
||||||
for {
|
for {
|
||||||
err := ReadPacket(reader, &packet)
|
err := ReadPacket(reader, &packet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
return connection.HandleConnectionError(err)
|
||||||
return nil
|
|
||||||
}
|
|
||||||
log.Printf("Error receiving packet: %v\n", err)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
if packet.Version != CurrentPacketVersion {
|
if packet.Version != CurrentPacketVersion {
|
||||||
log.Printf("Incorrect packet version: %v\n", packet.Version)
|
log.Printf("Incorrect packet version: %v\n", packet.Version)
|
||||||
return fmt.Errorf("incorrect packet version: %d", packet.Version)
|
return connection.HandleConnectionError(fmt.Errorf("incorrect packet version: %d", packet.Version))
|
||||||
}
|
}
|
||||||
if packet.DataLength == 0 {
|
if packet.DataLength == 0 {
|
||||||
go p.HandleData(packet.MessageType, CallResult{
|
go p.HandleData(packet.MessageType, CallResult{
|
||||||
@@ -71,7 +64,7 @@ func (p *PacketQueue) HandleConnection(connection net.Conn) error {
|
|||||||
data, err := GetPacketData(reader, packet.DataLength)
|
data, err := GetPacketData(reader, packet.DataLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error receiving packet data: %v\n", err)
|
log.Printf("Error receiving packet data: %v\n", err)
|
||||||
return err
|
return connection.HandleConnectionError(err)
|
||||||
} else {
|
} else {
|
||||||
go p.HandleData(packet.MessageType, CallResult{
|
go p.HandleData(packet.MessageType, CallResult{
|
||||||
StatusCode: packet.StatusCode,
|
StatusCode: packet.StatusCode,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,76 +28,51 @@ func (c *Client) Close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CartTCPClient struct {
|
type CartTCPClient struct {
|
||||||
net.Conn
|
*PersistentConnection
|
||||||
ErrorCount int
|
ErrorCount int
|
||||||
address string
|
address string
|
||||||
*CartPacketQueue
|
*CartPacketQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCartTCPClient(address string) (*CartTCPClient, error) {
|
func NewCartTCPClient(address string) (*CartTCPClient, error) {
|
||||||
connection, err := net.Dial("tcp", address)
|
connection, err := NewPersistentConnection(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &CartTCPClient{
|
return &CartTCPClient{
|
||||||
ErrorCount: 0,
|
ErrorCount: 0,
|
||||||
Conn: connection,
|
PersistentConnection: connection,
|
||||||
address: address,
|
address: address,
|
||||||
CartPacketQueue: NewCartPacketQueue(connection),
|
CartPacketQueue: NewCartPacketQueue(connection),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CartTCPClient) Connect() error {
|
|
||||||
if m.Conn == nil {
|
|
||||||
connection, err := net.Dial("tcp", m.address)
|
|
||||||
if err != nil {
|
|
||||||
m.ErrorCount++
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
m.ErrorCount = 0
|
|
||||||
m.Conn = connection
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *CartTCPClient) SendPacket(messageType uint32, id CartId, data []byte) error {
|
func (m *CartTCPClient) SendPacket(messageType uint32, id CartId, data []byte) error {
|
||||||
err := m.Connect()
|
|
||||||
|
|
||||||
if err != nil {
|
err := binary.Write(m.Conn, binary.LittleEndian, CartPacket{
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = binary.Write(m.Conn, binary.LittleEndian, CartPacket{
|
|
||||||
Version: CurrentPacketVersion,
|
Version: CurrentPacketVersion,
|
||||||
MessageType: messageType,
|
MessageType: messageType,
|
||||||
DataLength: uint32(len(data)),
|
DataLength: uint32(len(data)),
|
||||||
Id: id,
|
Id: id,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return m.HandleConnectionError(err)
|
||||||
}
|
}
|
||||||
_, err = m.Conn.Write(data)
|
_, err = m.Conn.Write(data)
|
||||||
m.Conn.SetDeadline(time.Now().Add(time.Second * 10))
|
return m.HandleConnectionError(err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (m *CartTCPClient) SendPacketFn(messageType uint16, id CartId, datafn func(w io.Writer) error) error {
|
|
||||||
// data, err := GetData(datafn)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// return m.SendPacket(messageType, id, data)
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (m *CartTCPClient) Call(messageType uint32, id CartId, responseType uint32, data []byte) (*CallResult, error) {
|
func (m *CartTCPClient) Call(messageType uint32, id CartId, responseType uint32, data []byte) (*CallResult, error) {
|
||||||
packetChan := m.Expect(responseType, id)
|
packetChan := m.Expect(responseType, id)
|
||||||
err := m.SendPacket(messageType, id, data)
|
err := m.SendPacket(messageType, id, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, m.HandleConnectionError(err)
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case ret := <-packetChan:
|
case ret := <-packetChan:
|
||||||
return &ret, nil
|
return &ret, nil
|
||||||
case <-time.After(time.Second * 10):
|
case <-time.After(time.Second):
|
||||||
return nil, fmt.Errorf("timeout")
|
log.Printf("Timeout waiting for cart response to message type %d\n", responseType)
|
||||||
|
return nil, m.HandleConnectionError(fmt.Errorf("timeout"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -24,54 +25,66 @@ func Dial(address string) (*Client, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TCPClient struct {
|
type TCPClient struct {
|
||||||
net.Conn
|
*PersistentConnection
|
||||||
ErrorCount int
|
ErrorCount int
|
||||||
address string
|
address string
|
||||||
*PacketQueue
|
*PacketQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTCPClient(address string) (*TCPClient, error) {
|
type PersistentConnection struct {
|
||||||
|
net.Conn
|
||||||
|
address string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPersistentConnection(address string) (*PersistentConnection, error) {
|
||||||
connection, err := net.Dial("tcp", address)
|
connection, err := net.Dial("tcp", address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return &PersistentConnection{
|
||||||
|
Conn: connection,
|
||||||
|
address: address,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PersistentConnection) Connect() error {
|
||||||
|
connection, err := net.Dial("tcp", m.address)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.Conn = connection
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PersistentConnection) Close() {
|
||||||
|
m.Conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
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{
|
return &TCPClient{
|
||||||
ErrorCount: 0,
|
ErrorCount: 0,
|
||||||
Conn: connection,
|
PersistentConnection: connection,
|
||||||
address: address,
|
address: address,
|
||||||
PacketQueue: NewPacketQueue(connection),
|
PacketQueue: NewPacketQueue(connection),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *TCPClient) Connect() error {
|
|
||||||
if m.Conn == nil {
|
|
||||||
connection, err := net.Dial("tcp", m.address)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
m.ErrorCount = 0
|
|
||||||
m.Conn = connection
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TCPClient) HandleConnectionError(err error) error {
|
|
||||||
if err != nil {
|
|
||||||
m.ErrorCount++
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TCPClient) Close() {
|
|
||||||
m.Conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TCPClient) SendPacket(messageType uint32, data []byte) error {
|
func (m *TCPClient) SendPacket(messageType uint32, data []byte) error {
|
||||||
err := m.Connect()
|
|
||||||
if err != nil {
|
err := binary.Write(m.Conn, binary.LittleEndian, Packet{
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = binary.Write(m.Conn, binary.LittleEndian, Packet{
|
|
||||||
Version: CurrentPacketVersion,
|
Version: CurrentPacketVersion,
|
||||||
MessageType: messageType,
|
MessageType: messageType,
|
||||||
StatusCode: 0,
|
StatusCode: 0,
|
||||||
@@ -81,29 +94,22 @@ func (m *TCPClient) SendPacket(messageType uint32, data []byte) error {
|
|||||||
return m.HandleConnectionError(err)
|
return m.HandleConnectionError(err)
|
||||||
}
|
}
|
||||||
_, err = m.Conn.Write(data)
|
_, err = m.Conn.Write(data)
|
||||||
m.Conn.SetDeadline(time.Now().Add(time.Second * 10))
|
|
||||||
return m.HandleConnectionError(err)
|
return m.HandleConnectionError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (m *TCPClient) SendPacketFn(messageType uint32, datafn func(w io.Writer) error) error {
|
|
||||||
// data, err := GetData(datafn)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// return m.SendPacket(messageType, data)
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (m *TCPClient) Call(messageType uint32, responseType uint32, data []byte) (*CallResult, error) {
|
func (m *TCPClient) Call(messageType uint32, responseType uint32, data []byte) (*CallResult, error) {
|
||||||
packetChan := m.Expect(responseType)
|
packetChan := m.Expect(responseType)
|
||||||
err := m.SendPacket(messageType, data)
|
err := m.SendPacket(messageType, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
m.RemoveListeners()
|
||||||
|
return nil, m.HandleConnectionError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case ret := <-packetChan:
|
case ret := <-packetChan:
|
||||||
return &ret, nil
|
return &ret, nil
|
||||||
case <-time.After(time.Second * 10):
|
case <-time.After(time.Second):
|
||||||
return nil, fmt.Errorf("timeout")
|
log.Printf("Timeout waiting for cart response to message type %d\n", responseType)
|
||||||
|
return nil, m.HandleConnectionError(fmt.Errorf("timeout"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user