/
transporter.go
130 lines (112 loc) · 2.7 KB
/
transporter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package ldbserver
import (
"encoding/binary"
"encoding/json"
"errors"
"hash/crc32"
"io"
pio "github.com/gogo/protobuf/io"
"github.com/gogo/protobuf/proto"
)
//go:generate protoc --gogo_out=. -I.:$GOPATH/src:/usr/local/include transport.proto
type DBServer interface {
serve(Transporter) error
Close()
}
type Transporter interface {
GetRequest() (*TransportRequest, error)
SendResponse(*TransportResponse) error
}
type TransporterFactory interface {
NewTransporter(r io.Reader, w io.Writer) Transporter
}
type MarshalingType int
const (
MarshalingTypeJson MarshalingType = iota
MarshalingTypeProtobuf
)
type JsonProtobufTransportFactory struct{ Mt MarshalingType }
func (f JsonProtobufTransportFactory) NewTransporter(r io.Reader, w io.Writer) Transporter {
ret := new(rwTransporter)
ret.mt = f.Mt
ret.req = r
ret.resp = w
return ret
}
type rwTransporter struct {
mt MarshalingType
req io.Reader
resp io.Writer
}
//func newRwTransporter(r io.Reader, w io.Writer, mt MarshalingType) *rwTransporter {
// ret := new(rwTransporter)
// ret.mt = mt
// ret.req = r
// ret.resp = w
// return ret
//}
func (rw *rwTransporter) GetRequest() (req *TransportRequest, err error) {
req = &TransportRequest{}
switch rw.mt {
case MarshalingTypeJson:
dec := json.NewDecoder(rw.req)
err = dec.Decode(req)
case MarshalingTypeProtobuf:
dec := pio.NewUint32DelimitedReader(rw.req, binary.LittleEndian, 1024*1024)
err = dec.ReadMsg(req)
}
if err == nil {
if !CheckBody(req.Body) {
err = errors.New("bad checksum in request body")
}
}
if err != nil {
return nil, err
}
return
}
func (rw *rwTransporter) SendResponse(resp *TransportResponse) error {
SetBodyChecksum(resp.Body)
switch rw.mt {
case MarshalingTypeJson:
enc := json.NewEncoder(rw.resp)
return enc.Encode(resp)
case MarshalingTypeProtobuf:
enc := pio.NewUint32DelimitedWriter(rw.resp, binary.LittleEndian)
return enc.WriteMsg(resp)
}
return errors.New("unsupported marshaling type")
}
// ------------
func MakeErrorResponse(code TransportResponse_Status, err error) *TransportResponse {
if err == nil {
return &TransportResponse{Status: code.Enum()}
}
return &TransportResponse{Status: code.Enum(), Body: &TransportBody{Data: []byte(err.Error())}}
}
func CheckBody(body *TransportBody) bool {
if body == nil {
return true
}
data := body.GetData()
if data == nil {
if body.GetChecksum() == 0 {
return true
} else {
return false
}
}
chk := crc32.ChecksumIEEE(data)
return chk == body.GetChecksum()
}
func SetBodyChecksum(body *TransportBody) {
if body == nil {
return
}
data := body.GetData()
if data == nil {
body.Checksum = proto.Uint32(0)
return
}
body.Checksum = proto.Uint32(crc32.ChecksumIEEE(data))
}