/
dice_server.go
196 lines (162 loc) · 4.03 KB
/
dice_server.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
package server
import (
"encoding/json"
"log"
"net/http"
"strconv"
"github.com/aakordas/creature_manager/pkg/dice"
"github.com/gorilla/mux"
)
// TODO: Make the responses get formed in a go routine, instead of everything
// staying in the main server.
// TODO: Testing for the functions that accept ResponseWriters and Requests.
type rollResponse struct {
Count int `json:"count" bson:"count"` // The number of dice that got rolled.
Sides int `json:"sides" bson:"sides"` // The number of sides each dice had.
Result int `json:"result" bson:"result"` // The result of the rolling.
}
type errorResponse struct {
Error string `json:"error" bson:"error"`
ErrorMessage string `json:"error_message" bson:"error_message"`
}
// writeHeader writes the header of a valid response.
// func writeHeader(w http.ResponseWriter) {
// w.Header().Set("Content-Type", "application/json")
// w.WriteHeader(http.StatusOK)
// }
// jsonEncode wraps the json.Encoder.Encode and error checking.
func jsonEncode(w http.ResponseWriter, enc *json.Encoder, v interface{}) {
if err := enc.Encode(v); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
// rollDice rolls the specified number of the specified dice.
func rollDice(sides, count int) (result int) {
d := chooseDice(sides)
if d == nil {
return 0
}
for i := 0; i < count; i++ {
result += d()
}
return result
}
// getSides gets the integer value from the sides from the passed string.
func getSides(sides string) int {
if sides == "" {
return 20
}
s, err := strconv.Atoi(sides)
if err != nil {
return 0
}
return s
}
// getCount gets the integer value from the count from the passed string.
func getCount(count string) int {
if count == "" {
return 1
}
c, err := strconv.Atoi(count)
if err != nil {
return 0
}
return c
}
func unexpectedError(w http.ResponseWriter) {
// TODO: Add some logging here, too?
http.Error(
w,
"The server might have encountered an error. Please try again.",
http.StatusInternalServerError,
)
}
// Roll is the handler for all the requested rolls of one die.
func Roll(w http.ResponseWriter, r *http.Request) {
sides := r.FormValue("sides")
count := r.FormValue("count")
s := getSides(sides)
if s == 0 {
unexpectedError(w)
return
}
c := getCount(count)
if c == 0 {
unexpectedError(w)
return
}
response(w, s, c)
}
// chooseDice chooses the appropriate dice given a number of sides and returns
// it and the number of sides as an integer..
func chooseDice(sides int) dice.Dice {
switch sides {
case 4:
return dice.D4
case 6:
return dice.D6
case 8:
return dice.D8
case 10:
return dice.D10
case 12:
return dice.D12
case 20:
return dice.D20
case 100:
return dice.D100
default:
return nil
}
}
// response deals with the response part of the HTTP response, whether that is an error response or not.
func response(w http.ResponseWriter, s, c int) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
result := rollDice(s, c)
enc := json.NewEncoder(w)
if result == 0 {
errorResponse := errorResponse{"invalid sides", "The dice requested is not available."}
jsonEncode(w, enc, errorResponse)
return
}
response := rollResponse{c, s, result}
jsonEncode(w, enc, response)
}
// RollN is the handler for all the requested rolls of n d dice, where n is
// specified with a query.
func RollN(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
sides := vars["sides"]
count := r.FormValue("count")
s := getSides(sides[1:])
if s == 0 {
unexpectedError(w)
return
}
c := getCount(count)
if c == 0 {
unexpectedError(w)
return
}
response(w, s, c)
}
// DRollN is the handlre for all the requested rolls of n d dice, where n is
// specified with a variable.
func DRollN(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
sides := vars["sides"]
count := vars["count"]
s := getSides(sides[1:])
if s == 0 {
unexpectedError(w)
return
}
c := getCount(count)
if c == 0 {
unexpectedError(w)
return
}
response(w, s, c)
}