| 3 | | # |
|---|
| 4 | | # $Id$ |
|---|
| 5 | | # |
|---|
| 6 | | |
|---|
| 7 | | import ModestMaps |
|---|
| 8 | | import StringIO |
|---|
| 9 | | import sys |
|---|
| 10 | | |
|---|
| 11 | | from urlparse import urlparse |
|---|
| 12 | | from cgi import parse_qs, escape |
|---|
| 13 | | import signal, thread, threading, time, sys |
|---|
| 14 | | import BaseHTTPServer, SocketServer, mimetypes |
|---|
| 15 | | import re |
|---|
| 16 | | import tempfile |
|---|
| 17 | | import textwrap |
|---|
| 18 | | import string |
|---|
| 19 | | import base64 |
|---|
| 20 | | import Image |
|---|
| 21 | | |
|---|
| 22 | | # ############################################################## |
|---|
| 23 | | |
|---|
| 24 | | global done, server |
|---|
| 25 | | |
|---|
| 26 | | done = False |
|---|
| 27 | | server = None |
|---|
| 28 | | |
|---|
| 29 | | # ############################################################## |
|---|
| 30 | | |
|---|
| 31 | | class WebServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): |
|---|
| 32 | | pass |
|---|
| 33 | | |
|---|
| 34 | | # ############################################################## |
|---|
| 35 | | |
|---|
| 36 | | class WebRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): |
|---|
| 37 | | |
|---|
| 38 | | # ########################################################## |
|---|
| 39 | | |
|---|
| 40 | | def __init__ (self, request, client_address, server) : |
|---|
| 41 | | self.__mrk = None |
|---|
| 42 | | BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, request, client_address, server) |
|---|
| 43 | | |
|---|
| 44 | | # ########################################################## |
|---|
| 45 | | |
|---|
| 46 | | def do_GET(self): |
|---|
| 47 | | |
|---|
| 48 | | scheme, host, path, params, query, hash = urlparse(self.path) |
|---|
| 49 | | params = parse_qs(query) |
|---|
| 50 | | |
|---|
| 51 | | args = self.validate_params(params) |
|---|
| 52 | | |
|---|
| 53 | | if not args : |
|---|
| 54 | | return |
|---|
| 55 | | |
|---|
| 56 | | img, meta = self.draw_map(args) |
|---|
| 57 | | |
|---|
| 58 | | if not img : |
|---|
| 59 | | return |
|---|
| 60 | | |
|---|
| 61 | | self.send_map(img, meta) |
|---|
| 62 | | return |
|---|
| 63 | | |
|---|
| 64 | | # ########################################################## |
|---|
| 65 | | |
|---|
| 66 | | def draw_map (self, args) : |
|---|
| 67 | | try : |
|---|
| 68 | | |
|---|
| 69 | | if args.has_key('bbox') : |
|---|
| 70 | | return self.draw_map_extentified(args) |
|---|
| 71 | | else : |
|---|
| 72 | | return self.draw_map_centered(args) |
|---|
| 73 | | |
|---|
| 74 | | except Exception, e : |
|---|
| 75 | | self.error(200, "composer error : %s" % e) |
|---|
| 76 | | return False |
|---|
| 77 | | |
|---|
| 78 | | # ########################################################## |
|---|
| 79 | | |
|---|
| 80 | | def draw_map_extentified (self, args) : |
|---|
| 81 | | |
|---|
| 82 | | provider = self.load_provider(args['provider']) |
|---|
| 83 | | |
|---|
| 84 | | coord, offset = ModestMaps.calculateMapExtent(provider, |
|---|
| 85 | | args['width'], args['height'], |
|---|
| 86 | | ModestMaps.Geo.Location(args['bbox'][0], args['bbox'][1]), |
|---|
| 87 | | ModestMaps.Geo.Location(args['bbox'][2], args['bbox'][3])) |
|---|
| 88 | | |
|---|
| 89 | | dim = ModestMaps.Core.Point(args['width'], args['height']) |
|---|
| 90 | | map = ModestMaps.Map(provider, dim, coord, offset) |
|---|
| 91 | | |
|---|
| 92 | | img = map.draw() |
|---|
| 93 | | meta = None |
|---|
| 94 | | |
|---|
| 95 | | if args.has_key('filter') : |
|---|
| 96 | | img = self.apply_filtering(img, args['filter']) |
|---|
| 97 | | |
|---|
| 98 | | #if args.has_key('markers') : |
|---|
| 99 | | # meta = self.add_markers(map, img, args) |
|---|
| 100 | | |
|---|
| 101 | | return (img, meta) |
|---|
| 102 | | |
|---|
| 103 | | # ########################################################## |
|---|
| 104 | | |
|---|
| 105 | | def draw_map_centered (self, args) : |
|---|
| 106 | | |
|---|
| 107 | | provider = self.load_provider(args['provider']) |
|---|
| 108 | | loc = ModestMaps.Geo.Location(args['latitude'], args['longitude']) |
|---|
| 109 | | |
|---|
| 110 | | # Migurski : "coordinate.zoomTo() returns a copy, |
|---|
| 111 | | # rather than modifying the coordinate in-place." |
|---|
| 112 | | |
|---|
| 113 | | coordinate = provider.locationCoordinate(loc) |
|---|
| 114 | | coordinate = coordinate.zoomTo(args['zoom']) |
|---|
| 115 | | |
|---|
| 116 | | coord, offset = ModestMaps.calculateMapCenter(provider, coordinate) |
|---|
| 117 | | dim = ModestMaps.Core.Point(args['width'], args['height']) |
|---|
| 118 | | |
|---|
| 119 | | map = ModestMaps.Map(provider, dim, coord, offset) |
|---|
| 120 | | |
|---|
| 121 | | img = map.draw() |
|---|
| 122 | | meta = None |
|---|
| 123 | | |
|---|
| 124 | | if args.has_key('filter') : |
|---|
| 125 | | img = self.apply_filtering(img, args['filter']) |
|---|
| 126 | | |
|---|
| 127 | | #if args.has_key('marker') : |
|---|
| 128 | | # self.add_marker(img, args) |
|---|
| 129 | | |
|---|
| 130 | | return (img, meta) |
|---|
| 131 | | |
|---|
| 132 | | # ########################################################## |
|---|
| 133 | | |
|---|
| 134 | | def pinwin(self) : |
|---|
| 135 | | |
|---|
| 136 | | return """iVBORw0KGgoAAAANSUhEUgAAAJ8AAACSCAYAAABbhRg+AAAACXBIWXMAAAsTAAALEwEAmpwYAAAK |
|---|
| 137 | | T2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AU |
|---|
| 138 | | kSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXX |
|---|
| 139 | | Pues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgAB |
|---|
| 140 | | eNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAt |
|---|
| 141 | | AGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3 |
|---|
| 142 | | AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dX |
|---|
| 143 | | Lh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+ |
|---|
| 144 | | 5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk |
|---|
| 145 | | 5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd |
|---|
| 146 | | 0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA |
|---|
| 147 | | 4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzA |
|---|
| 148 | | BhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/ph |
|---|
| 149 | | CJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5 |
|---|
| 150 | | h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+ |
|---|
| 151 | | Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhM |
|---|
| 152 | | WE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQ |
|---|
| 153 | | AkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+Io |
|---|
| 154 | | UspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdp |
|---|
| 155 | | r+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZ |
|---|
| 156 | | D5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61Mb |
|---|
| 157 | | U2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY |
|---|
| 158 | | /R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllir |
|---|
| 159 | | SKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79u |
|---|
| 160 | | p+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6Vh |
|---|
| 161 | | lWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1 |
|---|
| 162 | | mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lO |
|---|
| 163 | | k06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7Ry |
|---|
| 164 | | FDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3I |
|---|
| 165 | | veRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+B |
|---|
| 166 | | Z7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/ |
|---|
| 167 | | 0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5p |
|---|
| 168 | | DoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5q |
|---|
| 169 | | PNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIs |
|---|
| 170 | | OpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5 |
|---|
| 171 | | hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQ |
|---|
| 172 | | rAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9 |
|---|
| 173 | | rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1d |
|---|
| 174 | | T1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aX |
|---|
| 175 | | Dm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7 |
|---|
| 176 | | vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3S |
|---|
| 177 | | PVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKa |
|---|
| 178 | | RptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO |
|---|
| 179 | | 32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21 |
|---|
| 180 | | e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfV |
|---|
| 181 | | P1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i |
|---|
| 182 | | /suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8 |
|---|
| 183 | | IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAEZ0FNQQAAsY58+1GTAAAAIGNIUk0AAHolAACA |
|---|
| 184 | | gwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAz1SURBVHja7J1bbBzVHca/M+s4tnGaNIlR |
|---|
| 185 | | KMW11QuIS1FZHooEJa1URISKVKlqVUEr1D6gSqhSpTz0iRceKlXJQx77FFSKQvvSSjQhIoI2IWlC |
|---|
| 186 | | YahpHBMhUyc2hGTXu7M7u7bXe5nTh51xjk9mdmfvs+vvi452tbHX4/Fvv//lnDkjpJRQZZrm5heo |
|---|
| 187 | | tisejwueBUB48HnQTUxMYHJykmemQ1pcXEQymSSEHnymaUpC1xsItzKAhveE4HVXPN+A4bke1X1N |
|---|
| 188 | | TExs6Rzb4KeQ7tfzsEtRhI8ifBRF+CjCR1GEjyJ8FEX4KMJHUYSPInwURfgowkdRhI8ifBRF+CjC |
|---|
| 189 | | RxE+iiJ8FOGjKMJHET6KInwU4aMowkcRPooifBThoyjCRxE+iiJ8FOGjCB9FET6K8FEU4aMIH0UR |
|---|
| 190 | | PorwURThowgfRRE+ivBRFOGjCB9FET6K8FEU4aMIH0X4KIrwUYSPoggfRfgoivBRhI+iCB9F+CiK |
|---|
| 191 | | 8FH9oCGegt5LCBG5Y5JSEr6twt8AfyBkENCEr7/SH9nXnzAhIBUCCV80FGvGSSIuqTxuPBeupUop |
|---|
| 192 | | JeGLhrb1OXyyDngSgKP/P+GLhrY3CZ2MKIQqcI4C3gaEQghB+KKhkTa4TFTg80bFBa3iDqE8AgDD |
|---|
| 193 | | bkQ0NiCO5yjgVTTYvP8XDLvR0mibcqyoOF4FQBlASQu3QoWR8PUnfFFxP6nB5bjQlRWnU6Hb1Dwk |
|---|
| 194 | | fP2X80Xd8YQCXs3+JeGLhoY70O7oFnyqu0GrbIMG4YuQ+u3voIKkQ+fUGIQvgor1KXh6/04tNrzh |
|---|
| 195 | | vXYLgIQvGhJ9eMxSg86rbvVRVuBTFxmwz0f4GoYtyOlKAIrKKCnupzqe9BYXcDEp1Wgx42jgebCt |
|---|
| 196 | | K49+rueo4BE+qtnK1nM7z+HWNQCLfuDpb0j4qEYLDD2/08HTw+0GeFJbTUr4qEbAc0KCpzqeX+hm |
|---|
| 197 | | q4Vq2vGKAeD5VbdSBlwQQuejmgm1RZ8czxc81Jh5ofNRYStb3fX04kLP8QIdj85H1QLPb5VKvXAb |
|---|
| 198 | | 2vHofFQY8NSWSlO9vLrOt7i4yFPfA0XovDfjeIG9vLDX/BrxeFwkk0mS0AMlk0k8/PDDT0esyPDL |
|---|
| 199 | | 8YoI7uVtmreVMrTx3cz56H5b2vX8wNPDbVCOp85eSCFEaOcTHqWmaUoAmJiYwOTkJOnoIHRepImA |
|---|
| 200 | | 6/mBV9JCbSGgug3VywsFnycPwjDqFqjqH2wQFJFQW6uX54FWUABsqLINw6JoZTci0zSvTk9PT+7e |
|---|
| 201 | | vbuj4C0sLHy8f//+X7tpgoGbS5AEqHaBV/EJsyp4ej+vace7JedrUs900pHy+Tzm5+dnCV5HKlvU |
|---|
| 202 | | CLcqgIHTZmqOp49uwHc+n8+ny+VyR86SZVm4fPnyaYLXsZZK0GLQda3K9c3xpJQIGh2HLx6PVwCc |
|---|
| 203 | | tG27/WdJSty4ccM5duzYBYLXEfCcEOD5NpFrOV43nQ8ATudyuY6EXMuyLp09ezat5qhkqGUAa81e |
|---|
| 204 | | BIGn9/LqjjBqx/RaR5zPsizMzc29g4Cr3am2VbYlnzCrwufbywsTuTrufPF4fLFYLF5cW1tra8hN |
|---|
| 205 | | JBLOyy+/fI7QtQ26oAWhfs7nuyC0Xp7XC+cDgFO2bT8wOjraljfL5XJIpVIfzszMZLsAnxxw+IDa |
|---|
| 206 | | C0L9Zi8CK9tGDKQbOR8AvN3OvM+yLMzOzp7xOYGdcoQghxiEoV/IXW9BaMUPvLCO1wvnezubza45 |
|---|
| 207 | | jjNqGK3xLKVEMpl0jh49eg6b9wARCoCiTW6ggtgp0KMQdvWWyjqCF4T6zl40ujt9GADbAl88Hl8z |
|---|
| 208 | | TfPtXC731M6dO1t6L9u2kUql3rt06VJGabEYbah4dbAc1N7IRg4IfPoSqaAFoeUgx+uU2rmY9Gw+ |
|---|
| 209 | | n28ZPrfKfcs9EVIBT+31yQYhDNorWCo/xxlAAPVmcqlGVXvLMvhmHK/rzufqeDab/d2dd97Z9Bs4 |
|---|
| 210 | | joNkMrn+6quvvuOelBg2b6JjNOh+QbuiO1pu47eRzSCAV2txaK0mcmiAIuF88Xj8ommai8VicXJ4 |
|---|
| 211 | | uLnt5mzbhm3bF0zTXHaPTc3xRBMnHzWgK2uPemthENwvaDZDdTvfXl4rrtcL5/Oq3uf27NnTdMi9 |
|---|
| 212 | | evXqcfdTKRW383a5DBNua7ldWfsjlH0SbWcAnM/vgxf0ofO9uLsf7712yrbtpuBzHAepVKpw+PDh |
|---|
| 213 | | E0qVG9NOTDvczm8LL939+tnxZEBLKSjV8N01tNV7r/XC+U6m0+nK1NRUrNGDz2azWFtbe2tubi6P |
|---|
| 214 | | 6k1RGsm//CpZPdyo+U69PeTkgMCHGv1LfXNH2Sg8kXK+eDyeNk3z/MrKyqPj4+MNh9xkMvlXnxNR |
|---|
| 215 | | L98L43bqjkrqowekX2MVAwIfUH9/5Fu+px+dz2u5NASf4zhIp9OFI0eOnNKA8xth3a6iuVvRx/nK |
|---|
| 216 | | CLGV14C4X1ARJZuFJ2o5n9dy+e2+fftCf0Mmk0GxWPz7mTNniqjeFsBQ2iz6QtJa7QR1VW45ALqg |
|---|
| 217 | | 5UIOBm+GIwyQvupX5/NWN+8eGgr39pZlIZFI/M2FbUgZHoC689W63ZLf/KXudvqlf4MQbhsNxS3D |
|---|
| 218 | | 06ravleLu7r5dD6fD/X1lUoFlmXZhw4dOqtAt62O86k3llOLCe+ClwKANeW5PpepV7gyaqNVtVo4 |
|---|
| 219 | | 1Vup3I6VzJ3aq+WUbds/3LVrV6iQWygUTp47d66M6m2gtmnOp0+ryRBu51dY6A1VBx2cSmvVOdp4 |
|---|
| 220 | | m/meHH8v4TuezWZDh9ylpaXXXegaBS9omZCe25V9wiw6GWq7kTN18ud34/hFpwg3TfPSfffdd+/I |
|---|
| 221 | | SPBtxcrlMmZmZqwDBw58a3l5edgtNkbcPt8wNs/t+s1TlmtAV6uo6HhhQefrnfMB1QuLasKXyWSw |
|---|
| 222 | | urr6xvLysqE5n+p6fh36ei2UUi/cjs7X+2pXDb2/mpiYqBly5+fnj/tUuIYGil+YLcJ/hUa9uVrZ |
|---|
| 223 | | D85B52tNNVc3l8tlZDKZzMGDB98L6XgeXH7QBc3R9mx9Hp2ve9dw+LVc1gD8e2VlJdD1crnc65Zl |
|---|
| 224 | | iQDwHGxeeau2UfQWStBS8J7N1TZ6zYM+utHq6OTx99r5gOo1vY/v2LHDF77Z2dk3tHArtB5eBcEz |
|---|
| 225 | | FUFFRSRWI9P5euh8AFAqlU74tVxKpRKy2ez1F198ccYnx9MvdCkEjHX4LwGPxMoUOh96C98jjzxy |
|---|
| 226 | | cW1t7XqpVLrF9TKZzJsumH7g6aFWna0IswS859NkrcLTjT9+J4+/62FX+6Gi8J2jTywsrGZy07l9 |
|---|
| 227 | | 6h5+lmVh/eTHn/rkeDIg1KpDndmQ3W6hsNqNeLUr978y5Uj5AoDn9/wrPZ6NZ+HBVywWsbqUwtfO |
|---|
| 228 | | rvzm+AMHv/KnG+deO5Y4/yk2z9XqfbyuT48x5+vDPp8L3ksAnpWQGP/IxuJyClNTUxBCwLIsDP8n |
|---|
| 229 | | CQPG6NTI3md+vu/ROxw4R/6cePcT1F/m3pOGMZ2vM+pEzveCEHi2SoaEsVrByOcFeBsJWZaFYTMJ |
|---|
| 230 | | IYCYMDA1svd7P5749i/cwmMd/vuH1KtoI6etkPNFCj65/5UnADyPTbYkMXbZhm3bKBaLKHyaxvDV |
|---|
| 231 | | PGIwMCRiGBZD+Ob4XQdemv7RU27+V6gBnkSfXGOxFardSOV8jpRPCoFxKavQebptzobltlxG319G |
|---|
| 232 | | TBgQEBACMGDAEGL43tu+9ASAEwAs+N/noa9WGW+FnK/VY2wvfHAejfmY6diVFXyWsuE4DnZ8kMaQ |
|---|
| 233 | | iG0slIoJAzEITG+//R4AXwbwOYBV9Pn2Fcz5ugxfTBh3+55IBxj9JIfi3iJGrxUgPedz4TOEgbtG |
|---|
| 234 | | 9uxx4buohdi+go7O1yP43FRl8y/h/hufs1HauQ1Dwrj5uhAwIBATBsqiIgDsBTCmgqduk9RrN6Dz |
|---|
| 235 | | Rdj51pzi/8Ziww8KAUAKCMjq/mZC4Asf5VHZXi0yPPgMITYelwqpFQDjuLlHi+w34Oh8PYQvVcrP |
|---|
| 236 | | jMV2P6i6niGqj9st914dG/C55bz7dR/kr2TVMOv3i9H56HyB+mj12ul9wzt/us2IDXvweSlbTAht |
|---|
| 237 | | yymxAWhBFitvpmevA8gBWJd+8ZvON3DO19Y+35P//f3JC/b8P6sH7w6IajsFRjW/23jmhl0BvJZ4 |
|---|
| 238 | | 99qxxPkFAAkA+aAmaz+Jfb4uOx+A/B8+/8cfAUw+tuvuezwI1TCs63hq5sbhpRMLbovlCoA8nW9r |
|---|
| 239 | | OF9br14TQsQA3PX9L97/k1/e8fjPnt770D2jxnAsoDipvJa4cO3Q0onFuZXP5gG8A+AtAEsAKsz5 |
|---|
| 240 | | Bj/nazd8cFsl3wDw2HP7HvvBd3fd+/WHdkztnh6ZGAOAhUJy9f3cQvaN9IfpvyTevQ7gOgDThe9j |
|---|
| 241 | | VBvMfRdmqWjAJ9yWyVcBxAHcD+AO97Xt7peuA8i7oXbWhe8T9zVJ+AhfK6FCoLr1xe0uhFPuc+9i |
|---|
| 242 | | jpxbXFxxoUugulq5a5tRU4MLn6eYG4bH3eHtFF50XS7vhtlKL3IOqrf6/wBfX9fxU9N0oAAAAABJ |
|---|
| 243 | | RU5ErkJggg==""" |
|---|
| 244 | | |
|---|
| 245 | | return pw |
|---|
| 246 | | |
|---|
| 247 | | # ########################################################## |
|---|
| 248 | | |
|---|
| 249 | | def get_marker (self, args) : |
|---|
| 250 | | |
|---|
| 251 | | # sort of pointless in a CGI-context |
|---|
| 252 | | # but think of the ponies... |
|---|
| 253 | | |
|---|
| 254 | | if not self.__mrk : |
|---|
| 255 | | pw = self.pinwin() |
|---|
| 256 | | self.__mrk = Image.open(StringIO.StringIO(base64.decodestring(pw))) |
|---|
| 257 | | |
|---|
| 258 | | return self.__mrk |
|---|
| 259 | | |
|---|
| 260 | | # ########################################################## |
|---|
| 261 | | |
|---|
| 262 | | def apply_filtering (self, img, filter) : |
|---|
| 263 | | |
|---|
| 264 | | return self.apply_atkinson_dithering(img) |
|---|
| 265 | | |
|---|
| 266 | | # ########################################################## |
|---|
| 267 | | |
|---|
| 268 | | # |
|---|
| 269 | | # http://mike.teczno.com/notes/atkinson.html |
|---|
| 270 | | # |
|---|
| 271 | | |
|---|
| 272 | | def apply_atkinson_dithering(self, img) : |
|---|
| 273 | | |
|---|
| 274 | | img = img.convert('L') |
|---|
| 275 | | |
|---|
| 276 | | threshold = 128*[0] + 128*[255] |
|---|
| 277 | | |
|---|
| 278 | | for y in range(img.size[1]): |
|---|
| 279 | | for x in range(img.size[0]): |
|---|
| 280 | | |
|---|
| 281 | | old = img.getpixel((x, y)) |
|---|
| 282 | | new = threshold[old] |
|---|
| 283 | | err = (old - new) >> 3 # divide by 8 |
|---|
| 284 | | |
|---|
| 285 | | img.putpixel((x, y), new) |
|---|
| 286 | | |
|---|
| 287 | | for nxy in [(x+1, y), (x+2, y), (x-1, y+1), (x, y+1), (x+1, y+1), (x, y+2)]: |
|---|
| 288 | | try: |
|---|
| 289 | | img.putpixel(nxy, img.getpixel(nxy) + err) |
|---|
| 290 | | except IndexError: |
|---|
| 291 | | pass |
|---|
| 292 | | |
|---|
| 293 | | return img.convert('RGBA') |
|---|
| 294 | | |
|---|
| 295 | | # ########################################################## |
|---|
| 296 | | |
|---|
| 297 | | def add_marker(self, img, args) : |
|---|
| 298 | | |
|---|
| 299 | | (x, y) = img.size |
|---|
| 300 | | marker = self.get_marker() |
|---|
| 301 | | |
|---|
| 302 | | if args['provider'] == args['marker'] : |
|---|
| 303 | | offset = 75 / 2 |
|---|
| 304 | | nw = (x / 2) - offset |
|---|
| 305 | | se = (y / 2) + offset |
|---|
| 306 | | thumb = img.crop((nw, nw, se, se)) |
|---|
| 307 | | |
|---|
| 308 | | else : |
|---|
| 309 | | args['height'] = 75 |
|---|
| 310 | | args['width'] = 75 |
|---|
| 311 | | args['provider'] = args['marker'] |
|---|
| 312 | | args['marker'] = '' |
|---|
| 313 | | args['dither'] = 0 |
|---|
| 314 | | thumb = self.draw_map(args) |
|---|
| 315 | | |
|---|
| 316 | | # |
|---|
| 317 | | |
|---|
| 318 | | marker.paste(thumb, (11, 10)) |
|---|
| 319 | | |
|---|
| 320 | | x = (x / 2) - 28 |
|---|
| 321 | | y = (y / 2) - 134 |
|---|
| 322 | | |
|---|
| 323 | | img.paste(marker, (x, y), marker) |
|---|
| 324 | | |
|---|
| 325 | | # ########################################################## |
|---|
| 326 | | |
|---|
| 327 | | def add_markers (self, mmap, img, args) : |
|---|
| 328 | | |
|---|
| 329 | | # note the mmap-iness of the 'map' object |
|---|
| 330 | | # apparently python is too stupid not to |
|---|
| 331 | | # confuse it with its own 'map' function... |
|---|
| 332 | | |
|---|
| 333 | | coords = {} |
|---|
| 334 | | |
|---|
| 335 | | for details in args['markers'] : |
|---|
| 336 | | res = self.add_marker2(mmap, img, details) |
|---|
| 337 | | |
|---|
| 338 | | label = "Marker-%s" % details['label'] |
|---|
| 339 | | |
|---|
| 340 | | if res : |
|---|
| 341 | | coords[label] = ",".join(map(str, res)) |
|---|
| 342 | | else : |
|---|
| 343 | | coords[label] = "FAIL" |
|---|
| 344 | | |
|---|
| 345 | | return coords |
|---|
| 346 | | |
|---|
| 347 | | # ########################################################## |
|---|
| 348 | | |
|---|
| 349 | | def add_marker2(self, map, img, args) : |
|---|
| 350 | | |
|---|
| 351 | | try : |
|---|
| 352 | | loc = ModestMaps.Geo.Location(args['latitude'], args['longitude']) |
|---|
| 353 | | pt = map.locationPoint(loc) |
|---|
| 354 | | except Exception, e : |
|---|
| 355 | | print "OH NOES %s" % e |
|---|
| 356 | | return False |
|---|
| 357 | | |
|---|
| 358 | | marker = self.get_marker(args) |
|---|
| 359 | | |
|---|
| 360 | | if args.has_key('fill') : |
|---|
| 361 | | marker = self.fill_marker(img, marker, args) |
|---|
| 362 | | |
|---|
| 363 | | x = int(pt.x) |
|---|
| 364 | | y = int(pt.y) |
|---|
| 365 | | |
|---|
| 366 | | mx = x - 28 |
|---|
| 367 | | my = y - 134 |
|---|
| 368 | | |
|---|
| 369 | | img.paste(marker, (mx, my), marker) |
|---|
| 370 | | return (x, y, mx, my) |
|---|
| 371 | | |
|---|
| 372 | | # ########################################################## |
|---|
| 373 | | |
|---|
| 374 | | def fill_marker(self, img, marker, args) : |
|---|
| 375 | | |
|---|
| 376 | | if args['provider'] == args['marker'] : |
|---|
| 377 | | offset = 75 / 2 |
|---|
| 378 | | nw = (x / 2) - offset |
|---|
| 379 | | se = (y / 2) + offset |
|---|
| 380 | | thumb = img.crop((nw, nw, se, se)) |
|---|
| 381 | | |
|---|
| 382 | | else : |
|---|
| 383 | | args['height'] = 75 |
|---|
| 384 | | args['width'] = 75 |
|---|
| 385 | | args['provider'] = args['marker'] |
|---|
| 386 | | args['marker'] = '' |
|---|
| 387 | | args['dither'] = 0 |
|---|
| 388 | | thumb = self.draw_map(args) |
|---|
| 389 | | |
|---|
| 390 | | # |
|---|
| 391 | | |
|---|
| 392 | | marker.paste(thumb, (11, 10)) |
|---|
| 393 | | return marker |
|---|
| 394 | | |
|---|
| 395 | | # ########################################################## |
|---|
| 396 | | |
|---|
| 397 | | def send_map (self, img, meta) : |
|---|
| 398 | | |
|---|
| 399 | | # Oh PIL, why don't you have a 'tostringDWIM' method? |
|---|
| 400 | | |
|---|
| 401 | | fh = StringIO.StringIO() |
|---|
| 402 | | img.save(fh, "PNG") |
|---|
| 403 | | |
|---|
| 404 | | self.send_response(200, "OK") |
|---|
| 405 | | self.send_header("Content-Type", "image/png") |
|---|
| 406 | | self.send_header("Content-Length", fh.len) |
|---|
| 407 | | self.send_header("X-Image-Height", img.size[1]) |
|---|
| 408 | | self.send_header("X-Image-Width", img.size[0]) |
|---|
| 409 | | |
|---|
| 410 | | if meta : |
|---|
| 411 | | for item in meta.keys() : |
|---|
| 412 | | header = "X-%s" % item |
|---|
| 413 | | self.send_header(header, meta[item]) |
|---|
| 414 | | |
|---|
| 415 | | self.end_headers() |
|---|
| 416 | | |
|---|
| 417 | | self.wfile.write(fh.getvalue()) |
|---|
| 418 | | return |
|---|
| 419 | | |
|---|
| 420 | | |
|---|
| 421 | | # ########################################################## |
|---|
| 422 | | |
|---|
| 423 | | def load_provider (self, value) : |
|---|
| 424 | | |
|---|
| 425 | | # Please for this method to be in MM itself... |
|---|
| 426 | | |
|---|
| 427 | | if value == 'MICROSOFT_ROAD': |
|---|
| 428 | | return ModestMaps.Microsoft.RoadProvider() |
|---|
| 429 | | |
|---|
| 430 | | elif value == 'MICROSOFT_AERIAL': |
|---|
| 431 | | return ModestMaps.Microsoft.AerialProvider() |
|---|
| 432 | | |
|---|
| 433 | | elif value == 'MICROSOFT_HYBRID': |
|---|
| 434 | | return ModestMaps.Microsoft.HybridProvider() |
|---|
| 435 | | |
|---|
| 436 | | elif value == 'GOOGLE_ROAD': |
|---|
| 437 | | return ModestMaps.Google.RoadProvider() |
|---|
| 438 | | |
|---|
| 439 | | elif value == 'GOOGLE_AERIAL': |
|---|
| 440 | | return ModestMaps.Google.AerialProvider() |
|---|
| 441 | | |
|---|
| 442 | | elif value == 'GOOGLE_HYBRID': |
|---|
| 443 | | return ModestMaps.Google.HybridProvider() |
|---|
| 444 | | |
|---|
| 445 | | elif value == 'YAHOO_ROAD': |
|---|
| 446 | | return ModestMaps.Yahoo.RoadProvider() |
|---|
| 447 | | |
|---|
| 448 | | elif value == 'YAHOO_AERIAL': |
|---|
| 449 | | return ModestMaps.Yahoo.AerialProvider() |
|---|
| 450 | | |
|---|
| 451 | | elif value == 'YAHOO_HYBRID': |
|---|
| 452 | | return ModestMaps.Yahoo.HybridProvider() |
|---|
| 453 | | |
|---|
| 454 | | else : |
|---|
| 455 | | return None |
|---|
| 456 | | |
|---|
| 457 | | # ########################################################## |
|---|
| 458 | | |
|---|
| 459 | | def validate_params (self, params) : |
|---|
| 460 | | |
|---|
| 461 | | if len(params.keys()) == 0 : |
|---|
| 462 | | self.help() |
|---|
| 463 | | return False |
|---|
| 464 | | |
|---|
| 465 | | # |
|---|
| 466 | | # I am a blank canvas |
|---|
| 467 | | # |
|---|
| 468 | | |
|---|
| 469 | | valid = {} |
|---|
| 470 | | |
|---|
| 471 | | # |
|---|
| 472 | | # Seeking love and affection... |
|---|
| 473 | | # |
|---|
| 474 | | |
|---|
| 475 | | re_coord = re.compile(r"^-?\d+(?:\.\d+)?$") |
|---|
| 476 | | re_num = re.compile(r"^\d+$") |
|---|
| 477 | | re_label = re.compile(r"^(?:[a-z0-9-_]+)$") |
|---|
| 478 | | re_provider = re.compile(r"^(GOOGLE|YAHOO|MICROSOFT)_(ROAD|HYBRID|AERIAL)$") |
|---|
| 479 | | |
|---|
| 480 | | # |
|---|
| 481 | | # Where am i? |
|---|
| 482 | | # |
|---|
| 483 | | |
|---|
| 484 | | if params.has_key('bbox') : |
|---|
| 485 | | |
|---|
| 486 | | bbox = params['bbox'][0].split(",") |
|---|
| 487 | | |
|---|
| 488 | | if len(bbox) != 4 : |
|---|
| 489 | | self.error(101, "Missing or incomplete %s parameter" % 'bbox') |
|---|
| 490 | | return False |
|---|
| 491 | | |
|---|
| 492 | | bbox = map(string.strip, bbox) |
|---|
| 493 | | |
|---|
| 494 | | for pt in bbox : |
|---|
| 495 | | if not re_coord.match(pt) : |
|---|
| 496 | | self.error(102, "Not a valid lat/long : %s" % pt) |
|---|
| 497 | | return False |
|---|
| 498 | | |
|---|
| 499 | | valid['bbox'] = map(float, bbox) |
|---|
| 500 | | |
|---|
| 501 | | else : |
|---|
| 502 | | |
|---|
| 503 | | for p in ('latitude', 'longitude') : |
|---|
| 504 | | |
|---|
| 505 | | if not params.has_key(p) : |
|---|
| 506 | | self.error(101, "Missing %s parameter" % p) |
|---|
| 507 | | return False |
|---|
| 508 | | |
|---|
| 509 | | if not re_coord.match(params[p][0]) : |
|---|
| 510 | | self.error(102, "Not a valid lat/long : %s" % p) |
|---|
| 511 | | return False |
|---|
| 512 | | |
|---|
| 513 | | valid[p] = float(params[p][0]) |
|---|
| 514 | | |
|---|
| 515 | | # |
|---|
| 516 | | |
|---|
| 517 | | if not params.has_key('accuracy') : |
|---|
| 518 | | self.error(101, "Missing %s parameter" % 'accuracy') |
|---|
| 519 | | return False |
|---|
| 520 | | |
|---|
| 521 | | if not re_num.match(params['accuracy'][0]) : |
|---|
| 522 | | self.error(102, "Not a valid number %s" % 'accuracy') |
|---|
| 523 | | return False |
|---|
| 524 | | |
|---|
| 525 | | valid['zoom'] = float(params['accuracy'][0]) |
|---|
| 526 | | |
|---|
| 527 | | # |
|---|
| 528 | | # dimensions |
|---|
| 529 | | # |
|---|
| 530 | | |
|---|
| 531 | | for p in ('height', 'width') : |
|---|
| 532 | | |
|---|
| 533 | | if not params.has_key(p) : |
|---|
| 534 | | self.error(101, "Missing %s parameter" % p) |
|---|
| 535 | | return False |
|---|
| 536 | | |
|---|
| 537 | | if not re_num.match(params[p][0]) : |
|---|
| 538 | | self.error(102, "Not a valid number %s" % p) |
|---|
| 539 | | return False |
|---|
| 540 | | |
|---|
| 541 | | valid[p] = int(params[p][0]) |
|---|
| 542 | | |
|---|
| 543 | | # |
|---|
| 544 | | # map provider |
|---|
| 545 | | # |
|---|
| 546 | | |
|---|
| 547 | | if not params.has_key('provider') : |
|---|
| 548 | | self.error(101, "Missing %s parameter" % p) |
|---|
| 549 | | return False |
|---|
| 550 | | |
|---|
| 551 | | if not re_provider.match(params['provider'][0].upper()) : |
|---|
| 552 | | self.error(102, "Not a valid provider") |
|---|
| 553 | | return False |
|---|
| 554 | | |
|---|
| 555 | | valid['provider'] = params['provider'][0].upper() |
|---|
| 556 | | |
|---|
| 557 | | # |
|---|
| 558 | | # markers? |
|---|
| 559 | | # |
|---|
| 560 | | |
|---|
| 561 | | #if params.has_key('marker') : |
|---|
| 562 | | # if not re_provider.match(params['marker'][0].upper()) : |
|---|
| 563 | | # self.error(102, "Not a valid marker provider") |
|---|
| 564 | | # return False |
|---|
| 565 | | # |
|---|
| 566 | | # valid['marker'] = params['marker'][0] |
|---|
| 567 | | |
|---|
| 568 | | # |
|---|
| 569 | | # markers? (the new new) |
|---|
| 570 | | # |
|---|
| 571 | | |
|---|
| 572 | | #if params.has_key('markers') : |
|---|
| 573 | | # |
|---|
| 574 | | # valid['markers'] = [] |
|---|
| 575 | | # |
|---|
| 576 | | # for pos in params['markers'] : |
|---|
| 577 | | # |
|---|
| 578 | | # marker_data = {} |
|---|
| 579 | | # |
|---|
| 580 | | # details = pos.split(",") |
|---|
| 581 | | # details = map(string.strip, details) |
|---|
| 582 | | # |
|---|
| 583 | | # if len(details) < 3 : |
|---|
| 584 | | # self.error(101, "Missing or incomplete %s parameter : %s" % ('marker', pos)) |
|---|
| 585 | | # return False |
|---|
| 586 | | # |
|---|
| 587 | | # if not re_label.match(details[0]) : |
|---|
| 588 | | # self.error(102, "Not a valid marker label : %s" % pos) |
|---|
| 589 | | # return False |
|---|
| 590 | | # |
|---|
| 591 | | # marker_data['label'] = unicode(details[0]) |
|---|
| 592 | | # |
|---|
| 593 | | # if not re_coord.match(details[1]) : |
|---|
| 594 | | # self.error(102, "Not a valid lat/long : %s" % pos) |
|---|
| 595 | | # return False |
|---|
| 596 | | # |
|---|
| 597 | | # marker_data['latitude'] = float(details[1]) |
|---|
| 598 | | # |
|---|
| 599 | | # if not re_coord.match(details[2]) : |
|---|
| 600 | | # self.error(102, "Not a valid lat/long : %s" % pos) |
|---|
| 601 | | # return False |
|---|
| 602 | | # |
|---|
| 603 | | # marker_data['longitude'] = float(details[2]) |
|---|
| 604 | | # |
|---|
| 605 | | # if len(details) > 3 : |
|---|
| 606 | | # |
|---|
| 607 | | # if not re_provider.match(details[3].upper()) : |
|---|
| 608 | | # self.error(102, "Not a valid marker provider") |
|---|
| 609 | | # return False |
|---|
| 610 | | # |
|---|
| 611 | | # marker_data['fill'] = unicode(details[3]) |
|---|
| 612 | | # |
|---|
| 613 | | # valid['markers'].append(marker_data) |
|---|
| 614 | | |
|---|
| 615 | | # |
|---|
| 616 | | # filters |
|---|
| 617 | | # |
|---|
| 618 | | |
|---|
| 619 | | if params.has_key('filter') and params['filter'][0]: |
|---|
| 620 | | valid['filter'] = params['filter'][0] |
|---|
| 621 | | |
|---|
| 622 | | # |
|---|
| 623 | | # whoooosh |
|---|
| 624 | | # |
|---|
| 625 | | |
|---|
| 626 | | # print valid |
|---|
| 627 | | return valid |
|---|
| 628 | | |
|---|
| 629 | | # ########################################################## |
|---|
| 630 | | |
|---|
| 631 | | def help (self) : |
|---|
| 632 | | |
|---|
| 633 | | self.send_response(200, "OK") |
|---|
| 634 | | self.send_header("Content-Type", "text/plain") |
|---|
| 635 | | self.end_headers() |
|---|
| 636 | | |
|---|
| 637 | | self.wfile.write("ws-compose.py - a bare bone HTTP interface to the ModestMaps map tile composer.\n\n") |
|---|
| 638 | | |
|---|
| 639 | | self.help_header("Example") |
|---|
| 640 | | #self.help_para("http://127.0.0.1:9999/?provider=GOOGLE_ROAD&marker=YAHOO_AERIAL&latitude=41.904688&longitude=12.494308&accuracy=17&height=500&width=500") |
|---|
| 641 | | self.help_para("http://127.0.0.1:9999/?provider=GOOGLE_ROAD&latitude=41.904688&longitude=12.494308&accuracy=17&height=500&width=500") |
|---|
| 642 | | self.help_para("Returns a PNG file of a map centered on the Santa Maria della Vittoria, in Rome.") |
|---|
| 643 | | |
|---|
| 644 | | self.help_header("Parameters") |
|---|
| 645 | | self.help_option('provider', 'A valid ModestMaps map tile provider.', True) |
|---|
| 646 | | #self.help_option('marker', 'A valid ModestMaps map tile provider. Used to overlay a "pinwin" marker over the chosen lat/lon point', False) |
|---|
| 647 | | self.help_option('latitude','A valid decimal latitude.', True) |
|---|
| 648 | | self.help_option('longitude', 'A valid decimal longitude.', True) |
|---|
| 649 | | self.help_option('accuracy', 'The zoom level / accuracy (as defined by ModestMaps rather than any individual tile provider) of the final image.', True) |
|---|
| 650 | | self.help_option('height', 'The height of the final image', True) |
|---|
| 651 | | self.help_option('width', 'The width of the final image', True) |
|---|
| 652 | | |
|---|
| 653 | | self.help_header("Errors") |
|---|
| 654 | | self.help_para("Errors are returned with the HTTP status code 500. Specific error codes and messages are returned both in the message body as XML and in the 'X-ErrorCode' and 'X-ErrorMessage' headers.") |
|---|
| 655 | | |
|---|
| 656 | | self.help_header("Notes") |
|---|
| 657 | | self.help_para("Currently, ws-compose only supports 'centered' maps; map images based on their geographic extent (bounding box) are not available at this time") |
|---|
| 658 | | |
|---|
| 659 | | self.help_header("Questions") |
|---|
| 660 | | self.help_qa("Is it fast?", "Not really. It is designed, primarily, to be run on the same machine that is calling the interface.") |
|---|
| 661 | | self.help_qa("Will it ever be fast?", "Sure. It is on The List (tm) to create a mod_python and/or wsgi version. Patches are welcome.") |
|---|
| 662 | | self.help_qa("Can I request map images asynchronously?", "Not yet.") |
|---|
| 663 | | self.help_qa("Can I get a pony?", "No.") |
|---|
| 664 | | |
|---|
| 665 | | self.help_header("License") |
|---|
| 666 | | self.help_para("Copyright (c) 2007 Aaron Straup Cope. All Rights Reserved. This is free software. You may redistribute it and/or modify it under the same terms the Perl Artistic License.") |
|---|
| 667 | | |
|---|
| 668 | | # ########################################################## |
|---|
| 669 | | |
|---|
| 670 | | def help_para(self, text) : |
|---|
| 671 | | |
|---|
| 672 | | self.wfile.write(textwrap.fill(text, 72)) |
|---|
| 673 | | self.wfile.write("\n\n") |
|---|
| 674 | | |
|---|
| 675 | | def help_header(self, title) : |
|---|
| 676 | | ln = "-" * 72 |
|---|
| 677 | | self.wfile.write("%s\n" % ln); |
|---|
| 678 | | self.wfile.write("%s\n" % title.upper()) |
|---|
| 679 | | self.wfile.write("%s\n\n" % ln); |
|---|
| 680 | | |
|---|
| 681 | | def help_option(self, opt, desc, required) : |
|---|
| 682 | | |
|---|
| 683 | | present = "required" |
|---|
| 684 | | |
|---|
| 685 | | if not required : |
|---|
| 686 | | present = "optional" |
|---|
| 687 | | |
|---|
| 688 | | self.wfile.write("* %s (%s)\n\n%s\n\n" % (opt, present, textwrap.fill(desc, 72, initial_indent="\t", subsequent_indent="\t"))) |
|---|
| 689 | | |
|---|
| 690 | | def help_qa(self, question, answer) : |
|---|
| 691 | | self.wfile.write("%s\n\n" % question) |
|---|
| 692 | | self.wfile.write("%s\n\n" % textwrap.fill(answer, 72, initial_indent="\t", subsequent_indent="\t")) |
|---|
| 693 | | |
|---|
| 694 | | # ########################################################## |
|---|
| 695 | | |
|---|
| 696 | | def error (self, err_code=999, err_msg="OH NOES!!! INVISIBLE ERRORZ!!!") : |
|---|
| 697 | | |
|---|
| 698 | | err_code = self.sanitize(err_code) |
|---|
| 699 | | err_msg = self.sanitize(err_msg) |
|---|
| 700 | | |
|---|
| 701 | | self.send_response(500, "Server Error") |
|---|
| 702 | | self.send_header("Content-Type", "application/xml") |
|---|
| 703 | | self.send_header("X-ErrorCode", err_code) |
|---|
| 704 | | self.send_header("X-ErrorMessage", err_msg) |
|---|
| 705 | | self.end_headers() |
|---|
| 706 | | self.wfile.write("<?xml version=\"1.0\" ?><error code=\"%s\">%s</error>" % (err_code, err_msg)) |
|---|
| 707 | | |
|---|
| 708 | | # ########################################################## |
|---|
| 709 | | |
|---|
| 710 | | def sanitize (self, str) : |
|---|
| 711 | | return escape(unicode(str)) |
|---|
| 712 | | |
|---|
| 713 | | # ############################################################## |
|---|
| 714 | | |
|---|
| 715 | | def serve(port): |
|---|
| 716 | | signal.signal(signal.SIGINT, terminate) |
|---|
| 717 | | thread.start_new_thread(runServer, (port,)) |
|---|
| 718 | | |
|---|
| 719 | | global done |
|---|
| 720 | | while not done: |
|---|
| 721 | | try: |
|---|
| 722 | | time.sleep(0.3) |
|---|
| 723 | | except IOError: |
|---|
| 724 | | pass |
|---|
| 725 | | |
|---|
| 726 | | global server |
|---|
| 727 | | server.server_close() |
|---|
| 728 | | |
|---|
| 729 | | def runServer(port): |
|---|
| 730 | | |
|---|
| 731 | | url = "http://127.0.0.1:%s" % port |
|---|
| 732 | | print "ws-compose server running on port %s" % port |
|---|
| 733 | | print "documentation and usage is available at %s/\n\n" % url |
|---|
| 734 | | |
|---|
| 735 | | global server |
|---|
| 736 | | server = WebServer(("", port), WebRequestHandler) |
|---|
| 737 | | server.allow_reuse_address = True |
|---|
| 738 | | server.serve_forever() |
|---|
| 739 | | |
|---|
| 740 | | def terminate(sig_num, frame): |
|---|
| 741 | | global done |
|---|
| 742 | | done = True |
|---|
| 743 | | |
|---|
| 744 | | # ############################################################## |
|---|
| 745 | | |
|---|
| 746 | | if __name__ == "__main__": |
|---|
| 747 | | |
|---|
| 748 | | if len(sys.argv) >= 2 : |
|---|
| 749 | | port = int(sys.argv[1]) |
|---|
| 750 | | else : |
|---|
| 751 | | port = 9999 |
|---|
| 752 | | |
|---|
| 753 | | serve(port) |
|---|
| | 3 | if __name__ == "__main__" : |
|---|
| | 4 | app = wscompose.server(wscompose.handler) |
|---|
| | 5 | app.loop() |
|---|