1+ import asyncio
12import os
2- import sys
33import random
44import re
55import json
6- import signal
7- from typing import Dict , List
6+ from typing import Dict , List , Optional , Set
87
98from hashlib import md5
109
11- import tornado .httpserver
12- import tornado .ioloop
1310import tornado .web
1411from tornado .escape import xhtml_unescape
15- from tornado .options import define , options
1612
17- define ("port" , default = 5000 , help = "run on the given port" , type = int )
18-
19- names = ['Nick' , 'Steve' , 'Andy' , 'Qi' , 'Fanny' , 'Sarah' , 'Cord' , 'Todd' ,
20- 'Chris' , 'Pasha' , 'Gabe' , 'Tony' , 'Jason' , 'Randal' , 'Ali' , 'Kim' ,
21- 'Rainer' , 'Guillaume' , 'Kelan' , 'David' , 'John' , 'Stephen' , 'Tom' , 'Steven' ,
22- 'Jen' , 'Marcus' , 'Edy' , 'Rachel' , 'Ethan' , 'Dan' , 'Darren' , 'Greg' ]
23-
24- humans_file = os .path .join (os .path .dirname (__file__ ), 'static' , 'humans.txt' )
25- messages_file = os .path .join (os .path .dirname (__file__ ), 'commit_messages.txt' )
26- messages : Dict [str , str ] = {}
27-
28- # Create a hash table of all commit messages
29- with open (messages_file , 'r' , encoding = 'utf-8' ) as messages_input :
30- for line in messages_input .readlines ():
31- messages [md5 (line .encode ('utf-8' )).hexdigest ()] = line
32-
33- names : List [str ] = []
34-
35- with open (humans_file , 'r' , encoding = 'utf-8' ) as humans_input :
36- humans_content = humans_input .read ()
37- for line in humans_content .split ("\n " ):
38- if "Name:" in line :
39- data = line [6 :].rstrip ()
40- if data .find ("github:" ) == 0 :
41- names .append (data [7 :])
42- else :
43- names .append (data .split (" " )[0 ])
13+ default_names = [
14+ "Ali" ,
15+ "Andy" ,
16+ "Brannon" ,
17+ "Chris" ,
18+ "Cord" ,
19+ "Dan" ,
20+ "Darren" ,
21+ "David" ,
22+ "Edy" ,
23+ "Ethan" ,
24+ "Fanny" ,
25+ "Gabe" ,
26+ "Ganesh" ,
27+ "Greg" ,
28+ "Guillaume" ,
29+ "James" ,
30+ "Jason" ,
31+ "Jay" ,
32+ "Jen" ,
33+ "John" ,
34+ "Kelan" ,
35+ "Kim" ,
36+ "Lauren" ,
37+ "Marcus" ,
38+ "Matt" ,
39+ "Matthias" ,
40+ "Mattie" ,
41+ "Mike" ,
42+ "Nate" ,
43+ "Nick" ,
44+ "Pasha" ,
45+ "Patrick" ,
46+ "Paul" ,
47+ "Preston" ,
48+ "Qi" ,
49+ "Rachel" ,
50+ "Rainer" ,
51+ "Randal" ,
52+ "Ryan" ,
53+ "Sarah" ,
54+ "Stephen" ,
55+ "Steve" ,
56+ "Steven" ,
57+ "Sunakshi" ,
58+ "Todd" ,
59+ "Tom" ,
60+ "Tony" ,
61+ ]
4462
4563num_re = re .compile (r"XNUM([0-9,]*)X" )
4664
47- def fill_line (message ):
48- message = message .replace ('XNAMEX' , random .choice (names ))
49- message = message .replace ('XUPPERNAMEX' , random .choice (names ).upper ())
50- message = message .replace ('XLOWERNAMEX' , random .choice (names ).lower ())
65+
66+ def fill_line (message : str , names : List [str ]) -> str :
67+ message = message .replace ("XNAMEX" , random .choice (names ))
68+ message = message .replace ("XUPPERNAMEX" , random .choice (names ).upper ())
69+ message = message .replace ("XLOWERNAMEX" , random .choice (names ).lower ())
5170
5271 nums = num_re .findall (message )
5372
@@ -57,13 +76,13 @@ def fill_line(message):
5776 value = nums .pop (0 ) or str (end )
5877 if "," in value :
5978 position = value .index ("," )
60- if position == 0 : # XNUM,5X
79+ if position == 0 : # XNUM,5X
6180 end = int (value [1 :])
62- elif position == len (value ) - 1 : # XNUM5,X
81+ elif position == len (value ) - 1 : # XNUM5,X
6382 start = int (value [:position ])
64- else : # XNUM1,5X
83+ else : # XNUM1,5X
6584 start = int (value [:position ])
66- end = int (value [position + 1 :])
85+ end = int (value [position + 1 :])
6786 else :
6887 end = int (value )
6988 if start > end :
@@ -74,66 +93,103 @@ def fill_line(message):
7493
7594 return message
7695
96+
7797class MainHandler (tornado .web .RequestHandler ):
78- def get (self , message_hash = None ):
79- if not message_hash :
80- message_hash = random .choice (list (messages .keys ()))
81- elif message_hash not in messages :
98+ def initialize (self , messages : Dict [str , str ], names : List [str ]):
99+ self .messages = messages
100+ self .names = names
101+
102+ def get (self , message_hash : Optional [str ] = None ):
103+ if message_hash is not None and message_hash not in self .messages :
82104 raise tornado .web .HTTPError (404 )
83105
84- message = fill_line (messages [message_hash ])
106+ if message_hash is None :
107+ message_hash = random .choice (list (self .messages .keys ()))
108+
109+ message = fill_line (self .messages [message_hash ], self .names )
85110
86111 self .output_message (message , message_hash )
87112
88113 def output_message (self , message , message_hash ):
89- self .set_header ('X-Message-Hash' , message_hash )
90- self .render ('index.html' , message = message , message_hash = message_hash )
114+ self .set_header ("X-Message-Hash" , message_hash )
115+ self .render ("index.html" , message = message , message_hash = message_hash )
116+
91117
92118class PlainTextHandler (MainHandler ):
93119 def output_message (self , message , message_hash ):
94- self .set_header ('Content-Type' , 'text/plain' )
95- self .set_header ('X-Message-Hash' , message_hash )
96- self .write (xhtml_unescape (message ).replace ('<br/>' , '\n ' ))
120+ self .set_header ("Content-Type" , "text/plain" )
121+ self .set_header ("X-Message-Hash" , message_hash )
122+ self .write (xhtml_unescape (message ).replace ("<br/>" , "\n " ))
123+
97124
98125class JsonHandler (MainHandler ):
99126 def output_message (self , message , message_hash ):
100- self .set_header ('Content-Type' , 'application/json' )
101- self .set_header ('X-Message-Hash' , message_hash )
102- self .write (json .dumps ({'hash' : message_hash , 'commit_message' :message .replace ('\n ' , '' ), 'permalink' : self .request .protocol + "://" + self .request .host + '/' + message_hash }))
127+ self .set_header ("Content-Type" , "application/json" )
128+ self .set_header ("X-Message-Hash" , message_hash )
129+ self .write (
130+ json .dumps (
131+ {
132+ "hash" : message_hash ,
133+ "commit_message" : message .replace ("\n " , "" ),
134+ "permalink" : f"{ self .request .protocol } ://{ self .request .host } /{ message_hash } " ,
135+ }
136+ )
137+ )
138+
103139
104140class HumansHandler (tornado .web .RequestHandler ):
105141 def get (self ):
106- self .set_header ('Content-Type' , 'text/plain' )
107- self .write (humans_content )
108-
109- class CommitmentApplication (tornado .web .Application ):
110- is_closing = False
111-
112- def signal_handler (self , signum , frame ):
113- self .is_closing = True
114-
115- def try_exit (self ):
116- if self .is_closing :
117- tornado .ioloop .IOLoop .instance ().stop ()
118-
119- settings = {
120- 'static_path' : os .path .join (os .path .dirname (__file__ ), 'static' ),
121- }
122-
123- application = CommitmentApplication ([
124- (r'/' , MainHandler ),
125- (r'/([a-z0-9]+)' , MainHandler ),
126- (r'/index.json' , JsonHandler ),
127- (r'/([a-z0-9]+).json' , JsonHandler ),
128- (r'/index.txt' , PlainTextHandler ),
129- (r'/([a-z0-9]+)/index.txt' , PlainTextHandler ),
130- (r'/humans.txt' , HumansHandler ),
131- ], ** settings )
132-
133- if __name__ == '__main__' :
134- tornado .options .parse_command_line ()
135- signal .signal (signal .SIGINT , application .signal_handler )
136- http_server = tornado .httpserver .HTTPServer (application )
137- http_server .listen (os .environ .get ("PORT" , 5000 ))
138- tornado .ioloop .PeriodicCallback (application .try_exit , 100 ).start ()
139- tornado .ioloop .IOLoop .instance ().start ()
142+ self .set_header ("Content-Type" , "text/plain" )
143+ self .write (self .humans_content )
144+
145+
146+ async def main ():
147+ humans_file = os .path .join (os .path .dirname (__file__ ), "static" , "humans.txt" )
148+ messages_file = os .path .join (os .path .dirname (__file__ ), "commit_messages.txt" )
149+ messages : Dict [str , str ] = {}
150+
151+ with open (messages_file , "r" , encoding = "utf-8" ) as messages_input :
152+ for line in messages_input .readlines ():
153+ messages [md5 (line .encode ("utf-8" )).hexdigest ()] = line
154+
155+ names : Set [str ] = set (list (default_names ))
156+
157+ with open (humans_file , "r" , encoding = "utf-8" ) as humans_input :
158+ humans_content = humans_input .read ()
159+ for line in humans_content .split ("\n " ):
160+ if "Name:" in line :
161+ line = line .removeprefix ("Name: " )
162+ if (found := line .find ("github" )) > - 1 :
163+ line = line [found :].removeprefix ("github:" ).removesuffix (")" )
164+ names .add (line )
165+ else :
166+ names .add (line .split (" " )[0 ])
167+
168+ settings = {
169+ "static_path" : os .path .join (os .path .dirname (__file__ ), "static" ),
170+ }
171+ values = {"messages" : messages , "names" : list (names )}
172+ application = tornado .web .Application (
173+ [
174+ (
175+ r"/(humans\.txt)" ,
176+ tornado .web .StaticFileHandler ,
177+ dict (path = settings ["static_path" ]),
178+ ),
179+ (r"/" , MainHandler , values ),
180+ (r"/([a-z0-9]+)" , MainHandler , values ),
181+ (r"/index\.json" , JsonHandler , values ),
182+ (r"/([a-z0-9]+)\.json" , JsonHandler , values ),
183+ (r"/([a-z0-9]+)/index\.json" , JsonHandler , values ),
184+ (r"/index\.txt" , PlainTextHandler , values ),
185+ (r"/([a-z0-9]+)/index\.txt" , PlainTextHandler , values ),
186+ (r"/([a-z0-9]+)\.txt" , PlainTextHandler , values ),
187+ ],
188+ ** settings ,
189+ )
190+ application .listen (os .environ .get ("PORT" , 5000 ))
191+ await asyncio .Event ().wait ()
192+
193+
194+ if __name__ == "__main__" :
195+ asyncio .run (main ())
0 commit comments