-
Notifications
You must be signed in to change notification settings - Fork 3
/
service_client.go
121 lines (99 loc) · 3.11 KB
/
service_client.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
package service
import (
"bufio"
"errors"
"io"
"github.com/pvarentsov/powtcp/internal/pkg/lib/hashcash"
"github.com/pvarentsov/powtcp/internal/pkg/lib/message"
)
// Opts - options to create new cache instance
type ClientOpts struct {
Logger Logger
Config ClientConfig
}
// NewClient - create new client-side service
func NewClient(opts ClientOpts) *Client {
return &Client{
logger: opts.Logger,
config: opts.Config,
}
}
// Client - client-side service
type Client struct {
logger Logger
config ClientConfig
}
// RequestResource - request server resource
func (c *Client) RequestResource(clientID string, rw io.ReadWriter) (resource string, err error) {
const op = "service.Client.RequestResource"
c.logger.Info("connection established", "clientID", clientID)
puzzleReqMsg := message.Message{
Command: message.CommandRequestPuzzle,
}
c.logger.Info("requesting puzzle", "clientID", clientID)
puzzle, err := c.request(clientID, puzzleReqMsg, rw)
if err != nil {
c.logger.Error(err.Error(), "op", op, "clientID", clientID)
return
}
c.logger.Info("puzzle received", "clientID", clientID, "puzzle", puzzle)
hashcash, err := hashcash.ParseHeader(puzzle)
if err != nil {
c.logger.Error(err.Error(), "op", op, "clientID", clientID)
return
}
c.logger.Info("solving puzzle", "clientID", clientID)
if err = hashcash.Compute(c.config.PuzzleComputeMaxAttempts()); err != nil {
c.logger.Error(err.Error(), "op", op, "clientID", clientID)
return
}
c.logger.Info("puzzle solved", "clientID", clientID, "counter", hashcash.Counter())
resourceReqMsg := message.Message{
Command: message.CommandRequestResource,
Payload: string(hashcash.Header()),
}
c.logger.Info("requesting resource", "clientID", clientID)
resource, err = c.request(clientID, resourceReqMsg, rw)
if err != nil {
c.logger.Error(err.Error(), "op", op, "clientID", clientID)
return
}
c.logger.Info("resource received", "clientID", clientID, "resource", resource)
return
}
func (c *Client) request(clientID string, msg message.Message, rw io.ReadWriter) (payload string, err error) {
if err = c.writeMsg(clientID, msg, rw); err != nil {
return
}
rawResMsg, err := bufio.NewReader(rw).ReadString(message.DelimiterMessage)
if err != nil {
return
}
resMsg, err := message.ParseMessage(rawResMsg)
if err != nil {
return
}
if err = c.checkResMessage(msg.Command, resMsg); err != nil {
return
}
return resMsg.Payload, nil
}
func (s *Client) writeMsg(clientID string, msg message.Message, w io.Writer) (err error) {
const op = "service.Client.writeMsg"
if _, err = w.Write(msg.Bytes()); err != nil {
s.logger.Error(err.Error(), "op", op, "clientID", clientID)
}
return
}
func (s *Client) checkResMessage(reqCmd message.Command, resMsg message.Message) (err error) {
if resMsg.Command == message.CommandError {
return errors.New(resMsg.Payload)
}
if reqCmd == message.CommandRequestPuzzle && resMsg.Command != message.CommandResponsePuzzle {
return ErrResponseCommandNotcorrect
}
if reqCmd == message.CommandRequestResource && resMsg.Command != message.CommandResponseResource {
return ErrResponseCommandNotcorrect
}
return
}