9
9
import maxminddb
10
10
from flask import Flask , request , send_from_directory , make_response
11
11
12
+ LIST_SAVE_INTERVAL = 5
12
13
13
14
app = Flask (__name__ , static_url_path = "" )
14
15
@@ -75,7 +76,7 @@ def index():
75
76
def list_json ():
76
77
# We have to make sure that the list isn't cached for too long,
77
78
# since it isn't really static.
78
- return send_from_directory (app .static_folder , "list.json" , max_age = 20 )
79
+ return send_from_directory (app .static_folder , "list.json" , max_age = LIST_SAVE_INTERVAL )
79
80
80
81
81
82
@app .route ("/geoip" )
@@ -607,10 +608,10 @@ def __init__(self):
607
608
self .maxClients = 0
608
609
self .storagePath = os .path .join (app .root_path , "store.json" )
609
610
self .publicPath = os .path .join (app .static_folder , "list.json" )
611
+ self .modified = True
610
612
self .lock = RLock ()
611
613
612
614
self .load ()
613
- self .purgeOld ()
614
615
615
616
def getWithIndex (self , ip , port ):
616
617
with self .lock :
@@ -636,17 +637,15 @@ def remove(self, server):
636
637
self .list .remove (server )
637
638
except ValueError :
638
639
return
639
- self .save ()
640
- self .savePublic ()
640
+ self .modified = True
641
641
642
642
def purgeOld (self ):
643
643
cutoff = int (time .time ()) - app .config ["PURGE_TIME" ]
644
644
with self .lock :
645
645
count = len (self .list )
646
646
self .list = [server for server in self .list if cutoff <= server .updateTime ]
647
647
if len (self .list ) < count :
648
- self .save ()
649
- self .savePublic ()
648
+ self .modified = True
650
649
651
650
def load (self ):
652
651
# TODO?: this is a poor man's database. maybe we should use sqlite3?
@@ -664,17 +663,32 @@ def load(self):
664
663
self .maxServers = data ["maxServers" ]
665
664
self .maxClients = data ["maxClients" ]
666
665
666
+ # rewrite once in case writing format or so changed
667
+ self .modified = True
668
+
667
669
def save (self ):
668
670
with self .lock :
671
+ self ._saveStorage ()
672
+ self ._savePublic ()
673
+ self .modified = False
674
+
675
+ def _saveStorage (self ):
676
+ with self .lock :
677
+ if not self .modified :
678
+ return
679
+
669
680
out_list = list (server .to_storage () for server in self .list )
670
681
dumpJsonToFile (self .storagePath , {
671
682
"list" : out_list ,
672
683
"maxServers" : self .maxServers ,
673
684
"maxClients" : self .maxClients
674
685
})
675
686
676
- def savePublic (self ):
687
+ def _savePublic (self ):
677
688
with self .lock :
689
+ if not self .modified and os .path .exists (self .publicPath ):
690
+ return
691
+
678
692
# sort, but don't modify internal list
679
693
sorted_list = sorted (self .list ,
680
694
key = (lambda server : server .get_score ()), reverse = True )
@@ -702,9 +716,7 @@ def update(self, server):
702
716
self .list [i ] = server
703
717
else :
704
718
self .list .append (server )
705
-
706
- self .save ()
707
- self .savePublic ()
719
+ self .modified = True
708
720
709
721
710
722
class ErrorTracker :
@@ -735,14 +747,20 @@ def cleanup(self):
735
747
self .table = table
736
748
737
749
738
- class PurgeThread (Thread ):
750
+ class TimerThread (Thread ):
739
751
def __init__ (self ):
740
- Thread .__init__ (self , daemon = True )
752
+ super () .__init__ (name = "TimerThread" , daemon = True )
741
753
def run (self ):
754
+ next_cleanup = 0
742
755
while True :
743
- time .sleep (60 )
744
- serverList .purgeOld ()
745
- errorTracker .cleanup ()
756
+ time .sleep (max (1 , LIST_SAVE_INTERVAL ))
757
+
758
+ if time .monotonic () >= next_cleanup :
759
+ serverList .purgeOld ()
760
+ errorTracker .cleanup ()
761
+ next_cleanup = time .monotonic () + 60
762
+
763
+ serverList .save ()
746
764
747
765
748
766
# Globals / Startup
@@ -751,7 +769,7 @@ def run(self):
751
769
752
770
errorTracker = ErrorTracker ()
753
771
754
- PurgeThread ().start ()
772
+ TimerThread ().start ()
755
773
756
774
if __name__ == "__main__" :
757
775
app .run (host = app .config ["HOST" ], port = app .config ["PORT" ])
0 commit comments