@@ -9,6 +9,7 @@ package goesl
9
9
import (
10
10
"bufio"
11
11
"bytes"
12
+ "context"
12
13
"fmt"
13
14
"io"
14
15
"net"
@@ -18,11 +19,17 @@ import (
18
19
"time"
19
20
)
20
21
22
+ type message struct {
23
+ err error
24
+ m * Message
25
+ }
26
+
21
27
// Main connection against ESL - Gotta add more description here
22
28
type SocketConnection struct {
23
29
net.Conn
24
- err chan error
25
- m chan * Message
30
+
31
+ receive chan message
32
+
26
33
mtx sync.Mutex
27
34
}
28
35
@@ -32,7 +39,7 @@ func (c *SocketConnection) Dial(network string, addr string, timeout time.Durati
32
39
}
33
40
34
41
// Send - Will send raw message to open net connection
35
- func (c * SocketConnection ) Send (cmd string ) error {
42
+ func (c * SocketConnection ) Send (ctx context. Context , cmd string ) error {
36
43
37
44
if strings .Contains (cmd , "\r \n " ) {
38
45
return fmt .Errorf (EInvalidCommandProvided , cmd )
@@ -42,6 +49,12 @@ func (c *SocketConnection) Send(cmd string) error {
42
49
c .mtx .Lock ()
43
50
defer c .mtx .Unlock ()
44
51
52
+ deadline , ok := ctx .Deadline ()
53
+ if ok {
54
+ _ = c .SetWriteDeadline (deadline )
55
+ defer func () { _ = c .SetWriteDeadline (time.Time {}) }()
56
+ }
57
+
45
58
_ , err := io .WriteString (c , cmd )
46
59
if err != nil {
47
60
return err
@@ -56,10 +69,10 @@ func (c *SocketConnection) Send(cmd string) error {
56
69
}
57
70
58
71
// SendMany - Will loop against passed commands and return 1st error if error happens
59
- func (c * SocketConnection ) SendMany (cmds []string ) error {
72
+ func (c * SocketConnection ) SendMany (ctx context. Context , cmds []string ) error {
60
73
61
74
for _ , cmd := range cmds {
62
- if err := c .Send (cmd ); err != nil {
75
+ if err := c .Send (ctx , cmd ); err != nil {
63
76
return err
64
77
}
65
78
}
@@ -68,7 +81,7 @@ func (c *SocketConnection) SendMany(cmds []string) error {
68
81
}
69
82
70
83
// SendEvent - Will loop against passed event headers
71
- func (c * SocketConnection ) SendEvent (eventHeaders []string ) error {
84
+ func (c * SocketConnection ) SendEvent (ctx context. Context , eventHeaders []string ) error {
72
85
if len (eventHeaders ) <= 0 {
73
86
return fmt .Errorf (ECouldNotSendEvent , len (eventHeaders ))
74
87
}
@@ -77,18 +90,20 @@ func (c *SocketConnection) SendEvent(eventHeaders []string) error {
77
90
c .mtx .Lock ()
78
91
defer c .mtx .Unlock ()
79
92
93
+ deadline , ok := ctx .Deadline ()
94
+ if ok {
95
+ _ = c .SetWriteDeadline (deadline )
96
+ defer func () { _ = c .SetWriteDeadline (time.Time {}) }()
97
+ }
98
+
80
99
_ , err := io .WriteString (c , "sendevent " )
81
100
if err != nil {
82
101
return err
83
102
}
84
103
85
104
for _ , eventHeader := range eventHeaders {
86
- _ , err := io .WriteString (c , eventHeader )
87
- if err != nil {
88
- return err
89
- }
90
105
91
- _ , err = io .WriteString (c , "\r \n " )
106
+ _ , err : = io .WriteString (c , eventHeader + "\r \n " )
92
107
if err != nil {
93
108
return err
94
109
}
@@ -104,27 +119,29 @@ func (c *SocketConnection) SendEvent(eventHeaders []string) error {
104
119
}
105
120
106
121
// Execute - Helper fuck to execute commands with its args and sync/async mode
107
- func (c * SocketConnection ) Execute (command , args string , sync bool ) (m * Message , err error ) {
108
- return c .SendMsg (map [string ]string {
109
- "call-command" : "execute" ,
110
- "execute-app-name" : command ,
111
- "execute-app-arg" : args ,
112
- "event-lock" : strconv .FormatBool (sync ),
113
- }, "" , "" )
122
+ func (c * SocketConnection ) Execute (ctx context.Context , command , args string , sync bool ) (m * Message , err error ) {
123
+ return c .SendMsg (ctx ,
124
+ map [string ]string {
125
+ "call-command" : "execute" ,
126
+ "execute-app-name" : command ,
127
+ "execute-app-arg" : args ,
128
+ "event-lock" : strconv .FormatBool (sync ),
129
+ }, "" , "" )
114
130
}
115
131
116
132
// ExecuteUUID - Helper fuck to execute uuid specific commands with its args and sync/async mode
117
- func (c * SocketConnection ) ExecuteUUID (uuid string , command string , args string , sync bool ) (m * Message , err error ) {
118
- return c .SendMsg (map [string ]string {
119
- "call-command" : "execute" ,
120
- "execute-app-name" : command ,
121
- "execute-app-arg" : args ,
122
- "event-lock" : strconv .FormatBool (sync ),
123
- }, uuid , "" )
133
+ func (c * SocketConnection ) ExecuteUUID (ctx context.Context , uuid string , command string , args string , sync bool ) (m * Message , err error ) {
134
+ return c .SendMsg (ctx ,
135
+ map [string ]string {
136
+ "call-command" : "execute" ,
137
+ "execute-app-name" : command ,
138
+ "execute-app-arg" : args ,
139
+ "event-lock" : strconv .FormatBool (sync ),
140
+ }, uuid , "" )
124
141
}
125
142
126
143
// SendMsg - Basically this func will send message to the opened connection
127
- func (c * SocketConnection ) SendMsg (msg map [string ]string , uuid , data string ) (m * Message , err error ) {
144
+ func (c * SocketConnection ) SendMsg (ctx context. Context , msg map [string ]string , uuid , data string ) (* Message , error ) {
128
145
129
146
b := bytes .NewBufferString ("sendmsg" )
130
147
@@ -160,19 +177,26 @@ func (c *SocketConnection) SendMsg(msg map[string]string, uuid, data string) (m
160
177
161
178
// lock mutex
162
179
c .mtx .Lock ()
163
- _ , err = b .WriteTo (c )
180
+ defer c .mtx .Unlock ()
181
+
182
+ deadline , ok := ctx .Deadline ()
183
+ if ok {
184
+ _ = c .SetWriteDeadline (deadline )
185
+ defer func () { _ = c .SetWriteDeadline (time.Time {}) }()
186
+ }
187
+
188
+ _ , err := b .WriteTo (c )
164
189
if err != nil {
165
- c .mtx .Unlock ()
166
190
return nil , err
167
191
}
168
- c .mtx .Unlock ()
169
192
170
- select {
171
- case err := <- c . err :
193
+ m , err := c . ReadMessage ( ctx )
194
+ if err != nil {
172
195
return nil , err
173
- case m := <- c .m :
174
- return m , nil
175
196
}
197
+
198
+ return m , nil
199
+
176
200
}
177
201
178
202
// OriginatorAdd - Will return originator address known as net.RemoteAddr()
@@ -183,40 +207,65 @@ func (c *SocketConnection) OriginatorAddr() net.Addr {
183
207
184
208
// ReadMessage - Will read message from channels and return them back accordingy.
185
209
// If error is received, error will be returned. If not, message will be returned back!
186
- func (c * SocketConnection ) ReadMessage () (* Message , error ) {
210
+ func (c * SocketConnection ) ReadMessage (ctx context. Context ) (* Message , error ) {
187
211
Debug ("Waiting for connection message to be received ..." )
188
212
213
+ var m message
189
214
select {
190
- case err := <- c .err :
191
- return nil , err
192
- case msg := <- c .m :
193
- return msg , nil
215
+ case m = <- c .receive :
216
+ case <- ctx .Done ():
217
+ return nil , fmt .Errorf ("context deadline exceeded" )
218
+ }
219
+
220
+ if m .m == nil {
221
+ return nil , fmt .Errorf ("unable to read message, channel closed" )
222
+ }
223
+
224
+ if m .err != nil {
225
+ return nil , m .err
194
226
}
227
+
228
+ return m .m , nil
195
229
}
196
230
231
+ const (
232
+ defaultHandleTimeout = time .Second
233
+ )
234
+
197
235
// Handle - Will handle new messages and close connection when there are no messages left to process
198
236
func (c * SocketConnection ) Handle () {
199
237
200
- done := make (chan bool )
238
+ done := make (chan struct {} )
201
239
202
240
go func () {
203
241
for {
204
- msg , err := newMessage (bufio .NewReaderSize (c , ReadBufferSize ), true )
205
242
243
+ msg , err := newMessage (bufio .NewReaderSize (c , ReadBufferSize ), true )
206
244
if err != nil {
207
- c .err <- err
208
- done <- true
245
+
246
+ select {
247
+ case c .receive <- message {err : err }:
248
+ case <- time .After (defaultHandleTimeout ):
249
+ }
250
+
251
+ close (done )
209
252
break
210
253
}
211
254
212
- c .m <- msg
255
+ select {
256
+ case c .receive <- message {m : msg }:
257
+ case <- time .After (defaultHandleTimeout ):
258
+ // if messages are getting dropped, receive syncronization will be messed up and unreliable
259
+ }
213
260
}
214
261
}()
215
262
216
263
<- done
217
264
265
+ close (c .receive )
266
+
218
267
// Closing the connection now as there's nothing left to do ...
219
- c .Close ()
268
+ _ = c .Close ()
220
269
}
221
270
222
271
// Close - Will close down net connection and return error if error happen
0 commit comments