@@ -13,6 +13,7 @@ const promisify = (f, ctx = null) => (...args) =>
13
13
const connectMongo = promisify ( MongoClient . connect ) ;
14
14
const scores = ( ) =>
15
15
connectMongo ( env . MONGO ) . then ( db => db . collection ( "scores" ) ) ;
16
+ const stats = ( ) => connectMongo ( env . MONGO ) . then ( db => db . collection ( "stats" ) ) ;
16
17
17
18
scores ( ) . then ( coll => promisify ( coll . count , coll ) ( ) ) . then ( count => {
18
19
console . log ( count + " scores" ) ;
@@ -46,6 +47,17 @@ const recordScore = doc =>
46
47
) ;
47
48
} ) ;
48
49
50
+ const fetchStats = ( ) =>
51
+ stats ( ) . then ( coll => {
52
+ const q = coll . find ( ) ;
53
+ return promisify ( q . toArray , q ) ( ) ;
54
+ } ) ;
55
+
56
+ const recordStats = doc =>
57
+ stats ( ) . then ( coll => {
58
+ return promisify ( coll . insertOne , coll ) ( doc ) ;
59
+ } ) ;
60
+
49
61
const app = require ( "express" ) ( ) ;
50
62
app . use ( require ( "body-parser" ) . json ( ) ) ;
51
63
app . use ( require ( "cors" ) ( ) ) ;
@@ -81,6 +93,88 @@ app.post("/test", (req, res) => {
81
93
}
82
94
} ) ;
83
95
96
+ function checkValidStat ( body ) {
97
+ if ( ! body || typeof body !== "object" ) {
98
+ throw new Error ( "invalid body" ) ;
99
+ }
100
+ if ( typeof body . userAgent !== "string" ) {
101
+ throw new Error ( "invalid body.userAgent" ) ;
102
+ }
103
+ if (
104
+ typeof body . config !== "object" ||
105
+ typeof body . config . quality !== "string" ||
106
+ typeof body . config . seed !== "string"
107
+ ) {
108
+ throw new Error ( "invalid body.config" ) ;
109
+ }
110
+ }
111
+ function checkValidSuccessStat ( body ) {
112
+ if ( ! body . stats || typeof body . stats !== "object" )
113
+ throw new Error ( "missing body.stats" ) ;
114
+ if ( typeof body . stats . averageFPS !== "number" )
115
+ throw new Error ( "invalid body.stats.averageFPS" ) ;
116
+ if ( typeof body . stats . bootTime !== "number" )
117
+ throw new Error ( "invalid body.stats.bootTime" ) ;
118
+ }
119
+ function checkValidFailureStat ( body ) {
120
+ if ( typeof body . error !== "string" ) throw new Error ( "missing body.error" ) ;
121
+ }
122
+
123
+ app . get ( "/stats" , ( req , res ) => {
124
+ fetchStats ( )
125
+ . then ( stats => {
126
+ const successEntries = stats . filter ( s => s . type === "success" ) ;
127
+ const failureEntries = stats . filter ( s => s . type === "failure" ) ;
128
+ const out = {
129
+ successCount : successEntries . length ,
130
+ failureCount : failureEntries . length ,
131
+ statsPerQuality : {
132
+ low : successEntries
133
+ . filter ( s => s . config . quality === "low" )
134
+ . map ( s => s . stats ) ,
135
+ medium : successEntries
136
+ . filter ( s => s . config . quality === "medium" )
137
+ . map ( s => s . stats ) ,
138
+ high : successEntries
139
+ . filter ( s => s . config . quality === "high" )
140
+ . map ( s => s . stats )
141
+ }
142
+ } ;
143
+ res . json ( out ) ;
144
+ } )
145
+ . catch ( e => {
146
+ console . error ( e ) ;
147
+ res . status ( 500 ) . send ( ) ;
148
+ } ) ;
149
+ } ) ;
150
+
151
+ app . post ( "/stats/failure" , ( req , res ) => {
152
+ Promise . resolve ( req . body )
153
+ . then ( body => {
154
+ checkValidStat ( body ) ;
155
+ checkValidFailureStat ( body ) ;
156
+ return recordStats ( Object . assign ( { type : "failure" } , body ) ) ;
157
+ } )
158
+ . then ( res . send ( ) )
159
+ . catch ( e => {
160
+ console . log ( e ) ;
161
+ res . status ( 500 ) . send ( ) ;
162
+ } ) ;
163
+ } ) ;
164
+ app . post ( "/stats/success" , ( req , res ) => {
165
+ Promise . resolve ( req . body )
166
+ . then ( body => {
167
+ checkValidStat ( body ) ;
168
+ checkValidSuccessStat ( body ) ;
169
+ return recordStats ( Object . assign ( { type : "success" } , body ) ) ;
170
+ } )
171
+ . then ( res . send ( ) )
172
+ . catch ( e => {
173
+ console . log ( e ) ;
174
+ res . status ( 500 ) . send ( ) ;
175
+ } ) ;
176
+ } ) ;
177
+
84
178
app . post ( "/" , ( req , res ) => {
85
179
// a GameState is sent to server
86
180
Promise . resolve ( req . body )
0 commit comments