forked from checksum0/go-electrum
-
Notifications
You must be signed in to change notification settings - Fork 1
/
transport.go
143 lines (121 loc) · 2.59 KB
/
transport.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
package electrum
import (
"bufio"
"context"
"crypto/tls"
"log"
"net"
"time"
)
// TCPTransport store information about the TCP transport.
type TCPTransport struct {
conn net.Conn
responses chan []byte
errors chan error
}
// DialerOption is a function that configures a TCPTransport.
type DialerOption func(*net.Dialer)
func withOptions(opts map[string]interface{}) []DialerOption {
var options []DialerOption
for k, v := range opts {
switch k {
case "timeout":
options = append(options, func(d *net.Dialer) {
d.Timeout = v.(time.Duration)
})
}
}
return options
}
// NewTCPTransport opens a new TCP connection to the remote server.
func NewTCPTransport(
ctx context.Context,
addr string,
options ...DialerOption,
) (*TCPTransport, error) {
var d = net.Dialer{}
for _, option := range options {
option(&d)
}
conn, err := d.DialContext(ctx, "tcp", addr)
if err != nil {
return nil, err
}
tcp := &TCPTransport{
conn: conn,
responses: make(chan []byte),
errors: make(chan error),
}
go tcp.listen()
return tcp, nil
}
// NewSSLTransport opens a new SSL connection to the remote server.
func NewSSLTransport(
ctx context.Context,
addr string,
config *tls.Config,
options ...DialerOption,
) (*TCPTransport, error) {
dialer := tls.Dialer{
NetDialer: &net.Dialer{},
Config: config,
}
for _, option := range options {
option(dialer.NetDialer)
}
conn, err := dialer.DialContext(ctx, "tcp", addr)
if err != nil {
return nil, err
}
tcp := &TCPTransport{
conn: conn,
responses: make(chan []byte),
errors: make(chan error),
}
go tcp.listen()
return tcp, nil
}
func (t *TCPTransport) listen() {
defer t.conn.Close()
reader := bufio.NewReader(t.conn)
for {
line, err := reader.ReadBytes(nl)
if err != nil {
t.errors <- err
break
}
if DebugMode {
log.Printf(
"%s [debug] %s -> %s",
time.Now().Format("2006-01-02 15:04:05"),
t.conn.RemoteAddr(),
line,
)
}
t.responses <- line
}
}
// SendMessage sends a message to the remote server through the TCP transport.
func (t *TCPTransport) SendMessage(body []byte) error {
if DebugMode {
log.Printf(
"%s [debug] %s <- %s",
time.Now().Format("2006-01-02 15:04:05"),
t.conn.RemoteAddr(),
body,
)
}
_, err := t.conn.Write(body)
return err
}
// Responses returns chan to TCP transport responses.
func (t *TCPTransport) Responses() <-chan []byte {
return t.responses
}
// Errors returns chan to TCP transport errors.
func (t *TCPTransport) Errors() <-chan error {
return t.errors
}
func (t *TCPTransport) Close() error {
return t.conn.Close()
}