srpc/connection.go

169 lines
3.1 KiB
Go
Raw Normal View History

package srpc
import (
2020-02-17 19:18:39 +01:00
"bytes"
2020-02-18 03:03:02 +01:00
"errors"
2020-02-17 01:30:24 +01:00
"io"
"net"
2020-02-17 01:30:24 +01:00
"sync"
)
2020-02-17 19:18:39 +01:00
type RPCMsgType uint8
const (
RPC_REQUEST RPCMsgType = 0
RPC_RESPONSE RPCMsgType = 1
RPC_HEARTBEAT RPCMsgType = 2
2020-02-18 03:03:02 +01:00
RPC_CLOSE RPCMsgType = 3
2020-02-17 19:18:39 +01:00
)
2020-02-18 03:03:02 +01:00
const RPCHeaderSize = 13
2020-02-17 19:18:39 +01:00
type RPCHeader struct {
RPCType RPCMsgType
Size uint64
}
type RPCHeartbeat struct {
2020-02-18 03:03:02 +01:00
OK bool
}
type RPCClose struct {
OK bool
2020-02-17 19:18:39 +01:00
}
2020-02-18 03:03:02 +01:00
type RPCCall struct {
Header RPCHeader
Payload interface{}
}
type IRPCConn interface {
2020-02-18 03:03:02 +01:00
Send(payload interface{}) error
Receive() (*RPCCall, error)
Close()
}
2020-02-18 03:03:02 +01:00
type NetConn struct {
sync.RWMutex
conn net.Conn
ed IEncoderDecoder
// interface
IRPCConn
}
2020-02-18 03:03:02 +01:00
func (tc *NetConn) Send(payload interface{}) (err error) {
2020-02-17 19:18:39 +01:00
var header RPCHeader
var hb, b bytes.Buffer
2020-02-19 01:36:18 +01:00
switch payload.(type) {
case *RPCHeartbeat:
2020-02-17 19:18:39 +01:00
header.RPCType = RPC_HEARTBEAT
2020-02-19 01:36:18 +01:00
break
case *RPCClose:
2020-02-18 03:03:02 +01:00
header.RPCType = RPC_CLOSE
2020-02-19 01:36:18 +01:00
break
case *RPCRequest:
2020-02-17 19:18:39 +01:00
header.RPCType = RPC_REQUEST
2020-02-19 01:36:18 +01:00
break
case *RPCResponse:
2020-02-17 19:18:39 +01:00
header.RPCType = RPC_RESPONSE
2020-02-19 01:36:18 +01:00
break
default:
2020-02-17 19:18:39 +01:00
return errors.New("srpc - Invalid RPC message type")
}
enc := tc.ed.NewEncoder(&b)
if err = enc.Encode(payload); err != nil {
return errors.New("srpc - Error: '" + err.Error() + "'")
}
header.Size = uint64(len(b.Bytes()))
2020-02-18 03:03:02 +01:00
enc = tc.ed.NewEncoder(&hb)
2020-02-17 19:18:39 +01:00
if err = enc.Encode(header); err != nil {
return errors.New("srpc - Error: '" + err.Error() + "'")
}
data := append([]byte{}, hb.Bytes()...)
data = append(data, b.Bytes()...)
2020-02-18 03:03:02 +01:00
tc.Lock()
defer tc.Unlock()
if n, err := tc.conn.Write(data); err != nil || n != len(data) {
2020-02-17 19:18:39 +01:00
return errors.New("srpc - Error writing message")
}
2020-02-18 03:03:02 +01:00
return nil
2020-02-17 19:18:39 +01:00
}
2020-02-18 03:03:02 +01:00
func (tc *NetConn) Receive() (ret *RPCCall, err error) {
2020-02-17 19:18:39 +01:00
var header RPCHeader
2020-02-18 03:03:02 +01:00
var payload interface{}
2020-02-17 19:18:39 +01:00
hb := make([]byte, RPCHeaderSize)
2020-02-18 03:03:02 +01:00
tc.Lock()
defer tc.Unlock()
if n, err := tc.conn.Read(hb); err != nil || n != RPCHeaderSize {
if err != nil {
if err == io.EOF {
header.RPCType = RPC_CLOSE
ret = &RPCCall{header, new(RPCClose)}
return ret, nil
}
}
2020-02-17 19:18:39 +01:00
return nil, errors.New("srpc - Error receiving message")
}
dec := tc.ed.NewDecoder(bytes.NewReader(hb))
if err = dec.Decode(&header); err != nil {
return nil, errors.New("srpc - Error: '" + err.Error() + "'")
}
switch header.RPCType {
case RPC_HEARTBEAT:
payload = new(RPCHeartbeat)
break
2020-02-18 03:03:02 +01:00
case RPC_CLOSE:
payload = new(RPCClose)
break
2020-02-17 19:18:39 +01:00
case RPC_REQUEST:
payload = new(RPCRequest)
break
case RPC_RESPONSE:
payload = new(RPCResponse)
break
default:
return nil, errors.New("srpc - Invalid RPC message type")
}
b := make([]byte, header.Size)
2020-02-18 03:03:02 +01:00
if n, err := tc.conn.Read(b); err != nil || n != int(header.Size) {
2020-02-17 19:18:39 +01:00
return nil, errors.New("srpc - Error receiving message")
}
2020-02-18 03:03:02 +01:00
dec = tc.ed.NewDecoder(bytes.NewReader(b))
2020-02-17 19:18:39 +01:00
if err = dec.Decode(payload); err != nil {
2020-02-18 03:03:02 +01:00
return nil, errors.New("srpc - Error: '" + err.Error() + "'")
}
2020-02-18 03:03:02 +01:00
ret = new(RPCCall)
ret.Header = header
ret.Payload = payload
2020-02-18 03:03:02 +01:00
return ret, nil
}
2020-02-18 03:03:02 +01:00
func (tc *NetConn) Close() {
tc.conn.Close()
}
2020-02-18 03:03:02 +01:00
func NewNetConn(conn net.Conn, ed IEncoderDecoder) *NetConn {
ret := &NetConn{}
ret.conn = conn
ret.ed = ed
return ret
}