/
server.py
executable file
·178 lines (135 loc) · 6.17 KB
/
server.py
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
#!/usr/bin/python
'''
@title: chaincountdownserver.py
@summary: Image generating http server
@author: AltSheets
@version: v10
@license Giveback license v05 http://altsheets.ddns.net/give/
@requires config.py, imaging.py,chaincountdown.py
@see chaincountdown.py for explanations & donation addresses
'''
import chaincountdown, imaging, helpers
from config import PORT_NUMBER, INFOPAGE, STYLESHEET, SUGGESTION
from config import SERVERS
from config import FILENAMEPIC, IMAGETYPES
from config import FONTS, IMAGEDEFAULTS, FONTSIZEFOOTER_MIN
from config import BASEDIR, TEMPDIRNAME
from config import PAGES, STATICDIR, MIMETYPE
import urlparse, mimetools, sys, os
from StringIO import StringIO
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
class ParsingException(Exception):
"Some errors can be answered specifically."
pass
def concatArgs(e):
"join the exception args to one string"
if type(e) == type(tuple()): several=e
else: several=e.args
return ", ". join(["%s"%arg for arg in several])
class myHandler(BaseHTTPRequestHandler):
"""This class handles any incoming request from the browser. Adapted from:
https://github.com/tanzilli/playground/blob/master/python/httpserver/example2.py
"""
# error codes: See BaseHTTPServer.py
OK = 200
BAD_REQUEST = 400
NOT_FOUND = 404
NOT_ACCEPTABLE = 406
INTERNAL_SERVER_ERROR = 500
NOT_IMPLEMENTED = 501
def parseUrl(self):
"Analyzes the user request. Detects problems."
o = urlparse.urlparse(self.path)
# scheme is: /pfn/123456.png?option1=value&option2=value
# platform name (e.g. "nxt" or "nhz" or "burst")
pfn = o.path.split("/")[1].lower()
if pfn =="hz": pfn="nhz"
if pfn=="": raise Exception("no platform specified")
if pfn not in SERVERS.keys():
raise ParsingException(self.NOT_IMPLEMENTED,
"Unknown chain. Contact me if you want your coin implemented here.")
# 123456.png
filename = o.path.split("/")[2]
filename, suffix = filename.split(".")
suffix=suffix.lower()
if suffix not in IMAGETYPES: raise ParsingException(self.BAD_REQUEST, "Wrong image type.")
try: BT = int(filename)
except Exception:
raise ParsingException(self.NOT_ACCEPTABLE, 'Your block height target is not numeric. ')
# make dict from user parameters, for the image (e.g. fontsize)
query = urlparse.parse_qs(o.query)
query = dict([(k,v[0]) for k,v in query.items()]) # list -> single argument
# if query.get("font", "") not in FONTS:
# print imaging.findMatchingFont( query.get("font", "") , FONTS)
if query.has_key("font") and imaging.findMatchingFont( query["font"], FONTS)==None :
raise ParsingException(self.NOT_ACCEPTABLE, 'Font not supported. Contact me, or change to standard font ')
return pfn, BT, suffix, query
def suggest(self):
"helping the user to understand what he should rather do"
host=mimetools.Message(StringIO(self.headers))["host"]
return (SUGGESTION % (host))
def makeImage(self, pfn, filename, suffix, BT, query):
"ask blockchain server, calculate text, make image - and save it to disk"
try:
_, text = chaincountdown.doTheChaChaCha(BT, pfn)
except Exception as e:
self.send_error(self.INTERNAL_SERVER_ERROR,
'Querying the blockchain server failed (%s)' % concatArgs(e))
return False
try:
o = helpers.replacedInDict(IMAGEDEFAULTS, query)
o["fontsizefooter"] = max (FONTSIZEFOOTER_MIN, int(o["fontsize"]) / 2)
imaging.textToImage(filename, text=text, **o)
except Exception as e:
self.send_error(self.BAD_REQUEST,
'Creating the image did not work (%s) ' % concatArgs(e.args) + self.suggest())
return False
return True
def do_GET(self):
"Handler for all GET requests:"
mimetype=""
if self.path == "/": self.path+=INFOPAGE
if self.path[1:] in PAGES:
self.path=filetosend=os.path.join(STATICDIR, self.path[1:])
mimetype=MIMETYPE[helpers.suffix(self.path)]
# create and return image
if mimetype=="":
try:
pfn, BT, suffix, query = self.parseUrl()
filetosend = TEMPDIRNAME+FILENAMEPIC+"."+suffix
except ParsingException as e:
self.send_error(e.args[0], "%s" % e.args[1])
return
except Exception as e:
msg = 'Something went wrong (%s).' % concatArgs(e)
self.send_error(self.NOT_FOUND, msg+self.suggest())
return
success = self.makeImage(pfn, filetosend, suffix, BT, query)
if not success: return # an http error code is already set in self.makeImage
# success:
mimetype='image/%s' % suffix
# serve the file:
try:
self.send_response(self.OK)
self.send_header('Content-type', mimetype)
self.end_headers()
f = open(filetosend, "rb")
self.wfile.write(f.read())
f.close()
return
except IOError as e:
self.send_error(self.NOT_FOUND,'File Not Found: %s' % self.path)
def server():
"A web server which returns generated images, or an index page."
try:
#Create a web server and define the handler to manage the incoming request
server = HTTPServer(('', PORT_NUMBER), myHandler)
print >> sys.stderr, 'Started httpserver on port: ' , PORT_NUMBER
#Wait forever for incoming http requests
server.serve_forever()
except KeyboardInterrupt:
print '^C received, shutting down the web server'
server.socket.close()
if __name__ == "__main__":
# testTextToPNG()
server()