forked from crypt0train/go-cgminer-api
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathtransport.go
89 lines (74 loc) · 2.18 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
package cgminer
import (
"bufio"
"bytes"
"encoding/json"
"io"
"net"
)
// AbstractResponse is generic command response which provides execution status
type AbstractResponse interface {
// HasError returns status error
HasError() error
}
// Transport encodes request and decodes response from cgminer API.
//
// CGMiner have two communication formats: JSON and plain-text.
// One of them or both might be enabled.
//
// Use corresponding transport for specific case.
type Transport interface {
// SendCommand encodes and sends passed command
SendCommand(conn net.Conn, cmd Command) error
// DecodeResponse reads and decodes response from CGMiner API connection.
//
// Response destination is passed to "out" and should be pointer.
//
// nil "out" value can be passed if command doesn't returns any response.
DecodeResponse(conn net.Conn, cmd Command, out AbstractResponse) error
}
var _ Transport = (*JSONTransport)(nil)
type JSONTransport struct{}
// NewJSONTransport returns JSON encoding/decoding transport
func NewJSONTransport() JSONTransport {
return JSONTransport{}
}
// SendCommand implements Transport interface
func (t JSONTransport) SendCommand(conn net.Conn, cmd Command) error {
return json.NewEncoder(conn).Encode(cmd)
}
// DecodeResponse implements Transport interface
func (t JSONTransport) DecodeResponse(conn net.Conn, cmd Command, out AbstractResponse) error {
rsp, err := readWithNullTerminator(conn)
if err != nil && err != io.EOF {
return err
}
// fix incorrect json response from miner ("}{")
if cmd.Command == "stats" {
rsp = bytes.Replace(rsp, []byte("}{"), []byte(","), 1)
}
isEmpty := out == nil
if isEmpty {
if len(rsp) == 0 {
return nil
}
out = new(GenericResponse)
}
if err := json.Unmarshal(rsp, out); err != nil {
if isEmpty {
// just omit error if consumer passed empty response output
return nil
}
return err
}
return out.HasError()
}
// readWithNullTerminator reads cgminer response, but stops
// at null terminator (0x00)
func readWithNullTerminator(r io.Reader) ([]byte, error) {
result, err := bufio.NewReader(r).ReadBytes(0x00)
if err != nil && err != io.EOF {
return nil, err
}
return bytes.TrimRight(result, "\x00"), nil
}