/
client.go
193 lines (164 loc) · 4.41 KB
/
client.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package protocols
import (
"fmt"
"sync"
"time"
"github.com/antongulenko/golib"
)
const (
DefaultTimeout = 1 * time.Second
)
type Client interface {
Close() error
Closed() bool
ResetConnection() // Will open new connection next time it's required
SetServer(server_addr string) error
Server() Addr
SetTimeout(timeout time.Duration)
Protocol() Protocol
String() string
SendPacket(packet *Packet) error
Send(code Code, val interface{}) error
SendRequest(code Code, val interface{}) (*Packet, error)
SendRequestPacket(packet *Packet) (reply *Packet, err error)
CheckReply(reply *Packet) error
CheckError(reply *Packet, expectedCode Code) error
}
type client struct {
serverAddr Addr
conn Conn
protocol Protocol
closed golib.StopChan
// TODO use lock
connLock sync.Mutex
// The worst case delay for one request will be up to two times this.
timeout time.Duration
}
func NewClient(protocol Protocol) Client {
return &client{
protocol: protocol,
closed: golib.NewStopChan(),
timeout: DefaultTimeout,
}
}
func NewClientFor(server string, protocol Protocol) (Client, error) {
client := NewClient(protocol)
if err := client.SetServer(server); err != nil {
_ = client.Close()
return nil, err
}
return client, nil
}
func NewMiniClient(fragment ProtocolFragment) Client {
return NewClient(NewMiniProtocol(fragment))
}
func NewMiniClientFor(server_addr string, fragment ProtocolFragment) (Client, error) {
proto := NewMiniProtocol(fragment)
return NewClientFor(server_addr, proto)
}
func (client *client) Close() (err error) {
client.closed.Enable(func() {
if client.conn != nil {
err = client.conn.Close()
}
})
return
}
func (client *client) Closed() bool {
return client.closed.Enabled()
}
func (client *client) String() string {
return fmt.Sprintf("%s at %s", client.Protocol().Name(), client.Server())
}
func (client *client) Protocol() Protocol {
return client.protocol
}
func (client *client) Server() Addr {
return client.serverAddr
}
func (client *client) SetTimeout(timeout time.Duration) {
client.timeout = timeout
}
func (client *client) SetServer(server_addr string) error {
addr, err := client.protocol.Transport().Resolve(server_addr)
if err != nil {
return err
}
client.serverAddr = addr
client.ResetConnection()
return nil
}
func (client *client) ResetConnection() {
if client.conn != nil {
_ = client.conn.Close() // Drop error...
client.conn = nil
}
}
func (client *client) checkServer() error {
if client.serverAddr == nil {
return fmt.Errorf("Use SetServer to configure %v client", client.protocol.Name())
}
if client.conn == nil {
conn, err := client.protocol.Transport().Dial(client.serverAddr, client.protocol)
if err != nil {
return err
}
client.conn = conn
}
return nil
}
func (client *client) SendPacket(packet *Packet) error {
if err := client.checkServer(); err != nil {
return err
}
return client.conn.Send(packet, client.timeout)
}
func (client *client) SendRequestPacket(packet *Packet) (reply *Packet, err error) {
client.connLock.Lock()
defer client.connLock.Unlock()
if err = client.checkServer(); err != nil {
return
}
if err = client.conn.Send(packet, client.timeout); err == nil {
reply, err = client.conn.Receive(client.timeout)
if err != nil {
err = fmt.Errorf("Receiving %s reply from %s: %s", client.protocol.Name(), client.conn.RemoteAddr(), err)
}
} else {
err = fmt.Errorf("Sending %s request to %s: %s", client.protocol.Name(), client.conn.RemoteAddr(), err)
}
client.ResetConnection() // TODO hack to make tcp work...
return
}
func (client *client) Send(code Code, val interface{}) error {
return client.SendPacket(&Packet{
Code: code,
Val: val,
})
}
func (client *client) SendRequest(code Code, val interface{}) (*Packet, error) {
return client.SendRequestPacket(&Packet{
Code: code,
Val: val,
})
}
func (client *client) CheckError(reply *Packet, expectedCode Code) error {
if reply.Code == CodeError {
var errString string
if reply.Code == CodeError {
errString, _ = reply.Val.(string)
}
return fmt.Errorf("%v error: %v", client.Protocol().Name(), errString)
}
if reply.Code != expectedCode {
return fmt.Errorf("Unexpected %s reply code %v. Expected %v. Payload: %v",
client.Protocol().Name(), reply.Code, expectedCode, reply.Val)
}
return nil
}
func (client *client) CheckReply(reply *Packet) error {
if err := client.CheckError(reply, CodeOK); err != nil {
return err
}
return nil
}