164 lines
3.5 KiB
Go
164 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"log"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type CartPacketQueue struct {
|
|
mu sync.RWMutex
|
|
expectedPackages map[CartMessage]*CartListener
|
|
}
|
|
|
|
const CurrentPacketVersion = 2
|
|
|
|
type CartListener map[CartId]Listener
|
|
|
|
func NewCartPacketQueue(connection *PersistentConnection) *CartPacketQueue {
|
|
queue := &CartPacketQueue{
|
|
expectedPackages: make(map[CartMessage]*CartListener),
|
|
}
|
|
go queue.HandleConnection(connection)
|
|
return queue
|
|
}
|
|
|
|
func (p *CartPacketQueue) RemoveListeners() {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
for _, l := range p.expectedPackages {
|
|
for _, l := range *l {
|
|
close(l.Chan)
|
|
}
|
|
}
|
|
p.expectedPackages = make(map[CartMessage]*CartListener)
|
|
}
|
|
|
|
func (p *CartPacketQueue) HandleConnection(connection *PersistentConnection) error {
|
|
defer p.RemoveListeners()
|
|
defer connection.Close()
|
|
var packet CartPacket
|
|
reader := bufio.NewReader(connection)
|
|
for {
|
|
err := ReadCartPacket(reader, &packet)
|
|
if err != nil {
|
|
log.Printf("Error receiving packet: %v\n", err)
|
|
return connection.HandleConnectionError(err)
|
|
}
|
|
if packet.Version != CurrentPacketVersion {
|
|
log.Printf("Incorrect version: %v\n", packet.Version)
|
|
return connection.HandleConnectionError(fmt.Errorf("incorrect version: %d", packet.Version))
|
|
}
|
|
if packet.DataLength == 0 {
|
|
go p.HandleData(packet.MessageType, packet.Id, CallResult{
|
|
StatusCode: packet.StatusCode,
|
|
Data: []byte{},
|
|
})
|
|
continue
|
|
}
|
|
data, err := GetPacketData(reader, packet.DataLength)
|
|
if err != nil {
|
|
log.Printf("Error receiving packet data: %v\n", err)
|
|
return connection.HandleConnectionError(err)
|
|
}
|
|
go p.HandleData(packet.MessageType, packet.Id, CallResult{
|
|
StatusCode: packet.StatusCode,
|
|
Data: data,
|
|
})
|
|
}
|
|
}
|
|
|
|
func (p *CartPacketQueue) HandleData(t CartMessage, id CartId, data CallResult) {
|
|
p.getListener(t, id, func(l *Listener) {
|
|
l.Chan <- data
|
|
l.Count--
|
|
})
|
|
// p.mu.Lock()
|
|
// defer p.mu.Unlock()
|
|
// pl, ok := p.expectedPackages[t]
|
|
// if ok {
|
|
// l, ok := (*pl)[id]
|
|
// if ok {
|
|
// l.Chan <- data
|
|
// l.Count--
|
|
// if l.Count == 0 {
|
|
// close(l.Chan)
|
|
// delete(*pl, id)
|
|
// }
|
|
// }
|
|
// }
|
|
}
|
|
|
|
func (p *CartPacketQueue) getListener(t CartMessage, id CartId, fn func(*Listener)) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
pl, ok := p.expectedPackages[t]
|
|
if ok {
|
|
l, ok := (*pl)[id]
|
|
if ok {
|
|
fn(&l)
|
|
if l.Count == 0 {
|
|
close(l.Chan)
|
|
delete(*pl, id)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func CallResultWithTimeout(onTimeout func() CallResult) chan CallResult {
|
|
ch := make(chan CallResult, 1)
|
|
resultCh := make(chan CallResult, 1)
|
|
select {
|
|
case ret := <-resultCh:
|
|
ch <- ret
|
|
case <-time.After(300 * time.Millisecond):
|
|
ch <- onTimeout()
|
|
}
|
|
return ch
|
|
}
|
|
|
|
func (p *CartPacketQueue) MakeChannel(messageType CartMessage, id CartId) chan CallResult {
|
|
return CallResultWithTimeout(func() CallResult {
|
|
p.getListener(messageType, id, func(l *Listener) {
|
|
l.Count--
|
|
})
|
|
return CallResult{
|
|
StatusCode: 504,
|
|
Data: []byte("timeout cart call"),
|
|
}
|
|
})
|
|
}
|
|
|
|
func (p *CartPacketQueue) Expect(messageType CartMessage, id CartId) <-chan CallResult {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
l, ok := p.expectedPackages[messageType]
|
|
if ok {
|
|
if idl, idOk := (*l)[id]; idOk {
|
|
idl.Count++
|
|
return idl.Chan
|
|
}
|
|
ch := p.MakeChannel(messageType, id)
|
|
|
|
(*l)[id] = Listener{
|
|
Chan: ch,
|
|
Count: 1,
|
|
}
|
|
|
|
return ch
|
|
}
|
|
|
|
ch := p.MakeChannel(messageType, id)
|
|
p.expectedPackages[messageType] = &CartListener{
|
|
id: Listener{
|
|
Chan: ch,
|
|
Count: 1,
|
|
},
|
|
}
|
|
|
|
return ch
|
|
|
|
}
|