131 lines
2.5 KiB
Go
131 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"net"
|
|
)
|
|
|
|
const (
|
|
RemoteGetState = uint16(0x01)
|
|
RemoteHandleMessage = uint16(0x02)
|
|
)
|
|
|
|
type RemoteGrainPool struct {
|
|
Hosts []string
|
|
grains map[CartId]RemoteGrain
|
|
}
|
|
|
|
func (id CartId) String() string {
|
|
return string(id[:])
|
|
}
|
|
|
|
func ToCartId(id string) CartId {
|
|
var result [16]byte
|
|
copy(result[:], []byte(id))
|
|
return result
|
|
}
|
|
|
|
type RemoteGrain struct {
|
|
client net.Conn
|
|
Id CartId
|
|
Address string
|
|
}
|
|
|
|
func NewRemoteGrain(id CartId, address string) *RemoteGrain {
|
|
return &RemoteGrain{
|
|
Id: id,
|
|
Address: address,
|
|
}
|
|
}
|
|
|
|
func (g *RemoteGrain) Connect() error {
|
|
if g.client == nil {
|
|
client, err := net.Dial("tcp", g.Address)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
g.client = client
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Packet struct {
|
|
Version uint16
|
|
MessageType uint16
|
|
Id CartId
|
|
DataLength uint16
|
|
}
|
|
|
|
func (g *RemoteGrain) SendPacket(messageType uint16, data []byte) error {
|
|
binary.Write(g.client, binary.LittleEndian, Packet{
|
|
Version: 2,
|
|
MessageType: messageType,
|
|
Id: g.Id,
|
|
DataLength: uint16(len(data)),
|
|
})
|
|
return binary.Write(g.client, binary.LittleEndian, data)
|
|
}
|
|
|
|
func (g *RemoteGrain) HandleMessage(message *Message, isReplay bool) ([]byte, error) {
|
|
data, err := GetData(message.Write)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = g.SendPacket(RemoteHandleMessage, data)
|
|
result := make([]byte, 65535)
|
|
g.client.Read(result)
|
|
return result, err
|
|
}
|
|
|
|
func (g *RemoteGrain) GetId() CartId {
|
|
return g.Id
|
|
}
|
|
|
|
func (g *RemoteGrain) GetCurrentState() (Grain, error) {
|
|
|
|
var reply CartGrain
|
|
err := g.SendPacket(RemoteGetState, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &reply, err
|
|
}
|
|
|
|
func NewRemoteGrainPool(addr ...string) *RemoteGrainPool {
|
|
return &RemoteGrainPool{
|
|
Hosts: addr,
|
|
grains: make(map[CartId]RemoteGrain),
|
|
}
|
|
}
|
|
|
|
func (p *RemoteGrainPool) findRemoteGrain(id CartId) *RemoteGrain {
|
|
grain, ok := p.grains[id]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return &grain
|
|
}
|
|
|
|
func (p *RemoteGrainPool) Process(id CartId, messages ...Message) (interface{}, error) {
|
|
var result interface{}
|
|
var err error
|
|
grain := p.findRemoteGrain(id)
|
|
if grain == nil {
|
|
grain = NewRemoteGrain(id, p.Hosts[0])
|
|
grain.Connect()
|
|
p.grains[id] = *grain
|
|
}
|
|
for _, message := range messages {
|
|
result, err = grain.HandleMessage(&message, false)
|
|
}
|
|
return result, err
|
|
}
|
|
|
|
func (p *RemoteGrainPool) Get(id CartId) (Grain, error) {
|
|
grain := p.findRemoteGrain(id)
|
|
if grain == nil {
|
|
return nil, nil
|
|
}
|
|
return grain.GetCurrentState()
|
|
}
|