forked from st3v/go-plugins
-
Notifications
You must be signed in to change notification settings - Fork 0
/
stream.go
131 lines (109 loc) · 1.97 KB
/
stream.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
package http
import (
"bufio"
"bytes"
"context"
"errors"
"io/ioutil"
"net"
"net/http"
"net/url"
"sync"
"github.com/micro/go-micro/client"
)
// Implements the streamer interface
type httpStream struct {
sync.RWMutex
address string
codec Codec
context context.Context
header http.Header
seq uint64
closed chan bool
err error
conn net.Conn
reader *bufio.Reader
request client.Request
}
var (
errShutdown = errors.New("connection is shut down")
)
func (h *httpStream) isClosed() bool {
select {
case <-h.closed:
return true
default:
return false
}
}
func (h *httpStream) Context() context.Context {
return h.context
}
func (h *httpStream) Request() client.Request {
return h.request
}
func (h *httpStream) Response() client.Response {
return nil
}
func (h *httpStream) Send(msg interface{}) error {
h.Lock()
defer h.Unlock()
if h.isClosed() {
h.err = errShutdown
return errShutdown
}
b, err := h.codec.Marshal(msg)
if err != nil {
return err
}
buf := &buffer{bytes.NewBuffer(b)}
defer buf.Close()
req := &http.Request{
Method: "POST",
URL: &url.URL{
Scheme: "http",
Host: h.address,
Path: h.request.Endpoint(),
},
Header: h.header,
Body: buf,
ContentLength: int64(len(b)),
Host: h.address,
}
return req.Write(h.conn)
}
func (h *httpStream) Recv(msg interface{}) error {
h.Lock()
defer h.Unlock()
if h.isClosed() {
h.err = errShutdown
return errShutdown
}
rsp, err := http.ReadResponse(h.reader, new(http.Request))
if err != nil {
return err
}
defer rsp.Body.Close()
b, err := ioutil.ReadAll(rsp.Body)
if err != nil {
return err
}
if rsp.StatusCode != 200 {
return errors.New(rsp.Status + ": " + string(b))
}
return h.codec.Unmarshal(b, msg)
}
func (h *httpStream) Error() error {
h.RLock()
defer h.RUnlock()
return h.err
}
func (h *httpStream) Close() error {
select {
case <-h.closed:
return nil
default:
close(h.closed)
return h.conn.Close()
}
}