-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient.go
142 lines (123 loc) · 3.3 KB
/
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/mainpart/tcp-pow/util"
"io"
"net"
"time"
)
func main() {
fmt.Println("start client")
configInst, err := util.LoadConfig("config.yaml")
if err != nil {
fmt.Println("error load config:", err)
return
}
ctx := context.Background()
ctx = context.WithValue(ctx, "config", configInst)
address := fmt.Sprintf("%s:%d", configInst.ServerHost, configInst.ServerPort)
err = runClient(ctx, address)
if err != nil {
fmt.Println("client error:", err)
}
}
func runClient(ctx context.Context, address string) error {
// client will send new request every 5 seconds endlessly
for {
message, err := handleConnectionClient(ctx, address)
if err != nil {
return err
}
fmt.Println("quote result:", message)
time.Sleep(5 * time.Second)
}
}
// создаем два запроса - в одном из них запрашиваем pow задачу
// во втором - даем ответ
func handleConnectionClient(ctx context.Context, address string) (string, error) {
// соединились с хостом
conn, err := net.Dial("tcp", address)
if err != nil {
return "", err
}
resource, err := util.GetRandSalt(10)
if err != nil {
return "", fmt.Errorf("err getting resource: %w", err)
}
// запросили задачку
err = util.SendMsg(util.Message{
Header: util.RequestChallenge,
Resource: resource,
}, conn)
if err != nil {
return "", fmt.Errorf("err send request: %w", err)
}
msgStr, err := readConnMsg(conn)
if err != nil {
return "", fmt.Errorf("err read msg: %w", err)
}
// закрыли соединение
_ = conn.Close()
msg, err := util.ParseMessage(string(msgStr))
if err != nil {
return "", fmt.Errorf("err parse msg: %w", err)
}
var hashcash util.Hashcash
err = json.Unmarshal([]byte(msg.Payload), &hashcash)
if err != nil {
return "", fmt.Errorf("err parse hashcash: %w", err)
}
fmt.Println("got hashcash:", hashcash)
// посчитали задачку
conf := ctx.Value("config").(*util.Config)
hashcash, err = hashcash.ComputeHashcash(conf.HashcashMaxIterations)
if err != nil {
return "", fmt.Errorf("err compute hashcash: %w", err)
}
fmt.Println("hashcash computed:", hashcash)
byteData, err := json.Marshal(hashcash)
if err != nil {
return "", fmt.Errorf("err marshal hashcash: %w", err)
}
// снова соединились с хостом
conn, err = net.Dial("tcp", address)
if err != nil {
return "", err
}
// отправили результат
err = util.SendMsg(util.Message{
Header: util.RequestResource,
Resource: resource,
Payload: string(byteData),
}, conn)
if err != nil {
return "", fmt.Errorf("err send request: %w", err)
}
// прочитали ответ
msgStr, err = readConnMsg(conn)
if err != nil {
return "", fmt.Errorf("err read msg: %w", err)
}
msg, err = util.ParseMessage(string(msgStr))
if err != nil {
return "", fmt.Errorf("err parse msg: %w", err)
}
return msg.Payload, nil
}
func readConnMsg(connect net.Conn) ([]byte, error) {
buf := make([]byte, 0, 4096) // big buffer
tmp := make([]byte, 256) // using small tmo buffer for demonstrating
for {
n, err := connect.Read(tmp)
if err != nil {
if err != io.EOF {
return nil, err
}
break
}
buf = append(buf, tmp[:n]...)
}
return buf, nil
}