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() }