-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathwow.go
103 lines (79 loc) · 2.76 KB
/
wow.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
package main
import (
"context"
"fmt"
"log/slog"
"strconv"
"strings"
"time"
"word-of-wisdom-go/internal/api/tcp/commands"
"word-of-wisdom-go/internal/services"
"go.uber.org/dig"
)
type WOWCommand interface {
Process(ctx context.Context, session *services.SessionIO) (string, error)
}
type WOWCommandFunc func(ctx context.Context, session *services.SessionIO) (string, error)
func (f WOWCommandFunc) Process(ctx context.Context, session *services.SessionIO) (string, error) {
return f(ctx, session)
}
var _ WOWCommandFunc = WOWCommandFunc(nil)
type challengesService interface {
SolveChallenge(ctx context.Context, complexity int, challenge string) (string, error)
}
type WOWCommandDeps struct {
dig.In
RootLogger *slog.Logger
// app layer
Challenges challengesService
}
func newWOWCommand(deps WOWCommandDeps) WOWCommand {
logger := deps.RootLogger.WithGroup("client")
return WOWCommandFunc(func(ctx context.Context, session *services.SessionIO) (string, error) {
logger.DebugContext(ctx, "Sending GET_WOW request")
if err := session.WriteLine(commands.CommandGetWow); err != nil {
return "", fmt.Errorf("failed to write to the server: %w", err)
}
line, err := session.ReadLine()
if err != nil {
return "", fmt.Errorf("failed to read the response: %w", err)
}
logger.DebugContext(ctx, "Got response", slog.String("data", line))
if strings.Index(line, commands.WowResponsePrefix) == 0 {
logger.DebugContext(ctx, "Got WOW response. No challenge required")
return strings.Trim(line[4:], " "), nil
}
if strings.Index(line, commands.ChallengeRequiredPrefix) != 0 {
return "", fmt.Errorf("got unexpected challenge requirement response %s: %w", line, err)
}
separatorIndex := strings.Index(line, ";")
challenge := strings.Trim(line[len(commands.ChallengeRequiredPrefix):separatorIndex], " ")
complexity, err := strconv.Atoi(line[separatorIndex+1:])
if err != nil {
return "", err
}
solveStartedAt := time.Now()
solution, err := deps.Challenges.SolveChallenge(ctx, complexity, challenge)
if err != nil {
return "", err
}
logger.DebugContext(
ctx,
"Challenge solved. Sending challenge result",
slog.Duration("solutionDuration", time.Since(solveStartedAt)),
slog.String("solution", solution),
)
if err = session.WriteLine(commands.ChallengeResultPrefix + solution); err != nil {
return "", fmt.Errorf("failed to write to the server: %w", err)
}
line, err = session.ReadLine()
if err != nil {
return "", fmt.Errorf("failed to read the response: %w", err)
}
logger.DebugContext(ctx, "Got response", slog.String("data", line))
if strings.Index(line, commands.WowResponsePrefix) == 0 {
return strings.Trim(line[4:], " "), nil
}
return "", fmt.Errorf("got unexpected WOW response %s", line)
})
}