• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gameap / gameap / 25960901307

16 May 2026 11:29AM UTC coverage: 76.887% (+0.2%) from 76.64%
25960901307

push

github

et-nik
audit logs tests

45395 of 59041 relevant lines covered (76.89%)

33895.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.13
/internal/api/servers/postconsole/handler.go
1
package postconsole
2

3
import (
4
        "context"
5
        "encoding/json"
6
        "net/http"
7
        "os"
8
        "path/filepath"
9

10
        "github.com/gameap/gameap/internal/api/base"
11
        serversbase "github.com/gameap/gameap/internal/api/servers/base"
12
        "github.com/gameap/gameap/internal/daemon"
13
        "github.com/gameap/gameap/internal/domain"
14
        "github.com/gameap/gameap/internal/filters"
15
        "github.com/gameap/gameap/internal/repositories"
16
        "github.com/gameap/gameap/pkg/api"
17
        "github.com/gameap/gameap/pkg/auth"
18
        "github.com/pkg/errors"
19
)
20

21
type daemonCommands interface {
22
        ExecuteCommand(
23
                ctx context.Context,
24
                node *domain.Node,
25
                command string,
26
                opts ...daemon.CommandServiceOption,
27
        ) (*daemon.CommandResult, error)
28
}
29

30
type fileService interface {
31
        Upload(
32
                ctx context.Context, node *domain.Node, filePath string,
33
                content []byte, perms os.FileMode, owner daemon.OwnerOptions,
34
        ) error
35
}
36

37
type Handler struct {
38
        serverFinder   *serversbase.ServerFinder
39
        abilityChecker *serversbase.AbilityChecker
40
        nodeRepo       repositories.NodeRepository
41
        daemonCommands daemonCommands
42
        fileService    fileService
43
        responder      base.Responder
44
}
45

46
func NewHandler(
47
        serverRepo repositories.ServerRepository,
48
        nodeRepo repositories.NodeRepository,
49
        rbac base.RBAC,
50
        daemonCommands daemonCommands,
51
        fs fileService,
52
        responder base.Responder,
53
) *Handler {
12✔
54
        return &Handler{
12✔
55
                serverFinder:   serversbase.NewServerFinder(serverRepo, rbac),
12✔
56
                abilityChecker: serversbase.NewAbilityChecker(rbac),
12✔
57
                nodeRepo:       nodeRepo,
12✔
58
                daemonCommands: daemonCommands,
12✔
59
                fileService:    fs,
12✔
60
                responder:      responder,
12✔
61
        }
12✔
62
}
12✔
63

64
func (h *Handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
11✔
65
        ctx := r.Context()
11✔
66

11✔
67
        session := auth.SessionFromContext(ctx)
11✔
68
        if !session.IsAuthenticated() {
12✔
69
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
1✔
70
                        errors.New("user not authenticated"),
1✔
71
                        http.StatusUnauthorized,
1✔
72
                ))
1✔
73

1✔
74
                return
1✔
75
        }
1✔
76

77
        input := api.NewInputReader(r)
10✔
78

10✔
79
        serverID, err := input.ReadUint("server")
10✔
80
        if err != nil {
11✔
81
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
1✔
82
                        errors.WithMessage(err, "invalid server id"),
1✔
83
                        http.StatusBadRequest,
1✔
84
                ))
1✔
85

1✔
86
                return
1✔
87
        }
1✔
88

89
        server, err := h.serverFinder.FindUserServer(ctx, session.User, serverID)
9✔
90
        if err != nil {
10✔
91
                h.responder.WriteError(ctx, rw, err)
1✔
92

1✔
93
                return
1✔
94
        }
1✔
95

96
        if err = h.abilityChecker.CheckOrError(
8✔
97
                ctx,
8✔
98
                session.User.ID,
8✔
99
                server.ID,
8✔
100
                []domain.AbilityName{domain.AbilityNameGameServerConsoleSend},
8✔
101
        ); err != nil {
9✔
102
                h.responder.WriteError(ctx, rw, err)
1✔
103

1✔
104
                return
1✔
105
        }
1✔
106

107
        var in consoleInput
7✔
108
        if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
8✔
109
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
1✔
110
                        errors.WithMessage(err, "failed to parse request body"),
1✔
111
                        http.StatusBadRequest,
1✔
112
                ))
1✔
113

1✔
114
                return
1✔
115
        }
1✔
116

117
        if err := in.validate(); err != nil {
7✔
118
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
1✔
119
                        err,
1✔
120
                        http.StatusBadRequest,
1✔
121
                ))
1✔
122

1✔
123
                return
1✔
124
        }
1✔
125

126
        if err := h.sendConsoleCommand(ctx, server, in.Command); err != nil {
8✔
127
                h.responder.WriteError(ctx, rw, errors.WithMessage(err, "failed to send console command"))
3✔
128

3✔
129
                return
3✔
130
        }
3✔
131

132
        h.responder.Write(ctx, rw, newConsoleResponse())
2✔
133
}
134

135
func (h *Handler) sendConsoleCommand(ctx context.Context, server *domain.Server, command string) error {
5✔
136
        nodes, err := h.nodeRepo.Find(ctx, &filters.FindNode{
5✔
137
                IDs: []uint{server.DSID},
5✔
138
        }, nil, &filters.Pagination{
5✔
139
                Limit: 1,
5✔
140
        })
5✔
141
        if err != nil {
5✔
142
                return errors.WithMessage(err, "failed to find node")
×
143
        }
×
144

145
        if len(nodes) == 0 {
6✔
146
                return api.NewNotFoundError("node not found")
1✔
147
        }
1✔
148

149
        node := &nodes[0]
4✔
150

4✔
151
        if node.ScriptSendCommand != nil && *node.ScriptSendCommand != "" {
6✔
152
                cmd := server.ReplaceServerShortcodes(node, *node.ScriptSendCommand, map[string]string{
2✔
153
                        "command": command,
2✔
154
                })
2✔
155

2✔
156
                _, err := h.daemonCommands.ExecuteCommand(ctx, node, cmd)
2✔
157
                if err != nil {
3✔
158
                        return errors.WithMessage(err, "failed to execute send command script")
1✔
159
                }
1✔
160

161
                return nil
1✔
162
        }
163

164
        return h.uploadInputFile(ctx, node, server, command)
2✔
165
}
166

167
func (h *Handler) uploadInputFile(
168
        ctx context.Context, node *domain.Node, server *domain.Server, command string,
169
) error {
2✔
170
        inputPath := filepath.Join(server.Dir, "input.txt")
2✔
171

2✔
172
        err := h.fileService.Upload(
2✔
173
                ctx, node, inputPath, []byte(command), 0o644, daemon.OwnerFromServer(server),
2✔
174
        )
2✔
175
        if err != nil {
3✔
176
                return errors.WithMessage(err, "failed to upload console command")
1✔
177
        }
1✔
178

179
        return nil
1✔
180
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc