6
6
from apscheduler .scheduler import Scheduler
7
7
from flask import Flask , request , send_from_directory
8
8
9
- serverList = []
10
- maxServers = 0
11
- maxClients = 0
12
- listLock = RLock ()
13
9
14
10
sched = Scheduler ()
15
11
sched .start ()
16
12
17
13
app = Flask (__name__ , static_url_path = "" )
18
14
app .config .from_pyfile ("config.py" )
19
15
16
+
20
17
@app .route ("/" )
21
18
def index ():
22
19
return app .send_static_file ("index.html" )
@@ -71,13 +68,13 @@ def announce():
71
68
server ["port" ] = int (server ["port" ])
72
69
#### End compatability code ####
73
70
74
- old = getServer (server ["ip" ], server ["port" ])
71
+ old = serverList . get (server ["ip" ], server ["port" ])
75
72
76
73
if server ["action" ] == "delete" :
77
74
if not old :
78
75
return "Server not found." , 500
79
- removeServer (old )
80
- saveList ()
76
+ serverList . remove (old )
77
+ serverList . save ()
81
78
return "Removed from server list."
82
79
elif not checkRequest (server ):
83
80
return "Invalid JSON data." , 400
@@ -117,7 +114,7 @@ def announce():
117
114
# Popularity
118
115
if old :
119
116
server ["updates" ] = old ["updates" ] + 1
120
- # This is actally a count of all the client numbers we've received,
117
+ # This is actually a count of all the client numbers we've received,
121
118
# it includes clients that were on in the previous update.
122
119
server ["total_clients" ] = old ["total_clients" ] + server ["clients" ]
123
120
else :
@@ -130,6 +127,11 @@ def announce():
130
127
return "Thanks, your request has been filed." , 202
131
128
132
129
130
+ @sched .interval_schedule (minutes = 1 , coalesce = True , max_instances = 1 )
131
+ def purgeOld ():
132
+ serverList .purgeOld ()
133
+
134
+
133
135
# Returns ping time in seconds (up), False (down), or None (error).
134
136
def serverUp (address , port ):
135
137
try :
@@ -153,75 +155,6 @@ def serverUp(address, port):
153
155
return None
154
156
155
157
156
- def getServerAndIndex (ip , port ):
157
- with listLock :
158
- for i , server in enumerate (serverList ):
159
- if server ["ip" ] == ip and server ["port" ] == port :
160
- return (i , server )
161
-
162
-
163
- def getServer (ip , port ):
164
- server = getServerAndIndex (ip , port )
165
- return server and server [1 ]
166
-
167
-
168
- def removeServer (server ):
169
- with listLock :
170
- try :
171
- serverList .remove (server )
172
- except :
173
- pass
174
-
175
-
176
- def sortList ():
177
- with listLock :
178
- serverList .sort (key = itemgetter ("clients" , "start" ), reverse = True )
179
-
180
- @sched .interval_schedule (minutes = 1 , coalesce = True , max_instances = 1 )
181
- def purgeOld ():
182
- with listLock :
183
- for server in serverList :
184
- if server ["update_time" ] < time .time () - app .config ["PURGE_TIME" ]:
185
- serverList .remove (server )
186
- saveList ()
187
-
188
-
189
- def loadList ():
190
- global serverList , maxServers , maxClients
191
- try :
192
- with open (os .path .join ("static" , app .config ["FILENAME" ]), "r" ) as fd :
193
- data = json .load (fd )
194
- except FileNotFoundError :
195
- return
196
- if not data :
197
- return
198
- with listLock :
199
- serverList = data ["list" ]
200
- maxServers = data ["total_max" ]["servers" ]
201
- maxClients = data ["total_max" ]["clients" ]
202
-
203
-
204
- def saveList ():
205
- global maxServers , maxClients
206
- with listLock :
207
- servers = len (serverList )
208
- clients = 0
209
- for server in serverList :
210
- clients += server ["clients" ]
211
-
212
- maxServers = max (servers , maxServers )
213
- maxClients = max (clients , maxClients )
214
-
215
- with open (os .path .join ("static" , app .config ["FILENAME" ]), "w" ) as fd :
216
- json .dump ({
217
- "total" : {"servers" : servers , "clients" : clients },
218
- "total_max" : {"servers" : maxServers , "clients" : maxClients },
219
- "list" : serverList
220
- },
221
- fd ,
222
- indent = "\t " if app .config ["DEBUG" ] else None )
223
-
224
-
225
158
# fieldName: (Required, Type, SubType)
226
159
fields = {
227
160
"action" : (True , "str" ),
@@ -312,23 +245,102 @@ def asyncFinishThread(server):
312
245
313
246
server ["ping" ] = serverUp (server ["address" ], server ["port" ])
314
247
if not server ["ping" ]:
248
+ app .logger .warning ("Server %s:%d has no ping."
249
+ % (server ["address" ], server ["port" ]))
315
250
return
316
251
317
252
del server ["action" ]
318
253
319
- with listLock :
320
- old = getServerAndIndex (server ["ip" ], server ["port" ])
321
- if old :
322
- serverList [old [0 ]] = server
323
- else :
324
- serverList .append (server )
254
+ serverList .update (server )
255
+
256
+
257
+ class ServerList :
258
+ def __init__ (self ):
259
+ self .list = []
260
+ self .maxServers = 0
261
+ self .maxClients = 0
262
+ self .lock = RLock ()
263
+ self .load ()
264
+ self .purgeOld ()
265
+
266
+ def getWithIndex (self , ip , port ):
267
+ with self .lock :
268
+ for i , server in enumerate (self .list ):
269
+ if server ["ip" ] == ip and server ["port" ] == port :
270
+ return (i , server )
271
+ return (None , None )
272
+
273
+ def get (self , ip , port ):
274
+ i , server = self .getWithIndex (ip , port )
275
+ return server
276
+
277
+ def removeServer (self , server ):
278
+ with lock :
279
+ try :
280
+ self .list .remove (server )
281
+ except :
282
+ pass
283
+
284
+ def sort (self ):
285
+ with self .lock :
286
+ self .list .sort (key = itemgetter ("clients" , "start" ), reverse = True )
287
+
288
+ def purgeOld (self ):
289
+ with self .lock :
290
+ for server in self .list :
291
+ if server ["update_time" ] < time .time () - app .config ["PURGE_TIME" ]:
292
+ self .list .remove (server )
293
+ self .save ()
294
+
295
+ def load (self ):
296
+ try :
297
+ with open (os .path .join ("static" , app .config ["FILENAME" ]), "r" ) as fd :
298
+ data = json .load (fd )
299
+ except FileNotFoundError :
300
+ return
325
301
326
- sortList ()
327
- saveList ()
302
+ if not data :
303
+ return
328
304
305
+ with self .lock :
306
+ self .list = data ["list" ]
307
+ self .maxServers = data ["total_max" ]["servers" ]
308
+ self .maxClients = data ["total_max" ]["clients" ]
309
+
310
+ def save (self ):
311
+ with self .lock :
312
+ servers = len (self .list )
313
+ clients = 0
314
+ for server in self .list :
315
+ clients += server ["clients" ]
316
+
317
+ self .maxServers = max (servers , self .maxServers )
318
+ self .maxClients = max (clients , self .maxClients )
319
+
320
+ with open (os .path .join ("static" , app .config ["FILENAME" ]), "w" ) as fd :
321
+ json .dump ({
322
+ "total" : {"servers" : servers , "clients" : clients },
323
+ "total_max" : {"servers" : self .maxServers , "clients" : self .maxClients },
324
+ "list" : self .list
325
+ },
326
+ fd ,
327
+ indent = "\t " if app .config ["DEBUG" ] else None
328
+ )
329
+
330
+ def update (self , server ):
331
+ with self .lock :
332
+ i , old = self .getWithIndex (server ["ip" ], server ["port" ])
333
+ if i is not None :
334
+ self .list [i ] = server
335
+ else :
336
+ self .list .append (server )
337
+
338
+ self .sort ()
339
+ self .save ()
340
+
341
+ serverList = ServerList ()
329
342
330
- loadList ()
331
- purgeOld ()
332
343
333
344
if __name__ == "__main__" :
334
345
app .run (host = app .config ["HOST" ], port = app .config ["PORT" ])
346
+
0 commit comments