forked from crypt0train/go-cgminer-api
-
Notifications
You must be signed in to change notification settings - Fork 3
/
cgminer.go
110 lines (92 loc) · 2.82 KB
/
cgminer.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
package cgminer
import (
"context"
"fmt"
"net"
"time"
)
// Dialer is abstract network dialer
type Dialer interface {
DialContext(ctx context.Context, network, address string) (net.Conn, error)
Dial(network, address string) (net.Conn, error)
}
// ConnectError represents API connection error
type ConnectError struct {
err error
}
// NewConnectError wraps error as ConnectError
func NewConnectError(baseError error) ConnectError {
return ConnectError{err: baseError}
}
// Error implements error
func (err ConnectError) Error() string {
return fmt.Sprintf("connect error (%s)", err.err)
}
// Unwrap implements error
func (err ConnectError) Unwrap() error {
return err.err
}
// CGMiner is cgminer API client
type CGMiner struct {
// Address is API endpoint address (host:port)
Address string
// Timeout is request timeout
Timeout time.Duration
// Dialer is network dialer
Dialer Dialer
// Transport is request and response decoder.
//
// CGMiner might have one of two API formats - JSON or plain text.
// JSON is default one.
Transport Transport
}
// Call sends command to cgminer API and writes result to passed response output
// or returns error.
//
// If command doesn't returns any response, nil "out" value should be passed.
//
// For context-based requests, use `CallContext()`
func (c *CGMiner) Call(cmd Command, out AbstractResponse) error {
return c.CallContext(context.Background(), cmd, out)
}
// CallContext sends command to cgminer API using the provided context.
//
// If command doesn't returns any response, nil "out" value should be passed.
func (c *CGMiner) CallContext(ctx context.Context, cmd Command, out AbstractResponse) error {
conn, err := c.Dialer.DialContext(ctx, "tcp", c.Address)
if err != nil {
return ConnectError{err: err}
}
defer conn.Close()
_ = conn.SetDeadline(time.Now().Add(c.Timeout))
if err = c.Transport.SendCommand(conn, cmd); err != nil {
return fmt.Errorf("failed to send cgminer command: %w", err)
}
return c.Transport.DecodeResponse(conn, cmd, out)
}
// RawCall sends command to CGMiner API and returns raw response as slice of bytes.
//
// Response error check should be performed manually.
func (c *CGMiner) RawCall(ctx context.Context, cmd Command) ([]byte, error) {
conn, err := c.Dialer.DialContext(ctx, "tcp", c.Address)
if err != nil {
return nil, ConnectError{err: err}
}
defer conn.Close()
_ = conn.SetDeadline(time.Now().Add(c.Timeout))
if err = c.Transport.SendCommand(conn, cmd); err != nil {
return nil, err
}
return readWithNullTerminator(conn)
}
// NewCGMiner returns a CGMiner client with JSON API transport
func NewCGMiner(hostname string, port int, timeout time.Duration) *CGMiner {
return &CGMiner{
Address: fmt.Sprintf("%s:%d", hostname, port),
Timeout: timeout,
Transport: NewJSONTransport(),
Dialer: &net.Dialer{
Timeout: timeout,
},
}
}